Bug type: crash
Component: MoveAutoInit
Bug location: llvm/lib/Transforms/Utils/MoveAutoInit.cpp: runMoveAutoInit
Issue title: [MoveAutoInit] Assertion `NodeB && "B must be in the tree"' failed.
Labels: crash
llvm:transforms
Reported by: JonPsson1

opt -O3 -sroa-skip-mem2reg -enable-dfa-jump-thread tc_dt.ll
[tc_dt.tar.gz](https://github.com/llvm/llvm-project/files/13928836/tc_dt.tar.gz)

GenericDomTree.h:501: NodeT* llvm::DominatorTreeBase<NodeT, IsPostDom>::findNearestCommonDominator(NodeT*, NodeT*) const [with NodeT = llvm::BasicBlock; 
bool IsPostDom = false]: Assertion `NodeB && "B must be in the tree"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.

Reduced test case attached, but have not looked into it. Adding people high in the log...


Comments: author: bjope
body: Reduced the test case and pipeline a bit more:

opt -S -o - -passes='dfa-jump-threading,move-auto-init' reduced.ll 

With reduced.ll being
```
define void @func_1() {
entry:
  %l_2586 = alloca [2 x i16], i32 0, align 2
  store i32 0, ptr %l_2586, align 2, !annotation !0
  br label %lbl_2844.preheader

lbl_2844.preheader:                               ; preds = %entry
  br label %lbl_2844

lbl_2844:                                         ; preds = %cleanup1473, %lbl_2844.preheader
  call void null()
  br label %cleanup1473

for.end516:                                       ; No predecessors!
  br label %cleanup1473

cleanup1473:                                      ; preds = %for.end516, %lbl_2844
  %cleanup.dest.slot.0 = phi i32 [ 0, %for.end516 ], [ 17, %lbl_2844 ]
  switch i32 %cleanup.dest.slot.0, label %cleanup1829 [
    i32 0, label %if.end1787
    i32 17, label %lbl_2844
  ]

if.end1787:                                       ; preds = %cleanup1473
  %cmp1789.not = icmp ult ptr null, %l_2586
  unreachable

cleanup1829:                                      ; preds = %cleanup1473
  ret void
}

!0 = !{!"auto-init"}

```
author: XChy
body: It seems that DFAJumpThreading broke the dominator tree analysis.
author: XChy
body: > It seems that DFAJumpThreading broke the dominator tree analysis.

In fact, *MoveAutoInit* should be to blame. This pass doesn't handle unreachable predecessors correctly. A reduced version without `DFAJumpThreading`: 
```llvm
declare void @dummy()

define void @func_1() {
entry:
  %p = alloca [2 x i16], i32 0, align 2
  store i32 0, ptr %p, align 2, !annotation !0
  br i1 true, label %loop, label %usebb

loop:
  call void @dummy()
  br label %loop

a:
  br label %loop

b:
  br label %loop

usebb:
  %use_p = icmp ult ptr null, %p
  ret void
}

!0 = !{!"auto-init"}
```

And after looking into the source, I found that this pass doesn't handle `catchswitch` well too. For example:
```llvm
declare void @dummy()

declare void @dummy1()

define void @func_1() personality ptr @dummy {
entry:
  %p = alloca [2 x i16], i32 0, align 2
  store i32 0, ptr %p, align 2, !annotation !0
  %call = invoke ptr @dummy() to label %clean unwind label %catchbb

unreachable:
  %call1 = invoke ptr @dummy() to label %clean unwind label %catchbb

clean:
  ret void

catchbb:
  %cs = catchswitch within none [label %pad, label %pad1] unwind to caller

pad:
  %c = catchpad within %cs [ptr null, i32 0, ptr null]
  call void @dummy1()
  ret void

pad1:
  %c1 = catchpad within %cs [ptr null, i32 0, ptr null]
  call void @dummy1()
  ret void
}

!0 = !{!"auto-init"}
```


Fix patch:
commit 26d3cd1d07ae3fc8312feb2ab3a3a86414f28c70
Author: XChy <xxs_chy@outlook.com>
Date:   Tue Jan 16 18:45:44 2024 +0800

    [MoveAutoInit] Ignore unreachable basicblocks and handle catchswitch (#78232)
    
    Fixes #78049
    This patch has done:
    - Ignore unreachable predecessors when looking for nearest common
    dominator.
    - Check catchswitch with `getFirstNonPHI`, instead of
    `getFirstInsertionPt`. The latter skips EHPad.

diff --git a/llvm/lib/Transforms/Utils/MoveAutoInit.cpp b/llvm/lib/Transforms/Utils/MoveAutoInit.cpp
index a977ad87b79f..9a5dba219cee 100644
--- a/llvm/lib/Transforms/Utils/MoveAutoInit.cpp
+++ b/llvm/lib/Transforms/Utils/MoveAutoInit.cpp
@@ -164,6 +164,9 @@ static bool runMoveAutoInit(Function &F, DominatorTree &DT, MemorySSA &MSSA) {
         if (TransitiveSuccessors.count(Pred))
           continue;
 
+        if (!DT.isReachableFromEntry(Pred))
+          continue;
+
         DominatingPredecessor =
             DominatingPredecessor
                 ? DT.findNearestCommonDominator(DominatingPredecessor, Pred)
@@ -178,9 +181,10 @@ static bool runMoveAutoInit(Function &F, DominatorTree &DT, MemorySSA &MSSA) {
 
     // CatchSwitchInst blocks can only have one instruction, so they are not
     // good candidates for insertion.
-    while (isa<CatchSwitchInst>(UsersDominator->getFirstInsertionPt())) {
+    while (isa<CatchSwitchInst>(UsersDominator->getFirstNonPHI())) {
       for (BasicBlock *Pred : predecessors(UsersDominator))
-        UsersDominator = DT.findNearestCommonDominator(UsersDominator, Pred);
+        if (DT.isReachableFromEntry(Pred))
+          UsersDominator = DT.findNearestCommonDominator(UsersDominator, Pred);
     }
 
     // We finally found a place where I can be moved while not introducing extra


Regression tests:
file: llvm/test/Transforms/MoveAutoInit/catchswitch.ll
commands: opt < %s -S -passes='move-auto-init' -verify-memoryssa
tests: test_name: test
test_body: declare void @dummy()

declare void @dummy1()

define void @test() personality ptr @dummy {
entry:
  %p = alloca [2 x i16], i32 0, align 2
  store i32 0, ptr %p, align 2, !annotation !0
  br label %middle

middle:                                           ; preds = %entry
  %call = invoke ptr @dummy()
          to label %clean unwind label %catchbb

clean:                                            ; preds = %middle
  ret void

catchbb:                                          ; preds = %middle
  %cs = catchswitch within none [label %pad, label %pad1] unwind to caller

pad:                                              ; preds = %catchbb
  %c = catchpad within %cs [i32 0]
  call void @dummy1()
  ret void

pad1:                                             ; preds = %catchbb
  %c1 = catchpad within %cs [i32 0]
  call void @dummy1()
  ret void
}

!0 = !{!"auto-init"}

file: llvm/test/Transforms/MoveAutoInit/loop.ll
commands: opt < %s -S -passes='move-auto-init' -verify-memoryssa
tests: test_name: foo
test_body: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

define void @foo(i32 %x) {
entry:
  %buffer = alloca [80 x i32], align 16
  call void @llvm.memset.p0.i64(ptr align 16 %buffer, i8 -86, i64 320, i1 false), !annotation !0
  br label %do.body

do.body:                                          ; preds = %do.cond, %entry
  %x.addr.0 = phi i32 [ %x, %entry ], [ %dec, %do.cond ]
  %arrayidx = getelementptr inbounds [80 x i32], ptr %buffer, i64 0, i64 0
  call void @dump(ptr %arrayidx)
  br label %do.cond

do.cond:                                          ; preds = %do.body
  %dec = add nsw i32 %x.addr.0, -1
  %tobool = icmp ne i32 %x.addr.0, 0
  br i1 %tobool, label %do.body, label %do.end

do.end:                                           ; preds = %do.cond
  ret void
}

; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)
declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #0

declare void @dump(ptr)

attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: write) }

!0 = !{!"auto-init"}

test_name: bar
test_body: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)
declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #0

declare void @dump(ptr)

define void @bar(i32 %x, i32 %y) {
entry:
  %buffer = alloca [80 x i32], align 16
  call void @llvm.memset.p0.i64(ptr align 16 %buffer, i8 -86, i64 320, i1 false), !annotation !0
  %tobool = icmp ne i32 %y, 0
  br i1 %tobool, label %if.then, label %if.end

if.then:                                          ; preds = %entry
  %add = add nsw i32 %x, %y
  br label %do.body

do.body:                                          ; preds = %do.cond, %if.then
  %x.addr.0 = phi i32 [ %add, %if.then ], [ %dec, %do.cond ]
  %arrayidx = getelementptr inbounds [80 x i32], ptr %buffer, i64 0, i64 0
  call void @dump(ptr %arrayidx)
  br label %do.cond

do.cond:                                          ; preds = %do.body
  %dec = add nsw i32 %x.addr.0, -1
  %tobool1 = icmp ne i32 %x.addr.0, 0
  br i1 %tobool1, label %do.body, label %do.end

do.end:                                           ; preds = %do.cond
  br label %if.end

if.end:                                           ; preds = %do.end, %entry
  ret void
}

attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: write) }

!0 = !{!"auto-init"}