diff options
Diffstat (limited to 'compiler/dex/quick/x86/target_x86.cc')
-rw-r--r-- | compiler/dex/quick/x86/target_x86.cc | 252 |
1 files changed, 251 insertions, 1 deletions
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index b281063a4a..5c993c5ac5 100644 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -416,7 +416,7 @@ int X86Mir2Lir::AllocTypedTempPair(bool fp_hint, if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) { low_reg = AllocTempDouble(); - high_reg = low_reg + 1; + high_reg = low_reg; // only one allocated! res = (low_reg & 0xff) | ((high_reg & 0xff) << 8); return res; } @@ -546,4 +546,254 @@ const char* X86Mir2Lir::GetTargetInstFmt(int opcode) { return X86Mir2Lir::EncodingMap[opcode].fmt; } +/* + * Return an updated location record with current in-register status. + * If the value lives in live temps, reflect that fact. No code + * is generated. If the live value is part of an older pair, + * clobber both low and high. + */ +// TODO: Reunify with common code after 'pair mess' has been fixed +RegLocation X86Mir2Lir::UpdateLocWide(RegLocation loc) { + DCHECK(loc.wide); + DCHECK(CheckCorePoolSanity()); + if (loc.location != kLocPhysReg) { + DCHECK((loc.location == kLocDalvikFrame) || + (loc.location == kLocCompilerTemp)); + // Are the dalvik regs already live in physical registers? + RegisterInfo* info_lo = AllocLive(loc.s_reg_low, kAnyReg); + + // Handle FP registers specially on x86. + if (info_lo && IsFpReg(info_lo->reg)) { + bool match = true; + + // We can't match a FP register with a pair of Core registers. + match = match && (info_lo->pair == 0); + + if (match) { + // We can reuse;update the register usage info. + loc.low_reg = info_lo->reg; + loc.high_reg = info_lo->reg; // Play nice with existing code. + loc.location = kLocPhysReg; + loc.vec_len = kVectorLength8; + DCHECK(IsFpReg(loc.low_reg)); + return loc; + } + // We can't easily reuse; clobber and free any overlaps. + if (info_lo) { + Clobber(info_lo->reg); + FreeTemp(info_lo->reg); + if (info_lo->pair) + Clobber(info_lo->partner); + } + } else { + RegisterInfo* info_hi = AllocLive(GetSRegHi(loc.s_reg_low), kAnyReg); + bool match = true; + match = match && (info_lo != NULL); + match = match && (info_hi != NULL); + // Are they both core or both FP? + match = match && (IsFpReg(info_lo->reg) == IsFpReg(info_hi->reg)); + // If a pair of floating point singles, are they properly aligned? + if (match && IsFpReg(info_lo->reg)) { + match &= ((info_lo->reg & 0x1) == 0); + match &= ((info_hi->reg - info_lo->reg) == 1); + } + // If previously used as a pair, it is the same pair? + if (match && (info_lo->pair || info_hi->pair)) { + match = (info_lo->pair == info_hi->pair); + match &= ((info_lo->reg == info_hi->partner) && + (info_hi->reg == info_lo->partner)); + } + if (match) { + // Can reuse - update the register usage info + loc.low_reg = info_lo->reg; + loc.high_reg = info_hi->reg; + loc.location = kLocPhysReg; + MarkPair(loc.low_reg, loc.high_reg); + DCHECK(!IsFpReg(loc.low_reg) || ((loc.low_reg & 0x1) == 0)); + return loc; + } + // Can't easily reuse - clobber and free any overlaps + if (info_lo) { + Clobber(info_lo->reg); + FreeTemp(info_lo->reg); + if (info_lo->pair) + Clobber(info_lo->partner); + } + if (info_hi) { + Clobber(info_hi->reg); + FreeTemp(info_hi->reg); + if (info_hi->pair) + Clobber(info_hi->partner); + } + } + } + return loc; +} + +// TODO: Reunify with common code after 'pair mess' has been fixed +RegLocation X86Mir2Lir::EvalLocWide(RegLocation loc, int reg_class, bool update) { + DCHECK(loc.wide); + int32_t new_regs; + int32_t low_reg; + int32_t high_reg; + + loc = UpdateLocWide(loc); + + /* If it is already in a register, we can assume proper form. Is it the right reg class? */ + if (loc.location == kLocPhysReg) { + DCHECK_EQ(IsFpReg(loc.low_reg), loc.IsVectorScalar()); + if (!RegClassMatches(reg_class, loc.low_reg)) { + /* It is the wrong register class. Reallocate and copy. */ + if (!IsFpReg(loc.low_reg)) { + // We want this in a FP reg, and it is in core registers. + DCHECK(reg_class != kCoreReg); + // Allocate this into any FP reg, and mark it with the right size. + low_reg = AllocTypedTemp(true, reg_class); + OpVectorRegCopyWide(low_reg, loc.low_reg, loc.high_reg); + CopyRegInfo(low_reg, loc.low_reg); + Clobber(loc.low_reg); + Clobber(loc.high_reg); + loc.low_reg = low_reg; + loc.high_reg = low_reg; // Play nice with existing code. + loc.vec_len = kVectorLength8; + } else { + // The value is in a FP register, and we want it in a pair of core registers. + DCHECK_EQ(reg_class, kCoreReg); + DCHECK_EQ(loc.low_reg, loc.high_reg); + new_regs = AllocTypedTempPair(false, kCoreReg); // Force to core registers. + low_reg = new_regs & 0xff; + high_reg = (new_regs >> 8) & 0xff; + DCHECK_NE(low_reg, high_reg); + OpRegCopyWide(low_reg, high_reg, loc.low_reg, loc.high_reg); + CopyRegInfo(low_reg, loc.low_reg); + CopyRegInfo(high_reg, loc.high_reg); + Clobber(loc.low_reg); + Clobber(loc.high_reg); + loc.low_reg = low_reg; + loc.high_reg = high_reg; + MarkPair(loc.low_reg, loc.high_reg); + DCHECK(!IsFpReg(loc.low_reg) || ((loc.low_reg & 0x1) == 0)); + } + } + return loc; + } + + DCHECK_NE(loc.s_reg_low, INVALID_SREG); + if (IsFpReg(loc.low_reg) && reg_class != kCoreReg) { + // Need a wide vector register. + low_reg = AllocTypedTemp(true, reg_class); + loc.low_reg = low_reg; + loc.high_reg = low_reg; // Play nice with existing code. + loc.vec_len = kVectorLength8; + if (update) { + loc.location = kLocPhysReg; + MarkLive(loc.low_reg, loc.s_reg_low); + } + DCHECK(IsFpReg(loc.low_reg)); + } else { + DCHECK_NE(GetSRegHi(loc.s_reg_low), INVALID_SREG); + + new_regs = AllocTypedTempPair(loc.fp, reg_class); + loc.low_reg = new_regs & 0xff; + loc.high_reg = (new_regs >> 8) & 0xff; + + MarkPair(loc.low_reg, loc.high_reg); + if (update) { + loc.location = kLocPhysReg; + MarkLive(loc.low_reg, loc.s_reg_low); + MarkLive(loc.high_reg, GetSRegHi(loc.s_reg_low)); + } + DCHECK(!IsFpReg(loc.low_reg) || ((loc.low_reg & 0x1) == 0)); + } + return loc; +} + +// TODO: Reunify with common code after 'pair mess' has been fixed +RegLocation X86Mir2Lir::EvalLoc(RegLocation loc, int reg_class, bool update) { + int new_reg; + + if (loc.wide) + return EvalLocWide(loc, reg_class, update); + + loc = UpdateLoc(loc); + + if (loc.location == kLocPhysReg) { + if (!RegClassMatches(reg_class, loc.low_reg)) { + /* Wrong register class. Realloc, copy and transfer ownership. */ + new_reg = AllocTypedTemp(loc.fp, reg_class); + OpRegCopy(new_reg, loc.low_reg); + CopyRegInfo(new_reg, loc.low_reg); + Clobber(loc.low_reg); + loc.low_reg = new_reg; + if (IsFpReg(loc.low_reg) && reg_class != kCoreReg) + loc.vec_len = kVectorLength4; + } + return loc; + } + + DCHECK_NE(loc.s_reg_low, INVALID_SREG); + + new_reg = AllocTypedTemp(loc.fp, reg_class); + loc.low_reg = new_reg; + if (IsFpReg(loc.low_reg) && reg_class != kCoreReg) + loc.vec_len = kVectorLength4; + + if (update) { + loc.location = kLocPhysReg; + MarkLive(loc.low_reg, loc.s_reg_low); + } + return loc; +} + +int X86Mir2Lir::AllocTempDouble() { + // We really don't need a pair of registers. + return AllocTempFloat(); +} + +// TODO: Reunify with common code after 'pair mess' has been fixed +void X86Mir2Lir::ResetDefLocWide(RegLocation rl) { + DCHECK(rl.wide); + RegisterInfo* p_low = IsTemp(rl.low_reg); + if (IsFpReg(rl.low_reg)) { + // We are using only the low register. + if (p_low && !(cu_->disable_opt & (1 << kSuppressLoads))) { + NullifyRange(p_low->def_start, p_low->def_end, p_low->s_reg, rl.s_reg_low); + } + ResetDef(rl.low_reg); + } else { + RegisterInfo* p_high = IsTemp(rl.high_reg); + if (p_low && !(cu_->disable_opt & (1 << kSuppressLoads))) { + DCHECK(p_low->pair); + NullifyRange(p_low->def_start, p_low->def_end, p_low->s_reg, rl.s_reg_low); + } + if (p_high && !(cu_->disable_opt & (1 << kSuppressLoads))) { + DCHECK(p_high->pair); + } + ResetDef(rl.low_reg); + ResetDef(rl.high_reg); + } +} + +void X86Mir2Lir::GenConstWide(RegLocation rl_dest, int64_t value) { + // Can we do this directly to memory? + rl_dest = UpdateLocWide(rl_dest); + if ((rl_dest.location == kLocDalvikFrame) || + (rl_dest.location == kLocCompilerTemp)) { + int32_t val_lo = Low32Bits(value); + int32_t val_hi = High32Bits(value); + int rBase = TargetReg(kSp); + int displacement = SRegOffset(rl_dest.s_reg_low); + + LIR * store = NewLIR3(kX86Mov32MI, rBase, displacement + LOWORD_OFFSET, val_lo); + AnnotateDalvikRegAccess(store, (displacement + LOWORD_OFFSET) >> 2, + false /* is_load */, true /* is64bit */); + store = NewLIR3(kX86Mov32MI, rBase, displacement + HIWORD_OFFSET, val_hi); + AnnotateDalvikRegAccess(store, (displacement + HIWORD_OFFSET) >> 2, + false /* is_load */, true /* is64bit */); + return; + } + + // Just use the standard code to do the generation. + Mir2Lir::GenConstWide(rl_dest, value); +} } // namespace art |