ART: Change rrr add and sub for ARM64
OpRegRegImm will fall back to loading a constant into a register
and then doing the operation with three registers. That is, for
example, the case when we allocate large stack frames. However,
the currently chosen operations are add/sub shifted, which does
*not* allow to specify SP (x31 will be interpreted as xzr). Switch
to add/sub extended. There won't be a practical difference, as we
do not call with anything other than 0 shift.
Change-Id: I2b78df9f044d2963e3e890777c855b339952f9f4
diff --git a/compiler/dex/quick/arm64/utility_arm64.cc b/compiler/dex/quick/arm64/utility_arm64.cc
index 2254b8b..9b32a46 100644
--- a/compiler/dex/quick/arm64/utility_arm64.cc
+++ b/compiler/dex/quick/arm64/utility_arm64.cc
@@ -660,6 +660,7 @@
int32_t log_imm = -1;
bool is_wide = r_dest.Is64Bit();
ArmOpcode wide = (is_wide) ? WIDE(0) : UNWIDE(0);
+ int info = 0;
switch (op) {
case kOpLsl: {
@@ -692,7 +693,14 @@
return NewLIR4(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), abs_value >> 12, 1);
} else {
log_imm = -1;
- alt_opcode = (neg) ? kA64Add4rrro : kA64Sub4rrro;
+ alt_opcode = (neg) ? kA64Add4rrre : kA64Sub4rrre;
+ // To make it correct, we need:
+ // 23..21 = 001 = extend
+ // 15..13 = 01x = LSL/UXTW/X / x defines wide or not
+ // 12..10 = 000 = no shift (in case of SP)
+ // => info = 00101x000
+ // => =0x 0 5 (0/8)
+ info = (is_wide ? 8 : 0) | 0x50;
}
break;
// case kOpRsub:
@@ -734,7 +742,7 @@
if (log_imm >= 0) {
return NewLIR3(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), log_imm);
} else {
- RegStorage r_scratch = AllocTemp();
+ RegStorage r_scratch;
if (IS_WIDE(wide)) {
r_scratch = AllocTempWide();
LoadConstantWide(r_scratch, value);
@@ -743,7 +751,7 @@
LoadConstant(r_scratch, value);
}
if (EncodingMap[alt_opcode].flags & IS_QUAD_OP)
- res = NewLIR4(alt_opcode | wide, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg(), 0);
+ res = NewLIR4(alt_opcode | wide, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg(), info);
else
res = NewLIR3(alt_opcode | wide, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg());
FreeTemp(r_scratch);