[llvm] [MoveAutoInit] Don't move auto-init instructions into EH pad blocks (PR #222100)

Nikhil Ludder via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 11:46:40 PDT 2026


https://github.com/badnikhil created https://github.com/llvm/llvm-project/pull/222100

`BasicBlock::getFirstInsertionPt()` skips a leading EH pad, but the MemorySSA update registers the moved instruction with `InsertionPlace::Beginning`. A `CatchPadInst` is itself a `MemoryDef`, so instruction order and access order disagree and `-verify-memoryssa` asserts. Extend the existing `CatchSwitchInst` guard to all EH pads.

Fixes #221568.

Written with claude-code (Opus 5); reviewed and tested locally.


>From 1545f5780369334df607d8ccda0fd7890ca2ec03 Mon Sep 17 00:00:00 2001
From: badnikhil <nikhilljatt at gmail.com>
Date: Wed, 9 Sep 2026 00:13:50 +0530
Subject: [PATCH] [MoveAutoInit] Don't move auto-init instructions into EH pad
 blocks

getFirstInsertionPt() skips a leading EH pad, but the MemorySSA update
places the moved access at the beginning of the block. A CatchPadInst is
itself a MemoryDef, so instruction order and access order disagree and
-verify-memoryssa asserts. Extend the CatchSwitchInst guard to all EH pads.

Fixes #221568.
---
 llvm/lib/Transforms/Utils/MoveAutoInit.cpp    |  9 ++--
 llvm/test/Transforms/MoveAutoInit/catchpad.ll | 48 +++++++++++++++++++
 2 files changed, 54 insertions(+), 3 deletions(-)
 create mode 100644 llvm/test/Transforms/MoveAutoInit/catchpad.ll

diff --git a/llvm/lib/Transforms/Utils/MoveAutoInit.cpp b/llvm/lib/Transforms/Utils/MoveAutoInit.cpp
index a3e44fb513a3d..aac430ddd7059 100644
--- a/llvm/lib/Transforms/Utils/MoveAutoInit.cpp
+++ b/llvm/lib/Transforms/Utils/MoveAutoInit.cpp
@@ -178,9 +178,12 @@ static bool runMoveAutoInit(Function &F, DominatorTree &DT, MemorySSA &MSSA) {
       UsersDominator = DominatingPredecessor;
     }
 
-    // CatchSwitchInst blocks can only have one instruction, so they are not
-    // good candidates for insertion.
-    while (isa<CatchSwitchInst>(UsersDominator->getFirstNonPHIIt())) {
+    // EH pad blocks are not good candidates for insertion: CatchSwitchInst
+    // blocks can only have one instruction, and for the other pads
+    // getFirstInsertionPt() skips the pad instruction, which may itself have a
+    // memory access, while the MemorySSA update below assumes the moved
+    // instruction becomes the first access of the block.
+    while (UsersDominator->isEHPad()) {
       for (BasicBlock *Pred : predecessors(UsersDominator))
         if (DT.isReachableFromEntry(Pred))
           UsersDominator = DT.findNearestCommonDominator(UsersDominator, Pred);
diff --git a/llvm/test/Transforms/MoveAutoInit/catchpad.ll b/llvm/test/Transforms/MoveAutoInit/catchpad.ll
new file mode 100644
index 0000000000000..447d013d42152
--- /dev/null
+++ b/llvm/test/Transforms/MoveAutoInit/catchpad.ll
@@ -0,0 +1,48 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt < %s -S -passes='move-auto-init' -verify-memoryssa | FileCheck %s
+
+; A CatchPadInst is a MemoryDef, so the auto-init store cannot be moved to the
+; beginning of its block, see #221568.
+
+declare void @dummy()
+
+define void @test() personality ptr @dummy {
+; CHECK-LABEL: define void @test() personality ptr @dummy {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[P:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    br label [[MIDDLE:%.*]]
+; CHECK:       middle:
+; CHECK-NEXT:    store i32 0, ptr [[P]], align 4, !annotation [[META0:![0-9]+]]
+; CHECK-NEXT:    invoke void @dummy()
+; CHECK-NEXT:            to label [[CLEAN:%.*]] unwind label [[CATCHBB:%.*]]
+; CHECK:       clean:
+; CHECK-NEXT:    ret void
+; CHECK:       catchbb:
+; CHECK-NEXT:    [[CS:%.*]] = catchswitch within none [label [[PAD:%.*]]] unwind to caller
+; CHECK:       pad:
+; CHECK-NEXT:    [[C:%.*]] = catchpad within [[CS]] [i32 0]
+; CHECK-NEXT:    ret void
+;
+entry:
+  %p = alloca i32, align 4
+  store i32 0, ptr %p, align 4, !annotation !0
+  br label %middle
+
+middle:
+  invoke void @dummy() to label %clean unwind label %catchbb
+
+clean:
+  ret void
+
+catchbb:
+  %cs = catchswitch within none [label %pad] unwind to caller
+
+pad:
+  %c = catchpad within %cs [i32 0]
+  ret void
+}
+
+!0 = !{!"auto-init"}
+;.
+; CHECK: [[META0]] = !{!"auto-init"}
+;.



More information about the llvm-commits mailing list