| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 |
| ; RUN: opt -S -passes=guard-widening < %s | FileCheck %s |
| |
| ; Function Attrs: nocallback nofree nosync willreturn |
| declare void @llvm.experimental.guard(i1, ...) #0 |
| |
| ; Hot loop, frequently entered, should widen. |
| define i32 @test_intrinsic_very_profitable(i32 %n, i1 %cond.1, i1 %cond.2) { |
| ; CHECK-LABEL: define i32 @test_intrinsic_very_profitable |
| ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]] |
| ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]] |
| ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] |
| ; CHECK-NEXT: [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100 |
| ; CHECK-NEXT: br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF0:![0-9]+]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1:![0-9]+]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i32 0 |
| ; CHECK: failed: |
| ; CHECK-NEXT: ret i32 -1 |
| ; |
| entry: |
| call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ] |
| %loop.precondition = icmp uge i32 %n, 100 |
| br i1 %loop.precondition, label %loop, label %failed, !prof !0 |
| |
| loop: ; preds = %loop, %entry |
| %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] |
| call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ] |
| %iv.next = add nuw nsw i32 %iv, 1 |
| %loop.cond = icmp ult i32 %iv.next, 100 |
| br i1 %loop.cond, label %loop, label %exit, !prof !1 |
| |
| exit: ; preds = %loop |
| ret i32 0 |
| |
| failed: ; preds = %entry |
| ret i32 -1 |
| } |
| |
| ; Even though the loop is rarely entered, it has so many iterations that the widening |
| ; is still profitable. |
| define i32 @test_intrinsic_profitable(i32 %n, i1 %cond.1, i1 %cond.2) { |
| ; CHECK-LABEL: define i32 @test_intrinsic_profitable |
| ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]] |
| ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]] |
| ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] |
| ; CHECK-NEXT: [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100 |
| ; CHECK-NEXT: br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF2:![0-9]+]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i32 0 |
| ; CHECK: failed: |
| ; CHECK-NEXT: ret i32 -1 |
| ; |
| entry: |
| call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ] |
| %loop.precondition = icmp uge i32 %n, 100 |
| br i1 %loop.precondition, label %loop, label %failed, !prof !2 |
| |
| loop: ; preds = %loop, %entry |
| %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] |
| call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ] |
| %iv.next = add nuw nsw i32 %iv, 1 |
| %loop.cond = icmp ult i32 %iv.next, 100 |
| br i1 %loop.cond, label %loop, label %exit, !prof !1 |
| |
| exit: ; preds = %loop |
| ret i32 0 |
| |
| failed: ; preds = %entry |
| ret i32 -1 |
| } |
| |
| ; Loop's hotness compensates rareness of its entrance. We still want to widen, because |
| ; it may open up some optimization opportunities. |
| define i32 @test_intrinsic_neutral(i32 %n, i1 %cond.1, i1 %cond.2) { |
| ; CHECK-LABEL: define i32 @test_intrinsic_neutral |
| ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]] |
| ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]] |
| ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] |
| ; CHECK-NEXT: [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100 |
| ; CHECK-NEXT: br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF3:![0-9]+]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i32 0 |
| ; CHECK: failed: |
| ; CHECK-NEXT: ret i32 -1 |
| ; |
| entry: |
| call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ] |
| %loop.precondition = icmp uge i32 %n, 100 |
| br i1 %loop.precondition, label %loop, label %failed, !prof !3 |
| |
| loop: ; preds = %loop, %entry |
| %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] |
| call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ] |
| %iv.next = add nuw nsw i32 %iv, 1 |
| %loop.cond = icmp ult i32 %iv.next, 100 |
| br i1 %loop.cond, label %loop, label %exit, !prof !1 |
| |
| exit: ; preds = %loop |
| ret i32 0 |
| |
| failed: ; preds = %entry |
| ret i32 -1 |
| } |
| |
| ; FIXME: This loop is so rarely entered, that we don't want to widen here. |
| define i32 @test_intrinsic_very_unprofitable(i32 %n, i1 %cond.1, i1 %cond.2) { |
| ; CHECK-LABEL: define i32 @test_intrinsic_very_unprofitable |
| ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]] |
| ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]] |
| ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] |
| ; CHECK-NEXT: [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100 |
| ; CHECK-NEXT: br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF4:![0-9]+]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i32 0 |
| ; CHECK: failed: |
| ; CHECK-NEXT: ret i32 -1 |
| ; |
| entry: |
| call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ] |
| %loop.precondition = icmp uge i32 %n, 100 |
| br i1 %loop.precondition, label %loop, label %failed, !prof !4 |
| |
| loop: ; preds = %loop, %entry |
| %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] |
| call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ] |
| %iv.next = add nuw nsw i32 %iv, 1 |
| %loop.cond = icmp ult i32 %iv.next, 100 |
| br i1 %loop.cond, label %loop, label %exit, !prof !1 |
| |
| exit: ; preds = %loop |
| ret i32 0 |
| |
| failed: ; preds = %entry |
| ret i32 -1 |
| } |
| |
| ; FIXME: This loop is so rarely entered, that we don't want to widen here. |
| define i32 @test_intrinsic_unprofitable(i32 %n, i1 %cond.1, i1 %cond.2) { |
| ; CHECK-LABEL: define i32 @test_intrinsic_unprofitable |
| ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]] |
| ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]] |
| ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] |
| ; CHECK-NEXT: [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100 |
| ; CHECK-NEXT: br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF5:![0-9]+]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 |
| ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100 |
| ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i32 0 |
| ; CHECK: failed: |
| ; CHECK-NEXT: ret i32 -1 |
| ; |
| entry: |
| call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ] |
| %loop.precondition = icmp uge i32 %n, 100 |
| br i1 %loop.precondition, label %loop, label %failed, !prof !5 |
| |
| loop: ; preds = %loop, %entry |
| %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] |
| call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ] |
| %iv.next = add nuw nsw i32 %iv, 1 |
| %loop.cond = icmp ult i32 %iv.next, 100 |
| br i1 %loop.cond, label %loop, label %exit, !prof !1 |
| |
| exit: ; preds = %loop |
| ret i32 0 |
| |
| failed: ; preds = %entry |
| ret i32 -1 |
| } |
| |
| attributes #0 = { nocallback nofree nosync willreturn } |
| |
| !0 = !{!"branch_weights", i32 1048576, i32 1} |
| !1 = !{!"branch_weights", i32 99, i32 1} |
| !2 = !{!"branch_weights", i32 1, i32 10} |
| !3 = !{!"branch_weights", i32 1, i32 99} |
| !4 = !{!"branch_weights", i32 1, i32 1048576} |
| !5 = !{!"branch_weights", i32 1, i32 1000} |