From 79ebc7186e5bd152b0e8bd3006ea2690a97204c5 Mon Sep 17 00:00:00 2001 From: Cameron Zwarich Date: Tue, 21 Dec 2010 06:54:43 +0000 Subject: [PATCH] Incremental progress towards a new implementation of StrongPHIElimination. Most of the problems with my last attempt were in the updating of LiveIntervals rather than the coalescing itself. Therefore, I decided to get that right first by essentially reimplementing the existing PHIElimination using LiveIntervals. It works correctly, with only a few tests failing (which may not be legitimate failures) and no new verifier failures (at least as far as I can tell, I didn't count the number per file). llvm-svn: 122321 --- llvm/lib/CodeGen/StrongPHIElimination.cpp | 189 +++++++++++++++++++++- 1 file changed, 186 insertions(+), 3 deletions(-) diff --git a/llvm/lib/CodeGen/StrongPHIElimination.cpp b/llvm/lib/CodeGen/StrongPHIElimination.cpp index c62b1cd360b9..b475432bcfbe 100644 --- a/llvm/lib/CodeGen/StrongPHIElimination.cpp +++ b/llvm/lib/CodeGen/StrongPHIElimination.cpp @@ -11,11 +11,15 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "strongphielim" +#include "PHIEliminationUtils.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/Support/ErrorHandling.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Support/Debug.h" using namespace llvm; namespace { @@ -28,6 +32,16 @@ namespace { virtual void getAnalysisUsage(AnalysisUsage&) const; bool runOnMachineFunction(MachineFunction&); + + private: + void InsertCopiesForPHI(MachineInstr*, MachineBasicBlock*); + + MachineRegisterInfo* MRI; + const TargetInstrInfo* TII; + LiveIntervals* LI; + + typedef DenseSet > CopySet; + CopySet InsertedCopies; }; } // namespace @@ -52,6 +66,175 @@ void StrongPHIElimination::getAnalysisUsage(AnalysisUsage& AU) const { MachineFunctionPass::getAnalysisUsage(AU); } -bool StrongPHIElimination::runOnMachineFunction(MachineFunction& Fn) { - llvm_unreachable("Strong phi elimination is not implemented"); +static MachineOperand* findLastUse(MachineBasicBlock* MBB, unsigned Reg) { + // FIXME: This only needs to check from the first terminator, as only the + // first terminator can use a virtual register. + for (MachineBasicBlock::reverse_iterator RI = MBB->rbegin(); ; ++RI) { + assert (RI != MBB->rend()); + MachineInstr* MI = &*RI; + + for (MachineInstr::mop_iterator OI = MI->operands_begin(), + OE = MI->operands_end(); OI != OE; ++OI) { + MachineOperand& MO = *OI; + if (MO.isReg() && MO.isUse() && MO.getReg() == Reg) + return &MO; + } + } + return NULL; +} + +bool StrongPHIElimination::runOnMachineFunction(MachineFunction& MF) { + MRI = &MF.getRegInfo(); + TII = MF.getTarget().getInstrInfo(); + LI = &getAnalysis(); + + // Insert copies for all PHI source and destination registers. + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + for (MachineBasicBlock::iterator BBI = I->begin(), BBE = I->end(); + BBI != BBE && BBI->isPHI(); ++BBI) { + InsertCopiesForPHI(BBI, I); + } + } + + // Adjust the live intervals of all PHI source registers to handle the case + // where the PHIs in successor blocks were the only later uses of the source + // register. + for (CopySet::iterator I = InsertedCopies.begin(), E = InsertedCopies.end(); + I != E; ++I) { + MachineBasicBlock* MBB = I->first; + unsigned SrcReg = I->second; + LiveInterval& SrcLI = LI->getInterval(SrcReg); + + bool isLiveOut = false; + for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(), + SE = MBB->succ_end(); SI != SE; ++SI) { + if (SrcLI.liveAt(LI->getMBBStartIdx(*SI))) { + isLiveOut = true; + break; + } + } + + if (isLiveOut) + continue; + + MachineOperand* LastUse = findLastUse(MBB, SrcReg); + assert(LastUse); + SrcLI.removeRange(LI->getInstructionIndex(LastUse->getParent()).getDefIndex(), + LI->getMBBEndIdx(MBB)); + LastUse->setIsKill(true); + } + + // Remove all PHI instructions from the function. + bool Changed = false; + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + MachineBasicBlock::iterator BBI = I->begin(), BBE = I->end(); + while (BBI != BBE && BBI->isPHI()) { + MachineInstr* PHI = BBI; + ++BBI; + LI->RemoveMachineInstrFromMaps(PHI); + PHI->eraseFromParent(); + Changed = true; + } + } + + LI->renumber(); + MF.verify(this); + + InsertedCopies.clear(); + + return Changed; +} + +void StrongPHIElimination::InsertCopiesForPHI(MachineInstr* PHI, + MachineBasicBlock* MBB) { + assert(PHI->isPHI()); + unsigned DestReg = PHI->getOperand(0).getReg(); + + const TargetRegisterClass* RC = MRI->getRegClass(DestReg); + unsigned CopyReg = MRI->createVirtualRegister(RC); + + MachineInstr* CopyInstr = BuildMI(*MBB, + MBB->SkipPHIsAndLabels(MBB->begin()), + PHI->getDebugLoc(), + TII->get(TargetOpcode::COPY), + DestReg).addReg(CopyReg); + LI->InsertMachineInstrInMaps(CopyInstr); + CopyInstr->getOperand(1).setIsKill(true); + + // Add the region from the beginning of MBB to the copy instruction to + // CopyReg's live interval, and give the VNInfo the phidef flag. + LiveInterval& CopyLI = LI->getOrCreateInterval(CopyReg); + SlotIndex MBBStartIndex = LI->getMBBStartIdx(MBB); + SlotIndex DestCopyIndex = LI->getInstructionIndex(CopyInstr); + VNInfo* CopyVNI = CopyLI.getNextValue(MBBStartIndex, + CopyInstr, + LI->getVNInfoAllocator()); + CopyVNI->setIsPHIDef(true); + CopyLI.addRange(LiveRange(MBBStartIndex, + DestCopyIndex.getDefIndex(), + CopyVNI)); + + // Adjust DestReg's live interval to adjust for its new definition at + // CopyInstr. + LiveInterval& DestLI = LI->getOrCreateInterval(DestReg); + SlotIndex PHIIndex = LI->getInstructionIndex(PHI); + DestLI.removeRange(PHIIndex.getDefIndex(), DestCopyIndex.getDefIndex()); + + VNInfo* DestVNI = DestLI.getVNInfoAt(DestCopyIndex.getDefIndex()); + assert(DestVNI); + DestVNI->def = DestCopyIndex.getDefIndex(); + + SmallPtrSet MBBsInsertedInto; + for (unsigned i = 1; i < PHI->getNumOperands(); i += 2) { + MachineOperand& SrcMO = PHI->getOperand(i); + unsigned SrcReg = SrcMO.getReg(); + unsigned SrcSubReg = SrcMO.getSubReg(); + + assert(TargetRegisterInfo::isVirtualRegister(SrcReg) && + "Machine PHI Operands must all be virtual registers!"); + + // If source is defined by an implicit def, there is no need to insert a + // copy. + // FIXME: For some reason, if LiveIntervals is run prior to PHI elimination + // implcit defs have no defining instruction. Is this expected? + MachineInstr* DefMI = MRI->getVRegDef(SrcReg); + if (!DefMI) + continue; + + MachineBasicBlock* PredBB = PHI->getOperand(i + 1).getMBB(); + + // A copy may have already been inserted in the predecessor in the case of a + // block with multiple incoming edges. + if (!MBBsInsertedInto.insert(PredBB)) + continue; + + MachineBasicBlock::iterator + CopyInsertPoint = findPHICopyInsertPoint(PredBB, MBB, SrcReg); + MachineInstr* CopyInstr = BuildMI(*PredBB, + CopyInsertPoint, + PHI->getDebugLoc(), + TII->get(TargetOpcode::COPY), + CopyReg).addReg(SrcReg, 0, SrcSubReg); + LI->InsertMachineInstrInMaps(CopyInstr); + + // addLiveRangeToEndOfBlock() also adds the phikill flag to the VNInfo for + // the newly added range. + LI->addLiveRangeToEndOfBlock(CopyReg, CopyInstr); + InsertedCopies.insert(std::make_pair(PredBB, SrcReg)); + + // If SrcReg is not live beyond the PHI, trim its interval so that it is no + // longer live-in to MBB. Note that SrcReg may appear in other PHIs that are + // processed later, but this is still correct to do at this point because we + // never rely on LiveIntervals being correct while inserting copies. + // FIXME: Should this just count uses at PHIs like the normal PHIElimination + // pass does? + LiveInterval& SrcLI = LI->getInterval(SrcReg); + SlotIndex MBBStartIndex = LI->getMBBStartIdx(MBB); + SlotIndex PHIIndex = LI->getInstructionIndex(PHI); + SlotIndex NextInstrIndex = PHIIndex.getNextIndex(); + if (SrcLI.liveAt(MBBStartIndex) && SrcLI.expiredAt(NextInstrIndex)) + SrcLI.removeRange(MBBStartIndex, PHIIndex, true); + } }