diff options
author | Andreas Gampe <agampe@google.com> | 2014-06-19 01:10:07 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2014-06-19 09:16:10 -0700 |
commit | 47b31aa855379471c06735b738396fa76e7c1988 (patch) | |
tree | dc3c4d0a3da150562a63e7b5c131e37586f45a50 /compiler | |
parent | 995b32cc8e94a9730d6cf663a23afc9c997c1771 (diff) | |
download | art-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.h | 4 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/assemble_arm64.cc | 8 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/call_arm64.cc | 7 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/codegen_arm64.h | 2 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/utility_arm64.cc | 50 |
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 { |