1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 2; RUN: opt -S -passes=guard-widening < %s | FileCheck %s 3 4; Function Attrs: nocallback nofree nosync willreturn 5declare void @llvm.experimental.guard(i1, ...) #0 6 7; Hot loop, frequently entered, should widen. 8define i32 @test_intrinsic_very_profitable(i32 %n, i1 %cond.1, i1 %cond.2) { 9; CHECK-LABEL: define i32 @test_intrinsic_very_profitable 10; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) { 11; CHECK-NEXT: entry: 12; CHECK-NEXT: [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]] 13; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]] 14; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 15; CHECK-NEXT: [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100 16; CHECK-NEXT: br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF0:![0-9]+]] 17; CHECK: loop: 18; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] 19; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 20; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100 21; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1:![0-9]+]] 22; CHECK: exit: 23; CHECK-NEXT: ret i32 0 24; CHECK: failed: 25; CHECK-NEXT: ret i32 -1 26; 27entry: 28 call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ] 29 %loop.precondition = icmp uge i32 %n, 100 30 br i1 %loop.precondition, label %loop, label %failed, !prof !0 31 32loop: ; preds = %loop, %entry 33 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] 34 call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ] 35 %iv.next = add nuw nsw i32 %iv, 1 36 %loop.cond = icmp ult i32 %iv.next, 100 37 br i1 %loop.cond, label %loop, label %exit, !prof !1 38 39exit: ; preds = %loop 40 ret i32 0 41 42failed: ; preds = %entry 43 ret i32 -1 44} 45 46; Even though the loop is rarely entered, it has so many iterations that the widening 47; is still profitable. 48define i32 @test_intrinsic_profitable(i32 %n, i1 %cond.1, i1 %cond.2) { 49; CHECK-LABEL: define i32 @test_intrinsic_profitable 50; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) { 51; CHECK-NEXT: entry: 52; CHECK-NEXT: [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]] 53; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]] 54; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 55; CHECK-NEXT: [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100 56; CHECK-NEXT: br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF2:![0-9]+]] 57; CHECK: loop: 58; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] 59; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 60; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100 61; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1]] 62; CHECK: exit: 63; CHECK-NEXT: ret i32 0 64; CHECK: failed: 65; CHECK-NEXT: ret i32 -1 66; 67entry: 68 call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ] 69 %loop.precondition = icmp uge i32 %n, 100 70 br i1 %loop.precondition, label %loop, label %failed, !prof !2 71 72loop: ; preds = %loop, %entry 73 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] 74 call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ] 75 %iv.next = add nuw nsw i32 %iv, 1 76 %loop.cond = icmp ult i32 %iv.next, 100 77 br i1 %loop.cond, label %loop, label %exit, !prof !1 78 79exit: ; preds = %loop 80 ret i32 0 81 82failed: ; preds = %entry 83 ret i32 -1 84} 85 86; Loop's hotness compensates rareness of its entrance. We still want to widen, because 87; it may open up some optimization opportunities. 88define i32 @test_intrinsic_neutral(i32 %n, i1 %cond.1, i1 %cond.2) { 89; CHECK-LABEL: define i32 @test_intrinsic_neutral 90; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) { 91; CHECK-NEXT: entry: 92; CHECK-NEXT: [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]] 93; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]] 94; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 95; CHECK-NEXT: [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100 96; CHECK-NEXT: br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF3:![0-9]+]] 97; CHECK: loop: 98; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] 99; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 100; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100 101; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1]] 102; CHECK: exit: 103; CHECK-NEXT: ret i32 0 104; CHECK: failed: 105; CHECK-NEXT: ret i32 -1 106; 107entry: 108 call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ] 109 %loop.precondition = icmp uge i32 %n, 100 110 br i1 %loop.precondition, label %loop, label %failed, !prof !3 111 112loop: ; preds = %loop, %entry 113 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] 114 call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ] 115 %iv.next = add nuw nsw i32 %iv, 1 116 %loop.cond = icmp ult i32 %iv.next, 100 117 br i1 %loop.cond, label %loop, label %exit, !prof !1 118 119exit: ; preds = %loop 120 ret i32 0 121 122failed: ; preds = %entry 123 ret i32 -1 124} 125 126; FIXME: This loop is so rarely entered, that we don't want to widen here. 127define i32 @test_intrinsic_very_unprofitable(i32 %n, i1 %cond.1, i1 %cond.2) { 128; CHECK-LABEL: define i32 @test_intrinsic_very_unprofitable 129; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) { 130; CHECK-NEXT: entry: 131; CHECK-NEXT: [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]] 132; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]] 133; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 134; CHECK-NEXT: [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100 135; CHECK-NEXT: br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF4:![0-9]+]] 136; CHECK: loop: 137; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] 138; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 139; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100 140; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1]] 141; CHECK: exit: 142; CHECK-NEXT: ret i32 0 143; CHECK: failed: 144; CHECK-NEXT: ret i32 -1 145; 146entry: 147 call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ] 148 %loop.precondition = icmp uge i32 %n, 100 149 br i1 %loop.precondition, label %loop, label %failed, !prof !4 150 151loop: ; preds = %loop, %entry 152 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] 153 call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ] 154 %iv.next = add nuw nsw i32 %iv, 1 155 %loop.cond = icmp ult i32 %iv.next, 100 156 br i1 %loop.cond, label %loop, label %exit, !prof !1 157 158exit: ; preds = %loop 159 ret i32 0 160 161failed: ; preds = %entry 162 ret i32 -1 163} 164 165; FIXME: This loop is so rarely entered, that we don't want to widen here. 166define i32 @test_intrinsic_unprofitable(i32 %n, i1 %cond.1, i1 %cond.2) { 167; CHECK-LABEL: define i32 @test_intrinsic_unprofitable 168; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) { 169; CHECK-NEXT: entry: 170; CHECK-NEXT: [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]] 171; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]] 172; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 173; CHECK-NEXT: [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100 174; CHECK-NEXT: br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF5:![0-9]+]] 175; CHECK: loop: 176; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] 177; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 178; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100 179; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1]] 180; CHECK: exit: 181; CHECK-NEXT: ret i32 0 182; CHECK: failed: 183; CHECK-NEXT: ret i32 -1 184; 185entry: 186 call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ] 187 %loop.precondition = icmp uge i32 %n, 100 188 br i1 %loop.precondition, label %loop, label %failed, !prof !5 189 190loop: ; preds = %loop, %entry 191 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] 192 call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ] 193 %iv.next = add nuw nsw i32 %iv, 1 194 %loop.cond = icmp ult i32 %iv.next, 100 195 br i1 %loop.cond, label %loop, label %exit, !prof !1 196 197exit: ; preds = %loop 198 ret i32 0 199 200failed: ; preds = %entry 201 ret i32 -1 202} 203 204attributes #0 = { nocallback nofree nosync willreturn } 205 206!0 = !{!"branch_weights", i32 1048576, i32 1} 207!1 = !{!"branch_weights", i32 99, i32 1} 208!2 = !{!"branch_weights", i32 1, i32 10} 209!3 = !{!"branch_weights", i32 1, i32 99} 210!4 = !{!"branch_weights", i32 1, i32 1048576} 211!5 = !{!"branch_weights", i32 1, i32 1000} 212