diff --git a/lib/CodeGen/RegisterScavenging.cpp b/lib/CodeGen/RegisterScavenging.cpp index eb1570df52c..c71d3be08b4 100644 --- a/lib/CodeGen/RegisterScavenging.cpp +++ b/lib/CodeGen/RegisterScavenging.cpp @@ -19,9 +19,11 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" using namespace llvm; @@ -76,6 +78,7 @@ void RegScavenger::enterBasicBlock(MachineBasicBlock *mbb) { const TargetMachine &TM = MF.getTarget(); TII = TM.getInstrInfo(); TRI = TM.getRegisterInfo(); + MRI = &MF.getRegInfo(); assert((NumPhysRegs == 0 || NumPhysRegs == TRI->getNumRegs()) && "Target changed?"); @@ -119,7 +122,7 @@ void RegScavenger::restoreScavengedReg() { return; TII->loadRegFromStackSlot(*MBB, MBBI, ScavengedReg, - ScavengingFrameIndex, ScavengedRC); + ScavengingFrameIndex, ScavengedRC); MachineBasicBlock::iterator II = prior(MBBI); TRI->eliminateFrameIndex(II, 0, this); setUsed(ScavengedReg); @@ -127,6 +130,40 @@ void RegScavenger::restoreScavengedReg() { ScavengedRC = NULL; } +/// isLiveInButUnusedBefore - Return true if register is livein the MBB not +/// not used before it reaches the MI that defines register. +static bool isLiveInButUnusedBefore(unsigned Reg, MachineInstr *MI, + MachineBasicBlock *MBB, + const TargetRegisterInfo *TRI, + MachineRegisterInfo* MRI) { + // First check if register is livein. + bool isLiveIn = false; + for (MachineBasicBlock::const_livein_iterator I = MBB->livein_begin(), + E = MBB->livein_end(); I != E; ++I) + if (Reg == *I || TRI->isSuperRegister(Reg, *I)) { + isLiveIn = true; + break; + } + if (!isLiveIn) + return false; + + // Is there any use of it before the specified MI? + SmallPtrSet UsesInMBB; + for (MachineRegisterInfo::use_iterator UI = MRI->use_begin(Reg), + UE = MRI->use_end(); UI != UE; ++UI) { + MachineInstr *UseMI = &*UI; + if (UseMI->getParent() == MBB) + UsesInMBB.insert(UseMI); + } + if (UsesInMBB.empty()) + return true; + + for (MachineBasicBlock::iterator I = MBB->begin(), E = MI; I != E; ++I) + if (UsesInMBB.count(&*I)) + return false; + return true; +} + void RegScavenger::forward() { // Move ptr forward. if (!Tracking) { @@ -203,7 +240,10 @@ void RegScavenger::forward() { if (RedefinesSuperRegPart(MI, MO, TRI)) continue; - assert((isUnused(Reg) || isReserved(Reg)) && + // Implicit def is allowed to "re-define" any register. + assert((isReserved(Reg) || isUnused(Reg) || + MI->getOpcode() == TargetInstrInfo::IMPLICIT_DEF || + isLiveInButUnusedBefore(Reg, MI, MBB, TRI, MRI)) && "Re-defining a live register!"); setUsed(Reg); } diff --git a/test/CodeGen/ARM/2008-04-04-ScavengerAssert.ll b/test/CodeGen/ARM/2008-04-04-ScavengerAssert.ll new file mode 100644 index 00000000000..74717f85dfd --- /dev/null +++ b/test/CodeGen/ARM/2008-04-04-ScavengerAssert.ll @@ -0,0 +1,60 @@ +; RUN: llvm-as < %s | llc -march=arm + +@numBinsY = external global i32 ; [#uses=1] + +declare double @pow(double, double) + +define void @main(i32 %argc, i8** %argv) noreturn nounwind { +entry: + br i1 false, label %bb34.outer.i.i.i, label %cond_false674 +bb34.outer.i.i.i: ; preds = %entry + br i1 false, label %bb2.i.i.i, label %bb47.i.i.i +bb2.i.i.i: ; preds = %bb34.outer.i.i.i + %tmp24.i.i.i = call double @pow( double 0.000000e+00, double 2.000000e+00 ) ; [#uses=0] + ret void +bb47.i.i.i: ; preds = %bb34.outer.i.i.i + br i1 false, label %bb220.i.i.i, label %bb62.preheader.i.i.i +bb62.preheader.i.i.i: ; preds = %bb47.i.i.i + ret void +bb220.i.i.i: ; preds = %bb47.i.i.i + br i1 false, label %bb248.i.i.i, label %cond_next232.i.i.i +cond_next232.i.i.i: ; preds = %bb220.i.i.i + ret void +bb248.i.i.i: ; preds = %bb220.i.i.i + br i1 false, label %bb300.i.i.i, label %cond_false256.i.i.i +cond_false256.i.i.i: ; preds = %bb248.i.i.i + ret void +bb300.i.i.i: ; preds = %bb248.i.i.i + store i32 undef, i32* @numBinsY, align 4 + ret void +cond_false674: ; preds = %entry + ret void +} + + %struct.anon = type { %struct.rnode*, %struct.rnode* } + %struct.ch_set = type { { i8, i8 }*, %struct.ch_set* } + %struct.pat_list = type { i32, %struct.pat_list* } + %struct.rnode = type { i16, { %struct.anon }, i16, %struct.pat_list*, %struct.pat_list* } + +define fastcc { i16, %struct.rnode* }* @get_token(i8** %s) nounwind { +entry: + br i1 false, label %bb42, label %bb78 +bb42: ; preds = %entry + br label %cond_next119.i +bb17.i: ; preds = %cond_next119.i + br i1 false, label %cond_true53.i, label %cond_false99.i +cond_true53.i: ; preds = %bb17.i + ret { i16, %struct.rnode* }* null +cond_false99.i: ; preds = %bb17.i + %tmp106.i = malloc %struct.ch_set ; <%struct.ch_set*> [#uses=1] + br i1 false, label %bb126.i, label %cond_next119.i +cond_next119.i: ; preds = %cond_false99.i, %bb42 + %curr_ptr.0.reg2mem.0.i = phi %struct.ch_set* [ %tmp106.i, %cond_false99.i ], [ null, %bb42 ] ; <%struct.ch_set*> [#uses=2] + %prev_ptr.0.reg2mem.0.i = phi %struct.ch_set* [ %curr_ptr.0.reg2mem.0.i, %cond_false99.i ], [ undef, %bb42 ] ; <%struct.ch_set*> [#uses=1] + br i1 false, label %bb126.i, label %bb17.i +bb126.i: ; preds = %cond_next119.i, %cond_false99.i + %prev_ptr.0.reg2mem.1.i = phi %struct.ch_set* [ %prev_ptr.0.reg2mem.0.i, %cond_next119.i ], [ %curr_ptr.0.reg2mem.0.i, %cond_false99.i ] ; <%struct.ch_set*> [#uses=0] + ret { i16, %struct.rnode* }* null +bb78: ; preds = %entry + ret { i16, %struct.rnode* }* null +}