summaryrefslogtreecommitdiffstats
path: root/compiler
diff options
context:
space:
mode:
authorAndreas Gampe <agampe@google.com>2014-06-19 01:10:07 -0700
committerAndreas Gampe <agampe@google.com>2014-06-19 09:16:10 -0700
commit47b31aa855379471c06735b738396fa76e7c1988 (patch)
treedc3c4d0a3da150562a63e7b5c131e37586f45a50 /compiler
parent995b32cc8e94a9730d6cf663a23afc9c997c1771 (diff)
downloadart-47b31aa855379471c06735b738396fa76e7c1988.zip
art-47b31aa855379471c06735b738396fa76e7c1988.tar.gz
art-47b31aa855379471c06735b738396fa76e7c1988.tar.bz2
ART: Start implementation of OpRegRegRegExtend for ARM64
We need a sign-extending add for packed-switch and sparse-switch, as the 32b values are signed offsets. This starts an implementation that is sufficient for the use cases. Change-Id: Ib5bae24b902077346a97d5e9e061533f9cdfcdb0
Diffstat (limited to 'compiler')
-rw-r--r--compiler/dex/quick/arm64/arm64_lir.h4
-rw-r--r--compiler/dex/quick/arm64/assemble_arm64.cc8
-rw-r--r--compiler/dex/quick/arm64/call_arm64.cc7
-rw-r--r--compiler/dex/quick/arm64/codegen_arm64.h2
-rw-r--r--compiler/dex/quick/arm64/utility_arm64.cc50
5 files changed, 51 insertions, 20 deletions
diff --git a/compiler/dex/quick/arm64/arm64_lir.h b/compiler/dex/quick/arm64/arm64_lir.h
index 3a6012e..3f32c51 100644
--- a/compiler/dex/quick/arm64/arm64_lir.h
+++ b/compiler/dex/quick/arm64/arm64_lir.h
@@ -220,7 +220,7 @@ enum ArmOpcode {
kA64Adc3rrr = kA64First, // adc [00011010000] rm[20-16] [000000] rn[9-5] rd[4-0].
kA64Add4RRdT, // add [s001000100] imm_12[21-10] rn[9-5] rd[4-0].
kA64Add4rrro, // add [00001011000] rm[20-16] imm_6[15-10] rn[9-5] rd[4-0].
- kA64Add4rrre, // add [00001011001] rm[20-16] option[15-13] imm_3[12-10] rn[9-5] rd[4-0].
+ kA64Add4RRre, // add [00001011001] rm[20-16] option[15-13] imm_3[12-10] rn[9-5] rd[4-0].
kA64Adr2xd, // adr [0] immlo[30-29] [10000] immhi[23-5] rd[4-0].
kA64And3Rrl, // and [00010010] N[22] imm_r[21-16] imm_s[15-10] rn[9-5] rd[4-0].
kA64And4rrro, // and [00001010] shift[23-22] [N=0] rm[20-16] imm_6[15-10] rn[9-5] rd[4-0].
@@ -330,7 +330,7 @@ enum ArmOpcode {
kA64Stlxr3wrX, // stlxr[11001000000] rs[20-16] [111111] rn[9-5] rt[4-0].
kA64Sub4RRdT, // sub [s101000100] imm_12[21-10] rn[9-5] rd[4-0].
kA64Sub4rrro, // sub [s1001011000] rm[20-16] imm_6[15-10] rn[9-5] rd[4-0].
- kA64Sub4rrre, // sub [s1001011001] rm[20-16] option[15-13] imm_3[12-10] rn[9-5] rd[4-0].
+ kA64Sub4RRre, // sub [s1001011001] rm[20-16] option[15-13] imm_3[12-10] rn[9-5] rd[4-0].
kA64Subs3rRd, // subs[s111000100] imm_12[21-10] rn[9-5] rd[4-0].
kA64Tst3rro, // tst alias of "ands rzr, arg1, arg2, arg3".
kA64Ubfm4rrdd, // ubfm[s10100110] N[22] imm_r[21-16] imm_s[15-10] rn[9-5] rd[4-0].
diff --git a/compiler/dex/quick/arm64/assemble_arm64.cc b/compiler/dex/quick/arm64/assemble_arm64.cc
index fe3bd6a..2a8da24 100644
--- a/compiler/dex/quick/arm64/assemble_arm64.cc
+++ b/compiler/dex/quick/arm64/assemble_arm64.cc
@@ -115,10 +115,10 @@ const ArmEncodingMap Arm64Mir2Lir::EncodingMap[kA64Last] = {
kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtRegR, 20, 16,
kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE1,
"add", "!0r, !1r, !2r!3o", kFixupNone),
- ENCODING_MAP(WIDE(kA64Add4rrre), SF_VARIANTS(0x0b200000),
+ ENCODING_MAP(WIDE(kA64Add4RRre), SF_VARIANTS(0x0b200000),
kFmtRegROrSp, 4, 0, kFmtRegROrSp, 9, 5, kFmtRegR, 20, 16,
kFmtExtend, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
- "add", "!0r, !1r, !2r!3o", kFixupNone),
+ "add", "!0r, !1r, !2r!3e", kFixupNone),
// Note: adr is binary, but declared as tertiary. The third argument is used while doing the
// fixups and contains information to identify the adr label.
ENCODING_MAP(kA64Adr2xd, NO_VARIANTS(0x10000000),
@@ -562,10 +562,10 @@ const ArmEncodingMap Arm64Mir2Lir::EncodingMap[kA64Last] = {
kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtRegR, 20, 16,
kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
"sub", "!0r, !1r, !2r!3o", kFixupNone),
- ENCODING_MAP(WIDE(kA64Sub4rrre), SF_VARIANTS(0x4b200000),
+ ENCODING_MAP(WIDE(kA64Sub4RRre), SF_VARIANTS(0x4b200000),
kFmtRegROrSp, 4, 0, kFmtRegROrSp, 9, 5, kFmtRegR, 20, 16,
kFmtExtend, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
- "sub", "!0r, !1r, !2r!3o", kFixupNone),
+ "sub", "!0r, !1r, !2r!3e", kFixupNone),
ENCODING_MAP(WIDE(kA64Subs3rRd), SF_VARIANTS(0x71000000),
kFmtRegR, 4, 0, kFmtRegROrSp, 9, 5, kFmtBitBlt, 21, 10,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index d81091d..1df576b 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -95,8 +95,7 @@ void Arm64Mir2Lir::GenSparseSwitch(MIR* mir, uint32_t table_offset,
tab_rec->anchor = switch_label;
// Add displacement to base branch address and go!
- // TODO(Arm64): generate "add x1, x1, w3, sxtw" rather than "add x1, x1, x3"?
- OpRegRegRegShift(kOpAdd, r_base, r_base, As64BitReg(r_disp), ENCODE_NO_SHIFT);
+ OpRegRegRegExtend(kOpAdd, r_base, r_base, As64BitReg(r_disp), kA64Sxtw, 0U);
NewLIR1(kA64Br1x, r_base.GetReg());
// Loop exit label.
@@ -141,7 +140,6 @@ void Arm64Mir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset,
// Load the displacement from the switch table
RegStorage disp_reg = AllocTemp();
- // TODO(Arm64): generate "ldr w3, [x1,w2,sxtw #2]" rather than "ldr w3, [x1,x2,lsl #2]"?
LoadBaseIndexed(table_base, As64BitReg(key_reg), As64BitReg(disp_reg), 2, k32);
// Get base branch address.
@@ -150,8 +148,7 @@ void Arm64Mir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset,
tab_rec->anchor = switch_label;
// Add displacement to base branch address and go!
- // TODO(Arm64): generate "add x4, x4, w3, sxtw" rather than "add x4, x4, x3"?
- OpRegRegRegShift(kOpAdd, branch_reg, branch_reg, As64BitReg(disp_reg), ENCODE_NO_SHIFT);
+ OpRegRegRegExtend(kOpAdd, branch_reg, branch_reg, As64BitReg(disp_reg), kA64Sxtw, 0U);
NewLIR1(kA64Br1x, branch_reg.GetReg());
// branch_over target here
diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h
index 0fa7f2b..f1270ec 100644
--- a/compiler/dex/quick/arm64/codegen_arm64.h
+++ b/compiler/dex/quick/arm64/codegen_arm64.h
@@ -241,6 +241,8 @@ class Arm64Mir2Lir : public Mir2Lir {
LIR* StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src, OpSize size);
LIR* OpRegRegRegShift(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2,
int shift);
+ LIR* OpRegRegRegExtend(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2,
+ A64RegExtEncodings ext, uint8_t amount);
LIR* OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r_src2, int shift);
LIR* OpRegRegExtend(OpKind op, RegStorage r_dest_src1, RegStorage r_src2, int shift);
static const ArmEncodingMap EncodingMap[kA64Last];
diff --git a/compiler/dex/quick/arm64/utility_arm64.cc b/compiler/dex/quick/arm64/utility_arm64.cc
index b3ca7c4..672aa88 100644
--- a/compiler/dex/quick/arm64/utility_arm64.cc
+++ b/compiler/dex/quick/arm64/utility_arm64.cc
@@ -644,6 +644,44 @@ LIR* Arm64Mir2Lir::OpRegRegRegShift(OpKind op, RegStorage r_dest, RegStorage r_s
}
}
+LIR* Arm64Mir2Lir::OpRegRegRegExtend(OpKind op, RegStorage r_dest, RegStorage r_src1,
+ RegStorage r_src2, A64RegExtEncodings ext, uint8_t amount) {
+ ArmOpcode opcode = kA64Brk1d;
+
+ switch (op) {
+ case kOpAdd:
+ opcode = kA64Add4RRre;
+ break;
+ case kOpSub:
+ opcode = kA64Sub4RRre;
+ break;
+ default:
+ LOG(FATAL) << "Unimplemented opcode: " << op;
+ break;
+ }
+ ArmOpcode widened_opcode = r_dest.Is64Bit() ? WIDE(opcode) : opcode;
+
+ if (r_dest.Is64Bit()) {
+ CHECK(r_src1.Is64Bit());
+
+ // dest determines whether the op is wide or not. Up-convert src2 when necessary.
+ // Note: this is not according to aarch64 specifications, but our encoding.
+ if (!r_src2.Is64Bit()) {
+ r_src2 = As64BitReg(r_src2);
+ }
+ } else {
+ CHECK(!r_src1.Is64Bit());
+ CHECK(!r_src2.Is64Bit());
+ }
+
+ // Sanity checks.
+ // 1) Amount is in the range 0..4
+ CHECK_LE(amount, 4);
+
+ return NewLIR4(widened_opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg(),
+ EncodeExtend(ext, amount));
+}
+
LIR* Arm64Mir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2) {
return OpRegRegRegShift(op, r_dest, r_src1, r_src2, ENCODE_NO_SHIFT);
}
@@ -694,14 +732,8 @@ LIR* Arm64Mir2Lir::OpRegRegImm64(OpKind op, RegStorage r_dest, RegStorage r_src1
return NewLIR4(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), abs_value >> 12, 1);
} else {
log_imm = -1;
- 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;
+ alt_opcode = (neg) ? kA64Add4RRre : kA64Sub4RRre;
+ info = EncodeExtend(is_wide ? kA64Uxtx : kA64Uxtw, 0);
}
break;
// case kOpRsub:
@@ -744,7 +776,7 @@ LIR* Arm64Mir2Lir::OpRegRegImm64(OpKind op, RegStorage r_dest, RegStorage r_src1
return NewLIR3(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), log_imm);
} else {
RegStorage r_scratch;
- if (IS_WIDE(wide)) {
+ if (is_wide) {
r_scratch = AllocTempWide();
LoadConstantWide(r_scratch, value);
} else {