[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