diff options
| -rw-r--r-- | compiler/dex/frontend.cc | 2 | ||||
| -rw-r--r-- | compiler/dex/quick/gen_loadstore.cc | 6 | ||||
| -rw-r--r-- | compiler/dex/quick/mir_to_lir-inl.h | 6 | ||||
| -rw-r--r-- | compiler/dex/quick/mir_to_lir.h | 35 | ||||
| -rw-r--r-- | compiler/dex/quick/ralloc_util.cc | 130 | ||||
| -rw-r--r-- | compiler/dex/quick/x86/codegen_x86.h | 13 | ||||
| -rw-r--r-- | compiler/dex/quick/x86/fp_x86.cc | 3 | ||||
| -rw-r--r-- | compiler/dex/quick/x86/int_x86.cc | 34 | ||||
| -rw-r--r-- | compiler/dex/quick/x86/target_x86.cc | 2 | ||||
| -rw-r--r-- | compiler/dex/quick/x86/utility_x86.cc | 26 |
10 files changed, 180 insertions, 77 deletions
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index 89c642d21e..d9d392f671 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -46,7 +46,7 @@ static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimi // (1 << kNullCheckElimination) | // (1 << kClassInitCheckElimination) | // (1 << kPromoteRegs) | - (1 << kTrackLiveTemps) | // FIXME: disable until liveness issue fixed. + // (1 << kTrackLiveTemps) | // (1 << kSafeOptimizations) | // (1 << kBBOpt) | // (1 << kMatch) | diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc index fc6af29119..faa9461728 100644 --- a/compiler/dex/quick/gen_loadstore.cc +++ b/compiler/dex/quick/gen_loadstore.cc @@ -233,7 +233,11 @@ void Mir2Lir::StoreValueWide(RegLocation rl_dest, RegLocation rl_src) { 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 f5d71c439d..b5b50a471e 100644 --- a/compiler/dex/quick/mir_to_lir-inl.h +++ b/compiler/dex/quick/mir_to_lir-inl.h @@ -27,8 +27,7 @@ namespace art { 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 @@ inline void Mir2Lir::ClobberBody(RegisterInfo* p) { // 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 4b1de4b21e..f762047d26 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -291,6 +291,20 @@ class Mir2Lir : public Backend { * 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 @@ class Mir2Lir : public Backend { 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 @@ class Mir2Lir : public Backend { 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 @@ class Mir2Lir : public Backend { 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 @@ class Mir2Lir : public Backend { 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 76553af9d7..ca9a3ab64f 100644 --- a/compiler/dex/quick/ralloc_util.cc +++ b/compiler/dex/quick/ralloc_util.cc @@ -39,8 +39,8 @@ void Mir2Lir::ResetRegPool() { } 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 @@ Mir2Lir::RegisterInfo::RegisterInfo(RegStorage r, uint64_t mask) 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::DumpRegPools() { 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::ClobberSRegBody(GrowableArray<RegisterInfo*>* regs, int s_reg) { */ 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 @@ RegStorage Mir2Lir::AllocTempBody(GrowableArray<RegisterInfo*> ®s, int* next_ 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 @@ RegStorage Mir2Lir::AllocTempBody(GrowableArray<RegisterInfo*> ®s, int* next_ 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 @@ RegStorage Mir2Lir::AllocLiveReg(int s_reg, int reg_class, bool wide) { 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 @@ bool Mir2Lir::IsLive(RegStorage reg) { 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 @@ void Mir2Lir::LockTemp(RegStorage reg) { 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 @@ RegLocation Mir2Lir::WideToNarrow(RegLocation rl) { 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::ResetDefTracking() { 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 @@ void Mir2Lir::FlushAllRegs() { FlushSpecificReg(info); } DCHECK(info->IsTemp()); - info->SetIsLive(false); + info->MarkDead(); info->SetSReg(INVALID_SREG); info->ResetDefBody(); info->SetIsWide(false); @@ -697,12 +733,12 @@ void Mir2Lir::MarkLiveReg(RegStorage reg, int s_reg) { 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 a03e5f2e04..c57b81341c 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -512,6 +512,19 @@ class X86Mir2Lir FINAL : public Mir2Lir { 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 d1c2e70c2c..22e554ea48 100644 --- a/compiler/dex/quick/x86/fp_x86.cc +++ b/compiler/dex/quick/x86/fp_x86.cc @@ -173,7 +173,8 @@ void X86Mir2Lir::GenLongToFP(RegLocation rl_dest, RegLocation rl_src, bool is_do * 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 ce5766f78f..698fce4178 100644 --- a/compiler/dex/quick/x86/int_x86.cc +++ b/compiler/dex/quick/x86/int_x86.cc @@ -1054,7 +1054,7 @@ void X86Mir2Lir::GenMulLong(Instruction::Code, RegLocation rl_dest, RegLocation 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 @@ void X86Mir2Lir::GenMulLong(Instruction::Code, RegLocation rl_dest, RegLocation 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::GenLongRegOrMemOp(RegLocation rl_dest, RegLocation rl_src, } 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 @@ void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src1, 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 @@ void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src1, // 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 @@ void X86Mir2Lir::GenLongImm(RegLocation rl_dest, RegLocation rl_src, Instruction 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 @@ void X86Mir2Lir::GenLongLongImm(RegLocation rl_dest, RegLocation rl_src1, 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 @@ void X86Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest, 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 @@ void X86Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest, 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 @@ void X86Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest, // 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 @@ void X86Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest, } } 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 05bef52077..bc33cb1fc3 100644 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -839,7 +839,7 @@ bool X86Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) { } } 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 8423ec4a50..03312fdaa3 100644 --- a/compiler/dex/quick/x86/utility_x86.cc +++ b/compiler/dex/quick/x86/utility_x86.cc @@ -890,4 +890,30 @@ void X86Mir2Lir::AnalyzeDoubleUse(RegLocation use) { } } +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 |