Bug type: crash
Component: LoopVectorize
Bug location: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp: LoopVectorizationCostModel::collectValuesToIgnore
Issue title: [VPlan] Assertion `VF.Width == Width && "VPlan cost model and legacy cost model disagreed"' failed.
Labels: vectorizers
crash
Reported by: patrick-rivos

Tested using 51d4980a133db12888207698e39c469cb7055cac

Testcase:
```llvm ir
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define void @f() #0 {
entry:
  br label %for.body

for.cond.cleanup:                                 ; preds = %cond.end7
  ret void

for.body:                                         ; preds = %cond.end7, %entry
  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %cond.end7 ]
  %xor1315 = phi i32 [ 0, %entry ], [ %xor, %cond.end7 ]
  %xor = xor i32 0, 0
  %arrayidx = getelementptr [1 x i16], ptr null, i64 0, i64 %indvars.iv
  %0 = load i16, ptr %arrayidx, align 2
  %tobool1.not = icmp eq i16 %0, 0
  br i1 %tobool1.not, label %cond.false, label %cond.end7

cond.false:                                       ; preds = %for.body
  %arrayidx3 = getelementptr [1 x i64], ptr null, i64 0, i64 %indvars.iv
  br label %cond.end7

cond.end7:                                        ; preds = %cond.false, %for.body
  %indvars.iv.next = add nsw i64 %indvars.iv, 3
  %1 = icmp eq i64 %indvars.iv.next, 0
  br i1 %1, label %for.cond.cleanup, label %for.body
}

attributes #0 = { "target-features"="+64bit,+a,+c,+d,+f,+m,+relax,+v,+zicsr,+zifencei,+zmmul,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b,-b,-e,-experimental-smmpm,-experimental-smnpm,-experimental-ssnpm,-experimental-sspm,-experimental-ssqosid,-experimental-supm,-experimental-zacas,-experimental-zalasr,-experimental-zicfilp,-experimental-zicfiss,-h,-shcounterenw,-shgatpa,-shtvala,-shvsatpa,-shvstvala,-shvstvecd,-smaia,-smcdeleg,-smcsrind,-smepmp,-smstateen,-ssaia,-ssccfg,-ssccptr,-sscofpmf,-sscounterenw,-sscsrind,-ssstateen,-ssstrict,-sstc,-sstvala,-sstvecd,-ssu64xl,-svade,-svadu,-svbare,-svinval,-svnapot,-svpbmt,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xsfcease,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xsifivecdiscarddlone,-xsifivecflushdlone,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-xwchc,-za128rs,-za64rs,-zaamo,-zabha,-zalrsc,-zama16b,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmop,-zcmp,-zcmt,-zdinx,-zfa,-zfbfmin,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zihintntl,-zihintpause,-zihpm,-zimop,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-ztso,-zvbb,-zvbc,-zvfbfmin,-zvfbfwma,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl4096b,-zvl512b,-zvl65536b,-zvl8192b" }
```

Backtrace:
```
> /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt -passes loop-vectorize reduced.ll -S
opt: /scratch/tc-testing/tc-compiler-fuzz-trunk/llvm/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:10123: bool llvm::LoopVectorizePass::processLoop(llvm::Loop*): Assertion `VF.Width == Width && "VPlan cost model and legacy cost model disagreed"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt -passes loop-vectorize reduced.ll -S
1.      Running pass "function(loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>)" on module "reduced.ll"
2.      Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "f"
 #0 0x00005e0a0dd8f3b0 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2f1f3b0)
 #1 0x00005e0a0dd8c7cf llvm::sys::RunSignalHandlers() (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2f1c7cf)
 #2 0x00005e0a0dd8c925 SignalHandler(int) Signals.cpp:0:0
 #3 0x000073a243a42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x000073a243a969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x000073a243a969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x000073a243a969fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x000073a243a42476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x000073a243a287f3 abort ./stdlib/abort.c:81:7
 #9 0x000073a243a2871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x000073a243a39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x00005e0a0cdaadd8 llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f3add8)
#12 0x00005e0a0cdad991 llvm::LoopVectorizePass::runImpl(llvm::Function&, llvm::ScalarEvolution&, llvm::LoopInfo&, llvm::TargetTransformInfo&, llvm::DominatorTree&, llvm::BlockFrequencyInfo*, llvm::TargetLibraryInfo*, llvm::DemandedBits&, llvm::AssumptionCache&, llvm::LoopAccessInfoManager&, llvm::OptimizationRemarkEmitter&, llvm::ProfileSummaryInfo*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f3d991)
#13 0x00005e0a0cdae110 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f3e110)
#14 0x00005e0a0bc1fda6 llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xdafda6)
#15 0x00005e0a0dba750e llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2d3750e)
#16 0x00005e0a0bc22f36 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xdb2f36)
#17 0x00005e0a0dba629b llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2d3629b)
#18 0x00005e0a0bc1f286 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xdaf286)
#19 0x00005e0a0dba43ed llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2d343ed)
#20 0x00005e0a0b4686b6 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x5f86b6)
#21 0x00005e0a0b45a2f1 optMain (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x5ea2f1)
#22 0x000073a243a29d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#23 0x000073a243a29e40 call_init ./csu/../csu/libc-start.c:128:20
#24 0x000073a243a29e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#25 0x00005e0a0b450185 _start (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x5e0185)
zsh: IOT instruction (core dumped)  /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt
```

Godbolt: https://godbolt.org/z/TnYreKbqn

@fhahn 

Found via fuzzer.

Comments: author: fhahn
body: Another case with dead instructions that get simplified by VPlan-DCE :/
author: patrick-rivos
body: Just to add a bit of context here: I'm hitting this assertion >300 times a day so I've allowlisted it in the fuzzer I run. There are likely other interesting cases where this assertion triggers but I don't have the bandwidth to deduplicate this failure to pull out those cases. :-(
author: preames
body: > Just to add a bit of context here: I'm hitting this assertion >300 times a day so I've allowlisted it in the fuzzer I run. There are likely other interesting cases where this assertion triggers but I don't have the bandwidth to deduplicate this failure to pull out those cases. :-(

@fhahn This assertion is triggering in a large number of fuzzer runs, and we have some reason to believe there are other failures be masked by this one.  (We have at least one instance of this found so far by accident.)  This needs to be either fixed or reverted so that tree is green.  
author: fhahn
body: Will look into a fix now that I'm back. The crash should not reproduce with `opt -passes='instcombine,simplifycfg,loop-vectorize'` for all instances of the same underlying issue.
author: nikic
body: @fhahn I feel like at this point this assertion is doing a lot more harm than good. It's very fragile, and doesn't seem to help in finding any genuine bugs, just incidental differences in simplification power.
author: artagnon
body: I was also looking into this bug briefly, but couldn't quite figure out why we didn't choose to rip out the legacy costing.
author: sjoerdmeijer
body: If e9e3a183d6d8d8729223b7131aa57fd9f02f0440 was supposed to fix this, then I can confirm I am still seeing this assert. 

If this is indeed something else or new, then I agree with @nikic that this assert is too fragile.
author: fhahn
body: The assertion originally surfaced real differences that needed fixing; the fuzzer-generated issues over the last weeks mostly were due to unsimplified input, which is very difficult to completely match without actually iteratively simplifying. Seeing the recent https://github.com/llvm/llvm-project/issues/104714 with a C reproducer it was a bit surprising that dead loads (and subsequent dead blocks/conditions) survive until LoopVectorize in the default pipeline.

There will be a number of code changes over the next few weeks/months which may introduce unintended divergences the assert is supposed to catch. For that reason it would be beneficial to keep the assert.

Ideally we would only check if no extra simplifications have been applied on the selected VPlan, which should be possible to check once #103033 lands.

We could also guard it with an option, similar to InstCombine's fix point iteration assertion, which can also trigger asserts by default on valid IR input.

> If [e9e3a18](https://github.com/llvm/llvm-project/commit/e9e3a183d6d8d8729223b7131aa57fd9f02f0440) was supposed to fix this, then I can confirm I am still seeing this assert.
> 

Could you share the reproducer somewhere? Would be good to check if this is due to the simplification issue mentioned above or a genuine divergence
author: sjoerdmeijer
body: > Could you share the reproducer somewhere? Would be good to check if this is due to the simplification issue mentioned above or a genuine divergence

This runs in the same assert with `opt -S -passes=loop-vectorize`: 

```
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
target triple = "aarch64-unknown-linux-gnu"

define void @foo() #0 {
entry:
  br label %for.body315.us.us

for.body315.us.us:                                ; preds = %cond.end388.us.us, %entry
  %indvars.iv10421 = phi i64 [ %indvars.iv.next1043, %cond.end388.us.us ], [ 0, %entry ]
  br i1 false, label %cond.end388.us.us, label %cond.true380.us.us

cond.true380.us.us:                               ; preds = %for.body315.us.us
  %0 = load i32, ptr null, align 4
  br label %cond.end388.us.us

cond.end388.us.us:                                ; preds = %cond.true380.us.us, %for.body315.us.us
  %indvars.iv.next1043 = add i64 %indvars.iv10421, 1
  %cmp313.us.us = icmp slt i64 %indvars.iv10421, 1
  br i1 %cmp313.us.us, label %for.body315.us.us, label %for.cond311.for.cond.cleanup314_crit_edge.loopexit, !llvm.loop !0

for.cond311.for.cond.cleanup314_crit_edge.loopexit: ; preds = %cond.end388.us.us
  ret void
}

attributes #0 = { "target-cpu"="neoverse-v2" }

!0 = distinct !{!0, !1, !2, !3}
!1 = !{!"llvm.loop.mustprogress"}
!2 = !{!"llvm.loop.vectorize.predicate.enable", i1 true}
!3 = !{!"llvm.loop.vectorize.enable", i1 true}
```

Fix patch:
commit e9e3a183d6d8d8729223b7131aa57fd9f02f0440
Author: Florian Hahn <flo@fhahn.com>
Date:   Sun Aug 18 12:51:17 2024 +0100

    [LV] Don't cost branches and conditions to empty blocks.
    
    Update the legacy cost model skip branches with successors blocks
    that are empty or only contain dead instructions, together with their
    conditions. Such branches and conditions won't result in any
    generated code and will be cleaned up by VPlan transforms.
    
    This fixes a difference between the legacy and VPlan-based cost model.
    
    When running LV in its usual pipeline position, such dead blocks should
    already have been cleaned up, but they might be generated manually or by
    fuzzers.
    
    Fixes https://github.com/llvm/llvm-project/issues/100591.

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 27e99694aafd..55c0ba3dd8f9 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -6730,9 +6730,12 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
     return RequiresScalarEpilogue &&
            !TheLoop->contains(cast<Instruction>(U)->getParent());
   };
+
+  LoopBlocksDFS DFS(TheLoop);
+  DFS.perform(LI);
   MapVector<Value *, SmallVector<Value *>> DeadInvariantStoreOps;
-  for (BasicBlock *BB : TheLoop->blocks())
-    for (Instruction &I : *BB) {
+  for (BasicBlock *BB : reverse(make_range(DFS.beginRPO(), DFS.endRPO())))
+    for (Instruction &I : reverse(*BB)) {
       // Find all stores to invariant variables. Since they are going to sink
       // outside the loop we do not need calculate cost for them.
       StoreInst *SI;
@@ -6765,6 +6768,13 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
         Value *PointerOp = getLoadStorePointerOperand(&I);
         DeadInterleavePointerOps.push_back(PointerOp);
       }
+
+      // Queue branches for analysis. They are dead, if their successors only
+      // contain dead instructions.
+      if (auto *Br = dyn_cast<BranchInst>(&I)) {
+        if (Br->isConditional())
+          DeadOps.push_back(&I);
+      }
     }
 
   // Mark ops feeding interleave group members as free, if they are only used
@@ -6789,8 +6799,36 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
   // Mark ops that would be trivially dead and are only used by ignored
   // instructions as free.
   BasicBlock *Header = TheLoop->getHeader();
+
+  // Returns true if the block contains only dead instructions. Such blocks will
+  // be removed by VPlan-to-VPlan transforms and won't be considered by the
+  // VPlan-based cost model, so skip them in the legacy cost-model as well.
+  auto IsEmptyBlock = [this](BasicBlock *BB) {
+    return all_of(*BB, [this](Instruction &I) {
+      return ValuesToIgnore.contains(&I) || VecValuesToIgnore.contains(&I) ||
+             (isa<BranchInst>(&I) && !cast<BranchInst>(&I)->isConditional());
+    });
+  };
   for (unsigned I = 0; I != DeadOps.size(); ++I) {
     auto *Op = dyn_cast<Instruction>(DeadOps[I]);
+
+    // Check if the branch should be considered dead.
+    if (auto *Br = dyn_cast_or_null<BranchInst>(Op)) {
+      BasicBlock *ThenBB = Br->getSuccessor(0);
+      BasicBlock *ElseBB = Br->getSuccessor(1);
+      bool ThenEmpty = IsEmptyBlock(ThenBB);
+      bool ElseEmpty = IsEmptyBlock(ElseBB);
+      if ((ThenEmpty && ElseEmpty) ||
+          (ThenEmpty && ThenBB->getSingleSuccessor() == ElseBB &&
+           ElseBB->phis().empty()) ||
+          (ElseEmpty && ElseBB->getSingleSuccessor() == ThenBB &&
+           ThenBB->phis().empty())) {
+        VecValuesToIgnore.insert(Br);
+        DeadOps.push_back(Br->getCondition());
+      }
+      continue;
+    }
+
     // Skip any op that shouldn't be considered dead.
     if (!Op || !TheLoop->contains(Op) ||
         (isa<PHINode>(Op) && Op->getParent() == Header) ||


Regression tests:
file: llvm/test/Transforms/LoopVectorize/RISCV/blocks-with-dead-instructions.ll
commands: opt -p loop-vectorize -S %s
tests: test_name: block_with_dead_inst_1
test_body: target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define void @block_with_dead_inst_1(ptr %src, i64 %N) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i16 [ 1, %entry ], [ %xor, %loop.latch ]
  %xor = xor i16 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %then, label %loop.latch

then:                                             ; preds = %loop.header
  %dead.gep = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

loop.latch:                                       ; preds = %then, %loop.header
  store i16 %xor, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 3
  %0 = icmp eq i64 %iv.next, %N
  br i1 %0, label %exit, label %loop.header

exit:                                             ; preds = %loop.latch
  ret void
}

attributes #0 = { "target-features"="+64bit,+v" }

test_name: multiple_blocks_with_dead_insts_4
test_body: target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define void @multiple_blocks_with_dead_insts_4(ptr %src, i64 %N) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i16 [ 1, %entry ], [ %xor, %loop.latch ]
  %xor = xor i16 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %then, label %else

then:                                             ; preds = %loop.header
  br label %then.1

then.1:                                           ; preds = %then
  %dead.gep.1 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

else:                                             ; preds = %loop.header
  %dead.gep.2 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

loop.latch:                                       ; preds = %else, %then.1
  store i16 %xor, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 3
  %ec = icmp eq i64 %iv.next, %N
  br i1 %ec, label %exit, label %loop.header

exit:                                             ; preds = %loop.latch
  ret void
}

attributes #0 = { "target-features"="+64bit,+v" }

test_name: empty_block_with_phi_1
test_body: target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define void @empty_block_with_phi_1(ptr %src, i64 %N) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i32 [ 1, %entry ], [ %xor, %loop.latch ]
  %xor = xor i32 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %then, label %loop.latch

then:                                             ; preds = %loop.header
  br label %loop.latch

loop.latch:                                       ; preds = %then, %loop.header
  %p = phi i16 [ %l, %loop.header ], [ 99, %then ]
  store i16 %p, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 1
  %0 = icmp eq i64 %iv.next, %N
  br i1 %0, label %exit, label %loop.header

exit:                                             ; preds = %loop.latch
  ret void
}

attributes #0 = { "target-features"="+64bit,+v" }

test_name: multiple_blocks_with_dead_insts_3
test_body: target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define void @multiple_blocks_with_dead_insts_3(ptr %src) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i16 [ 0, %entry ], [ %xor, %loop.latch ]
  %xor = xor i16 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %then, label %else

then:                                             ; preds = %loop.header
  %dead.gep.1 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

else:                                             ; preds = %loop.header
  %dead.gep.2 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

loop.latch:                                       ; preds = %else, %then
  store i16 %xor, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 3
  %ec = icmp eq i64 %iv.next, 1000
  br i1 %ec, label %exit, label %loop.header

exit:                                             ; preds = %loop.latch
  ret void
}

attributes #0 = { "target-features"="+64bit,+v" }

test_name: multiple_blocks_with_dead_inst_multiple_successors_5
test_body: target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define void @multiple_blocks_with_dead_inst_multiple_successors_5(ptr %src) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i16 [ 1, %entry ], [ %xor, %loop.latch ]
  %xor = xor i16 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %then, label %else

then:                                             ; preds = %loop.header
  br label %then.1

then.1:                                           ; preds = %then
  %dead.gep.1 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

else:                                             ; preds = %loop.header
  br label %else.2

else.2:                                           ; preds = %else
  %dead.gep.2 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

loop.latch:                                       ; preds = %else.2, %then.1
  store i16 %xor, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 3
  %ec = icmp eq i64 %iv.next, 1000
  br i1 %ec, label %exit, label %loop.header

exit:                                             ; preds = %loop.latch
  ret void
}

attributes #0 = { "target-features"="+64bit,+v" }

test_name: multiple_blocks_with_dead_inst_multiple_successors_6
test_body: target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define void @multiple_blocks_with_dead_inst_multiple_successors_6(ptr %src, i1 %ic, i64 %N) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i16 [ 1, %entry ], [ %xor, %loop.latch ]
  %xor = xor i16 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %then, label %else

then:                                             ; preds = %loop.header
  br i1 %ic, label %then.1, label %else

then.1:                                           ; preds = %then
  %dead.gep.1 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

else:                                             ; preds = %then, %loop.header
  br label %else.2

else.2:                                           ; preds = %else
  %dead.gep.2 = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

loop.latch:                                       ; preds = %else.2, %then.1
  store i16 %xor, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 3
  %ec = icmp eq i64 %iv.next, %N
  br i1 %ec, label %exit, label %loop.header

exit:                                             ; preds = %loop.latch
  ret void
}

attributes #0 = { "target-features"="+64bit,+v" }

test_name: empty_block_with_phi_2
test_body: target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define void @empty_block_with_phi_2(ptr %src, i64 %N) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i32 [ 1, %entry ], [ %xor, %loop.latch ]
  %xor = xor i32 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %loop.latch, label %else

else:                                             ; preds = %loop.header
  br label %loop.latch

loop.latch:                                       ; preds = %else, %loop.header
  %p = phi i16 [ %l, %loop.header ], [ 99, %else ]
  store i16 %p, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 1
  %0 = icmp eq i64 %iv.next, %N
  br i1 %0, label %exit, label %loop.header

exit:                                             ; preds = %loop.latch
  ret void
}

attributes #0 = { "target-features"="+64bit,+v" }

test_name: block_with_dead_inst_2
test_body: target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define void @block_with_dead_inst_2(ptr %src) #0 {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %xor1315 = phi i16 [ 0, %entry ], [ %xor, %loop.latch ]
  %xor = xor i16 0, 0
  %gep = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep, align 2
  %c = icmp eq i16 %l, 0
  br i1 %c, label %loop.latch, label %else

else:                                             ; preds = %loop.header
  %dead.gep = getelementptr i64, ptr %src, i64 %iv
  br label %loop.latch

loop.latch:                                       ; preds = %else, %loop.header
  store i16 %xor, ptr %gep, align 2
  %iv.next = add nsw i64 %iv, 3
  %ec = icmp eq i64 %iv.next, 1000
  br i1 %ec, label %exit, label %loop.header

exit:                                             ; preds = %loop.latch
  ret void
}

attributes #0 = { "target-features"="+64bit,+v" }