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