Bug type: crash
Component: MemorySSAUpdater
Bug location: llvm/lib/Analysis/MemorySSAUpdater.cpp: MemorySSAUpdater::fixupDefs
MemorySSAUpdater::insertDef
Issue title: [clang] Crash at O1: Assertion `MSSA->dominates(NewDef, FirstDef) && "Should have dominated the new access"' failed
Labels: loopoptim
crash-on-valid
Reported by: cardigan1008

When I compiled this code with -O1, it crashed:

```c
int a, b, c, d;
long e, f;
long *g;
char h;
static long i[];
void j() {
  while (1) {
    if (a == 0)
      break;
    if (a == 1) {
      if (b == 0)
        break;
    } else if (a == 2)
      if (c)
        break;
      else
        a;
  }
}
void k() {
  for (; d; e++) {
    h = 2;
    for (; h; h++) {
      *g || (i[1] &= 0);
      --f;
    }
    j();
  }
}
```

Compiler Explorer: https://godbolt.org/z/fGf7hjTxe

Crash is

```
clang: /root/llvm-project/llvm/lib/Analysis/MemorySSAUpdater.cpp:504: void llvm::MemorySSAUpdater::fixupDefs(const llvm::SmallVectorImpl<llvm::WeakVH>&): Assertion `MSSA->dominates(NewDef, FirstDef) && "Should have dominated the new access"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/clang -gdwarf-4 -g -o /app/output.s -mllvm --x86-asm-syntax=intel -fno-verbose-asm -S --gcc-toolchain=/opt/compiler-explorer/gcc-snapshot -fcolor-diagnostics -fno-crash-diagnostics -O1 -Wall -Wextra <source>
1.	<eof> parser at end of file
2.	Optimizer
3.	Running pass "function<eager-inv>(float2int,lower-constant-intrinsics,loop(loop-rotate<header-duplication;no-prepare-for-lto>,loop-deletion),loop-distribute,inject-tli-mappings,loop-vectorize<interleave-forced-only;vectorize-forced-only;>,infer-alignment,loop-load-elim,instcombine<max-iterations=1;no-verify-fixpoint>,simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,vector-combine,instcombine<max-iterations=1;no-verify-fixpoint>,loop-unroll<O1>,transform-warning,sroa<preserve-cfg>,infer-alignment,instcombine<max-iterations=1;no-verify-fixpoint>,loop-mssa(licm<allowspeculation>),alignment-from-assumptions,loop-sink,instsimplify,div-rem-pairs,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;speculate-unpredictables>)" on module "<source>"
4.	Running pass "loop-mssa(licm<allowspeculation>)" on function "k"
 #0 0x0000000003bf59c8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x3bf59c8)
 #1 0x0000000003bf36cc llvm::sys::CleanupOnSignal(unsigned long) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x3bf36cc)
 #2 0x0000000003b40db8 CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0
 #3 0x0000751620442520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007516204969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #5 0x0000751620442476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #6 0x00007516204287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #7 0x000075162042871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #8 0x0000751620439e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #9 0x0000000002bf1b11 llvm::MemorySSAUpdater::fixupDefs(llvm::SmallVectorImpl<llvm::WeakVH> const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x2bf1b11)
#10 0x0000000002bf205b llvm::MemorySSAUpdater::insertDef(llvm::MemoryDef*, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x2bf205b)
#11 0x00000000039fa897 (anonymous namespace)::LoopPromoter::doExtraRewritesBeforeFinalDeletion() LICM.cpp:0:0
#12 0x0000000003d8281e llvm::LoadAndStorePromoter::run(llvm::SmallVectorImpl<llvm::Instruction*> const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x3d8281e)
#13 0x00000000039f8dae llvm::promoteLoopAccessesToScalars(llvm::SmallSetVector<llvm::Value*, 8u> const&, llvm::SmallVectorImpl<llvm::BasicBlock*>&, llvm::SmallVectorImpl<llvm::ilist_iterator_w_bits<llvm::ilist_detail::node_options<llvm::Instruction, true, false, void, true, llvm::BasicBlock>, false, false>>&, llvm::SmallVectorImpl<llvm::MemoryAccess*>&, llvm::PredIteratorCache&, llvm::LoopInfo*, llvm::DominatorTree*, llvm::AssumptionCache*, llvm::TargetLibraryInfo const*, llvm::TargetTransformInfo*, llvm::Loop*, llvm::MemorySSAUpdater&, llvm::ICFLoopSafetyInfo*, llvm::OptimizationRemarkEmitter*, bool, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x39f8dae)
#14 0x0000000003a06a36 (anonymous namespace)::LoopInvariantCodeMotion::runOnLoop(llvm::Loop*, llvm::AAResults*, llvm::LoopInfo*, llvm::DominatorTree*, llvm::AssumptionCache*, llvm::TargetLibraryInfo*, llvm::TargetTransformInfo*, llvm::ScalarEvolution*, llvm::MemorySSA*, llvm::OptimizationRemarkEmitter*, bool) (.part.0) LICM.cpp:0:0
#15 0x0000000003a075f8 llvm::LICMPass::run(llvm::Loop&, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>&, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x3a075f8)
#16 0x00000000052606ee llvm::detail::PassModel<llvm::Loop, llvm::LICMPass, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&>::run(llvm::Loop&, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>&, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x52606ee)
#17 0x0000000003a0fd93 llvm::FunctionToLoopPassAdaptor::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x3a0fd93)
#18 0x00000000010ee88e llvm::detail::PassModel<llvm::Function, llvm::FunctionToLoopPassAdaptor, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x10ee88e)
#19 0x00000000035a6b68 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x35a6b68)
#20 0x00000000010eee9e llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x10eee9e)
#21 0x00000000035a558e llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x35a558e)
#22 0x00000000010ee54e llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x10ee54e)
#23 0x00000000035a4fc0 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x35a4fc0)
#24 0x0000000003ea6cd3 (anonymous namespace)::EmitAssemblyHelper::RunOptimizationPipeline(clang::BackendAction, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream>>&, std::unique_ptr<llvm::ToolOutputFile, std::default_delete<llvm::ToolOutputFile>>&, clang::BackendConsumer*) BackendUtil.cpp:0:0
#25 0x0000000003eaa4e5 clang::EmitBackendOutput(clang::DiagnosticsEngine&, clang::HeaderSearchOptions const&, clang::CodeGenOptions const&, clang::TargetOptions const&, clang::LangOptions const&, llvm::StringRef, llvm::Module*, clang::BackendAction, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream>>, clang::BackendConsumer*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x3eaa4e5)
#26 0x00000000045780ae clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x45780ae)
#27 0x00000000065135cc clang::ParseAST(clang::Sema&, bool, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x65135cc)
#28 0x0000000004578488 clang::CodeGenAction::ExecuteAction() (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x4578488)
#29 0x0000000004832ba9 clang::FrontendAction::Execute() (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x4832ba9)
#30 0x00000000047b2a9e clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x47b2a9e)
#31 0x000000000491d8ee clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x491d8ee)
#32 0x0000000000ca9677 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0xca9677)
#33 0x0000000000ca123a ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#34 0x00000000045bb689 void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const::'lambda'()>(long) Job.cpp:0:0
#35 0x0000000003b41264 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x3b41264)
#36 0x00000000045bbc7f clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const (.part.0) Job.cpp:0:0
#37 0x0000000004581f6d clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x4581f6d)
#38 0x000000000458305d clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&, bool) const (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x458305d)
#39 0x000000000458a415 clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x458a415)
#40 0x0000000000ca64e3 clang_main(int, char**, llvm::ToolContext const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0xca64e3)
#41 0x0000000000b7d0f4 main (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0xb7d0f4)
#42 0x0000751620429d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#43 0x0000751620429e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#44 0x0000000000ca0cee _start (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0xca0cee)
```

Comments: author: dtcxzyw
body: Reproducer: https://godbolt.org/z/T33hbvach
```
; bin/opt -passes=licm test.ll -S
define void @k(ptr %p) {
entry:
  br label %for.cond1.preheader

for.cond1.preheader:                              ; preds = %j.exit, %entry
  br label %for.body3

for.body3:                                        ; preds = %for.body3, %for.cond1.preheader
  %dec10 = phi i64 [ 0, %for.cond1.preheader ], [ 1, %for.body3 ]
  store i64 %dec10, ptr %p, align 8
  br i1 false, label %for.end, label %for.body3

for.end:                                          ; preds = %for.body3
  switch i32 0, label %j.exit [
    i32 0, label %j.exit
    i32 2, label %if.end12.preheader.i
    i32 1, label %if.then2.i
  ]

if.then2.i:                                       ; preds = %if.end12.preheader.i, %for.end
  br i1 false, label %j.exit, label %if.end12.preheader.i

if.end12.preheader.i:                             ; preds = %if.end12.preheader.i, %if.then2.i, %for.end
  switch i32 0, label %if.end12.preheader.i.split [
    i32 0, label %if.end12.preheader.i
    i32 1, label %if.then2.i
  ]

if.end12.preheader.i.split:                       ; preds = %if.end12.preheader.i
  store i8 0, ptr %p, align 1
  ret void

j.exit:                                           ; preds = %if.then2.i, %for.end, %for.end
  store i64 0, ptr %p, align 8
  br label %for.cond1.preheader
}

```
author: nikic
body: Cleaned up the naming a bit:
```llvm
define void @test(ptr %p) {
entry:
  br label %loop0

loop0:                                            ; preds = %loop0.latch, %entry
  br label %loop1

loop1:                                            ; preds = %loop1, %loop0
  %dec10 = phi i64 [ 0, %loop0 ], [ 1, %loop1 ]
  store i64 %dec10, ptr %p
  br i1 false, label %loop1.exit, label %loop1

loop1.exit:                                       ; preds = %loop1
  switch i32 0, label %loop0.latch [
    i32 0, label %loop0.latch
    i32 2, label %loop3.preheader
    i32 1, label %loop2
  ]

loop2:                                            ; preds = %loop2.latch, %loop1.exit
  br i1 false, label %loop0.latch, label %loop3.preheader

loop3.preheader:                                  ; preds = %loop1.exit, %loop2
  br label %loop3

loop3:                                            ; preds = %loop3.preheader, %loop3
  switch i32 0, label %exit [
    i32 0, label %loop3
    i32 1, label %loop2.latch
  ]

loop2.latch:                                      ; preds = %loop3
  br label %loop2

loop0.latch:                                      ; preds = %loop2, %loop1.exit, %loop1.exit
  store i64 0, ptr %p
  br label %loop0

exit:                                             ; preds = %loop3
  store i64 1, ptr %p
  ret void
}
```

Initial observations:

 * Store is inserted into loop1.exit
 * No MemoryPhis are created for defining access
 * IDF is loop0, which already has MemoryPhi. So the fixup list only contains the new MemoryDef.

The first fixupDefs call produces:
```llvm
define void @test(ptr %p) {
entry:
  br label %loop0

loop0:                                            ; preds = %loop0.latch, %entry
; 4 = MemoryPhi({entry,liveOnEntry},{loop0.latch,2})
  br label %loop1

loop1:                                            ; preds = %loop1, %loop0
; 5 = MemoryPhi({loop0,4},{loop1,1})
  %dec10 = phi i64 [ 0, %loop0 ], [ 1, %loop1 ]
; 1 = MemoryDef(5)
  store i64 %dec10, ptr %p, align 4
  br i1 false, label %loop1.exit, label %loop1

loop1.exit:                                       ; preds = %loop1
  %dec10.lcssa = phi i64 [ %dec10, %loop1 ]
; 6 = MemoryDef(1)
  store i64 %dec10.lcssa, ptr %p, align 4
  switch i32 0, label %loop0.latch [
    i32 0, label %loop0.latch
    i32 2, label %loop3.preheader
    i32 1, label %loop2
  ]

loop2:                                            ; preds = %loop2.latch, %loop1.exit
; 8 = MemoryPhi({loop2.latch,9},{loop1.exit,6})
  br i1 false, label %loop0.latch, label %loop3.preheader

loop3.preheader:                                  ; preds = %loop2, %loop1.exit
; 9 = MemoryPhi({loop2,8},{loop1.exit,6})
  br label %loop3

loop3:                                            ; preds = %loop3, %loop3.preheader
  switch i32 0, label %exit [
    i32 0, label %loop3
    i32 1, label %loop2.latch
  ]

loop2.latch:                                      ; preds = %loop3
  br label %loop2

loop0.latch:                                      ; preds = %loop2, %loop1.exit, %loop1.exit
; 2 = MemoryDef(1)
  store i64 0, ptr %p, align 4
  br label %loop0

exit:                                             ; preds = %loop3
; 3 = MemoryDef(9)
  store i64 1, ptr %p, align 4
  ret void
}
```
The phis are inserted when process the store in exit. And then the next fixupDefs() call asserts when processing the store in loop0.latch.

The non-dominating access is `8 = MemoryPhi({loop2.latch,9},{loop1.exit,6})`.

I guess at this point the assumption is that we have already inserted all the necessary IDF phis, but it may not happen if we insert new phis during fixupDefs.
author: nikic
body: Something I don't get in the fixupDefs implementation is why this returns after updating a single def: https://github.com/llvm/llvm-project/blob/7f1185058279afeb2c88243edc031f06e27cc21b/llvm/lib/Analysis/MemorySSAUpdater.cpp#L511 That doesn't look correct.

For this test case, just replacing `return` with `continue` results in a different assert though, as phis are expected to be handled separately.

Fix patch:
commit d1408667de830da8817c24cb9788da6caae551c7
Author: Nikita Popov <npopov@redhat.com>
Date:   Thu Sep 4 10:23:29 2025 +0200

    [MemorySSA] Don't create phi nodes in fixupDefs() (#156021)
    
    The general flow when inserting MemoryDefs is:
    
     * Insert the def and set it's defining access (may insert phis)
     * Insert IDF phis
     * Update defining access for defs after the new one (fixupDefs)
     * Rename uses if requested
    
    fixupDefs() uses getPreviousDef() which can create new MemoryPHIs, but
    for which we're not going to insert IDF phis, so the required dominance
    property may not hold.
    
    I believe this is a leftover from a time before the "Insert IDF phis"
    step existed. Now that step should already ensure that all necessary
    MemoryPhis have been inserted, and we only need to update them.
    
    The fixupDefs() implementation was also returning after updating a
    single access, which is not right.
    
    Fixes https://github.com/llvm/llvm-project/issues/47875.
    Fixes https://github.com/llvm/llvm-project/issues/117157.
    Fixes https://github.com/llvm/llvm-project/issues/152998.
    Fixes https://github.com/llvm/llvm-project/issues/155161.
    Fixes https://github.com/llvm/llvm-project/issues/155184.

diff --git a/llvm/lib/Analysis/MemorySSAUpdater.cpp b/llvm/lib/Analysis/MemorySSAUpdater.cpp
index ecfecb03c375..bb3e679219ae 100644
--- a/llvm/lib/Analysis/MemorySSAUpdater.cpp
+++ b/llvm/lib/Analysis/MemorySSAUpdater.cpp
@@ -411,17 +411,11 @@ void MemorySSAUpdater::insertDef(MemoryDef *MD, bool RenameUses) {
     FixupList.push_back(MD);
   }
 
-  // Remember the index where we stopped inserting new phis above, since the
-  // fixupDefs call in the loop below may insert more, that are already minimal.
+  // Update defining access of following defs.
   unsigned NewPhiIndexEnd = InsertedPHIs.size();
-
-  while (!FixupList.empty()) {
-    unsigned StartingPHISize = InsertedPHIs.size();
-    fixupDefs(FixupList);
-    FixupList.clear();
-    // Put any new phis on the fixup list, and process them
-    FixupList.append(InsertedPHIs.begin() + StartingPHISize, InsertedPHIs.end());
-  }
+  fixupDefs(FixupList);
+  assert(NewPhiIndexEnd == InsertedPHIs.size() &&
+         "Should not insert new phis during fixupDefs()");
 
   // Optimize potentially non-minimal phis added in this method.
   unsigned NewPhiSize = NewPhiIndexEnd - NewPhiIndex;
@@ -504,11 +498,8 @@ void MemorySSAUpdater::fixupDefs(const SmallVectorImpl<WeakVH> &Vars) {
         assert(MSSA->dominates(NewDef, FirstDef) &&
                "Should have dominated the new access");
 
-        // This may insert new phi nodes, because we are not guaranteed the
-        // block we are processing has a single pred, and depending where the
-        // store was inserted, it may require phi nodes below it.
-        cast<MemoryDef>(FirstDef)->setDefiningAccess(getPreviousDef(FirstDef));
-        return;
+        cast<MemoryDef>(FirstDef)->setDefiningAccess(NewDef);
+        continue;
       }
       // We didn't find a def, so we must continue.
       for (const auto *S : successors(FixupBlock)) {


Regression tests:
file: llvm/test/Transforms/LICM/pr117157.ll
commands: opt -S -passes=licm -verify-memoryssa < %s
tests: test_name: <module>
test_body: 
define void @test(ptr %p) {
;
entry:
  br label %loop0

loop0:                                            ; preds = %loop0.latch, %entry
  br label %loop1

loop1:                                            ; preds = %loop1, %loop0
  %dec10 = phi i64 [ 0, %loop0 ], [ 1, %loop1 ]
  store i64 %dec10, ptr %p
  br i1 false, label %loop1.exit, label %loop1

loop1.exit:                                       ; preds = %loop1
  switch i32 0, label %loop0.latch [
  i32 0, label %loop0.latch
  i32 2, label %loop3.preheader
  i32 1, label %loop2
  ]

loop2:                                            ; preds = %loop2.latch, %loop1.exit
  br i1 false, label %loop0.latch, label %loop3.preheader

loop3.preheader:                                  ; preds = %loop1.exit, %loop2
  br label %loop3

loop3:                                            ; preds = %loop3.preheader, %loop3
  switch i32 0, label %exit [
  i32 0, label %loop3
  i32 1, label %loop2.latch
  ]

loop2.latch:                                      ; preds = %loop3
  br label %loop2

loop0.latch:                                      ; preds = %loop2, %loop1.exit, %loop1.exit
  store i64 0, ptr %p
  br label %loop0

exit:                                             ; preds = %loop3
  store i64 1, ptr %p
  ret void
}