diff --git a/lib/CodeGen/RegAllocLocal.cpp b/lib/CodeGen/RegAllocLocal.cpp index 1885fabab85..920ba5732ad 100644 --- a/lib/CodeGen/RegAllocLocal.cpp +++ b/lib/CodeGen/RegAllocLocal.cpp @@ -189,6 +189,9 @@ namespace { /// void removePhysReg(unsigned PhysReg); + void storeVirtReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned VirtReg, unsigned PhysReg, bool isKill); + /// spillVirtReg - This method spills the value specified by PhysReg into /// the virtual register slot specified by VirtReg. It then updates the RA /// data structures to indicate the fact that PhysReg is now available. @@ -286,6 +289,17 @@ void RALocal::removePhysReg(unsigned PhysReg) { PhysRegsUseOrder.erase(It); } +/// storeVirtReg - Store a virtual register to its assigned stack slot. +void RALocal::storeVirtReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned VirtReg, unsigned PhysReg, + bool isKill) { + const TargetRegisterClass *RC = MF->getRegInfo().getRegClass(VirtReg); + int FrameIndex = getStackSpaceFor(VirtReg, RC); + DEBUG(dbgs() << " to stack slot #" << FrameIndex); + TII->storeRegToStackSlot(MBB, I, PhysReg, isKill, FrameIndex, RC); + ++NumStores; // Update statistics +} /// spillVirtReg - This method spills the value specified by PhysReg into the /// virtual register slot specified by VirtReg. It then updates the RA data @@ -309,15 +323,11 @@ void RALocal::spillVirtReg(MachineBasicBlock &MBB, // Otherwise, there is a virtual register corresponding to this physical // register. We only need to spill it into its stack slot if it has been // modified. - const TargetRegisterClass *RC = MF->getRegInfo().getRegClass(VirtReg); - int FrameIndex = getStackSpaceFor(VirtReg, RC); - DEBUG(dbgs() << " to stack slot #" << FrameIndex); // If the instruction reads the register that's spilled, (e.g. this can // happen if it is a move to a physical register), then the spill // instruction is not a kill. bool isKill = !(I != MBB.end() && I->readsRegister(PhysReg)); - TII->storeRegToStackSlot(MBB, I, PhysReg, isKill, FrameIndex, RC); - ++NumStores; // Update statistics + storeVirtReg(MBB, I, VirtReg, PhysReg, isKill); } getVirt2PhysRegMapSlot(VirtReg) = 0; // VirtReg no longer available @@ -801,9 +811,12 @@ void RALocal::AllocateBasicBlock(MachineBasicBlock &MBB) { dbgs() << "\nStarting RegAlloc of: " << *MI; dbgs() << " Regs have values: "; for (unsigned i = 0; i != TRI->getNumRegs(); ++i) - if (PhysRegsUsed[i] != -1 && PhysRegsUsed[i] != -2) + if (PhysRegsUsed[i] != -1 && PhysRegsUsed[i] != -2) { + if (PhysRegsUsed[i] && isVirtRegModified(PhysRegsUsed[i])) + dbgs() << "*"; dbgs() << "[" << TRI->getName(i) << ",%reg" << PhysRegsUsed[i] << "] "; + } dbgs() << '\n'; }); @@ -1092,6 +1105,20 @@ void RALocal::AllocateBasicBlock(MachineBasicBlock &MBB) { } } + // If this instruction is a call, make sure there are no dirty registers. The + // call might throw an exception, and the landing pad expects to find all + // registers in stack slots. + if (TID.isCall()) + for (unsigned i = 0, e = TRI->getNumRegs(); i != e; ++i) { + if (PhysRegsUsed[i] <= 0) continue; + unsigned VirtReg = PhysRegsUsed[i]; + if (!isVirtRegModified(VirtReg)) continue; + DEBUG(dbgs() << " Storing dirty %reg" << VirtReg); + storeVirtReg(MBB, MI, VirtReg, i, false); + markVirtRegModified(VirtReg, false); + DEBUG(dbgs() << " because the call might throw\n"); + } + // Finally, if this is a noop copy instruction, zap it. (Except that if // the copy is dead, it must be kept to avoid messing up liveness info for // the register scavenger. See pr4100.) diff --git a/test/CodeGen/X86/2010-04-30-LocalAlloc-LandingPad.ll b/test/CodeGen/X86/2010-04-30-LocalAlloc-LandingPad.ll new file mode 100644 index 00000000000..f5048afd7cc --- /dev/null +++ b/test/CodeGen/X86/2010-04-30-LocalAlloc-LandingPad.ll @@ -0,0 +1,143 @@ +; RUN: llc < %s -O0 -regalloc=local -relocation-model=pic -disable-fp-elim | FileCheck %s +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32" +target triple = "i386-apple-darwin10.0.0" + +%struct.S = type { [2 x i8*] } + +@_ZTIi = external constant i8* ; [#uses=1] +@.str = internal constant [4 x i8] c"%p\0A\00" ; <[4 x i8]*> [#uses=1] +@llvm.used = appending global [1 x i8*] [i8* bitcast (i8* (%struct.S*, i32, %struct.S*)* @_Z4test1SiS_ to i8*)], section "llvm.metadata" ; <[1 x i8*]*> [#uses=0] + +; Verify that %esi gets spilled before the call. +; CHECK: Z4test1SiS +; CHECK: movl %esi,{{.*}}(%ebp) +; CHECK: call __Z6throwsv + +define i8* @_Z4test1SiS_(%struct.S* byval %s1, i32 %n, %struct.S* byval %s2) ssp { +entry: + %retval = alloca i8*, align 4 ; [#uses=2] + %n.addr = alloca i32, align 4 ; [#uses=1] + %_rethrow = alloca i8* ; [#uses=4] + %0 = alloca i32, align 4 ; [#uses=1] + %cleanup.dst = alloca i32 ; [#uses=3] + %cleanup.dst7 = alloca i32 ; [#uses=6] + store i32 %n, i32* %n.addr + invoke void @_Z6throwsv() + to label %invoke.cont unwind label %try.handler + +invoke.cont: ; preds = %entry + store i32 1, i32* %cleanup.dst7 + br label %finally + +terminate.handler: ; preds = %match.end + %exc = call i8* @llvm.eh.exception() ; [#uses=1] + %1 = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %exc, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i32 1) ; [#uses=0] + call void @_ZSt9terminatev() noreturn nounwind + unreachable + +try.handler: ; preds = %entry + %exc1 = call i8* @llvm.eh.exception() ; [#uses=3] + %selector = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %exc1, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null) ; [#uses=1] + %2 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) ; [#uses=1] + %3 = icmp eq i32 %selector, %2 ; [#uses=1] + br i1 %3, label %match, label %catch.next + +match: ; preds = %try.handler + %4 = call i8* @__cxa_begin_catch(i8* %exc1) ; [#uses=1] + %5 = bitcast i8* %4 to i32* ; [#uses=1] + %6 = load i32* %5 ; [#uses=1] + store i32 %6, i32* %0 + %call = invoke i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), %struct.S* %s2) + to label %invoke.cont2 unwind label %match.handler ; [#uses=0] + +invoke.cont2: ; preds = %match + store i32 1, i32* %cleanup.dst + br label %match.end + +match.handler: ; preds = %match + %exc3 = call i8* @llvm.eh.exception() ; [#uses=2] + %7 = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %exc3, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i32 0) ; [#uses=0] + store i8* %exc3, i8** %_rethrow + store i32 2, i32* %cleanup.dst + br label %match.end + +cleanup.pad: ; preds = %cleanup.switch + store i32 1, i32* %cleanup.dst7 + br label %finally + +cleanup.pad4: ; preds = %cleanup.switch + store i32 2, i32* %cleanup.dst7 + br label %finally + +match.end: ; preds = %match.handler, %invoke.cont2 + invoke void @__cxa_end_catch() + to label %invoke.cont5 unwind label %terminate.handler + +invoke.cont5: ; preds = %match.end + br label %cleanup.switch + +cleanup.switch: ; preds = %invoke.cont5 + %tmp = load i32* %cleanup.dst ; [#uses=1] + switch i32 %tmp, label %cleanup.end [ + i32 1, label %cleanup.pad + i32 2, label %cleanup.pad4 + ] + +cleanup.end: ; preds = %cleanup.switch + %exc6 = call i8* @llvm.eh.exception() ; [#uses=1] + store i8* %exc6, i8** %_rethrow + store i32 2, i32* %cleanup.dst7 + br label %finally + +catch.next: ; preds = %try.handler + store i8* %exc1, i8** %_rethrow + store i32 2, i32* %cleanup.dst7 + br label %finally + +finally: ; preds = %catch.next, %cleanup.end, %cleanup.pad4, %cleanup.pad, %invoke.cont + br label %cleanup.switch9 + +cleanup.switch9: ; preds = %finally + %tmp8 = load i32* %cleanup.dst7 ; [#uses=1] + switch i32 %tmp8, label %cleanup.end10 [ + i32 1, label %finally.end + i32 2, label %finally.throw + ] + +cleanup.end10: ; preds = %cleanup.switch9 + br label %finally.end + +finally.throw: ; preds = %cleanup.switch9 + %8 = load i8** %_rethrow ; [#uses=1] + call void @_Unwind_Resume_or_Rethrow(i8* %8) + unreachable + +finally.end: ; preds = %cleanup.end10, %cleanup.switch9 + %tmp11 = getelementptr inbounds %struct.S* %s1, i32 0, i32 0 ; <[2 x i8*]*> [#uses=1] + %arraydecay = getelementptr inbounds [2 x i8*]* %tmp11, i32 0, i32 0 ; [#uses=1] + %arrayidx = getelementptr inbounds i8** %arraydecay, i32 1 ; [#uses=1] + %tmp12 = load i8** %arrayidx ; [#uses=1] + store i8* %tmp12, i8** %retval + %9 = load i8** %retval ; [#uses=1] + ret i8* %9 +} + +declare void @_Z6throwsv() ssp + +declare i32 @__gxx_personality_v0(...) + +declare i8* @llvm.eh.exception() nounwind readonly + +declare i32 @llvm.eh.selector(i8*, i8*, ...) nounwind + +declare void @_ZSt9terminatev() + +declare void @_Unwind_Resume_or_Rethrow(i8*) + +declare i32 @llvm.eh.typeid.for(i8*) nounwind + +declare i8* @__cxa_begin_catch(i8*) + +declare i32 @printf(i8*, ...) + +declare void @__cxa_end_catch()