diff --git a/llvm/include/llvm/CodeGen/LiveIntervals.h b/llvm/include/llvm/CodeGen/LiveIntervals.h --- a/llvm/include/llvm/CodeGen/LiveIntervals.h +++ b/llvm/include/llvm/CodeGen/LiveIntervals.h @@ -310,16 +310,16 @@ /// \param UpdateFlags Update live intervals for nonallocatable physregs. void handleMove(MachineInstr &MI, bool UpdateFlags = false); - /// Update intervals for operands of \p MI so that they begin/end on the - /// SlotIndex for \p BundleStart. + /// Update intervals of operands of all instructions in the newly + /// created bundle specified by \p BundleStart. /// /// \param UpdateFlags Update live intervals for nonallocatable physregs. /// - /// Requires MI and BundleStart to have SlotIndexes, and assumes - /// existing liveness is accurate. BundleStart should be the first - /// instruction in the Bundle. - void handleMoveIntoBundle(MachineInstr &MI, MachineInstr &BundleStart, - bool UpdateFlags = false); + /// Assumes existing liveness is accurate. + /// \pre BundleStart should be the first instruction in the Bundle. + /// \pre BundleStart should not have a have SlotIndex as one will be assigned. + void handleMoveIntoNewBundle(MachineInstr &BundleStart, + bool UpdateFlags = false); /// Update live intervals for instructions in a range of iterators. It is /// intended for use after target hooks that may insert or remove diff --git a/llvm/include/llvm/CodeGen/SlotIndexes.h b/llvm/include/llvm/CodeGen/SlotIndexes.h --- a/llvm/include/llvm/CodeGen/SlotIndexes.h +++ b/llvm/include/llvm/CodeGen/SlotIndexes.h @@ -382,13 +382,15 @@ } /// Returns the base index for the given instruction. - SlotIndex getInstructionIndex(const MachineInstr &MI) const { + SlotIndex getInstructionIndex(const MachineInstr &MI, + bool IgnoreBundle = false) const { // Instructions inside a bundle have the same number as the bundle itself. auto BundleStart = getBundleStart(MI.getIterator()); auto BundleEnd = getBundleEnd(MI.getIterator()); // Use the first non-debug instruction in the bundle to get SlotIndex. const MachineInstr &BundleNonDebug = - *skipDebugInstructionsForward(BundleStart, BundleEnd); + IgnoreBundle ? MI + : *skipDebugInstructionsForward(BundleStart, BundleEnd); assert(!BundleNonDebug.isDebugInstr() && "Could not use a debug instruction to query mi2iMap."); Mi2IndexMap::const_iterator itr = mi2iMap.find(&BundleNonDebug); @@ -573,7 +575,11 @@ /// Removes machine instruction (bundle) \p MI from the mapping. /// This should be called before MachineInstr::eraseFromParent() is used to /// remove a whole bundle or an unbundled instruction. - void removeMachineInstrFromMaps(MachineInstr &MI); + /// If \p AllowBundled is set then this can be used on a bundled + /// instruction; however, this exists to support handleMoveIntoBundle, + /// and in general removeSingleMachineInstrFromMaps should be used instead. + void removeMachineInstrFromMaps(MachineInstr &MI, + bool AllowBundled = false); /// Removes a single machine instruction \p MI from the mapping. /// This should be called before MachineInstr::eraseFromBundle() is used to diff --git a/llvm/lib/CodeGen/LiveIntervals.cpp b/llvm/lib/CodeGen/LiveIntervals.cpp --- a/llvm/lib/CodeGen/LiveIntervals.cpp +++ b/llvm/lib/CodeGen/LiveIntervals.cpp @@ -1478,13 +1478,43 @@ HME.updateAllRanges(&MI); } -void LiveIntervals::handleMoveIntoBundle(MachineInstr &MI, - MachineInstr &BundleStart, - bool UpdateFlags) { - SlotIndex OldIndex = Indexes->getInstructionIndex(MI); - SlotIndex NewIndex = Indexes->getInstructionIndex(BundleStart); - HMEditor HME(*this, *MRI, *TRI, OldIndex, NewIndex, UpdateFlags); - HME.updateAllRanges(&MI); +void LiveIntervals::handleMoveIntoNewBundle(MachineInstr &BundleStart, + bool UpdateFlags) { + assert((BundleStart.getOpcode() == TargetOpcode::BUNDLE) && + "Bundle start is not a bundle"); + SmallVector ToProcess; + const SlotIndex NewIndex = Indexes->insertMachineInstrInMaps(BundleStart); + auto BundleEnd = getBundleEnd(BundleStart.getIterator()); + + auto I = BundleStart.getIterator(); + I++; + while (I != BundleEnd) { + if (!Indexes->hasIndex(*I)) + continue; + SlotIndex OldIndex = Indexes->getInstructionIndex(*I, true); + ToProcess.push_back(OldIndex); + Indexes->removeMachineInstrFromMaps(*I, true); + I++; + } + for (SlotIndex OldIndex : ToProcess) { + HMEditor HME(*this, *MRI, *TRI, OldIndex, NewIndex, UpdateFlags); + HME.updateAllRanges(&BundleStart); + } + + // Fix up dead defs + const SlotIndex Index = getInstructionIndex(BundleStart); + for (unsigned Idx = 0, E = BundleStart.getNumOperands(); Idx != E; ++Idx) { + MachineOperand &MO = BundleStart.getOperand(Idx); + if (!MO.isReg()) + continue; + Register Reg = MO.getReg(); + if (Reg.isVirtual() && hasInterval(Reg) && !MO.isUndef()) { + LiveInterval &LI = getInterval(Reg); + LiveQueryResult LRQ = LI.Query(Index); + if (LRQ.isDeadDef()) + MO.setIsDead(); + } + } } void LiveIntervals::repairOldRegInRange(const MachineBasicBlock::iterator Begin, diff --git a/llvm/lib/CodeGen/SlotIndexes.cpp b/llvm/lib/CodeGen/SlotIndexes.cpp --- a/llvm/lib/CodeGen/SlotIndexes.cpp +++ b/llvm/lib/CodeGen/SlotIndexes.cpp @@ -112,9 +112,10 @@ return false; } -void SlotIndexes::removeMachineInstrFromMaps(MachineInstr &MI) { - assert(!MI.isBundledWithPred() && - "Use removeSingleMachineInstrFromMaps() instread"); +void SlotIndexes::removeMachineInstrFromMaps(MachineInstr &MI, + bool AllowBundled) { + assert((AllowBundled || !MI.isBundledWithPred()) && + "Use removeSingleMachineInstrFromMaps() instead"); Mi2IndexMap::iterator mi2iItr = mi2iMap.find(&MI); if (mi2iItr == mi2iMap.end()) return; @@ -141,7 +142,7 @@ // instruction. if (MI.isBundledWithSucc()) { // Only the first instruction of a bundle should have an index assigned. - assert(!MI.isBundledWithPred() && "Should have first bundle isntruction"); + assert(!MI.isBundledWithPred() && "Should be first bundle instruction"); MachineBasicBlock::instr_iterator Next = std::next(MI.getIterator()); MachineInstr &NextMI = *Next; diff --git a/llvm/unittests/MI/LiveIntervalTest.cpp b/llvm/unittests/MI/LiveIntervalTest.cpp --- a/llvm/unittests/MI/LiveIntervalTest.cpp +++ b/llvm/unittests/MI/LiveIntervalTest.cpp @@ -128,6 +128,27 @@ LIS.handleMove(FromInstr, true); } +/** + * Move instructions numbered \p From inclusive through instruction number + * \p To into a newly formed bundle and update affected liveness intervals + * with LiveIntervalAnalysis::handleMoveIntoNewBundle(). + */ +static void testHandleMoveIntoNewBundle(MachineFunction &MF, LiveIntervals &LIS, + unsigned From, unsigned To, + unsigned BlockNum = 0) { + MachineInstr &FromInstr = getMI(MF, From, BlockNum); + MachineInstr &ToInstr = getMI(MF, To, BlockNum); + MachineBasicBlock &MBB = *FromInstr.getParent(); + MachineBasicBlock::instr_iterator I = FromInstr.getIterator(); + + // Build bundle + finalizeBundle(MBB, I, std::next(ToInstr.getIterator())); + + // Update LiveIntervals + MachineBasicBlock::instr_iterator BundleStart = std::prev(I); + LIS.handleMoveIntoNewBundle(*BundleStart, true); +} + static void liveIntervalTest(StringRef MIRFunc, LiveIntervalTest T) { LLVMContext Context; std::unique_ptr TM = createTargetMachine(); @@ -462,6 +483,96 @@ testHandleMove(MF, LIS, 4, 1, 1); }); } + +TEST(LiveIntervalTest, BundleUse) { + liveIntervalTest(R"MIR( + %0 = IMPLICIT_DEF + S_NOP 0 + S_NOP 0, implicit %0 + S_NOP 0 +)MIR", [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMoveIntoNewBundle(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, BundleDef) { + liveIntervalTest(R"MIR( + %0 = IMPLICIT_DEF + S_NOP 0 + S_NOP 0, implicit %0 + S_NOP 0 +)MIR", [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMoveIntoNewBundle(MF, LIS, 0, 1); + }); +} + +TEST(LiveIntervalTest, BundleRedef) { + liveIntervalTest(R"MIR( + %0 = IMPLICIT_DEF + S_NOP 0 + %0 = IMPLICIT_DEF implicit %0(tied-def 0) + S_NOP 0, implicit %0 +)MIR", [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMoveIntoNewBundle(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, BundleInternalUse) { + liveIntervalTest(R"MIR( + %0 = IMPLICIT_DEF + S_NOP 0 + S_NOP 0, implicit %0 + S_NOP 0 +)MIR", [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMoveIntoNewBundle(MF, LIS, 0, 2); + }); +} + +TEST(LiveIntervalTest, BundleUndefUse) { + liveIntervalTest(R"MIR( + %0 = IMPLICIT_DEF + S_NOP 0 + S_NOP 0, implicit undef %0 + S_NOP 0 +)MIR", [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMoveIntoNewBundle(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, BundleSubRegUse) { + liveIntervalTest(R"MIR( + successors: %bb.1, %bb.2 + undef %0.sub0 = IMPLICIT_DEF + %0.sub1 = IMPLICIT_DEF + S_CBRANCH_VCCNZ %bb.2, implicit undef $vcc + S_BRANCH %bb.1 + bb.1: + S_NOP 0 + S_NOP 0, implicit %0.sub1 + bb.2: + S_NOP 0, implicit %0.sub1 +)MIR", [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMoveIntoNewBundle(MF, LIS, 0, 1, 1); + }); +} + +TEST(LiveIntervalTest, BundleSubRegDef) { + liveIntervalTest(R"MIR( + successors: %bb.1, %bb.2 + undef %0.sub0 = IMPLICIT_DEF + %0.sub1 = IMPLICIT_DEF + S_CBRANCH_VCCNZ %bb.2, implicit undef $vcc + S_BRANCH %bb.1 + bb.1: + S_NOP 0 + S_NOP 0, implicit %0.sub1 + bb.2: + S_NOP 0, implicit %0.sub1 +)MIR", [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMoveIntoNewBundle(MF, LIS, 0, 1, 0); + }); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); initLLVM();