Compiler/assembler fix
There are three Thumb encodings for push and pop, and one of
them (Thumb2/t2) requires at least two registers in the push/pop
list. This CL adds the single-register encoding (which is really
just another name for a standard base-modifying load/store).
Change-Id: I963c472a0d5f288654417dbd85758d6b5cc61388
diff --git a/src/compiler/codegen/arm/ArmLIR.h b/src/compiler/codegen/arm/ArmLIR.h
index daa1396..1e4022e 100644
--- a/src/compiler/codegen/arm/ArmLIR.h
+++ b/src/compiler/codegen/arm/ArmLIR.h
@@ -693,6 +693,8 @@
kThumb2SubsRRI12, /* setflags encoding */
kThumb2OrrRRRs, /* orrx [111010100101] rn[19..16] [0000] rd[11..8]
[0000] rm[3..0] */
+ kThumb2Push1, /* t3 encoding of push */
+ kThumb2Pop1, /* t3 encoding of pop */
kArmLast,
} ArmOpcode;
diff --git a/src/compiler/codegen/arm/Assemble.cc b/src/compiler/codegen/arm/Assemble.cc
index bbd97b4..af71efe 100644
--- a/src/compiler/codegen/arm/Assemble.cc
+++ b/src/compiler/codegen/arm/Assemble.cc
@@ -953,6 +953,16 @@
kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
"orrs", "!0C, !1C, !2C!3H", 2),
+ ENCODING_MAP(kThumb2Push1, 0xf84d0d04,
+ kFmtBitBlt, 15, 12, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1,
+ IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE0
+ | IS_STORE, "push1", "!0C", 2),
+ ENCODING_MAP(kThumb2Pop1, 0xf85d0b04,
+ kFmtBitBlt, 15, 12, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1,
+ IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF0
+ | IS_LOAD, "pop1", "!0C", 2),
};
@@ -1167,6 +1177,30 @@
} else {
lir->operands[1] = delta >> 1;
}
+ } else if (lir->opcode == kThumb2Push ||
+ lir->opcode == kThumb2Pop) {
+ if (__builtin_popcount(lir->operands[0]) == 1) {
+ /*
+ * The standard push/pop multiple instruction
+ * requires at least two registers in the list.
+ * If we've got just one, switch to the single-reg
+ * encoding.
+ */
+ lir->opcode = (lir->opcode == kThumb2Push)
+ ? kThumb2Push1 : kThumb2Pop1;
+ int reg = 0;
+ while (lir->operands[0]) {
+ if (lir->operands[0] & 0x1) {
+ break;
+ } else {
+ reg++;
+ lir->operands[0] >>= 1;
+ }
+ }
+ lir->operands[0] = reg;
+ oatSetupResourceMasks(lir);
+ res = kRetryAll;
+ }
} else if (lir->opcode == kThumbBCond ||
lir->opcode == kThumb2BCond) {
ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;