| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 | 
 | ; RUN: opt -S -passes="loop-mssa(loop-instsimplify,simple-loop-unswitch<nontrivial>)" < %s | FileCheck %s | 
 |  | 
 | @vtable = constant ptr @foo | 
 |  | 
 | declare void @foo() memory(none) | 
 | declare void @bar() | 
 |  | 
 | ; The call becomes known readnone after simplification, but still have a | 
 | ; MemoryAccess. Make sure this does not lead to an assertion failure. | 
 | define void @test(i1 %c) { | 
 | ; CHECK-LABEL: define void @test( | 
 | ; CHECK-SAME: i1 [[C:%.*]]) { | 
 | ; CHECK-NEXT:    [[C_FR:%.*]] = freeze i1 [[C]] | 
 | ; CHECK-NEXT:    br i1 [[C_FR]], label [[DOTSPLIT_US:%.*]], label [[DOTSPLIT:%.*]] | 
 | ; CHECK:       .split.us: | 
 | ; CHECK-NEXT:    br label [[LOOP_US:%.*]] | 
 | ; CHECK:       loop.us: | 
 | ; CHECK-NEXT:    call void @foo() | 
 | ; CHECK-NEXT:    br label [[EXIT_SPLIT_US:%.*]] | 
 | ; CHECK:       exit.split.us: | 
 | ; CHECK-NEXT:    br label [[EXIT:%.*]] | 
 | ; CHECK:       .split: | 
 | ; CHECK-NEXT:    br label [[LOOP:%.*]] | 
 | ; CHECK:       loop: | 
 | ; CHECK-NEXT:    call void @foo() | 
 | ; CHECK-NEXT:    br label [[LOOP]] | 
 | ; CHECK:       exit: | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   br label %loop | 
 |  | 
 | loop: | 
 |   %fn = load ptr, ptr @vtable, align 8 | 
 |   call void %fn() | 
 |   br i1 %c, label %exit, label %loop | 
 |  | 
 | exit: | 
 |   ret void | 
 | } | 
 |  | 
 | ; Variant with another access after the call. | 
 | define void @test2(i1 %c, ptr %p) { | 
 | ; CHECK-LABEL: define void @test2( | 
 | ; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) { | 
 | ; CHECK-NEXT:    [[C_FR:%.*]] = freeze i1 [[C]] | 
 | ; CHECK-NEXT:    br i1 [[C_FR]], label [[DOTSPLIT_US:%.*]], label [[DOTSPLIT:%.*]] | 
 | ; CHECK:       .split.us: | 
 | ; CHECK-NEXT:    br label [[LOOP_US:%.*]] | 
 | ; CHECK:       loop.us: | 
 | ; CHECK-NEXT:    call void @foo() | 
 | ; CHECK-NEXT:    call void @bar() | 
 | ; CHECK-NEXT:    br label [[EXIT_SPLIT_US:%.*]] | 
 | ; CHECK:       exit.split.us: | 
 | ; CHECK-NEXT:    br label [[EXIT:%.*]] | 
 | ; CHECK:       .split: | 
 | ; CHECK-NEXT:    br label [[LOOP:%.*]] | 
 | ; CHECK:       loop: | 
 | ; CHECK-NEXT:    call void @foo() | 
 | ; CHECK-NEXT:    call void @bar() | 
 | ; CHECK-NEXT:    br label [[LOOP]] | 
 | ; CHECK:       exit: | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   br label %loop | 
 |  | 
 | loop: | 
 |   %fn = load ptr, ptr @vtable, align 8 | 
 |   call void %fn() | 
 |   call void @bar() | 
 |   br i1 %c, label %exit, label %loop | 
 |  | 
 | exit: | 
 |   ret void | 
 | } | 
 |  | 
 | ; Variant with another access after the call and no access before the call. | 
 | define void @test3(i1 %c, ptr %p) { | 
 | ; CHECK-LABEL: define void @test3( | 
 | ; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) { | 
 | ; CHECK-NEXT:    [[C_FR:%.*]] = freeze i1 [[C]] | 
 | ; CHECK-NEXT:    br i1 [[C_FR]], label [[DOTSPLIT_US:%.*]], label [[DOTSPLIT:%.*]] | 
 | ; CHECK:       .split.us: | 
 | ; CHECK-NEXT:    br label [[LOOP_US:%.*]] | 
 | ; CHECK:       loop.us: | 
 | ; CHECK-NEXT:    br label [[SPLIT_US:%.*]] | 
 | ; CHECK:       split.us: | 
 | ; CHECK-NEXT:    call void @foo() | 
 | ; CHECK-NEXT:    call void @bar() | 
 | ; CHECK-NEXT:    br label [[EXIT_SPLIT_US:%.*]] | 
 | ; CHECK:       exit.split.us: | 
 | ; CHECK-NEXT:    br label [[EXIT:%.*]] | 
 | ; CHECK:       .split: | 
 | ; CHECK-NEXT:    br label [[LOOP:%.*]] | 
 | ; CHECK:       loop: | 
 | ; CHECK-NEXT:    br label [[SPLIT:%.*]] | 
 | ; CHECK:       split: | 
 | ; CHECK-NEXT:    call void @foo() | 
 | ; CHECK-NEXT:    call void @bar() | 
 | ; CHECK-NEXT:    br label [[LOOP]] | 
 | ; CHECK:       exit: | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   br label %loop | 
 |  | 
 | loop: | 
 |   %fn = load ptr, ptr @vtable, align 8 | 
 |   br label %split | 
 |  | 
 | split: | 
 |   call void %fn() | 
 |   call void @bar() | 
 |   br i1 %c, label %exit, label %loop | 
 |  | 
 | exit: | 
 |   ret void | 
 | } | 
 |  | 
 | ; Variants of the above test with swapped branch destinations. | 
 |  | 
 | define void @test1_swapped(i1 %c) { | 
 | ; CHECK-LABEL: define void @test1_swapped( | 
 | ; CHECK-SAME: i1 [[C:%.*]]) { | 
 | ; CHECK-NEXT:  start: | 
 | ; CHECK-NEXT:    [[C_FR:%.*]] = freeze i1 [[C]] | 
 | ; CHECK-NEXT:    br i1 [[C_FR]], label [[START_SPLIT_US:%.*]], label [[START_SPLIT:%.*]] | 
 | ; CHECK:       start.split.us: | 
 | ; CHECK-NEXT:    br label [[LOOP_US:%.*]] | 
 | ; CHECK:       loop.us: | 
 | ; CHECK-NEXT:    call void @foo() | 
 | ; CHECK-NEXT:    br label [[LOOP_US]] | 
 | ; CHECK:       start.split: | 
 | ; CHECK-NEXT:    br label [[LOOP:%.*]] | 
 | ; CHECK:       loop: | 
 | ; CHECK-NEXT:    call void @foo() | 
 | ; CHECK-NEXT:    br label [[EXIT:%.*]] | 
 | ; CHECK:       exit: | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 | start: | 
 |   br label %loop | 
 |  | 
 | loop: | 
 |   %fn = load ptr, ptr @vtable, align 8 | 
 |   call void %fn() | 
 |   br i1 %c, label %loop, label %exit | 
 |  | 
 | exit: | 
 |   ret void | 
 | } | 
 |  | 
 | define void @test2_swapped(i1 %c, ptr %p) { | 
 | ; CHECK-LABEL: define void @test2_swapped( | 
 | ; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) { | 
 | ; CHECK-NEXT:    [[C_FR:%.*]] = freeze i1 [[C]] | 
 | ; CHECK-NEXT:    br i1 [[C_FR]], label [[DOTSPLIT_US:%.*]], label [[DOTSPLIT:%.*]] | 
 | ; CHECK:       .split.us: | 
 | ; CHECK-NEXT:    br label [[LOOP_US:%.*]] | 
 | ; CHECK:       loop.us: | 
 | ; CHECK-NEXT:    call void @foo() | 
 | ; CHECK-NEXT:    call void @bar() | 
 | ; CHECK-NEXT:    br label [[LOOP_US]] | 
 | ; CHECK:       .split: | 
 | ; CHECK-NEXT:    br label [[LOOP:%.*]] | 
 | ; CHECK:       loop: | 
 | ; CHECK-NEXT:    call void @foo() | 
 | ; CHECK-NEXT:    call void @bar() | 
 | ; CHECK-NEXT:    br label [[EXIT:%.*]] | 
 | ; CHECK:       exit: | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   br label %loop | 
 |  | 
 | loop: | 
 |   %fn = load ptr, ptr @vtable, align 8 | 
 |   call void %fn() | 
 |   call void @bar() | 
 |   br i1 %c, label %loop, label %exit | 
 |  | 
 | exit: | 
 |   ret void | 
 | } | 
 |  | 
 | define void @test3_swapped(i1 %c, ptr %p) { | 
 | ; CHECK-LABEL: define void @test3_swapped( | 
 | ; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) { | 
 | ; CHECK-NEXT:    [[C_FR:%.*]] = freeze i1 [[C]] | 
 | ; CHECK-NEXT:    br i1 [[C_FR]], label [[DOTSPLIT_US:%.*]], label [[DOTSPLIT:%.*]] | 
 | ; CHECK:       .split.us: | 
 | ; CHECK-NEXT:    br label [[LOOP_US:%.*]] | 
 | ; CHECK:       loop.us: | 
 | ; CHECK-NEXT:    br label [[SPLIT_US:%.*]] | 
 | ; CHECK:       split.us: | 
 | ; CHECK-NEXT:    call void @foo() | 
 | ; CHECK-NEXT:    call void @bar() | 
 | ; CHECK-NEXT:    br label [[LOOP_US]] | 
 | ; CHECK:       .split: | 
 | ; CHECK-NEXT:    br label [[LOOP:%.*]] | 
 | ; CHECK:       loop: | 
 | ; CHECK-NEXT:    br label [[SPLIT:%.*]] | 
 | ; CHECK:       split: | 
 | ; CHECK-NEXT:    call void @foo() | 
 | ; CHECK-NEXT:    call void @bar() | 
 | ; CHECK-NEXT:    br label [[EXIT:%.*]] | 
 | ; CHECK:       exit: | 
 | ; CHECK-NEXT:    ret void | 
 | ; | 
 |   br label %loop | 
 |  | 
 | loop: | 
 |   %fn = load ptr, ptr @vtable, align 8 | 
 |   br label %split | 
 |  | 
 | split: | 
 |   call void %fn() | 
 |   call void @bar() | 
 |   br i1 %c, label %loop, label %exit | 
 |  | 
 | exit: | 
 |   ret void | 
 | } |