diff options
author | Chao-ying Fu <chao-ying.fu@intel.com> | 2014-06-06 17:32:37 -0700 |
---|---|---|
committer | buzbee <buzbee@google.com> | 2014-06-07 12:11:00 -0700 |
commit | e0ccdc0dd166136cd43e5f54201179a4496d33e8 (patch) | |
tree | f1dc404f7024898c2381a7ca4b79a3337e26f3b8 /compiler/dex/quick | |
parent | 8550197244d470bf7645075e5400750f2cab4e42 (diff) | |
download | android_art-e0ccdc0dd166136cd43e5f54201179a4496d33e8.tar.gz android_art-e0ccdc0dd166136cd43e5f54201179a4496d33e8.tar.bz2 android_art-e0ccdc0dd166136cd43e5f54201179a4496d33e8.zip |
x86_64: Add long bytecode supports (1/2)
This patch includes switch enabling and GenFillArray,
assembler changes, updates of regalloc behavior for 64-bit,
usage in basic utility operations, loading constants,
and update for memory operations.
Change-Id: I6d8aa35a75c5fd01d69c38a770c3398d0188cc8a
Signed-off-by: Chao-ying Fu <chao-ying.fu@intel.com>
Signed-off-by: Serguei Katkov <serguei.i.katkov@intel.com>
Signed-off-by: Dmitry Petrochenko <dmitry.petrochenko@intel.com>
Signed-off-by: Mark Mendell <mark.p.mendell@intel.com>
Diffstat (limited to 'compiler/dex/quick')
-rw-r--r-- | compiler/dex/quick/gen_loadstore.cc | 36 | ||||
-rw-r--r-- | compiler/dex/quick/x86/assemble_x86.cc | 28 | ||||
-rw-r--r-- | compiler/dex/quick/x86/call_x86.cc | 39 | ||||
-rw-r--r-- | compiler/dex/quick/x86/int_x86.cc | 136 | ||||
-rw-r--r-- | compiler/dex/quick/x86/target_x86.cc | 14 | ||||
-rw-r--r-- | compiler/dex/quick/x86/utility_x86.cc | 171 | ||||
-rw-r--r-- | compiler/dex/quick/x86/x86_lir.h | 12 |
7 files changed, 291 insertions, 145 deletions
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc index 2c8b9b9adf..6ef793427c 100644 --- a/compiler/dex/quick/gen_loadstore.cc +++ b/compiler/dex/quick/gen_loadstore.cc @@ -391,24 +391,34 @@ RegLocation Mir2Lir::ForceTemp(RegLocation loc) { return loc; } -// FIXME: will need an update for 64-bit core regs. RegLocation Mir2Lir::ForceTempWide(RegLocation loc) { DCHECK(loc.wide); DCHECK(loc.location == kLocPhysReg); DCHECK(!loc.reg.IsFloat()); - if (IsTemp(loc.reg.GetLow())) { - Clobber(loc.reg.GetLow()); - } else { - RegStorage temp_low = AllocTemp(); - OpRegCopy(temp_low, loc.reg.GetLow()); - loc.reg.SetLowReg(temp_low.GetReg()); - } - if (IsTemp(loc.reg.GetHigh())) { - Clobber(loc.reg.GetHigh()); + + if (!loc.reg.IsPair()) { + if (IsTemp(loc.reg)) { + Clobber(loc.reg); + } else { + RegStorage temp = AllocTempWide(); + OpRegCopy(temp, loc.reg); + loc.reg = temp; + } } else { - RegStorage temp_high = AllocTemp(); - OpRegCopy(temp_high, loc.reg.GetHigh()); - loc.reg.SetHighReg(temp_high.GetReg()); + if (IsTemp(loc.reg.GetLow())) { + Clobber(loc.reg.GetLow()); + } else { + RegStorage temp_low = AllocTemp(); + OpRegCopy(temp_low, loc.reg.GetLow()); + loc.reg.SetLowReg(temp_low.GetReg()); + } + if (IsTemp(loc.reg.GetHigh())) { + Clobber(loc.reg.GetHigh()); + } else { + RegStorage temp_high = AllocTemp(); + OpRegCopy(temp_high, loc.reg.GetHigh()); + loc.reg.SetHighReg(temp_high.GetReg()); + } } // Ensure that this doesn't represent the original SR any more. diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc index 39a036560e..c3832969a4 100644 --- a/compiler/dex/quick/x86/assemble_x86.cc +++ b/compiler/dex/quick/x86/assemble_x86.cc @@ -317,6 +317,7 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0, #undef UNARY_ENCODING_MAP { kx86Cdq32Da, kRegOpcode, NO_OPERAND | REG_DEFAD_USEA, { 0, 0, 0x99, 0, 0, 0, 0, 0 }, "Cdq", "" }, + { kx86Cqo64Da, kRegOpcode, NO_OPERAND | REG_DEFAD_USEA, { REX_W, 0, 0x99, 0, 0, 0, 0, 0 }, "Cqo", "" }, { kX86Bswap32R, kRegOpcode, IS_UNARY_OP | REG_DEF0_USE0, { 0, 0, 0x0F, 0xC8, 0, 0, 0, 0 }, "Bswap32R", "!0r" }, { kX86Push32R, kRegOpcode, IS_UNARY_OP | REG_USE0 | REG_USE_SP | REG_DEF_SP | IS_STORE, { 0, 0, 0x50, 0, 0, 0, 0, 0 }, "Push32R", "!0r" }, { kX86Pop32R, kRegOpcode, IS_UNARY_OP | REG_DEF0 | REG_USE_SP | REG_DEF_SP | IS_LOAD, { 0, 0, 0x58, 0, 0, 0, 0, 0 }, "Pop32R", "!0r" }, @@ -326,6 +327,11 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0, { kX86 ## opname ## RM, kRegMem, IS_LOAD | IS_TERTIARY_OP | reg_def | REG_USE1, { prefix, 0, 0x0F, opcode, 0, 0, 0, 0 }, #opname "RM", "!0r,[!1r+!2d]" }, \ { kX86 ## opname ## RA, kRegArray, IS_LOAD | IS_QUIN_OP | reg_def | REG_USE12, { prefix, 0, 0x0F, opcode, 0, 0, 0, 0 }, #opname "RA", "!0r,[!1r+!2r<<!3d+!4d]" } +#define EXT_0F_REX_W_ENCODING_MAP(opname, prefix, opcode, reg_def) \ +{ kX86 ## opname ## RR, kRegReg, IS_BINARY_OP | reg_def | REG_USE1, { prefix, REX_W, 0x0F, opcode, 0, 0, 0, 0 }, #opname "RR", "!0r,!1r" }, \ +{ kX86 ## opname ## RM, kRegMem, IS_LOAD | IS_TERTIARY_OP | reg_def | REG_USE1, { prefix, REX_W, 0x0F, opcode, 0, 0, 0, 0 }, #opname "RM", "!0r,[!1r+!2d]" }, \ +{ kX86 ## opname ## RA, kRegArray, IS_LOAD | IS_QUIN_OP | reg_def | REG_USE12, { prefix, REX_W, 0x0F, opcode, 0, 0, 0, 0 }, #opname "RA", "!0r,[!1r+!2r<<!3d+!4d]" } + #define EXT_0F_ENCODING2_MAP(opname, prefix, opcode, opcode2, reg_def) \ { kX86 ## opname ## RR, kRegReg, IS_BINARY_OP | reg_def | REG_USE1, { prefix, 0, 0x0F, opcode, opcode2, 0, 0, 0 }, #opname "RR", "!0r,!1r" }, \ { kX86 ## opname ## RM, kRegMem, IS_LOAD | IS_TERTIARY_OP | reg_def | REG_USE1, { prefix, 0, 0x0F, opcode, opcode2, 0, 0, 0 }, #opname "RM", "!0r,[!1r+!2d]" }, \ @@ -341,8 +347,12 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0, EXT_0F_ENCODING_MAP(Cvtsi2sd, 0xF2, 0x2A, REG_DEF0), EXT_0F_ENCODING_MAP(Cvtsi2ss, 0xF3, 0x2A, REG_DEF0), + EXT_0F_REX_W_ENCODING_MAP(Cvtsqi2sd, 0xF2, 0x2A, REG_DEF0), + EXT_0F_REX_W_ENCODING_MAP(Cvtsqi2ss, 0xF3, 0x2A, REG_DEF0), EXT_0F_ENCODING_MAP(Cvttsd2si, 0xF2, 0x2C, REG_DEF0), EXT_0F_ENCODING_MAP(Cvttss2si, 0xF3, 0x2C, REG_DEF0), + EXT_0F_REX_W_ENCODING_MAP(Cvttsd2sqi, 0xF2, 0x2C, REG_DEF0), + EXT_0F_REX_W_ENCODING_MAP(Cvttss2sqi, 0xF3, 0x2C, REG_DEF0), EXT_0F_ENCODING_MAP(Cvtsd2si, 0xF2, 0x2D, REG_DEF0), EXT_0F_ENCODING_MAP(Cvtss2si, 0xF3, 0x2D, REG_DEF0), EXT_0F_ENCODING_MAP(Ucomisd, 0x66, 0x2E, SETS_CCODES|REG_USE0), @@ -428,10 +438,19 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0, { kX86MovhpsAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014, { 0x0, 0, 0x0F, 0x17, 0, 0, 0, 0 }, "MovhpsAR", "[!0r+!1r<<!2d+!3d],!4r" }, EXT_0F_ENCODING_MAP(Movdxr, 0x66, 0x6E, REG_DEF0), + EXT_0F_REX_W_ENCODING_MAP(Movqxr, 0x66, 0x6E, REG_DEF0), + { kX86MovqrxRR, kRegRegStore, IS_BINARY_OP | REG_DEF0 | REG_USE1, { 0x66, REX_W, 0x0F, 0x7E, 0, 0, 0, 0 }, "MovqrxRR", "!0r,!1r" }, + { kX86MovqrxMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02, { 0x66, REX_W, 0x0F, 0x7E, 0, 0, 0, 0 }, "MovqrxMR", "[!0r+!1d],!2r" }, + { kX86MovqrxAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014, { 0x66, REX_W, 0x0F, 0x7E, 0, 0, 0, 0 }, "MovqrxAR", "[!0r+!1r<<!2d+!3d],!4r" }, + { kX86MovdrxRR, kRegRegStore, IS_BINARY_OP | REG_DEF0 | REG_USE1, { 0x66, 0, 0x0F, 0x7E, 0, 0, 0, 0 }, "MovdrxRR", "!0r,!1r" }, { kX86MovdrxMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02, { 0x66, 0, 0x0F, 0x7E, 0, 0, 0, 0 }, "MovdrxMR", "[!0r+!1d],!2r" }, { kX86MovdrxAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014, { 0x66, 0, 0x0F, 0x7E, 0, 0, 0, 0 }, "MovdrxAR", "[!0r+!1r<<!2d+!3d],!4r" }, + { kX86MovsxdRR, kRegReg, IS_BINARY_OP | REG_DEF0 | REG_USE1, { REX_W, 0, 0x63, 0, 0, 0, 0, 0 }, "MovsxdRR", "!0r,!1r" }, + { kX86MovsxdRM, kRegMem, IS_LOAD | IS_TERTIARY_OP | REG_DEF0 | REG_USE1, { REX_W, 0, 0x63, 0, 0, 0, 0, 0 }, "MovsxdRM", "!0r,[!1r+!2d]" }, + { kX86MovsxdRA, kRegArray, IS_LOAD | IS_QUIN_OP | REG_DEF0 | REG_USE12, { REX_W, 0, 0x63, 0, 0, 0, 0, 0 }, "MovsxdRA", "!0r,[!1r+!2r<<!3d+!4d]" }, + { kX86Set8R, kRegCond, IS_BINARY_OP | REG_DEF0 | USES_CCODES, { 0, 0, 0x0F, 0x90, 0, 0, 0, 0 }, "Set8R", "!1c !0r" }, { kX86Set8M, kMemCond, IS_STORE | IS_TERTIARY_OP | REG_USE0 | USES_CCODES, { 0, 0, 0x0F, 0x90, 0, 0, 0, 0 }, "Set8M", "!2c [!0r+!1d]" }, { kX86Set8A, kArrayCond, IS_STORE | IS_QUIN_OP | REG_USE01 | USES_CCODES, { 0, 0, 0x0F, 0x90, 0, 0, 0, 0 }, "Set8A", "!4c [!0r+!1r<<!2d+!3d]" }, @@ -442,6 +461,7 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0, EXT_0F_ENCODING_MAP(Imul16, 0x66, 0xAF, REG_USE0 | REG_DEF0 | SETS_CCODES), EXT_0F_ENCODING_MAP(Imul32, 0x00, 0xAF, REG_USE0 | REG_DEF0 | SETS_CCODES), + EXT_0F_ENCODING_MAP(Imul64, REX_W, 0xAF, REG_USE0 | REG_DEF0 | SETS_CCODES), { kX86CmpxchgRR, kRegRegStore, IS_BINARY_OP | REG_DEF0 | REG_USE01 | REG_DEFA_USEA | SETS_CCODES, { 0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Cmpxchg", "!0r,!1r" }, { kX86CmpxchgMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02 | REG_DEFA_USEA | SETS_CCODES, { 0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Cmpxchg", "[!0r+!1d],!2r" }, @@ -507,7 +527,7 @@ size_t X86Mir2Lir::ComputeSize(const X86EncodingMap* entry, int base, int displa } if (displacement != 0 || LowRegisterBits(RegStorage::RegNum(base)) == rs_rBP.GetRegNum()) { // BP requires an explicit displacement, even when it's 0. - if (entry->opcode != kX86Lea32RA) { + if (entry->opcode != kX86Lea32RA && entry->opcode != kX86Lea64RA) { DCHECK_NE(entry->flags & (IS_LOAD | IS_STORE), 0ULL) << entry->name; } size += IS_SIMM8(displacement) ? 1 : 4; @@ -676,7 +696,7 @@ int X86Mir2Lir::GetInsnSize(LIR* lir) { case kMacro: // lir operands - 0: reg DCHECK_EQ(lir->opcode, static_cast<int>(kX86StartOfMethod)); return 5 /* call opcode + 4 byte displacement */ + 1 /* pop reg */ + - ComputeSize(&X86Mir2Lir::EncodingMap[kX86Sub32RI], 0, 0, + ComputeSize(&X86Mir2Lir::EncodingMap[Gen64Bit() ? kX86Sub64RI : kX86Sub32RI], 0, 0, lir->operands[0], NO_REG, false) - // shorter ax encoding (RegStorage::RegNum(lir->operands[0]) == rs_rAX.GetRegNum() ? 1 : 0); @@ -1408,8 +1428,8 @@ void X86Mir2Lir::EmitMacro(const X86EncodingMap* entry, uint8_t reg, int offset) DCHECK_LT(RegStorage::RegNum(reg), 8); code_buffer_.push_back(0x58 + RegStorage::RegNum(reg)); // pop reg - EmitRegImm(&X86Mir2Lir::EncodingMap[kX86Sub32RI], RegStorage::RegNum(reg), - offset + 5 /* size of call +0 */); + EmitRegImm(&X86Mir2Lir::EncodingMap[Gen64Bit() ? kX86Sub64RI : kX86Sub32RI], + RegStorage::RegNum(reg), offset + 5 /* size of call +0 */); } void X86Mir2Lir::EmitUnimplemented(const X86EncodingMap* entry, LIR* lir) { diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc index fc0b305fc3..f5fce34f2b 100644 --- a/compiler/dex/quick/x86/call_x86.cc +++ b/compiler/dex/quick/x86/call_x86.cc @@ -86,11 +86,19 @@ void X86Mir2Lir::GenPackedSwitch(MIR* mir, DexOffset table_offset, if (base_of_code_ != nullptr) { // We can use the saved value. RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low); - rl_method = LoadValue(rl_method, kCoreReg); + if (rl_method.wide) { + rl_method = LoadValueWide(rl_method, kCoreReg); + } else { + rl_method = LoadValue(rl_method, kCoreReg); + } start_of_method_reg = rl_method.reg; store_method_addr_used_ = true; } else { - start_of_method_reg = AllocTemp(); + if (Gen64Bit()) { + start_of_method_reg = AllocTempWide(); + } else { + start_of_method_reg = AllocTemp(); + } NewLIR1(kX86StartOfMethod, start_of_method_reg.GetReg()); } int low_key = s4FromSwitchData(&table[2]); @@ -108,9 +116,14 @@ void X86Mir2Lir::GenPackedSwitch(MIR* mir, DexOffset table_offset, // Load the displacement from the switch table RegStorage disp_reg = AllocTemp(); - NewLIR5(kX86PcRelLoadRA, disp_reg.GetReg(), start_of_method_reg.GetReg(), keyReg.GetReg(), 2, WrapPointer(tab_rec)); + NewLIR5(kX86PcRelLoadRA, disp_reg.GetReg(), start_of_method_reg.GetReg(), keyReg.GetReg(), + 2, WrapPointer(tab_rec)); // Add displacement to start of method - OpRegReg(kOpAdd, start_of_method_reg, disp_reg); + if (Gen64Bit()) { + NewLIR2(kX86Add64RR, start_of_method_reg.GetReg(), disp_reg.GetReg()); + } else { + OpRegReg(kOpAdd, start_of_method_reg, disp_reg); + } // ..and go! LIR* switch_branch = NewLIR1(kX86JmpR, start_of_method_reg.GetReg()); tab_rec->anchor = switch_branch; @@ -150,13 +163,18 @@ void X86Mir2Lir::GenFillArrayData(DexOffset table_offset, RegLocation rl_src) { if (base_of_code_ != nullptr) { // We can use the saved value. RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low); - LoadValueDirect(rl_method, rs_rX86_ARG2); + if (rl_method.wide) { + LoadValueDirectWide(rl_method, rs_rX86_ARG2); + } else { + LoadValueDirect(rl_method, rs_rX86_ARG2); + } store_method_addr_used_ = true; } else { + // TODO(64) force to be 64-bit NewLIR1(kX86StartOfMethod, rs_rX86_ARG2.GetReg()); } NewLIR2(kX86PcRelAdr, rs_rX86_ARG1.GetReg(), WrapPointer(tab_rec)); - NewLIR2(kX86Add32RR, rs_rX86_ARG1.GetReg(), rs_rX86_ARG2.GetReg()); + NewLIR2(Gen64Bit() ? kX86Add64RR : kX86Add32RR, rs_rX86_ARG1.GetReg(), rs_rX86_ARG2.GetReg()); if (Is64BitInstructionSet(cu_->instruction_set)) { CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(8, pHandleFillArrayData), rs_rX86_ARG0, rs_rX86_ARG1, true); @@ -264,9 +282,10 @@ void X86Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) { OpRegThreadMem(kOpCmp, rs_rX86_SP, Thread::StackEndOffset<4>()); } LIR* branch = OpCondBranch(kCondUlt, nullptr); - AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, - frame_size_ - - GetInstructionSetPointerSize(cu_->instruction_set))); + AddSlowPath( + new(arena_)StackOverflowSlowPath(this, branch, + frame_size_ - + GetInstructionSetPointerSize(cu_->instruction_set))); } FlushIns(ArgLocs, rl_method); @@ -276,7 +295,7 @@ void X86Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) { setup_method_address_[0] = NewLIR1(kX86StartOfMethod, rs_rX86_ARG0.GetReg()); int displacement = SRegOffset(base_of_code_->s_reg_low); // Native pointer - must be natural word size. - setup_method_address_[1] = StoreWordDisp(rs_rX86_SP, displacement, rs_rX86_ARG0); + setup_method_address_[1] = StoreBaseDisp(rs_rX86_SP, displacement, rs_rX86_ARG0, Gen64Bit() ? k64 : k32); } FreeTemp(rs_rX86_ARG0); diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc index 1cc16b9e12..92069be14f 100644 --- a/compiler/dex/quick/x86/int_x86.cc +++ b/compiler/dex/quick/x86/int_x86.cc @@ -108,7 +108,7 @@ LIR* X86Mir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) { } if (r_dest.IsFloat() || r_src.IsFloat()) return OpFpRegCopy(r_dest, r_src); - LIR* res = RawLIR(current_dalvik_offset_, kX86Mov32RR, + LIR* res = RawLIR(current_dalvik_offset_, r_dest.Is64Bit() ? kX86Mov64RR : kX86Mov32RR, r_dest.GetReg(), r_src.GetReg()); if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) { res->flags.is_nop = true; @@ -133,36 +133,51 @@ void X86Mir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) { } else { // TODO: Prevent this from happening in the code. The result is often // unused or could have been loaded more easily from memory. - NewLIR2(kX86MovdxrRR, r_dest.GetReg(), r_src.GetLowReg()); - RegStorage r_tmp = AllocTempDouble(); - NewLIR2(kX86MovdxrRR, r_tmp.GetReg(), r_src.GetHighReg()); - NewLIR2(kX86PunpckldqRR, r_dest.GetReg(), r_tmp.GetReg()); - FreeTemp(r_tmp); + if (!r_src.IsPair()) { + DCHECK(!r_dest.IsPair()); + NewLIR2(kX86MovqxrRR, r_dest.GetReg(), r_src.GetReg()); + } else { + NewLIR2(kX86MovdxrRR, r_dest.GetReg(), r_src.GetLowReg()); + RegStorage r_tmp = AllocTempDouble(); + NewLIR2(kX86MovdxrRR, r_tmp.GetReg(), r_src.GetHighReg()); + NewLIR2(kX86PunpckldqRR, r_dest.GetReg(), r_tmp.GetReg()); + FreeTemp(r_tmp); + } } } else { if (src_fp) { - NewLIR2(kX86MovdrxRR, r_dest.GetLowReg(), r_src.GetReg()); - RegStorage temp_reg = AllocTempDouble(); - NewLIR2(kX86MovsdRR, temp_reg.GetReg(), r_src.GetReg()); - NewLIR2(kX86PsrlqRI, temp_reg.GetReg(), 32); - NewLIR2(kX86MovdrxRR, r_dest.GetHighReg(), temp_reg.GetReg()); + if (!r_dest.IsPair()) { + DCHECK(!r_src.IsPair()); + NewLIR2(kX86MovqrxRR, r_dest.GetReg(), r_src.GetReg()); + } else { + NewLIR2(kX86MovdrxRR, r_dest.GetLowReg(), r_src.GetReg()); + RegStorage temp_reg = AllocTempDouble(); + NewLIR2(kX86MovsdRR, temp_reg.GetReg(), r_src.GetReg()); + NewLIR2(kX86PsrlqRI, temp_reg.GetReg(), 32); + NewLIR2(kX86MovdrxRR, r_dest.GetHighReg(), temp_reg.GetReg()); + } } else { - DCHECK(r_dest.IsPair()); - DCHECK(r_src.IsPair()); - // Handle overlap - if (r_src.GetHighReg() == r_dest.GetLowReg() && r_src.GetLowReg() == r_dest.GetHighReg()) { - // Deal with cycles. - RegStorage temp_reg = AllocTemp(); - OpRegCopy(temp_reg, r_dest.GetHigh()); - OpRegCopy(r_dest.GetHigh(), r_dest.GetLow()); - OpRegCopy(r_dest.GetLow(), temp_reg); - FreeTemp(temp_reg); - } else if (r_src.GetHighReg() == r_dest.GetLowReg()) { - OpRegCopy(r_dest.GetHigh(), r_src.GetHigh()); - OpRegCopy(r_dest.GetLow(), r_src.GetLow()); + DCHECK_EQ(r_dest.IsPair(), r_src.IsPair()); + if (!r_src.IsPair()) { + // Just copy the register directly. + OpRegCopy(r_dest, r_src); } else { - OpRegCopy(r_dest.GetLow(), r_src.GetLow()); - OpRegCopy(r_dest.GetHigh(), r_src.GetHigh()); + // Handle overlap + if (r_src.GetHighReg() == r_dest.GetLowReg() && + r_src.GetLowReg() == r_dest.GetHighReg()) { + // Deal with cycles. + RegStorage temp_reg = AllocTemp(); + OpRegCopy(temp_reg, r_dest.GetHigh()); + OpRegCopy(r_dest.GetHigh(), r_dest.GetLow()); + OpRegCopy(r_dest.GetLow(), temp_reg); + FreeTemp(temp_reg); + } else if (r_src.GetHighReg() == r_dest.GetLowReg()) { + OpRegCopy(r_dest.GetHigh(), r_src.GetHigh()); + OpRegCopy(r_dest.GetLow(), r_src.GetLow()); + } else { + OpRegCopy(r_dest.GetLow(), r_src.GetLow()); + OpRegCopy(r_dest.GetHigh(), r_src.GetHigh()); + } } } } @@ -832,7 +847,11 @@ LIR* X86Mir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) { // Address the start of the method RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low); - LoadValueDirectFixed(rl_method, reg); + if (rl_method.wide) { + LoadValueDirectWideFixed(rl_method, reg); + } else { + LoadValueDirectFixed(rl_method, reg); + } store_method_addr_used_ = true; // Load the proper value from the literal area. @@ -1695,40 +1714,50 @@ X86OpCode X86Mir2Lir::GetOpcode(Instruction::Code op, RegLocation dest, RegLocat bool is_high_op) { bool rhs_in_mem = rhs.location != kLocPhysReg; bool dest_in_mem = dest.location != kLocPhysReg; + bool is64Bit = Gen64Bit(); DCHECK(!rhs_in_mem || !dest_in_mem); switch (op) { case Instruction::ADD_LONG: case Instruction::ADD_LONG_2ADDR: if (dest_in_mem) { - return is_high_op ? kX86Adc32MR : kX86Add32MR; + return is64Bit ? kX86Add64MR : is_high_op ? kX86Adc32MR : kX86Add32MR; } else if (rhs_in_mem) { - return is_high_op ? kX86Adc32RM : kX86Add32RM; + return is64Bit ? kX86Add64RM : is_high_op ? kX86Adc32RM : kX86Add32RM; } - return is_high_op ? kX86Adc32RR : kX86Add32RR; + return is64Bit ? kX86Add64RR : is_high_op ? kX86Adc32RR : kX86Add32RR; case Instruction::SUB_LONG: case Instruction::SUB_LONG_2ADDR: if (dest_in_mem) { - return is_high_op ? kX86Sbb32MR : kX86Sub32MR; + return is64Bit ? kX86Sub64MR : is_high_op ? kX86Sbb32MR : kX86Sub32MR; } else if (rhs_in_mem) { - return is_high_op ? kX86Sbb32RM : kX86Sub32RM; + return is64Bit ? kX86Sub64RM : is_high_op ? kX86Sbb32RM : kX86Sub32RM; } - return is_high_op ? kX86Sbb32RR : kX86Sub32RR; + return is64Bit ? kX86Sub64RR : is_high_op ? kX86Sbb32RR : kX86Sub32RR; case Instruction::AND_LONG_2ADDR: case Instruction::AND_LONG: if (dest_in_mem) { - return kX86And32MR; + return is64Bit ? kX86And64MR : kX86And32MR; + } + if (is64Bit) { + return rhs_in_mem ? kX86And64RM : kX86And64RR; } return rhs_in_mem ? kX86And32RM : kX86And32RR; case Instruction::OR_LONG: case Instruction::OR_LONG_2ADDR: if (dest_in_mem) { - return kX86Or32MR; + return is64Bit ? kX86Or64MR : kX86Or32MR; + } + if (is64Bit) { + return rhs_in_mem ? kX86Or64RM : kX86Or64RR; } return rhs_in_mem ? kX86Or32RM : kX86Or32RR; case Instruction::XOR_LONG: case Instruction::XOR_LONG_2ADDR: if (dest_in_mem) { - return kX86Xor32MR; + return is64Bit ? kX86Xor64MR : kX86Xor32MR; + } + if (is64Bit) { + return rhs_in_mem ? kX86Xor64RM : kX86Xor64RR; } return rhs_in_mem ? kX86Xor32RM : kX86Xor32RR; default: @@ -1740,6 +1769,7 @@ X86OpCode X86Mir2Lir::GetOpcode(Instruction::Code op, RegLocation dest, RegLocat X86OpCode X86Mir2Lir::GetOpcode(Instruction::Code op, RegLocation loc, bool is_high_op, int32_t value) { bool in_mem = loc.location != kLocPhysReg; + bool is64Bit = Gen64Bit(); bool byte_imm = IS_SIMM8(value); DCHECK(in_mem || !loc.reg.IsFloat()); switch (op) { @@ -1747,43 +1777,61 @@ X86OpCode X86Mir2Lir::GetOpcode(Instruction::Code op, RegLocation loc, bool is_h case Instruction::ADD_LONG_2ADDR: if (byte_imm) { if (in_mem) { - return is_high_op ? kX86Adc32MI8 : kX86Add32MI8; + return is64Bit ? kX86Add64MI8 : is_high_op ? kX86Adc32MI8 : kX86Add32MI8; } - return is_high_op ? kX86Adc32RI8 : kX86Add32RI8; + return is64Bit ? kX86Add64RI8 : is_high_op ? kX86Adc32RI8 : kX86Add32RI8; } if (in_mem) { - return is_high_op ? kX86Adc32MI : kX86Add32MI; + return is64Bit ? kX86Add64MI : is_high_op ? kX86Adc32MI : kX86Add32MI; } - return is_high_op ? kX86Adc32RI : kX86Add32RI; + return is64Bit ? kX86Add64RI : is_high_op ? kX86Adc32RI : kX86Add32RI; case Instruction::SUB_LONG: case Instruction::SUB_LONG_2ADDR: if (byte_imm) { if (in_mem) { - return is_high_op ? kX86Sbb32MI8 : kX86Sub32MI8; + return is64Bit ? kX86Sub64MI8 : is_high_op ? kX86Sbb32MI8 : kX86Sub32MI8; } - return is_high_op ? kX86Sbb32RI8 : kX86Sub32RI8; + return is64Bit ? kX86Sub64RI8 : is_high_op ? kX86Sbb32RI8 : kX86Sub32RI8; } if (in_mem) { - return is_high_op ? kX86Sbb32MI : kX86Sub32MI; + return is64Bit ? kX86Sub64MI : is_high_op ? kX86Sbb32MI : kX86Sub32MI; } - return is_high_op ? kX86Sbb32RI : kX86Sub32RI; + return is64Bit ? kX86Sub64RI : is_high_op ? kX86Sbb32RI : kX86Sub32RI; case Instruction::AND_LONG_2ADDR: case Instruction::AND_LONG: if (byte_imm) { + if (is64Bit) { + return in_mem ? kX86And64MI8 : kX86And64RI8; + } return in_mem ? kX86And32MI8 : kX86And32RI8; } + if (is64Bit) { + return in_mem ? kX86And64MI : kX86And64RI; + } return in_mem ? kX86And32MI : kX86And32RI; case Instruction::OR_LONG: case Instruction::OR_LONG_2ADDR: if (byte_imm) { + if (is64Bit) { + return in_mem ? kX86Or64MI8 : kX86Or64RI8; + } return in_mem ? kX86Or32MI8 : kX86Or32RI8; } + if (is64Bit) { + return in_mem ? kX86Or64MI : kX86Or64RI; + } return in_mem ? kX86Or32MI : kX86Or32RI; case Instruction::XOR_LONG: case Instruction::XOR_LONG_2ADDR: if (byte_imm) { + if (is64Bit) { + return in_mem ? kX86Xor64MI8 : kX86Xor64RI8; + } return in_mem ? kX86Xor32MI8 : kX86Xor32RI8; } + if (is64Bit) { + return in_mem ? kX86Xor64MI : kX86Xor64RI; + } return in_mem ? kX86Xor32MI : kX86Xor32RI; default: LOG(FATAL) << "Unexpected opcode: " << op; diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index 160ec620b0..100ed13c8c 100644 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -687,6 +687,14 @@ bool X86Mir2Lir::SupportsVolatileLoadStore(OpSize size) { } RegisterClass X86Mir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) { + // X86_64 can handle any size. + if (Gen64Bit()) { + if (size == kReference) { + return kRefReg; + } + return kCoreReg; + } + if (UNLIKELY(is_volatile)) { // On x86, atomic 64-bit load/store requires an fp register. // Smaller aligned load/store is atomic for both core and fp registers. @@ -1425,7 +1433,11 @@ void X86Mir2Lir::GenConst128(BasicBlock* bb, MIR* mir) { // Address the start of the method. RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low); - rl_method = LoadValue(rl_method, kCoreReg); + if (rl_method.wide) { + rl_method = LoadValueWide(rl_method, kCoreReg); + } else { + rl_method = LoadValue(rl_method, kCoreReg); + } // Load the proper value from the literal area. // We don't know the proper offset for the value, so pick one that will force diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc index 618b3a5987..d074d8104d 100644 --- a/compiler/dex/quick/x86/utility_x86.cc +++ b/compiler/dex/quick/x86/utility_x86.cc @@ -89,11 +89,8 @@ LIR* X86Mir2Lir::LoadConstantNoClobber(RegStorage r_dest, int value) { res = NewLIR2(kX86Xor32RR, r_dest.GetReg(), r_dest.GetReg()); } else { // Note, there is no byte immediate form of a 32 bit immediate move. - if (r_dest.Is64Bit()) { - res = NewLIR2(kX86Mov64RI, r_dest.GetReg(), value); - } else { - res = NewLIR2(kX86Mov32RI, r_dest.GetReg(), value); - } + // 64-bit immediate is not supported by LIR structure + res = NewLIR2(kX86Mov32RI, r_dest.GetReg(), value); } if (r_dest_save.IsFloat()) { @@ -120,8 +117,8 @@ LIR* X86Mir2Lir::OpCondBranch(ConditionCode cc, LIR* target) { LIR* X86Mir2Lir::OpReg(OpKind op, RegStorage r_dest_src) { X86OpCode opcode = kX86Bkpt; switch (op) { - case kOpNeg: opcode = kX86Neg32R; break; - case kOpNot: opcode = kX86Not32R; break; + case kOpNeg: opcode = r_dest_src.Is64Bit() ? kX86Neg64R : kX86Neg32R; break; + case kOpNot: opcode = r_dest_src.Is64Bit() ? kX86Not64R : kX86Not32R; break; case kOpRev: opcode = kX86Bswap32R; break; case kOpBlx: opcode = kX86CallR; break; default: @@ -138,6 +135,9 @@ LIR* X86Mir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) { switch (op) { case kOpAdd: opcode = byte_imm ? kX86Add64RI8 : kX86Add64RI; break; case kOpSub: opcode = byte_imm ? kX86Sub64RI8 : kX86Sub64RI; break; + case kOpLsl: opcode = kX86Sal64RI; break; + case kOpLsr: opcode = kX86Shr64RI; break; + case kOpAsr: opcode = kX86Sar64RI; break; default: LOG(FATAL) << "Bad case in OpRegImm (64-bit) " << op; } @@ -189,6 +189,7 @@ LIR* X86Mir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) { } LIR* X86Mir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2) { + bool is64Bit = r_dest_src1.Is64Bit(); X86OpCode opcode = kX86Nop; bool src2_must_be_cx = false; switch (op) { @@ -207,33 +208,34 @@ LIR* X86Mir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2) OpReg(kOpRev, r_dest_src1); return OpRegImm(kOpAsr, r_dest_src1, 16); // X86 binary opcodes - case kOpSub: opcode = kX86Sub32RR; break; - case kOpSbc: opcode = kX86Sbb32RR; break; - case kOpLsl: opcode = kX86Sal32RC; src2_must_be_cx = true; break; - case kOpLsr: opcode = kX86Shr32RC; src2_must_be_cx = true; break; - case kOpAsr: opcode = kX86Sar32RC; src2_must_be_cx = true; break; - case kOpMov: opcode = kX86Mov32RR; break; - case kOpCmp: opcode = kX86Cmp32RR; break; - case kOpAdd: opcode = kX86Add32RR; break; - case kOpAdc: opcode = kX86Adc32RR; break; - case kOpAnd: opcode = kX86And32RR; break; - case kOpOr: opcode = kX86Or32RR; break; - case kOpXor: opcode = kX86Xor32RR; break; + case kOpSub: opcode = is64Bit ? kX86Sub64RR : kX86Sub32RR; break; + case kOpSbc: opcode = is64Bit ? kX86Sbb64RR : kX86Sbb32RR; break; + case kOpLsl: opcode = is64Bit ? kX86Sal64RC : kX86Sal32RC; src2_must_be_cx = true; break; + case kOpLsr: opcode = is64Bit ? kX86Shr64RC : kX86Shr32RC; src2_must_be_cx = true; break; + case kOpAsr: opcode = is64Bit ? kX86Sar64RC : kX86Sar32RC; src2_must_be_cx = true; break; + case kOpMov: opcode = is64Bit ? kX86Mov64RR : kX86Mov32RR; break; + case kOpCmp: opcode = is64Bit ? kX86Cmp64RR : kX86Cmp32RR; break; + case kOpAdd: opcode = is64Bit ? kX86Add64RR : kX86Add32RR; break; + case kOpAdc: opcode = is64Bit ? kX86Adc64RR : kX86Adc32RR; break; + case kOpAnd: opcode = is64Bit ? kX86And64RR : kX86And32RR; break; + case kOpOr: opcode = is64Bit ? kX86Or64RR : kX86Or32RR; break; + case kOpXor: opcode = is64Bit ? kX86Xor64RR : kX86Xor32RR; break; case kOp2Byte: // TODO: there are several instances of this check. A utility function perhaps? // TODO: Similar to Arm's reg < 8 check. Perhaps add attribute checks to RegStorage? // Use shifts instead of a byte operand if the source can't be byte accessed. if (r_src2.GetRegNum() >= rs_rX86_SP.GetRegNum()) { - NewLIR2(kX86Mov32RR, r_dest_src1.GetReg(), r_src2.GetReg()); - NewLIR2(kX86Sal32RI, r_dest_src1.GetReg(), 24); - return NewLIR2(kX86Sar32RI, r_dest_src1.GetReg(), 24); + NewLIR2(is64Bit ? kX86Mov64RR : kX86Mov32RR, r_dest_src1.GetReg(), r_src2.GetReg()); + NewLIR2(is64Bit ? kX86Sal64RI : kX86Sal32RI, r_dest_src1.GetReg(), is64Bit ? 56 : 24); + return NewLIR2(is64Bit ? kX86Sar64RI : kX86Sar32RI, r_dest_src1.GetReg(), + is64Bit ? 56 : 24); } else { - opcode = kX86Movsx8RR; + opcode = is64Bit ? kX86Bkpt : kX86Movsx8RR; } break; - case kOp2Short: opcode = kX86Movsx16RR; break; - case kOp2Char: opcode = kX86Movzx16RR; break; - case kOpMul: opcode = kX86Imul32RR; break; + case kOp2Short: opcode = is64Bit ? kX86Bkpt : kX86Movsx16RR; break; + case kOp2Char: opcode = is64Bit ? kX86Bkpt : kX86Movzx16RR; break; + case kOpMul: opcode = is64Bit ? kX86Bkpt : kX86Imul32RR; break; default: LOG(FATAL) << "Bad case in OpRegReg " << op; break; @@ -354,16 +356,17 @@ LIR* X86Mir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, Re } LIR* X86Mir2Lir::OpRegMem(OpKind op, RegStorage r_dest, RegStorage r_base, int offset) { + bool is64Bit = r_dest.Is64Bit(); X86OpCode opcode = kX86Nop; switch (op) { // X86 binary opcodes - case kOpSub: opcode = kX86Sub32RM; break; - case kOpMov: opcode = kX86Mov32RM; break; - case kOpCmp: opcode = kX86Cmp32RM; break; - case kOpAdd: opcode = kX86Add32RM; break; - case kOpAnd: opcode = kX86And32RM; break; - case kOpOr: opcode = kX86Or32RM; break; - case kOpXor: opcode = kX86Xor32RM; break; + case kOpSub: opcode = is64Bit ? kX86Sub64RM : kX86Sub32RM; break; + case kOpMov: opcode = is64Bit ? kX86Mov64RM : kX86Mov32RM; break; + case kOpCmp: opcode = is64Bit ? kX86Cmp64RM : kX86Cmp32RM; break; + case kOpAdd: opcode = is64Bit ? kX86Add64RM : kX86Add32RM; break; + case kOpAnd: opcode = is64Bit ? kX86And64RM : kX86And32RM; break; + case kOpOr: opcode = is64Bit ? kX86Or64RM : kX86Or32RM; break; + case kOpXor: opcode = is64Bit ? kX86Xor64RM : kX86Xor32RM; break; case kOp2Byte: opcode = kX86Movsx8RM; break; case kOp2Short: opcode = kX86Movsx16RM; break; case kOp2Char: opcode = kX86Movzx16RM; break; @@ -382,63 +385,68 @@ LIR* X86Mir2Lir::OpRegMem(OpKind op, RegStorage r_dest, RegStorage r_base, int o LIR* X86Mir2Lir::OpMemReg(OpKind op, RegLocation rl_dest, int r_value) { DCHECK_NE(rl_dest.location, kLocPhysReg); int displacement = SRegOffset(rl_dest.s_reg_low); + bool is64Bit = rl_dest.wide != 0; X86OpCode opcode = kX86Nop; switch (op) { - case kOpSub: opcode = kX86Sub32MR; break; - case kOpMov: opcode = kX86Mov32MR; break; - case kOpCmp: opcode = kX86Cmp32MR; break; - case kOpAdd: opcode = kX86Add32MR; break; - case kOpAnd: opcode = kX86And32MR; break; - case kOpOr: opcode = kX86Or32MR; break; - case kOpXor: opcode = kX86Xor32MR; break; - case kOpLsl: opcode = kX86Sal32MC; break; - case kOpLsr: opcode = kX86Shr32MC; break; - case kOpAsr: opcode = kX86Sar32MC; break; + case kOpSub: opcode = is64Bit ? kX86Sub64MR : kX86Sub32MR; break; + case kOpMov: opcode = is64Bit ? kX86Mov64MR : kX86Mov32MR; break; + case kOpCmp: opcode = is64Bit ? kX86Cmp64MR : kX86Cmp32MR; break; + case kOpAdd: opcode = is64Bit ? kX86Add64MR : kX86Add32MR; break; + case kOpAnd: opcode = is64Bit ? kX86And64MR : kX86And32MR; break; + case kOpOr: opcode = is64Bit ? kX86Or64MR : kX86Or32MR; break; + case kOpXor: opcode = is64Bit ? kX86Xor64MR : kX86Xor32MR; break; + case kOpLsl: opcode = is64Bit ? kX86Sal64MC : kX86Sal32MC; break; + case kOpLsr: opcode = is64Bit ? kX86Shr64MC : kX86Shr32MC; break; + case kOpAsr: opcode = is64Bit ? kX86Sar64MC : kX86Sar32MC; break; default: LOG(FATAL) << "Bad case in OpMemReg " << op; break; } LIR *l = NewLIR3(opcode, rs_rX86_SP.GetReg(), displacement, r_value); - AnnotateDalvikRegAccess(l, displacement >> 2, true /* is_load */, false /* is_64bit */); - AnnotateDalvikRegAccess(l, displacement >> 2, false /* is_load */, false /* is_64bit */); + AnnotateDalvikRegAccess(l, displacement >> 2, true /* is_load */, is64Bit /* is_64bit */); + AnnotateDalvikRegAccess(l, displacement >> 2, false /* is_load */, is64Bit /* is_64bit */); return l; } LIR* X86Mir2Lir::OpRegMem(OpKind op, RegStorage r_dest, RegLocation rl_value) { DCHECK_NE(rl_value.location, kLocPhysReg); + bool is64Bit = r_dest.Is64Bit(); int displacement = SRegOffset(rl_value.s_reg_low); X86OpCode opcode = kX86Nop; switch (op) { - case kOpSub: opcode = kX86Sub32RM; break; - case kOpMov: opcode = kX86Mov32RM; break; - case kOpCmp: opcode = kX86Cmp32RM; break; - case kOpAdd: opcode = kX86Add32RM; break; - case kOpAnd: opcode = kX86And32RM; break; - case kOpOr: opcode = kX86Or32RM; break; - case kOpXor: opcode = kX86Xor32RM; break; - case kOpMul: opcode = kX86Imul32RM; break; + case kOpSub: opcode = is64Bit ? kX86Sub64RM : kX86Sub32RM; break; + case kOpMov: opcode = is64Bit ? kX86Mov64RM : kX86Mov32RM; break; + case kOpCmp: opcode = is64Bit ? kX86Cmp64RM : kX86Cmp32RM; break; + case kOpAdd: opcode = is64Bit ? kX86Add64RM : kX86Add32RM; break; + case kOpAnd: opcode = is64Bit ? kX86And64RM : kX86And32RM; break; + case kOpOr: opcode = is64Bit ? kX86Or64RM : kX86Or32RM; break; + case kOpXor: opcode = is64Bit ? kX86Xor64RM : kX86Xor32RM; break; + case kOpMul: opcode = is64Bit ? kX86Bkpt : kX86Imul32RM; break; default: LOG(FATAL) << "Bad case in OpRegMem " << op; break; } LIR *l = NewLIR3(opcode, r_dest.GetReg(), rs_rX86_SP.GetReg(), displacement); - AnnotateDalvikRegAccess(l, displacement >> 2, true /* is_load */, false /* is_64bit */); + AnnotateDalvikRegAccess(l, displacement >> 2, true /* is_load */, is64Bit /* is_64bit */); return l; } LIR* X86Mir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2) { + bool is64Bit = r_dest.Is64Bit(); if (r_dest != r_src1 && r_dest != r_src2) { if (op == kOpAdd) { // lea special case, except can't encode rbp as base if (r_src1 == r_src2) { OpRegCopy(r_dest, r_src1); return OpRegImm(kOpLsl, r_dest, 1); } else if (r_src1 != rs_rBP) { - return NewLIR5(kX86Lea32RA, r_dest.GetReg(), r_src1.GetReg() /* base */, - r_src2.GetReg() /* index */, 0 /* scale */, 0 /* disp */); + return NewLIR5(is64Bit ? kX86Lea64RA : kX86Lea32RA, r_dest.GetReg(), + r_src1.GetReg() /* base */, r_src2.GetReg() /* index */, + 0 /* scale */, 0 /* disp */); } else { - return NewLIR5(kX86Lea32RA, r_dest.GetReg(), r_src2.GetReg() /* base */, - r_src1.GetReg() /* index */, 0 /* scale */, 0 /* disp */); + return NewLIR5(is64Bit ? kX86Lea64RA : kX86Lea32RA, r_dest.GetReg(), + r_src2.GetReg() /* base */, r_src1.GetReg() /* index */, + 0 /* scale */, 0 /* disp */); } } else { OpRegCopy(r_dest, r_src1); @@ -476,10 +484,10 @@ LIR* X86Mir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, } LIR* X86Mir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src, int value) { - if (op == kOpMul) { + if (op == kOpMul && !Gen64Bit()) { X86OpCode opcode = IS_SIMM8(value) ? kX86Imul32RRI8 : kX86Imul32RRI; return NewLIR3(opcode, r_dest.GetReg(), r_src.GetReg(), value); - } else if (op == kOpAnd) { + } else if (op == kOpAnd && !Gen64Bit()) { if (value == 0xFF && r_src.Low4()) { return NewLIR2(kX86Movzx8RR, r_dest.GetReg(), r_src.GetReg()); } else if (value == 0xFFFF) { @@ -492,8 +500,9 @@ LIR* X86Mir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src, int return NewLIR5(kX86Lea32RA, r_dest.GetReg(), r5sib_no_base /* base */, r_src.GetReg() /* index */, value /* scale */, 0 /* disp */); } else if (op == kOpAdd) { // lea add special case - return NewLIR5(kX86Lea32RA, r_dest.GetReg(), r_src.GetReg() /* base */, - rs_rX86_SP.GetReg()/*r4sib_no_index*/ /* index */, 0 /* scale */, value /* disp */); + return NewLIR5(Gen64Bit() ? kX86Lea64RA : kX86Lea32RA, r_dest.GetReg(), + r_src.GetReg() /* base */, rs_rX86_SP.GetReg()/*r4sib_no_index*/ /* index */, + 0 /* scale */, value /* disp */); } OpRegCopy(r_dest, r_src); } @@ -556,7 +565,11 @@ LIR* X86Mir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) { // Address the start of the method RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low); - rl_method = LoadValue(rl_method, kCoreReg); + if (rl_method.wide) { + rl_method = LoadValueWide(rl_method, kCoreReg); + } else { + rl_method = LoadValue(rl_method, kCoreReg); + } // Load the proper value from the literal area. // We don't know the proper offset for the value, so pick one that will force @@ -582,8 +595,20 @@ LIR* X86Mir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) { } } } else { - res = LoadConstantNoClobber(r_dest.GetLow(), val_lo); - LoadConstantNoClobber(r_dest.GetHigh(), val_hi); + if (r_dest.IsPair()) { + res = LoadConstantNoClobber(r_dest.GetLow(), val_lo); + LoadConstantNoClobber(r_dest.GetHigh(), val_hi); + } else { + // TODO(64) make int64_t value parameter of LoadConstantNoClobber + if (val_lo < 0) { + val_hi += 1; + } + res = LoadConstantNoClobber(RegStorage::Solo32(r_dest.GetReg()), val_hi); + NewLIR2(kX86Sal64RI, r_dest.GetReg(), 32); + if (val_lo != 0) { + NewLIR2(kX86Add64RI, r_dest.GetReg(), val_lo); + } + } } return res; } @@ -601,6 +626,8 @@ LIR* X86Mir2Lir::LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int case kDouble: if (r_dest.IsFloat()) { opcode = is_array ? kX86MovsdRA : kX86MovsdRM; + } else if (!pair) { + opcode = is_array ? kX86Mov64RA : kX86Mov64RM; } else { opcode = is_array ? kX86Mov32RA : kX86Mov32RM; } @@ -742,13 +769,10 @@ LIR* X86Mir2Lir::StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int case kDouble: if (r_src.IsFloat()) { opcode = is_array ? kX86MovsdAR : kX86MovsdMR; + } else if (!pair) { + opcode = is_array ? kX86Mov64AR : kX86Mov64MR; } else { - if (Gen64Bit()) { - opcode = is_array ? kX86Mov64AR : kX86Mov64MR; - } else { - // TODO(64): pair = true; - opcode = is_array ? kX86Mov32AR : kX86Mov32MR; - } + opcode = is_array ? kX86Mov32AR : kX86Mov32MR; } // TODO: double store is to unaligned address DCHECK_EQ((displacement & 0x3), 0); @@ -855,7 +879,7 @@ void X86Mir2Lir::AnalyzeMIR() { // Did we need a pointer to the method code? if (store_method_addr_) { - base_of_code_ = mir_graph_->GetNewCompilerTemp(kCompilerTempVR, false); + base_of_code_ = mir_graph_->GetNewCompilerTemp(kCompilerTempVR, Gen64Bit() == true); } else { base_of_code_ = nullptr; } @@ -971,6 +995,7 @@ RegLocation X86Mir2Lir::UpdateLocTyped(RegLocation loc, int reg_class) { loc.location = kLocDalvikFrame; } } + DCHECK(CheckCorePoolSanity()); return loc; } @@ -984,7 +1009,7 @@ RegLocation X86Mir2Lir::UpdateLocWideTyped(RegLocation loc, int reg_class) { loc.location = kLocDalvikFrame; } } + DCHECK(CheckCorePoolSanity()); return loc; } - } // namespace art diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h index f290548b96..e550488a03 100644 --- a/compiler/dex/quick/x86/x86_lir.h +++ b/compiler/dex/quick/x86/x86_lir.h @@ -377,6 +377,9 @@ const RegLocation x86_loc_c_return const RegLocation x86_loc_c_return_wide {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, RegStorage(RegStorage::k64BitPair, rAX, rDX), INVALID_SREG, INVALID_SREG}; +const RegLocation x86_64_loc_c_return_wide + {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, + RegStorage(RegStorage::k64BitSolo, rAX), INVALID_SREG, INVALID_SREG}; const RegLocation x86_loc_c_return_float {kLocPhysReg, 0, 0, 0, 1, 0, 0, 0, 1, RegStorage(RegStorage::k32BitSolo, fr0), INVALID_SREG, INVALID_SREG}; @@ -519,6 +522,7 @@ enum X86OpCode { UnaryOpcode(kX86Divmod, DaR, DaM, DaA), UnaryOpcode(kX86Idivmod, DaR, DaM, DaA), kx86Cdq32Da, + kx86Cqo64Da, kX86Bswap32R, kX86Push32R, kX86Pop32R, #undef UnaryOpcode @@ -532,8 +536,12 @@ enum X86OpCode { kX86MovssAR, Binary0fOpCode(kX86Cvtsi2sd), // int to double Binary0fOpCode(kX86Cvtsi2ss), // int to float + Binary0fOpCode(kX86Cvtsqi2sd), // long to double + Binary0fOpCode(kX86Cvtsqi2ss), // long to float Binary0fOpCode(kX86Cvttsd2si), // truncating double to int Binary0fOpCode(kX86Cvttss2si), // truncating float to int + Binary0fOpCode(kX86Cvttsd2sqi), // truncating double to long + Binary0fOpCode(kX86Cvttss2sqi), // truncating float to long Binary0fOpCode(kX86Cvtsd2si), // rounding double to int Binary0fOpCode(kX86Cvtss2si), // rounding float to int Binary0fOpCode(kX86Ucomisd), // unordered double compare @@ -601,11 +609,15 @@ enum X86OpCode { kX86MovhpsRM, kX86MovhpsRA, // load packed single FP values from m64 to high quadword of xmm kX86MovhpsMR, kX86MovhpsAR, // store packed single FP values from high quadword of xmm to m64 Binary0fOpCode(kX86Movdxr), // move into xmm from gpr + Binary0fOpCode(kX86Movqxr), // move into xmm from 64 bit gpr + kX86MovqrxRR, kX86MovqrxMR, kX86MovqrxAR, // move into 64 bit reg from xmm kX86MovdrxRR, kX86MovdrxMR, kX86MovdrxAR, // move into reg from xmm + kX86MovsxdRR, kX86MovsxdRM, kX86MovsxdRA, // move 32 bit to 64 bit with sign extension kX86Set8R, kX86Set8M, kX86Set8A, // set byte depending on condition operand kX86Mfence, // memory barrier Binary0fOpCode(kX86Imul16), // 16bit multiply Binary0fOpCode(kX86Imul32), // 32bit multiply + Binary0fOpCode(kX86Imul64), // 64bit multiply kX86CmpxchgRR, kX86CmpxchgMR, kX86CmpxchgAR, // compare and exchange kX86LockCmpxchgMR, kX86LockCmpxchgAR, // locked compare and exchange kX86LockCmpxchg8bM, kX86LockCmpxchg8bA, // locked compare and exchange |