[MIR][MachineInstr] Update MachineInstr::eraseFromParent() to return an iterator (#179787)

Unlike LLVM IR `Instruction::eraseFromParent()`,
`MachineInstr::eraseFromParent()` is void and does not return the
iterator following the erased instruction. Returning an iterator can be
very helpful for example when we are erasing MachineInstrs while
iterating, as it provides a convenient way to get a valid iterator.

This patch updates `MachineInstr::eraseFromParent()` to return a
`MachineBlock::iterator` (which is a
`MachineInstrBundleIterator<MachineInstr>`). If the erased instruction
is the head of a bundle, then the returned iterator points to the next
bundle (see unittest).
This commit is contained in:
vporpo 2026-03-13 13:39:13 -07:00 committed by GitHub
parent 3a526fba72
commit 40ea2f3513
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 67 additions and 7 deletions

View File

@ -22,6 +22,7 @@
#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Analysis/MemoryLocation.h"
#include "llvm/CodeGen/MachineInstrBundleIterator.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/TargetOpcodes.h"
@ -1329,7 +1330,10 @@ public:
/// If this instruction is the header of a bundle, the whole bundle is erased.
/// This function can not be used for instructions inside a bundle, use
/// eraseFromBundle() to erase individual bundled instructions.
LLVM_ABI void eraseFromParent();
/// \returns the iterator following the erased instruction. If this is the
/// header of a bundle it returns the iterator following the erased bundle
/// iterator.
LLVM_ABI MachineInstrBundleIterator<MachineInstr> eraseFromParent();
/// Unlink 'this' from its basic block and delete it.
///

View File

@ -797,9 +797,9 @@ MachineInstr *MachineInstr::removeFromBundle() {
return getParent()->remove_instr(this);
}
void MachineInstr::eraseFromParent() {
MachineBasicBlock::iterator MachineInstr::eraseFromParent() {
assert(getParent() && "Not embedded in a basic block!");
getParent()->erase(this);
return getParent()->erase(this);
}
void MachineInstr::eraseFromBundle() {

View File

@ -926,8 +926,7 @@ bool SIFixSGPRCopies::lowerSpecialCase(MachineInstr &MI,
llvm_unreachable("failed to constrain register");
} else if (tryMoveVGPRConstToSGPR(MI.getOperand(1), DstReg, MI.getParent(),
MI, MI.getDebugLoc())) {
I = std::next(I);
MI.eraseFromParent();
I = MI.eraseFromParent();
}
return true;
}

View File

@ -2481,8 +2481,7 @@ bool SIMemoryLegalizer::run(MachineFunction &MF) {
MO.setIsInternalRead(false);
}
MI->eraseFromParent();
MI = II->getIterator();
MI = MI->eraseFromParent();
}
if (MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic) {

View File

@ -613,4 +613,62 @@ TEST(MachineInstrTest, SpliceOperands) {
EXPECT_EQ(MI->getNumOperands(), 10U);
}
// Checks the iterator returned by MacineInstr::eraseFromParent().
TEST(MachineInstr, EraseFromParentReturnedIterator) {
LLVMContext Ctx;
Module Mod("Module", Ctx);
auto MF = createMachineFunction(Ctx, Mod);
auto MBB = MF->CreateMachineBasicBlock();
MCInstrDesc MCID = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
MachineInstr *MI1 = MF->CreateMachineInstr(MCID, DebugLoc());
MBB->insert(MBB->end(), MI1);
MachineInstr *MI2 = MF->CreateMachineInstr(MCID, DebugLoc());
MBB->insert(MBB->end(), MI2);
MachineBasicBlock::iterator It1 = MI1->eraseFromParent();
EXPECT_EQ(It1, MI2->getIterator());
MachineBasicBlock::iterator It2 = MI2->eraseFromParent();
EXPECT_EQ(It2, MBB->end());
}
// Checks the iterator returned by MacineInstr::eraseFromParent() when
// instructions are in bundles.
TEST(MachineInstr, EraseFromParentReturnedIteratorBundle) {
LLVMContext Ctx;
Module Mod("Module", Ctx);
auto MF = createMachineFunction(Ctx, Mod);
auto MBB = MF->CreateMachineBasicBlock();
MCInstrDesc MCID = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// Bundle1 {
// MI1B1
// MI2B1
// }
// Bundle2 {
// MI1B2
// MI2B2
// }
MachineInstr *MI1B1 = MF->CreateMachineInstr(MCID, DebugLoc());
MBB->insert(MBB->end(), MI1B1);
MachineInstr *MI2B1 = MF->CreateMachineInstr(MCID, DebugLoc());
MBB->insert(MBB->end(), MI2B1);
MI2B1->bundleWithPred();
MachineInstr *MI1B2 = MF->CreateMachineInstr(MCID, DebugLoc());
MBB->insert(MBB->end(), MI1B2);
MachineInstr *MI2B2 = MF->CreateMachineInstr(MCID, DebugLoc());
MBB->insert(MBB->end(), MI2B2);
MI2B2->bundleWithPred();
// MI1B1->eraseFromParent() erases the whole Bundle1.
// The returned iterator matches the head of Bundle2.
MachineBasicBlock::iterator It1 = MI1B1->eraseFromParent();
EXPECT_EQ(It1, MI1B2->getIterator());
// Erasing MI1B2 erases the whole Bundle2.
MachineBasicBlock::iterator It2 = MI1B2->eraseFromParent();
EXPECT_EQ(It2, MBB->end());
}
} // end namespace