Quick compiler: Fix liveness tracking
Rework temp register liveness tracking to play nicely with aliased
physical registers, and re-enable liveness tracking optimization.
Add a pair of x86 utility routines that act like UpdateLoc(),
but only show in-register live temps if they are of the expected
register class.
Change-Id: I92779e0da2554689103e7488025be281f1a58989
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc
index fc6af29..faa9461 100644
--- a/compiler/dex/quick/gen_loadstore.cc
+++ b/compiler/dex/quick/gen_loadstore.cc
@@ -233,7 +233,11 @@
if (IsLive(rl_src.reg) ||
IsPromoted(rl_src.reg) ||
(rl_dest.location == kLocPhysReg)) {
- // Src is live or promoted or Dest has assigned reg.
+ /*
+ * If src reg[s] are tied to the original Dalvik vreg via liveness or promotion, we
+ * can't repurpose them. Similarly, if the dest reg[s] are tied to Dalvik vregs via
+ * promotion, we can't just re-assign. In these cases, we have to copy.
+ */
rl_dest = EvalLoc(rl_dest, kAnyReg, false);
OpRegCopyWide(rl_dest.reg, rl_src.reg);
} else {
diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h
index f5d71c4..b5b50a4 100644
--- a/compiler/dex/quick/mir_to_lir-inl.h
+++ b/compiler/dex/quick/mir_to_lir-inl.h
@@ -27,8 +27,7 @@
inline void Mir2Lir::ClobberBody(RegisterInfo* p) {
if (p->IsTemp()) {
DCHECK(!(p->IsLive() && p->IsDirty())) << "Live & dirty temp in clobber";
- p->SetIsLive(false);
- p->SetSReg(INVALID_SREG);
+ p->MarkDead();
p->ResetDefBody();
if (p->IsWide()) {
p->SetIsWide(false);
@@ -36,8 +35,7 @@
// Register pair - deal with the other half.
p = GetRegInfo(p->Partner());
p->SetIsWide(false);
- p->SetIsLive(false);
- p->SetSReg(INVALID_SREG);
+ p->MarkDead();
p->ResetDefBody();
}
}
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 4b1de4b..f762047 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -291,6 +291,20 @@
* 0x0000ffff for 512-bit view of ymm1 // future expansion, if needed
* 0xffffffff for 1024-bit view of ymm1 // future expansion, if needed
*
+ * The "liveness" of a register is handled in a similar way. The liveness_ storage is
+ * held in the widest member of an aliased set. Note, though, that for a temp register to
+ * reused as live, it must both be marked live and the associated SReg() must match the
+ * desired s_reg. This gets a little complicated when dealing with aliased registers. All
+ * members of an aliased set will share the same liveness flags, but each will individually
+ * maintain s_reg_. In this way we can know that at least one member of an
+ * aliased set is live, but will only fully match on the appropriate alias view. For example,
+ * if Arm d1 is live as a double and has s_reg_ set to Dalvik v8 (which also implies v9
+ * because it is wide), its aliases s2 and s3 will show as live, but will have
+ * s_reg_ == INVALID_SREG. An attempt to later AllocLiveReg() of v9 with a single-precision
+ * view will fail because although s3's liveness bit is set, its s_reg_ will not match v9.
+ * This will cause all members of the aliased set to be clobbered and AllocLiveReg() will
+ * report that v9 is currently not live as a single (which is what we want).
+ *
* NOTE: the x86 usage is still somewhat in flux. There are competing notions of how
* to treat xmm registers:
* 1. Treat them all as 128-bits wide, but denote how much data used via bytes field.
@@ -319,14 +333,18 @@
bool InUse() { return (storage_mask_ & master_->used_storage_) != 0; }
void MarkInUse() { master_->used_storage_ |= storage_mask_; }
void MarkFree() { master_->used_storage_ &= ~storage_mask_; }
+ bool IsLive() { return (master_->liveness_ & storage_mask_) == storage_mask_; }
+ void MarkLive() { master_->liveness_ |= storage_mask_; }
+ void MarkDead() {
+ master_->liveness_ &= ~storage_mask_;
+ SetSReg(INVALID_SREG);
+ }
RegStorage GetReg() { return reg_; }
void SetReg(RegStorage reg) { reg_ = reg; }
bool IsTemp() { return is_temp_; }
void SetIsTemp(bool val) { is_temp_ = val; }
bool IsWide() { return wide_value_; }
void SetIsWide(bool val) { wide_value_ = val; }
- bool IsLive() { return live_; }
- void SetIsLive(bool val) { live_ = val; }
bool IsDirty() { return dirty_; }
void SetIsDirty(bool val) { dirty_ = val; }
RegStorage Partner() { return partner_; }
@@ -336,7 +354,13 @@
uint64_t DefUseMask() { return def_use_mask_; }
void SetDefUseMask(uint64_t def_use_mask) { def_use_mask_ = def_use_mask; }
RegisterInfo* Master() { return master_; }
- void SetMaster(RegisterInfo* master) { master_ = master; }
+ void SetMaster(RegisterInfo* master) {
+ master_ = master;
+ if (master != this) {
+ master_->aliased_ = true;
+ }
+ }
+ bool IsAliased() { return aliased_; }
uint32_t StorageMask() { return storage_mask_; }
void SetStorageMask(uint32_t storage_mask) { storage_mask_ = storage_mask; }
LIR* DefStart() { return def_start_; }
@@ -350,12 +374,13 @@
RegStorage reg_;
bool is_temp_; // Can allocate as temp?
bool wide_value_; // Holds a Dalvik wide value (either itself, or part of a pair).
- bool live_; // Is there an associated SSA name?
bool dirty_; // If live, is it dirty?
+ bool aliased_; // Is this the master for other aliased RegisterInfo's?
RegStorage partner_; // If wide_value, other reg of pair or self if 64-bit register.
int s_reg_; // Name of live value.
uint64_t def_use_mask_; // Resources for this element.
uint32_t used_storage_; // 1 bit per 4 bytes of storage. Unused by aliases.
+ uint32_t liveness_; // 1 bit per 4 bytes of storage. Unused by aliases.
RegisterInfo* master_; // Pointer to controlling storage mask.
uint32_t storage_mask_; // Track allocation of sub-units.
LIR *def_start_; // Starting inst in last def sequence.
@@ -598,8 +623,8 @@
void DumpRegPools();
/* Mark a temp register as dead. Does not affect allocation state. */
void Clobber(RegStorage reg);
- void ClobberSRegBody(GrowableArray<RegisterInfo*>* regs, int s_reg);
void ClobberSReg(int s_reg);
+ void ClobberAliases(RegisterInfo* info);
int SRegToPMap(int s_reg);
void RecordCorePromotion(RegStorage reg, int s_reg);
RegStorage AllocPreservedCoreReg(int s_reg);
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index 76553af..ca9a3ab 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -39,8 +39,8 @@
}
Mir2Lir::RegisterInfo::RegisterInfo(RegStorage r, uint64_t mask)
- : reg_(r), is_temp_(false), wide_value_(false), live_(false),
- dirty_(false), partner_(r), s_reg_(INVALID_SREG), def_use_mask_(mask), master_(this) {
+ : reg_(r), is_temp_(false), wide_value_(false), dirty_(false), aliased_(false), partner_(r),
+ s_reg_(INVALID_SREG), def_use_mask_(mask), master_(this) {
switch (r.StorageSize()) {
case 0: storage_mask_ = 0xffffffff; break;
case 4: storage_mask_ = 0x00000001; break;
@@ -51,6 +51,7 @@
case 128: storage_mask_ = 0xffffffff; break;
}
used_storage_ = r.Valid() ? ~storage_mask_ : storage_mask_;
+ liveness_ = used_storage_;
}
Mir2Lir::RegisterPool::RegisterPool(Mir2Lir* m2l, ArenaAllocator* arena,
@@ -139,23 +140,28 @@
void Mir2Lir::Clobber(RegStorage reg) {
if (reg.IsPair()) {
+ DCHECK(!GetRegInfo(reg.GetLow())->IsAliased());
ClobberBody(GetRegInfo(reg.GetLow()));
+ DCHECK(!GetRegInfo(reg.GetHigh())->IsAliased());
ClobberBody(GetRegInfo(reg.GetHigh()));
} else {
- ClobberBody(GetRegInfo(reg));
+ RegisterInfo* info = GetRegInfo(reg);
+ if (info->IsAliased()) {
+ ClobberAliases(info);
+ } else if (info != info->Master() && info->Master()->SReg() != INVALID_SREG) {
+ ClobberBody(info->Master());
+ }
+ ClobberBody(info);
}
}
-void Mir2Lir::ClobberSRegBody(GrowableArray<RegisterInfo*>* regs, int s_reg) {
- GrowableArray<RegisterInfo*>::Iterator it(regs);
- for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
- if ((info->SReg() == s_reg) ||
- (info->IsWide() && (GetRegInfo(info->Partner())->SReg() == s_reg))) {
- // NOTE: a single s_reg may appear multiple times, so we can't short-circuit.
- if (info->IsTemp()) {
- info->SetIsLive(false);
- }
- info->ResetDefBody();
+void Mir2Lir::ClobberAliases(RegisterInfo* info) {
+ DCHECK(info->IsAliased());
+ GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
+ for (RegisterInfo* tmpreg_info = iter.Next(); tmpreg_info != NULL; tmpreg_info = iter.Next()) {
+ if (tmpreg_info->Master() == info) {
+ // tmpreg_info is an alias of info.
+ ClobberBody(tmpreg_info);
}
}
}
@@ -173,15 +179,19 @@
*/
void Mir2Lir::ClobberSReg(int s_reg) {
if (s_reg != INVALID_SREG) {
- /* Reset live temp tracking sanity checker */
- if (kIsDebugBuild) {
- if (s_reg == live_sreg_) {
- live_sreg_ = INVALID_SREG;
+ if (kIsDebugBuild && s_reg == live_sreg_) {
+ live_sreg_ = INVALID_SREG;
+ }
+ GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
+ for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) {
+ if (info->SReg() == s_reg) {
+ if (info->IsAliased()) {
+ // TUNING: if this gets hot, we could add links to follow - aliasing is static.
+ ClobberAliases(info);
+ }
+ ClobberBody(info);
}
}
- ClobberSRegBody(®_pool_->core_regs_, s_reg);
- ClobberSRegBody(®_pool_->sp_regs_, s_reg);
- ClobberSRegBody(®_pool_->dp_regs_, s_reg);
}
}
@@ -296,9 +306,14 @@
if (next >= num_regs)
next = 0;
RegisterInfo* info = regs.Get(next);
+ // Try to allocate a register that doesn't hold a live value.
if (info->IsTemp() && !info->InUse() && !info->IsLive()) {
Clobber(info->GetReg());
info->MarkInUse();
+ /*
+ * NOTE: "wideness" is an attribute of how the container is used, not its physical size.
+ * The caller will set wideness as appropriate.
+ */
info->SetIsWide(false);
*next_temp = next + 1;
return info->GetReg();
@@ -306,11 +321,14 @@
next++;
}
next = *next_temp;
+ // No free non-live regs. Anything we can kill?
for (int i = 0; i< num_regs; i++) {
if (next >= num_regs)
next = 0;
RegisterInfo* info = regs.Get(next);
if (info->IsTemp() && !info->InUse()) {
+ // Got one. Kill it.
+ ClobberSReg(info->SReg());
Clobber(info->GetReg());
info->MarkInUse();
info->SetIsWide(false);
@@ -367,39 +385,47 @@
reg = FindLiveReg(wide ? reg_pool_->dp_regs_ : reg_pool_->sp_regs_, s_reg);
}
if (!reg.Valid() && (reg_class != kFPReg)) {
+ // TODO: add 64-bit core pool similar to above.
reg = FindLiveReg(reg_pool_->core_regs_, s_reg);
}
if (reg.Valid()) {
- if (wide && reg.Is32Bit() && !reg.IsFloat()) {
- // Only allow reg pairs for Core.
+ if (wide && !reg.IsFloat() && !Is64BitInstructionSet(cu_->instruction_set)) {
+ // Only allow reg pairs for core regs on 32-bit targets.
RegStorage high_reg = FindLiveReg(reg_pool_->core_regs_, s_reg + 1);
if (high_reg.Valid()) {
- RegisterInfo* info_lo = GetRegInfo(reg);
- RegisterInfo* info_hi = GetRegInfo(high_reg);
- if (info_lo->IsTemp()) {
- info_lo->MarkInUse();
- }
- if (info_hi->IsTemp()) {
- info_hi->MarkInUse();
- }
reg = RegStorage::MakeRegPair(reg, high_reg);
MarkWide(reg);
} else {
- // Only half available - clobber.
- Clobber(reg);
+ // Only half available.
reg = RegStorage::InvalidReg();
}
}
- if (reg.Valid() && !reg.IsPair()) {
+ if (reg.Valid() && (wide != GetRegInfo(reg)->IsWide())) {
+ // Width mismatch - don't try to reuse.
+ reg = RegStorage::InvalidReg();
+ }
+ }
+ if (reg.Valid()) {
+ if (reg.IsPair()) {
+ RegisterInfo* info_low = GetRegInfo(reg.GetLow());
+ RegisterInfo* info_high = GetRegInfo(reg.GetHigh());
+ if (info_low->IsTemp()) {
+ info_low->MarkInUse();
+ }
+ if (info_high->IsTemp()) {
+ info_high->MarkInUse();
+ }
+ } else {
RegisterInfo* info = GetRegInfo(reg);
if (info->IsTemp()) {
info->MarkInUse();
}
}
- if (reg.Valid() && (wide != GetRegInfo(reg)->IsWide())) {
- // Width mismatch - don't try to reuse.
- Clobber(reg);
- reg = RegStorage::InvalidReg();
+ } else {
+ // Either not found, or something didn't match up. Clobber to prevent any stale instances.
+ ClobberSReg(s_reg);
+ if (wide) {
+ ClobberSReg(s_reg + 1);
}
}
return reg;
@@ -424,6 +450,7 @@
if (reg.IsPair()) {
RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
+ DCHECK_EQ(p_lo->IsLive(), p_hi->IsLive());
res = p_lo->IsLive() || p_hi->IsLive();
} else {
RegisterInfo* p = GetRegInfo(reg);
@@ -482,13 +509,13 @@
RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
p_lo->MarkInUse();
- p_lo->SetIsLive(false);
+ p_lo->MarkDead();
p_hi->MarkInUse();
- p_hi->SetIsLive(false);
+ p_hi->MarkDead();
} else {
RegisterInfo* p = GetRegInfo(reg);
p->MarkInUse();
- p->SetIsLive(false);
+ p->MarkDead();
}
}
@@ -567,6 +594,18 @@
info_hi->ResetDefBody();
}
rl.reg = rl.reg.GetLow();
+ } else {
+ /*
+ * TODO: If not a pair, we can't just drop the high register. On some targets, we may be
+ * able to re-cast the 64-bit register as 32 bits, so it might be worthwhile to revisit
+ * this code. Will probably want to make this a virtual function.
+ */
+ // Can't narrow 64-bit register. Clobber.
+ if (GetRegInfo(rl.reg)->IsTemp()) {
+ Clobber(rl.reg);
+ FreeTemp(rl.reg);
+ }
+ rl.location = kLocDalvikFrame;
}
}
rl.wide = false;
@@ -609,10 +648,7 @@
void Mir2Lir::ClobberAllRegs() {
GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) {
- info->SetIsLive(false);
- info->SetSReg(INVALID_SREG);
- info->ResetDefBody();
- info->SetIsWide(false);
+ ClobberBody(info);
}
}
@@ -671,7 +707,7 @@
FlushSpecificReg(info);
}
DCHECK(info->IsTemp());
- info->SetIsLive(false);
+ info->MarkDead();
info->SetSReg(INVALID_SREG);
info->ResetDefBody();
info->SetIsWide(false);
@@ -697,12 +733,12 @@
if (s_reg != INVALID_SREG) {
ClobberSReg(s_reg);
if (info->IsTemp()) {
- info->SetIsLive(true);
+ info->MarkLive();
}
} else {
// Can't be live if no associated s_reg.
DCHECK(info->IsTemp());
- info->SetIsLive(false);
+ info->MarkDead();
}
info->SetSReg(s_reg);
}
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index a03e5f2..c57b813 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -512,6 +512,19 @@
void Materialize();
/*
+ * Mir2Lir's UpdateLoc() looks to see if the Dalvik value is currently live in any temp register
+ * without regard to data type. In practice, this can result in UpdateLoc returning a
+ * location record for a Dalvik float value in a core register, and vis-versa. For targets
+ * which can inexpensively move data between core and float registers, this can often be a win.
+ * However, for x86 this is generally not a win. These variants of UpdateLoc()
+ * take a register class argument - and will return an in-register location record only if
+ * the value is live in a temp register of the correct class. Additionally, if the value is in
+ * a temp register of the wrong register class, it will be clobbered.
+ */
+ RegLocation UpdateLocTyped(RegLocation loc, int reg_class);
+ RegLocation UpdateLocWideTyped(RegLocation loc, int reg_class);
+
+ /*
* @brief Analyze MIR before generating code, to prepare for the code generation.
*/
void AnalyzeMIR();
diff --git a/compiler/dex/quick/x86/fp_x86.cc b/compiler/dex/quick/x86/fp_x86.cc
index d1c2e70..22e554e 100644
--- a/compiler/dex/quick/x86/fp_x86.cc
+++ b/compiler/dex/quick/x86/fp_x86.cc
@@ -173,7 +173,8 @@
* If the result's location is in memory, then we do not need to do anything
* more since the fstp has already placed the correct value in memory.
*/
- RegLocation rl_result = is_double ? UpdateLocWide(rl_dest) : UpdateLoc(rl_dest);
+ RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest, kFPReg) :
+ UpdateLocTyped(rl_dest, kFPReg);
if (rl_result.location == kLocPhysReg) {
/*
* We already know that the result is in a physical register but do not know if it is the
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index ce5766f..698fce4 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1054,7 +1054,7 @@
int32_t val_hi = High32Bits(val);
FlushAllRegs();
LockCallTemps(); // Prepare for explicit register usage.
- rl_src1 = UpdateLocWide(rl_src1);
+ rl_src1 = UpdateLocWideTyped(rl_src1, kCoreReg);
bool src1_in_reg = rl_src1.location == kLocPhysReg;
int displacement = SRegOffset(rl_src1.s_reg_low);
@@ -1100,8 +1100,8 @@
FlushAllRegs();
LockCallTemps(); // Prepare for explicit register usage.
- rl_src1 = UpdateLocWide(rl_src1);
- rl_src2 = UpdateLocWide(rl_src2);
+ rl_src1 = UpdateLocWideTyped(rl_src1, kCoreReg);
+ rl_src2 = UpdateLocWideTyped(rl_src2, kCoreReg);
// At this point, the VRs are in their home locations.
bool src1_in_reg = rl_src1.location == kLocPhysReg;
@@ -1227,12 +1227,12 @@
}
void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op) {
- rl_dest = UpdateLocWide(rl_dest);
+ rl_dest = UpdateLocWideTyped(rl_dest, kCoreReg);
if (rl_dest.location == kLocPhysReg) {
// Ensure we are in a register pair
RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
- rl_src = UpdateLocWide(rl_src);
+ rl_src = UpdateLocWideTyped(rl_src, kCoreReg);
GenLongRegOrMemOp(rl_result, rl_src, op);
StoreFinalValueWide(rl_dest, rl_result);
return;
@@ -1285,7 +1285,7 @@
rl_result = ForceTempWide(rl_result);
// Perform the operation using the RHS.
- rl_src2 = UpdateLocWide(rl_src2);
+ rl_src2 = UpdateLocWideTyped(rl_src2, kCoreReg);
GenLongRegOrMemOp(rl_result, rl_src2, op);
// And now record that the result is in the temp.
@@ -1296,8 +1296,8 @@
// It wasn't in registers, so it better be in memory.
DCHECK((rl_dest.location == kLocDalvikFrame) ||
(rl_dest.location == kLocCompilerTemp));
- rl_src1 = UpdateLocWide(rl_src1);
- rl_src2 = UpdateLocWide(rl_src2);
+ rl_src1 = UpdateLocWideTyped(rl_src1, kCoreReg);
+ rl_src2 = UpdateLocWideTyped(rl_src2, kCoreReg);
// Get one of the source operands into temporary register.
rl_src1 = LoadValueWide(rl_src1, kCoreReg);
@@ -1731,7 +1731,7 @@
int64_t val = mir_graph_->ConstantValueWide(rl_src);
int32_t val_lo = Low32Bits(val);
int32_t val_hi = High32Bits(val);
- rl_dest = UpdateLocWide(rl_dest);
+ rl_dest = UpdateLocWideTyped(rl_dest, kCoreReg);
// Can we just do this into memory?
if ((rl_dest.location == kLocDalvikFrame) ||
@@ -1779,8 +1779,8 @@
int64_t val = mir_graph_->ConstantValueWide(rl_src2);
int32_t val_lo = Low32Bits(val);
int32_t val_hi = High32Bits(val);
- rl_dest = UpdateLocWide(rl_dest);
- rl_src1 = UpdateLocWide(rl_src1);
+ rl_dest = UpdateLocWideTyped(rl_dest, kCoreReg);
+ rl_src1 = UpdateLocWideTyped(rl_src1, kCoreReg);
// Can we do this directly into the destination registers?
if (rl_dest.location == kLocPhysReg && rl_src1.location == kLocPhysReg &&
@@ -2070,7 +2070,7 @@
if (unary) {
rl_lhs = LoadValue(rl_lhs, kCoreReg);
- rl_result = UpdateLoc(rl_dest);
+ rl_result = UpdateLocTyped(rl_dest, kCoreReg);
rl_result = EvalLoc(rl_dest, kCoreReg, true);
OpRegReg(op, rl_result.reg, rl_lhs.reg);
} else {
@@ -2080,7 +2080,7 @@
LoadValueDirectFixed(rl_rhs, t_reg);
if (is_two_addr) {
// Can we do this directly into memory?
- rl_result = UpdateLoc(rl_dest);
+ rl_result = UpdateLocTyped(rl_dest, kCoreReg);
rl_rhs = LoadValue(rl_rhs, kCoreReg);
if (rl_result.location != kLocPhysReg) {
// Okay, we can do this into memory
@@ -2104,12 +2104,12 @@
// Multiply is 3 operand only (sort of).
if (is_two_addr && op != kOpMul) {
// Can we do this directly into memory?
- rl_result = UpdateLoc(rl_dest);
+ rl_result = UpdateLocTyped(rl_dest, kCoreReg);
if (rl_result.location == kLocPhysReg) {
// Ensure res is in a core reg
rl_result = EvalLoc(rl_dest, kCoreReg, true);
// Can we do this from memory directly?
- rl_rhs = UpdateLoc(rl_rhs);
+ rl_rhs = UpdateLocTyped(rl_rhs, kCoreReg);
if (rl_rhs.location != kLocPhysReg) {
OpRegMem(op, rl_result.reg, rl_rhs);
StoreFinalValue(rl_dest, rl_result);
@@ -2137,8 +2137,8 @@
}
} else {
// Try to use reg/memory instructions.
- rl_lhs = UpdateLoc(rl_lhs);
- rl_rhs = UpdateLoc(rl_rhs);
+ rl_lhs = UpdateLocTyped(rl_lhs, kCoreReg);
+ rl_rhs = UpdateLocTyped(rl_rhs, kCoreReg);
// We can't optimize with FP registers.
if (!IsOperationSafeWithoutTemps(rl_lhs, rl_rhs)) {
// Something is difficult, so fall back to the standard case.
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 05bef52..bc33cb1 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -839,7 +839,7 @@
}
} else {
// Runtime start index.
- rl_start = UpdateLoc(rl_start);
+ rl_start = UpdateLocTyped(rl_start, kCoreReg);
if (rl_start.location == kLocPhysReg) {
// Handle "start index < 0" case.
OpRegReg(kOpXor, rs_rBX, rs_rBX);
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index 8423ec4..03312fd 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -890,4 +890,30 @@
}
}
+RegLocation X86Mir2Lir::UpdateLocTyped(RegLocation loc, int reg_class) {
+ loc = UpdateLoc(loc);
+ if ((loc.location == kLocPhysReg) && (loc.fp != loc.reg.IsFloat())) {
+ if (GetRegInfo(loc.reg)->IsTemp()) {
+ Clobber(loc.reg);
+ FreeTemp(loc.reg);
+ loc.reg = RegStorage::InvalidReg();
+ loc.location = kLocDalvikFrame;
+ }
+ }
+ return loc;
+}
+
+RegLocation X86Mir2Lir::UpdateLocWideTyped(RegLocation loc, int reg_class) {
+ loc = UpdateLocWide(loc);
+ if ((loc.location == kLocPhysReg) && (loc.fp != loc.reg.IsFloat())) {
+ if (GetRegInfo(loc.reg)->IsTemp()) {
+ Clobber(loc.reg);
+ FreeTemp(loc.reg);
+ loc.reg = RegStorage::InvalidReg();
+ loc.location = kLocDalvikFrame;
+ }
+ }
+ return loc;
+}
+
} // namespace art