diff options
author | Jakob Stoklund Olesen <stoklund@2pi.dk> | 2010-06-29 19:15:30 +0000 |
---|---|---|
committer | Jakob Stoklund Olesen <stoklund@2pi.dk> | 2010-06-29 19:15:30 +0000 |
commit | d1303d2a66241c70e0e35dac371636c883235df8 (patch) | |
tree | 34e77e5ecc80dcd6250928df68c0d03d56dfcfca | |
parent | 5d52165e4e2f83e6e66063382f323435da21090d (diff) | |
download | external_llvm-d1303d2a66241c70e0e35dac371636c883235df8.zip external_llvm-d1303d2a66241c70e0e35dac371636c883235df8.tar.gz external_llvm-d1303d2a66241c70e0e35dac371636c883235df8.tar.bz2 |
Fix the handling of partial redefines in the fast register allocator.
A partial redefine needs to be treated like a tied operand, and the register
must be reloaded while processing use operands.
This fixes a bug where partially redefined registers were processed as normal
defs with a reload added. The reload could clobber another use operand if it was
a kill that allowed register reuse.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@107193 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/RegAllocFast.cpp | 56 | ||||
-rw-r--r-- | test/CodeGen/ARM/2010-06-29-PartialRedefFastAlloc.ll | 22 |
2 files changed, 61 insertions, 17 deletions
diff --git a/lib/CodeGen/RegAllocFast.cpp b/lib/CodeGen/RegAllocFast.cpp index 38e650b..fd03b34 100644 --- a/lib/CodeGen/RegAllocFast.cpp +++ b/lib/CodeGen/RegAllocFast.cpp @@ -515,7 +515,6 @@ RAFast::defineVirtReg(MachineInstr *MI, unsigned OpNum, bool New; tie(LRI, New) = LiveVirtRegs.insert(std::make_pair(VirtReg, LiveReg())); LiveReg &LR = LRI->second; - bool PartialRedef = MI->getOperand(OpNum).getSubReg(); if (New) { // If there is no hint, peek at the only use of this register. if ((!Hint || !TargetRegisterInfo::isPhysicalRegister(Hint)) && @@ -527,15 +526,7 @@ RAFast::defineVirtReg(MachineInstr *MI, unsigned OpNum, Hint = DstReg; } allocVirtReg(MI, *LRI, Hint); - // If this is only a partial redefinition, we must reload the other parts. - if (PartialRedef && MI->readsVirtualRegister(VirtReg)) { - const TargetRegisterClass *RC = MRI->getRegClass(VirtReg); - int FI = getStackSpaceFor(VirtReg, RC); - DEBUG(dbgs() << "Reloading for partial redef: %reg" << VirtReg << "\n"); - TII->loadRegFromStackSlot(*MBB, MI, LR.PhysReg, FI, RC, TRI); - ++NumLoads; - } - } else if (LR.LastUse && !PartialRedef) { + } else if (LR.LastUse) { // Redefining a live register - kill at the last use, unless it is this // instruction defining VirtReg multiple times. if (LR.LastUse != MI || LR.LastUse->getOperand(LR.LastOpNum).isUse()) @@ -571,10 +562,16 @@ RAFast::reloadVirtReg(MachineInstr *MI, unsigned OpNum, } else if (LR.Dirty) { if (isLastUseOfLocalReg(MO)) { DEBUG(dbgs() << "Killing last use: " << MO << "\n"); - MO.setIsKill(); + if (MO.isUse()) + MO.setIsKill(); + else + MO.setIsDead(); } else if (MO.isKill()) { DEBUG(dbgs() << "Clearing dubious kill: " << MO << "\n"); MO.setIsKill(false); + } else if (MO.isDead()) { + DEBUG(dbgs() << "Clearing dubious dead: " << MO << "\n"); + MO.setIsDead(false); } } else if (MO.isKill()) { // We must remove kill flags from uses of reloaded registers because the @@ -583,6 +580,9 @@ RAFast::reloadVirtReg(MachineInstr *MI, unsigned OpNum, // This would cause a second reload of %x into a different register. DEBUG(dbgs() << "Clearing clean kill: " << MO << "\n"); MO.setIsKill(false); + } else if (MO.isDead()) { + DEBUG(dbgs() << "Clearing clean dead: " << MO << "\n"); + MO.setIsDead(false); } assert(LR.PhysReg && "Register not assigned"); LR.LastUse = MI; @@ -625,7 +625,8 @@ void RAFast::handleThroughOperands(MachineInstr *MI, if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg)) continue; - if (MO.isEarlyClobber() || MI->isRegTiedToDefOperand(i)) { + if (MO.isEarlyClobber() || MI->isRegTiedToDefOperand(i) || + (MO.getSubReg() && MI->readsVirtualRegister(Reg))) { if (ThroughRegs.insert(Reg)) DEBUG(dbgs() << " %reg" << Reg); } @@ -649,6 +650,7 @@ void RAFast::handleThroughOperands(MachineInstr *MI, } } + SmallVector<unsigned, 8> PartialDefs; DEBUG(dbgs() << "Allocating tied uses and early clobbers.\n"); for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { MachineOperand &MO = MI->getOperand(i); @@ -663,6 +665,14 @@ void RAFast::handleThroughOperands(MachineInstr *MI, LiveRegMap::iterator LRI = reloadVirtReg(MI, i, Reg, 0); unsigned PhysReg = LRI->second.PhysReg; setPhysReg(MI, i, PhysReg); + // Note: we don't update the def operand yet. That would cause the normal + // def-scan to attempt spilling. + } else if (MO.getSubReg() && MI->readsVirtualRegister(Reg)) { + DEBUG(dbgs() << "Partial redefine: " << MO << "\n"); + // Reload the register, but don't assign to the operand just yet. + // That would confuse the later phys-def processing pass. + LiveRegMap::iterator LRI = reloadVirtReg(MI, i, Reg, 0); + PartialDefs.push_back(LRI->second.PhysReg); } else if (MO.isEarlyClobber()) { // Note: defineVirtReg may invalidate MO. LiveRegMap::iterator LRI = defineVirtReg(MI, i, Reg, 0); @@ -683,6 +693,10 @@ void RAFast::handleThroughOperands(MachineInstr *MI, for (const unsigned *AS = TRI->getAliasSet(Reg); *AS; ++AS) UsedInInstr.set(*AS); } + + // Also mark PartialDefs as used to avoid reallocation. + for (unsigned i = 0, e = PartialDefs.size(); i != e; ++i) + UsedInInstr.set(PartialDefs[i]); } void RAFast::AllocateBasicBlock() { @@ -767,7 +781,10 @@ void RAFast::AllocateBasicBlock() { // Mark physreg uses and early clobbers as used. // Find the end of the virtreg operands unsigned VirtOpEnd = 0; - bool hasTiedOps = false, hasEarlyClobbers = false, hasPhysDefs = false; + bool hasTiedOps = false; + bool hasEarlyClobbers = false; + bool hasPartialRedefs = false; + bool hasPhysDefs = false; for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { MachineOperand &MO = MI->getOperand(i); if (!MO.isReg()) continue; @@ -775,11 +792,15 @@ void RAFast::AllocateBasicBlock() { if (!Reg) continue; if (TargetRegisterInfo::isVirtualRegister(Reg)) { VirtOpEnd = i+1; - if (MO.isUse()) + if (MO.isUse()) { hasTiedOps = hasTiedOps || TID.getOperandConstraint(i, TOI::TIED_TO) != -1; - else if (MO.isEarlyClobber()) - hasEarlyClobbers = true; + } else { + if (MO.isEarlyClobber()) + hasEarlyClobbers = true; + if (MO.getSubReg() && MI->readsVirtualRegister(Reg)) + hasPartialRedefs = true; + } continue; } if (!Allocatable.test(Reg)) continue; @@ -800,7 +821,8 @@ void RAFast::AllocateBasicBlock() { // operands. // We didn't detect inline asm tied operands above, so just make this extra // pass for all inline asm. - if (MI->isInlineAsm() || hasEarlyClobbers || (hasTiedOps && hasPhysDefs)) { + if (MI->isInlineAsm() || hasEarlyClobbers || hasPartialRedefs || + (hasTiedOps && hasPhysDefs)) { handleThroughOperands(MI, VirtDead); // Don't attempt coalescing when we have funny stuff going on. CopyDst = 0; diff --git a/test/CodeGen/ARM/2010-06-29-PartialRedefFastAlloc.ll b/test/CodeGen/ARM/2010-06-29-PartialRedefFastAlloc.ll new file mode 100644 index 0000000..389629e --- /dev/null +++ b/test/CodeGen/ARM/2010-06-29-PartialRedefFastAlloc.ll @@ -0,0 +1,22 @@ +; RUN: llc < %s -O0 -mcpu=cortex-a8 | FileCheck %s +target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32" +target triple = "thumbv7-apple-darwin10" + +; This tests the fast register allocator's handling of partial redefines: +; +; %reg1026<def> = VMOVv16i8 0, pred:14, pred:%reg0 +; %reg1028:dsub_1<def> = EXTRACT_SUBREG %reg1026<kill>, 1 +; +; %reg1026 gets allocated %Q0, and if %reg1028 is reloaded for the partial redef, +; it cannot also get %Q0. + +; CHECK: vmov.i8 q0, #0x0 +; CHECK-NOT: vld1.64 {d0,d1} +; CHECK: vmov.f64 d3, d0 + +define i32 @main(i32 %argc, i8** %argv) nounwind { +entry: + %0 = shufflevector <2 x i64> undef, <2 x i64> zeroinitializer, <2 x i32> <i32 1, i32 2> ; <<2 x i64>> [#uses=1] + store <2 x i64> %0, <2 x i64>* undef, align 16 + ret i32 undef +} |