; 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}