[llvm] [LLVM][GlobalISel] Support Blocks Created During Instruction Selection (PR #192625)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 17 03:32:37 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-globalisel
Author: Yeongu Choe (YeonguChoe)
<details>
<summary>Changes</summary>
## Summary
The previous implementation of selectMachineFunction could not handle blocks created during instruction selection (gMIR->MIR). I added cache (`VirtualRegisterCache`) that captures the machine function state before instruction selection and if new block is created, then the machine function is reverted back to previous statue using the cache. Also, newly created block is queued into list (`BlockSuccessorList`).
## Algorithm
```python
BlockSuccessorList ← [Input Block]
while BlockSuccessorList is not empty:
CurrentBlock ← last block from BlockSuccessorList
CurrentBlockSuccessorIterator ← CurrentBlock's successor iterator
if CurrentBlockSuccessorIterator has remaining successors:
Add the successor block to BlockSuccessorList
continue
VirtualRegisterCache ← current state of virtual registers
if a new block is created while instruction selection:
revert virtual register state using VirtualRegisterCache
put CurrentBlock back to BlockSuccessorList
else
Remove the rightmost block from BlockSuccessorList
```
## Visualization
<img width="600" alt="Screenshot 2026-04-17 at 6 24 06 AM" src="https://github.com/user-attachments/assets/33f6b9a5-938b-469a-a096-155e80ee8e12" />
---
Full diff: https://github.com/llvm/llvm-project/pull/192625.diff
2 Files Affected:
- (modified) llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp (+52-19)
- (modified) llvm/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp (+29)
``````````diff
diff --git a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
index 5fb31a04e5fd0..3a8da02e2b622 100644
--- a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
@@ -10,6 +10,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SetVector.h"
@@ -179,9 +181,6 @@ bool InstructionSelect::selectMachineFunction(MachineFunction &MF) {
*MI);
return false;
}
- // FIXME: We could introduce new blocks and will need to fix the outer loop.
- // Until then, keep track of the number of blocks to assert that we don't.
- const size_t NumBlocks = MF.size();
#endif
// Keep track of selected blocks, so we can delete unreachable ones later.
DenseSet<MachineBasicBlock *> SelectedBlocks;
@@ -198,15 +197,46 @@ bool InstructionSelect::selectMachineFunction(MachineFunction &MF) {
RAIIDelegateInstaller DelInstaller(MF, &AllObservers);
ISel->AllObservers = &AllObservers;
- for (MachineBasicBlock *MBB : post_order(&MF)) {
- ISel->CurMBB = MBB;
- SelectedBlocks.insert(MBB);
+ SmallVector<
+ std::pair<MachineBasicBlock *, MachineBasicBlock::succ_iterator>>
+ BlockSuccessorList;
+ DenseSet<MachineBasicBlock *> VisitedBlocks;
- // Select instructions in reverse block order.
- MIIMaintainer.MII = MBB->rbegin();
- for (auto End = MBB->rend(); MIIMaintainer.MII != End;) {
+ auto AppendBlockSuccessor = [&](MachineBasicBlock *Block) {
+ if (!VisitedBlocks.contains(Block)) {
+ VisitedBlocks.insert(Block);
+ BlockSuccessorList.emplace_back(Block, Block->succ_begin());
+ }
+ };
+ AppendBlockSuccessor(&MF.front());
+
+ while (!BlockSuccessorList.empty()) {
+ MachineBasicBlock *&CurrentBlock = BlockSuccessorList.back().first;
+ MachineBasicBlock::succ_iterator &CurrentBlockSuccessorIterator =
+ BlockSuccessorList.back().second;
+
+ if (CurrentBlockSuccessorIterator != CurrentBlock->succ_end()) {
+ MachineBasicBlock *CurrentBlockSuccessor =
+ *CurrentBlockSuccessorIterator++;
+ AppendBlockSuccessor(CurrentBlockSuccessor);
+ continue;
+ }
+
+ DenseMap<Register, RegClassOrRegBank> VirtualRegisterCache;
+ for (const MachineInstr &Instruction : *CurrentBlock)
+ for (const MachineOperand &Operand : Instruction.operands())
+ if (Operand.isReg() && Operand.getReg().isVirtual())
+ VirtualRegisterCache.try_emplace(
+ Operand.getReg(), MRI.getRegClassOrRegBank(Operand.getReg()));
+
+ const size_t BlockCountBeforeSelection = MF.size();
+
+ ISel->CurMBB = CurrentBlock;
+ SelectedBlocks.insert(CurrentBlock);
+
+ MIIMaintainer.MII = CurrentBlock->rbegin();
+ for (auto End = CurrentBlock->rend(); MIIMaintainer.MII != End;) {
MachineInstr &MI = *MIIMaintainer.MII;
- // Increment early to skip instructions inserted by select().
++MIIMaintainer.MII;
LLVM_DEBUG(dbgs() << "\nSelect: " << MI);
@@ -218,6 +248,18 @@ bool InstructionSelect::selectMachineFunction(MachineFunction &MF) {
}
LLVM_DEBUG(MIIMaintainer.reportFullyCreatedInstrs());
}
+
+ if (MF.size() > BlockCountBeforeSelection) {
+ for (auto &VirtualRegisterEntry : VirtualRegisterCache)
+ MRI.setRegClassOrRegBank(VirtualRegisterEntry.first,
+ VirtualRegisterEntry.second);
+ SelectedBlocks.erase(CurrentBlock);
+ BlockSuccessorList.pop_back();
+ VisitedBlocks.erase(CurrentBlock);
+ AppendBlockSuccessor(CurrentBlock);
+ continue;
+ }
+ BlockSuccessorList.pop_back();
}
}
@@ -290,15 +332,6 @@ bool InstructionSelect::selectMachineFunction(MachineFunction &MF) {
return false;
}
}
-
- if (MF.size() != NumBlocks) {
- MachineOptimizationRemarkMissed R("gisel-select", "GISelFailure",
- MF.getFunction().getSubprogram(),
- /*MBB=*/nullptr);
- R << "inserting blocks is not supported yet";
- reportGISelFailure(MF, MORE, R);
- return false;
- }
#endif
if (!DebugCounter::shouldExecute(GlobalISelCounter)) {
diff --git a/llvm/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp b/llvm/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp
index 223798342b3ee..df8c012fb8ffe 100644
--- a/llvm/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp
@@ -1,5 +1,6 @@
#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
#include "GISelMITest.h"
+#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/LegacyPassManager.h"
@@ -71,4 +72,32 @@ TEST_F(AArch64GISelMITest, TestInstructionSelectErase) {
EXPECT_EQ(ISel.NumSelected, 3);
}
+class CustomISel : public InstructionSelector {
+public:
+ bool select(MachineInstr &MI) override {
+ static bool Triggered = false;
+ if (!Triggered) {
+ Triggered = true;
+ auto &MF = *MI.getMF();
+ MF.push_back(MF.CreateMachineBasicBlock());
+ MI.getParent()->addSuccessor(&MF.back());
+ }
+ return true;
+ }
+ void setupGeneratedPerFunctionState(MachineFunction &) override {}
+};
+
+TEST_F(AArch64GISelMITest, NewBlockWhileInstructionSelection) {
+ setUp(R"(
+ $x0 = COPY %2(s64)
+)");
+ if (!TM)
+ GTEST_SKIP();
+ CustomISel ISel;
+ InstructionSelect Pass;
+ Pass.setInstructionSelector(&ISel);
+ ASSERT_EQ(MF->size(), 1u);
+ Pass.selectMachineFunction(*MF);
+ EXPECT_EQ(MF->size(), 2u);
+}
} // namespace
``````````
</details>
https://github.com/llvm/llvm-project/pull/192625
More information about the llvm-commits
mailing list