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