/// \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
}
/// 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);
/// 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
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<SlotIndex, 16> 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,
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;
// 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;
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<LLVMTargetMachine> TM = createTargetMachine();
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();