diff --git a/lib/CodeGen/VirtRegMap.cpp b/lib/CodeGen/VirtRegMap.cpp index 609e12d53ec..3793af077db 100644 --- a/lib/CodeGen/VirtRegMap.cpp +++ b/lib/CodeGen/VirtRegMap.cpp @@ -302,6 +302,7 @@ namespace { MachineRegisterInfo *RegInfo; const TargetRegisterInfo *TRI; const TargetInstrInfo *TII; + DenseMap DistanceMap; public: bool runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM) { RegInfo = &MF.getRegInfo(); @@ -333,6 +334,9 @@ namespace { return true; } private: + void TransferDeadness(MachineBasicBlock *MBB, unsigned CurDist, + unsigned Reg, BitVector &RegKills, + std::vector &KillOps); bool PrepForUnfoldOpti(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MII, std::vector &MaybeDeadStores, @@ -943,6 +947,7 @@ bool LocalSpiller::PrepForUnfoldOpti(MachineBasicBlock &MBB, VRM.assignVirt2Phys(UnfoldVR, UnfoldPR); VRM.virtFolded(VirtReg, FoldedMI, VirtRegMap::isRef); MII = MBB.insert(MII, FoldedMI); + InvalidateKills(MI, RegKills, KillOps); VRM.RemoveMachineInstrFromMaps(&MI); MBB.erase(&MI); return true; @@ -1026,6 +1031,49 @@ void LocalSpiller::SpillRegToStackSlot(MachineBasicBlock &MBB, ++NumStores; } +/// TransferDeadness - A identity copy definition is dead and it's being +/// removed. Find the last def or use and mark it as dead / kill. +void LocalSpiller::TransferDeadness(MachineBasicBlock *MBB, unsigned CurDist, + unsigned Reg, BitVector &RegKills, + std::vector &KillOps) { + int LastUDDist = -1; + MachineInstr *LastUDMI = NULL; + for (MachineRegisterInfo::reg_iterator RI = RegInfo->reg_begin(Reg), + RE = RegInfo->reg_end(); RI != RE; ++RI) { + MachineInstr *UDMI = &*RI; + if (UDMI->getParent() != MBB) + continue; + DenseMap::iterator DI = DistanceMap.find(UDMI); + if (DI == DistanceMap.end() || DI->second > CurDist) + continue; + if ((int)DI->second < LastUDDist) + continue; + LastUDDist = DI->second; + LastUDMI = UDMI; + } + + if (LastUDMI) { + const TargetInstrDesc &TID = LastUDMI->getDesc(); + MachineOperand *LastUD = NULL; + for (unsigned i = 0, e = LastUDMI->getNumOperands(); i != e; ++i) { + MachineOperand &MO = LastUDMI->getOperand(i); + if (!MO.isRegister() || MO.getReg() != Reg) + continue; + if (!LastUD || (LastUD->isUse() && MO.isDef())) + LastUD = &MO; + if (TID.getOperandConstraint(i, TOI::TIED_TO) != -1) + return; + } + if (LastUD->isDef()) + LastUD->setIsDead(); + else { + LastUD->setIsKill(); + RegKills.set(Reg); + KillOps[Reg] = LastUD; + } + } +} + /// rewriteMBB - Keep track of which spills are available even after the /// register allocator is done with them. If possible, avid reloading vregs. void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) { @@ -1054,6 +1102,8 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) { std::vector KillOps; KillOps.resize(TRI->getNumRegs(), NULL); + unsigned Dist = 0; + DistanceMap.clear(); for (MachineBasicBlock::iterator MII = MBB.begin(), E = MBB.end(); MII != E; ) { MachineBasicBlock::iterator NextMII = MII; ++NextMII; @@ -1431,6 +1481,7 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) { InvalidateKill(InReg, RegKills, KillOps); } + InvalidateKills(MI, RegKills, KillOps); VRM.RemoveMachineInstrFromMaps(&MI); MBB.erase(&MI); Erased = true; @@ -1442,6 +1493,7 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) { if (PhysReg && TII->unfoldMemoryOperand(MF, &MI, PhysReg, false, false, NewMIs)) { MBB.insert(MII, NewMIs[0]); + InvalidateKills(MI, RegKills, KillOps); VRM.RemoveMachineInstrFromMaps(&MI); MBB.erase(&MI); Erased = true; @@ -1476,6 +1528,7 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) { NewStore = NewMIs[1]; MBB.insert(MII, NewStore); VRM.addSpillSlotUse(SS, NewStore); + InvalidateKills(MI, RegKills, KillOps); VRM.RemoveMachineInstrFromMaps(&MI); MBB.erase(&MI); Erased = true; @@ -1549,6 +1602,13 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) { if (TII->isMoveInstr(MI, Src, Dst) && Src == Dst) { ++NumDCE; DOUT << "Removing now-noop copy: " << MI; + SmallVector KillRegs; + InvalidateKills(MI, RegKills, KillOps, &KillRegs); + if (MO.isDead() && !KillRegs.empty()) { + assert(KillRegs[0] == Dst); + // Last def is now dead. + TransferDeadness(&MBB, Dist, Src, RegKills, KillOps); + } VRM.RemoveMachineInstrFromMaps(&MI); MBB.erase(&MI); Erased = true; @@ -1626,6 +1686,7 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) { if (TII->isMoveInstr(MI, Src, Dst) && Src == Dst) { ++NumDCE; DOUT << "Removing now-noop copy: " << MI; + InvalidateKills(MI, RegKills, KillOps); VRM.RemoveMachineInstrFromMaps(&MI); MBB.erase(&MI); Erased = true; @@ -1636,6 +1697,7 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) { } } ProcessNextInst: + DistanceMap.insert(std::make_pair(&MI, Dist++)); if (!Erased && !BackTracked) { for (MachineBasicBlock::iterator II = MI; II != NextMII; ++II) UpdateKills(*II, RegKills, KillOps); diff --git a/test/CodeGen/ARM/2008-05-19-ScavengerAssert.ll b/test/CodeGen/ARM/2008-05-19-ScavengerAssert.ll new file mode 100644 index 00000000000..e98126bf87a --- /dev/null +++ b/test/CodeGen/ARM/2008-05-19-ScavengerAssert.ll @@ -0,0 +1,22 @@ +; RUN: llvm-as < %s | llc -mtriple=arm-apple-darwin + + %struct.Decoders = type { i32**, i16***, i16****, i16***, i16**, i8**, i8** } +@decoders = external global %struct.Decoders ; <%struct.Decoders*> [#uses=1] + +declare i8* @calloc(i32, i32) + +declare fastcc i32 @get_mem2Dint(i32***, i32, i32) + +define fastcc void @init_global_buffers() nounwind { +entry: + %tmp151 = tail call fastcc i32 @get_mem2Dint( i32*** getelementptr (%struct.Decoders* @decoders, i32 0, i32 0), i32 16, i32 16 ) ; [#uses=1] + %tmp158 = tail call i8* @calloc( i32 0, i32 4 ) ; [#uses=0] + br i1 false, label %cond_true166, label %bb190.preheader + +bb190.preheader: ; preds = %entry + %memory_size.3555 = add i32 0, %tmp151 ; [#uses=0] + unreachable + +cond_true166: ; preds = %entry + unreachable +}