Quick: PC-relative loads from dex cache arrays on x86.
Rewrite all PC-relative addressing on x86 and implement
PC-relative loads from dex cache arrays. Don't adjust the
base to point to the start of the method, let it point to
the anchor, i.e. the target of the "call +0" insn.
Change-Id: Ic22544a8bc0c5e49eb00a75154dc8f3ead816989
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 5def5c8..075f721 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1324,11 +1324,6 @@
return true;
}
-// When we don't know the proper offset for the value, pick one that will force
-// 4 byte offset. We will fix this up in the assembler or linker later to have
-// the right value.
-static constexpr int kDummy32BitOffset = 256;
-
void X86Mir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
if (cu_->target64) {
// We can do this directly using RIP addressing.
@@ -1339,27 +1334,48 @@
return;
}
- CHECK(base_of_code_ != nullptr);
-
- // Address the start of the method
- RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
- if (rl_method.wide) {
- LoadValueDirectWideFixed(rl_method, reg);
- } else {
- LoadValueDirectFixed(rl_method, reg);
- }
- store_method_addr_used_ = true;
+ // Get the PC to a register and get the anchor.
+ LIR* anchor;
+ RegStorage r_pc = GetPcAndAnchor(&anchor);
// Load the proper value from the literal area.
ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
- LIR* res = NewLIR3(kX86Mov32RM, reg.GetReg(), reg.GetReg(), kDummy32BitOffset);
+ LIR* res = NewLIR3(kX86Mov32RM, reg.GetReg(), r_pc.GetReg(), kDummy32BitOffset);
+ res->operands[4] = WrapPointer(anchor);
res->target = target;
res->flags.fixup = kFixupLoad;
}
bool X86Mir2Lir::CanUseOpPcRelDexCacheArrayLoad() const {
- // TODO: Implement for 32-bit.
- return cu_->target64 && dex_cache_arrays_layout_.Valid();
+ return dex_cache_arrays_layout_.Valid();
+}
+
+LIR* X86Mir2Lir::OpLoadPc(RegStorage r_dest) {
+ DCHECK(!cu_->target64);
+ LIR* call = NewLIR1(kX86CallI, 0);
+ call->flags.fixup = kFixupLabel;
+ LIR* pop = NewLIR1(kX86Pop32R, r_dest.GetReg());
+ pop->flags.fixup = kFixupLabel;
+ DCHECK(NEXT_LIR(call) == pop);
+ return call;
+}
+
+RegStorage X86Mir2Lir::GetPcAndAnchor(LIR** anchor, RegStorage r_tmp) {
+ if (pc_rel_base_reg_.Valid()) {
+ DCHECK(setup_pc_rel_base_reg_ != nullptr);
+ *anchor = NEXT_LIR(setup_pc_rel_base_reg_);
+ DCHECK(*anchor != nullptr);
+ DCHECK_EQ((*anchor)->opcode, kX86Pop32R);
+ pc_rel_base_reg_used_ = true;
+ return pc_rel_base_reg_;
+ } else {
+ RegStorage r_pc = r_tmp.Valid() ? r_tmp : AllocTempRef();
+ LIR* load_pc = OpLoadPc(r_pc);
+ *anchor = NEXT_LIR(load_pc);
+ DCHECK(*anchor != nullptr);
+ DCHECK_EQ((*anchor)->opcode, kX86Pop32R);
+ return r_pc;
+ }
}
void X86Mir2Lir::OpPcRelDexCacheArrayLoad(const DexFile* dex_file, int offset,
@@ -1369,11 +1385,18 @@
mov->flags.fixup = kFixupLabel;
mov->operands[3] = WrapPointer(dex_file);
mov->operands[4] = offset;
+ mov->target = mov; // Used for pc_insn_offset (not used by x86-64 relative patcher).
dex_cache_access_insns_.push_back(mov);
} else {
- // TODO: Implement for 32-bit.
- LOG(FATAL) << "Unimplemented.";
- UNREACHABLE();
+ // Get the PC to a register and get the anchor. Use r_dest for the temp if needed.
+ LIR* anchor;
+ RegStorage r_pc = GetPcAndAnchor(&anchor, r_dest);
+ LIR* mov = NewLIR3(kX86Mov32RM, r_dest.GetReg(), r_pc.GetReg(), kDummy32BitOffset);
+ mov->flags.fixup = kFixupLabel;
+ mov->operands[3] = WrapPointer(dex_file);
+ mov->operands[4] = offset;
+ mov->target = anchor; // Used for pc_insn_offset.
+ dex_cache_access_insns_.push_back(mov);
}
}