1; RUN: opt -passes='loop(unswitch<nontrivial>),verify<loops>' -simple-loop-unswitch-guards -S < %s | FileCheck %s 2; RUN: opt -simple-loop-unswitch -enable-nontrivial-unswitch -simple-loop-unswitch-guards -S < %s | FileCheck %s 3; RUN: opt -passes='loop-mssa(unswitch<nontrivial>),verify<loops>' -simple-loop-unswitch-guards -verify-memoryssa -S < %s | FileCheck %s 4 5declare void @llvm.experimental.guard(i1, ...) 6 7define void @test_simple_case(i1 %cond, i32 %N) { 8; CHECK-LABEL: @test_simple_case( 9; CHECK-NEXT: entry: 10; CHECK-NEXT: br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] 11; CHECK: entry.split.us: 12; CHECK-NEXT: br label [[LOOP_US:%.*]] 13; CHECK: loop.us: 14; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[GUARDED_US:%.*]] ] 15; CHECK-NEXT: br label [[GUARDED_US]] 16; CHECK: guarded.us: 17; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1 18; CHECK-NEXT: [[LOOP_COND_US:%.*]] = icmp slt i32 [[IV_NEXT_US]], [[N:%.*]] 19; CHECK-NEXT: br i1 [[LOOP_COND_US]], label [[LOOP_US]], label [[EXIT_SPLIT_US:%.*]] 20; CHECK: deopt: 21; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] 22; CHECK-NEXT: unreachable 23; 24 25entry: 26 br label %loop 27 28loop: 29 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] 30 call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] 31 %iv.next = add i32 %iv, 1 32 %loop.cond = icmp slt i32 %iv.next, %N 33 br i1 %loop.cond, label %loop, label %exit 34 35exit: 36 ret void 37} 38 39define void @test_two_guards(i1 %cond1, i1 %cond2, i32 %N) { 40; CHECK-LABEL: @test_two_guards( 41; CHECK-NEXT: entry: 42; CHECK-NEXT: br i1 [[COND1:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] 43; CHECK: entry.split.us: 44; CHECK-NEXT: br i1 [[COND2:%.*]], label [[ENTRY_SPLIT_US_SPLIT_US:%.*]], label [[ENTRY_SPLIT_US_SPLIT:%.*]] 45; CHECK: entry.split.us.split.us: 46; CHECK-NEXT: br label [[LOOP_US_US:%.*]] 47; CHECK: loop.us.us: 48; CHECK-NEXT: [[IV_US_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US_SPLIT_US]] ], [ [[IV_NEXT_US_US:%.*]], [[GUARDED_US2:%.*]] ] 49; CHECK-NEXT: br label [[GUARDED_US_US:%.*]] 50; CHECK: guarded.us.us: 51; CHECK-NEXT: br label [[GUARDED_US2]] 52; CHECK: guarded.us2: 53; CHECK-NEXT: [[IV_NEXT_US_US]] = add i32 [[IV_US_US]], 1 54; CHECK-NEXT: [[LOOP_COND_US_US:%.*]] = icmp slt i32 [[IV_NEXT_US_US]], [[N:%.*]] 55; CHECK-NEXT: br i1 [[LOOP_COND_US_US]], label [[LOOP_US_US]], label [[EXIT_SPLIT_US_SPLIT_US:%.*]] 56; CHECK: deopt1: 57; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] 58; CHECK-NEXT: unreachable 59; CHECK: deopt: 60; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] 61; CHECK-NEXT: unreachable 62; CHECK: exit: 63; CHECK-NEXT: ret void 64; 65 66entry: 67 br label %loop 68 69loop: 70 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] 71 call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] 72 call void (i1, ...) @llvm.experimental.guard(i1 %cond2) [ "deopt"() ] 73 %iv.next = add i32 %iv, 1 74 %loop.cond = icmp slt i32 %iv.next, %N 75 br i1 %loop.cond, label %loop, label %exit 76 77exit: 78 ret void 79} 80 81define void @test_conditional_guards(i1 %cond, i32 %N) { 82; CHECK-LABEL: @test_conditional_guards( 83; CHECK-NEXT: entry: 84; CHECK-NEXT: br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] 85; CHECK: entry.split.us: 86; CHECK-NEXT: br label [[LOOP_US:%.*]] 87; CHECK: loop.us: 88; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[BACKEDGE_US:%.*]] ] 89; CHECK-NEXT: [[CONDITION_US:%.*]] = icmp eq i32 [[IV_US]], 123 90; CHECK-NEXT: br i1 [[CONDITION_US]], label [[GUARD_US:%.*]], label [[BACKEDGE_US]] 91; CHECK: guard.us: 92; CHECK-NEXT: br label [[GUARDED_US:%.*]] 93; CHECK: backedge.us: 94; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1 95; CHECK-NEXT: [[LOOP_COND_US:%.*]] = icmp slt i32 [[IV_NEXT_US]], [[N:%.*]] 96; CHECK-NEXT: br i1 [[LOOP_COND_US]], label [[LOOP_US]], label [[EXIT_SPLIT_US:%.*]] 97; CHECK: loop: 98; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] 99; CHECK-NEXT: [[CONDITION:%.*]] = icmp eq i32 [[IV]], 123 100; CHECK-NEXT: br i1 [[CONDITION]], label [[GUARD:%.*]], label [[BACKEDGE]] 101; CHECK: guard: 102; CHECK-NEXT: br label [[DEOPT:%.*]] 103; CHECK: deopt: 104; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] 105; CHECK-NEXT: unreachable 106; CHECK: backedge: 107; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 108; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N]] 109; CHECK-NEXT: br i1 [[LOOP_COND]], label %loop, label [[EXIT_SPLIT:%.*]] 110; 111 112entry: 113 br label %loop 114 115loop: 116 %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ] 117 %condition = icmp eq i32 %iv, 123 118 br i1 %condition, label %guard, label %backedge 119 120guard: 121 call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] 122 br label %backedge 123 124backedge: 125 %iv.next = add i32 %iv, 1 126 %loop.cond = icmp slt i32 %iv.next, %N 127 br i1 %loop.cond, label %loop, label %exit 128 129exit: 130 ret void 131} 132 133define void @test_nested_loop(i1 %cond, i32 %N) { 134; CHECK-LABEL: @test_nested_loop( 135; CHECK-NEXT: entry: 136; CHECK-NEXT: br i1 [[COND:%.*]], label [[ENTRY_SPLIT:%.*]], label [[OUTER_LOOP_SPLIT:%.*]] 137; CHECK: entry.split: 138; CHECK-NEXT: br label [[OUTER_LOOP:%.*]] 139; CHECK: outer_loop: 140; CHECK-NEXT: br label [[OUTER_LOOP_SPLIT_US:%.*]] 141; CHECK: outer_loop.split.us: 142; CHECK-NEXT: br label [[LOOP_US:%.*]] 143; CHECK: loop.us: 144; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[OUTER_LOOP_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[GUARDED_US:%.*]] ] 145; CHECK-NEXT: br label [[GUARDED_US]] 146; CHECK: guarded.us: 147; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1 148; CHECK-NEXT: [[LOOP_COND_US:%.*]] = icmp slt i32 [[IV_NEXT_US]], [[N:%.*]] 149; CHECK-NEXT: br i1 [[LOOP_COND_US]], label [[LOOP_US]], label [[OUTER_BACKEDGE_SPLIT_US:%.*]] 150; CHECK: outer_backedge.split.us: 151; CHECK-NEXT: br label [[OUTER_BACKEDGE:%.*]] 152; CHECK: deopt: 153; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] 154; CHECK-NEXT: unreachable 155; CHECK: outer_backedge: 156; CHECK-NEXT: br i1 false, label [[OUTER_LOOP]], label [[EXIT:%.*]] 157; 158 159entry: 160 br label %outer_loop 161 162outer_loop: 163 br label %loop 164 165loop: 166 %iv = phi i32 [ 0, %outer_loop ], [ %iv.next, %loop ] 167 call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] 168 %iv.next = add i32 %iv, 1 169 %loop.cond = icmp slt i32 %iv.next, %N 170 br i1 %loop.cond, label %loop, label %outer_backedge 171 172outer_backedge: 173 br i1 undef, label %outer_loop, label %exit 174 175exit: 176 ret void 177} 178 179define void @test_sibling_loops(i1 %cond1, i1 %cond2, i32 %N) { 180; CHECK-LABEL: @test_sibling_loops( 181; CHECK-NEXT: entry: 182; CHECK-NEXT: br i1 [[COND1:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] 183; CHECK: [[IV1_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV1_NEXT_US:%.*]], [[GUARDED_US:%.*]] ] 184; CHECK-NEXT: br label [[GUARDED_US]] 185; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] 186; CHECK-NEXT: unreachable 187; CHECK: [[IV2_US:%.*]] = phi i32 [ 0, [[BETWEEN:%.*]] ], [ [[IV1_NEXT_US2:%.*]], [[GUARDED_US2:%.*]] ] 188; CHECK-NEXT: br label [[GUARDED_US2]] 189; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] 190; CHECK-NEXT: unreachable 191; 192 193entry: 194 br label %loop1 195 196loop1: 197 %iv1 = phi i32 [ 0, %entry ], [ %iv1.next, %loop1 ] 198 call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] 199 %iv1.next = add i32 %iv1, 1 200 %loop1.cond = icmp slt i32 %iv1.next, %N 201 br i1 %loop1.cond, label %loop1, label %between 202 203between: 204 br label %loop2 205 206loop2: 207 %iv2 = phi i32 [ 0, %between ], [ %iv2.next, %loop2 ] 208 call void (i1, ...) @llvm.experimental.guard(i1 %cond2) [ "deopt"() ] 209 %iv2.next = add i32 %iv2, 1 210 %loop2.cond = icmp slt i32 %iv2.next, %N 211 br i1 %loop2.cond, label %loop2, label %exit 212 213exit: 214 ret void 215} 216 217; Check that we don't do anything because of cleanuppad. 218; CHECK-LABEL: @test_cleanuppad( 219; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] 220; CHECK-NOT: call void (i1, ...) @llvm.experimental.guard( 221define void @test_cleanuppad(i1 %cond, i32 %N) personality i32 (...)* @__CxxFrameHandler3 { 222 223entry: 224 br label %loop 225 226loop: 227 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] 228 call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] 229 %iv.next = add i32 %iv, 1 230 invoke void @may_throw(i32 %iv) to label %loop unwind label %exit 231 232exit: 233 %cp = cleanuppad within none [] 234 cleanupret from %cp unwind to caller 235 236} 237 238declare void @may_throw(i32 %i) 239declare i32 @__CxxFrameHandler3(...) 240