forked from OSchip/llvm-project
821 lines
24 KiB
LLVM
821 lines
24 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -guard-widening-widen-frequent-branches=true -guard-widening-frequent-branch-threshold=1000 -S -guard-widening < %s | FileCheck %s
|
|
; RUN: opt -guard-widening-widen-frequent-branches=true -guard-widening-frequent-branch-threshold=1000 -S -passes='require<branch-prob>,guard-widening' < %s | FileCheck %s
|
|
|
|
declare void @llvm.experimental.guard(i1,...)
|
|
declare void @foo()
|
|
declare void @bar()
|
|
|
|
; Check that we don't widen without branch probability.
|
|
define void @test_01(i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @test_01(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br i1 %cond_1, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
if.false:
|
|
call void @bar()
|
|
br label %merge
|
|
|
|
merge:
|
|
ret void
|
|
}
|
|
|
|
; Check that we don't widen with branch probability below threshold.
|
|
define void @test_02(i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @test_02(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !0
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br i1 %cond_1, label %if.true, label %if.false, !prof !0
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
if.false:
|
|
call void @bar()
|
|
br label %merge
|
|
|
|
merge:
|
|
ret void
|
|
}
|
|
|
|
; Check that we widen conditions of explicit branches into dominating guards
|
|
; when the probability is high enough.
|
|
define void @test_03(i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @test_03(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 true, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !1
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br i1 %cond_1, label %if.true, label %if.false, !prof !1
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
if.false:
|
|
call void @bar()
|
|
br label %merge
|
|
|
|
merge:
|
|
ret void
|
|
}
|
|
|
|
; Similar to test_03, but the likely taken branch is the false branch.
|
|
define void @test_03_not_taken(i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @test_03_not_taken(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND_1:%.*]], true
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[INVERTED]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 false, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !2
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br i1 %cond_1, label %if.true, label %if.false, !prof !3
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
if.false:
|
|
call void @bar()
|
|
br label %merge
|
|
|
|
merge:
|
|
ret void
|
|
}
|
|
|
|
; Widen loop-invariant condition into the guard in preheader.
|
|
define void @test_04(i1 %cond_0, i1 %cond_1, i32 %n) {
|
|
; CHECK-LABEL: @test_04(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[MERGE:%.*]] ]
|
|
; CHECK-NEXT: br i1 true, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !1
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %merge ]
|
|
br i1 %cond_1, label %if.true, label %if.false, !prof !1
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
if.false:
|
|
call void @bar()
|
|
br label %merge
|
|
|
|
merge:
|
|
%iv.next = add i32 %iv, 1
|
|
%cond = icmp slt i32 %iv.next, %n
|
|
br i1 %cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Similar to test_04, but the likely taken branch is the false branch.
|
|
define void @test_04_not_taken(i1 %cond_0, i1 %cond_1, i32 %n) {
|
|
; CHECK-LABEL: @test_04_not_taken(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND_1:%.*]], true
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[INVERTED]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[MERGE:%.*]] ]
|
|
; CHECK-NEXT: br i1 false, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !2
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %merge ]
|
|
br i1 %cond_1, label %if.true, label %if.false, !prof !3
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
if.false:
|
|
call void @bar()
|
|
br label %merge
|
|
|
|
merge:
|
|
%iv.next = add i32 %iv, 1
|
|
%cond = icmp slt i32 %iv.next, %n
|
|
br i1 %cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Widen loop-invariant condition into the guard in the same loop.
|
|
define void @test_05(i1 %cond_0, i1 %cond_1, i32 %n) {
|
|
; CHECK-LABEL: @test_05(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[MERGE:%.*]] ]
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 true, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !1
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %merge ]
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br i1 %cond_1, label %if.true, label %if.false, !prof !1
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
if.false:
|
|
call void @bar()
|
|
br label %merge
|
|
|
|
merge:
|
|
%iv.next = add i32 %iv, 1
|
|
%cond = icmp slt i32 %iv.next, %n
|
|
br i1 %cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Similar to test_05, but the likely taken branch is the false branch.
|
|
define void @test_05_not_taken(i1 %cond_0, i1 %cond_1, i32 %n) {
|
|
; CHECK-LABEL: @test_05_not_taken(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[MERGE:%.*]] ]
|
|
; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND_1:%.*]], true
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[INVERTED]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 false, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !2
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %merge ]
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br i1 %cond_1, label %if.true, label %if.false, !prof !3
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
if.false:
|
|
call void @bar()
|
|
br label %merge
|
|
|
|
merge:
|
|
%iv.next = add i32 %iv, 1
|
|
%cond = icmp slt i32 %iv.next, %n
|
|
br i1 %cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Some of checks are frequently taken and some are not, make sure that we only
|
|
; widen frequent ones.
|
|
define void @test_06(i1 %cond_0, i1 %cond_1, i1 %cond_2, i1 %cond_3, i1 %cond_4, i32 %n) {
|
|
; CHECK-LABEL: @test_06(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_2:%.*]]
|
|
; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_4:%.*]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[IF_TRUE_1:%.*]], label [[IF_FALSE_1:%.*]], !prof !3
|
|
; CHECK: if.true_1:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE_1:%.*]]
|
|
; CHECK: if.false_1:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[MERGE_1]]
|
|
; CHECK: merge_1:
|
|
; CHECK-NEXT: br i1 true, label [[IF_TRUE_2:%.*]], label [[IF_FALSE_2:%.*]], !prof !1
|
|
; CHECK: if.true_2:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE_2:%.*]]
|
|
; CHECK: if.false_2:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[MERGE_2]]
|
|
; CHECK: merge_2:
|
|
; CHECK-NEXT: br i1 [[COND_3:%.*]], label [[IF_TRUE_3:%.*]], label [[IF_FALSE_3:%.*]], !prof !3
|
|
; CHECK: if.true_3:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE_3:%.*]]
|
|
; CHECK: if.false_3:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[MERGE_3]]
|
|
; CHECK: merge_3:
|
|
; CHECK-NEXT: br i1 true, label [[IF_TRUE_4:%.*]], label [[IF_FALSE_4:%.*]], !prof !1
|
|
; CHECK: if.true_4:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: if.false_4:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
br i1 %cond_1, label %if.true_1, label %if.false_1, !prof !2
|
|
|
|
if.true_1:
|
|
call void @foo()
|
|
br label %merge_1
|
|
|
|
if.false_1:
|
|
call void @bar()
|
|
br label %merge_1
|
|
|
|
merge_1:
|
|
br i1 %cond_2, label %if.true_2, label %if.false_2, !prof !1
|
|
|
|
if.true_2:
|
|
call void @foo()
|
|
br label %merge_2
|
|
|
|
if.false_2:
|
|
call void @bar()
|
|
br label %merge_2
|
|
|
|
merge_2:
|
|
br i1 %cond_3, label %if.true_3, label %if.false_3, !prof !2
|
|
|
|
if.true_3:
|
|
call void @foo()
|
|
br label %merge_3
|
|
|
|
if.false_3:
|
|
call void @bar()
|
|
br label %merge_3
|
|
|
|
merge_3:
|
|
br i1 %cond_4, label %if.true_4, label %if.false_4, !prof !1
|
|
|
|
if.true_4:
|
|
call void @foo()
|
|
br label %backedge
|
|
|
|
if.false_4:
|
|
call void @bar()
|
|
br label %backedge
|
|
|
|
backedge:
|
|
%iv.next = add i32 %iv, 1
|
|
%cond = icmp slt i32 %iv.next, %n
|
|
br i1 %cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Similar to test_06, but the likely taken branch is the false branch.
|
|
define void @test_06_not_taken(i1 %cond_0, i1 %cond_1, i1 %cond_2, i1 %cond_3, i1 %cond_4, i32 %n) {
|
|
; CHECK-LABEL: @test_06_not_taken(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND_2:%.*]], true
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[INVERTED]]
|
|
; CHECK-NEXT: [[INVERTED1:%.*]] = xor i1 [[COND_4:%.*]], true
|
|
; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[WIDE_CHK]], [[INVERTED1]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[IF_TRUE_1:%.*]], label [[IF_FALSE_1:%.*]], !prof !3
|
|
; CHECK: if.true_1:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE_1:%.*]]
|
|
; CHECK: if.false_1:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[MERGE_1]]
|
|
; CHECK: merge_1:
|
|
; CHECK-NEXT: br i1 false, label [[IF_TRUE_2:%.*]], label [[IF_FALSE_2:%.*]], !prof !2
|
|
; CHECK: if.true_2:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE_2:%.*]]
|
|
; CHECK: if.false_2:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[MERGE_2]]
|
|
; CHECK: merge_2:
|
|
; CHECK-NEXT: br i1 [[COND_3:%.*]], label [[IF_TRUE_3:%.*]], label [[IF_FALSE_3:%.*]], !prof !3
|
|
; CHECK: if.true_3:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE_3:%.*]]
|
|
; CHECK: if.false_3:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[MERGE_3]]
|
|
; CHECK: merge_3:
|
|
; CHECK-NEXT: br i1 false, label [[IF_TRUE_4:%.*]], label [[IF_FALSE_4:%.*]], !prof !2
|
|
; CHECK: if.true_4:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: if.false_4:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
br i1 %cond_1, label %if.true_1, label %if.false_1, !prof !2
|
|
|
|
if.true_1:
|
|
call void @foo()
|
|
br label %merge_1
|
|
|
|
if.false_1:
|
|
call void @bar()
|
|
br label %merge_1
|
|
|
|
merge_1:
|
|
br i1 %cond_2, label %if.true_2, label %if.false_2, !prof !3
|
|
|
|
if.true_2:
|
|
call void @foo()
|
|
br label %merge_2
|
|
|
|
if.false_2:
|
|
call void @bar()
|
|
br label %merge_2
|
|
|
|
merge_2:
|
|
br i1 %cond_3, label %if.true_3, label %if.false_3, !prof !2
|
|
|
|
if.true_3:
|
|
call void @foo()
|
|
br label %merge_3
|
|
|
|
if.false_3:
|
|
call void @bar()
|
|
br label %merge_3
|
|
|
|
merge_3:
|
|
br i1 %cond_4, label %if.true_4, label %if.false_4, !prof !3
|
|
|
|
if.true_4:
|
|
call void @foo()
|
|
br label %backedge
|
|
|
|
if.false_4:
|
|
call void @bar()
|
|
br label %backedge
|
|
|
|
backedge:
|
|
%iv.next = add i32 %iv, 1
|
|
%cond = icmp slt i32 %iv.next, %n
|
|
br i1 %cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Check triangle CFG pattern.
|
|
define void @test_07(i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @test_07(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 true, label [[IF_TRUE:%.*]], label [[MERGE:%.*]], !prof !1
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br i1 %cond_1, label %if.true, label %merge, !prof !1
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
merge:
|
|
ret void
|
|
}
|
|
|
|
; Similar to test_07, but the likely taken branch is the false branch.
|
|
define void @test_07_not_taken(i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @test_07_not_taken(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND_1:%.*]], true
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[INVERTED]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 false, label [[IF_TRUE:%.*]], label [[MERGE:%.*]], !prof !2
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br i1 %cond_1, label %if.true, label %merge, !prof !3
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
merge:
|
|
ret void
|
|
}
|
|
|
|
define void @test_08(i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @test_08(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 true, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !1
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br i1 %cond_1, label %if.true, label %if.false, !prof !1
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
if.false:
|
|
ret void
|
|
|
|
merge:
|
|
ret void
|
|
}
|
|
|
|
define void @test_08_not_taken(i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @test_08_not_taken(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND_1:%.*]], true
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[INVERTED]]
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 false, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !2
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br i1 %cond_1, label %if.true, label %if.false, !prof !3
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
if.false:
|
|
ret void
|
|
|
|
merge:
|
|
ret void
|
|
}
|
|
|
|
; Check that L >u C0 && L >u C1 -> L >u max(C0, C1).
|
|
define void @test_09(i32 %L) {
|
|
; CHECK-LABEL: @test_09(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COND_0:%.*]] = icmp ugt i32 [[L:%.*]], 123
|
|
; CHECK-NEXT: [[COND_1:%.*]] = icmp ugt i32 [[L]], 456
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = icmp uge i32 [[L]], 457
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 true, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !1
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cond_0 = icmp ugt i32 %L, 123
|
|
%cond_1 = icmp ugt i32 %L, 456
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br i1 %cond_1, label %if.true, label %if.false, !prof !1
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
if.false:
|
|
ret void
|
|
|
|
merge:
|
|
ret void
|
|
}
|
|
|
|
; Check that L >u C0 && !(L <=u C1) -> L >u max(C0, C1).
|
|
define void @test_09_not_taken(i32 %L) {
|
|
; CHECK-LABEL: @test_09_not_taken(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COND_0:%.*]] = icmp ugt i32 [[L:%.*]], 123
|
|
; CHECK-NEXT: [[COND_1:%.*]] = icmp ule i32 [[L]], 456
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = icmp uge i32 [[L]], 457
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 false, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !2
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cond_0 = icmp ugt i32 %L, 123
|
|
%cond_1 = icmp ule i32 %L, 456
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br i1 %cond_1, label %if.true, label %if.false, !prof !3
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
if.false:
|
|
ret void
|
|
|
|
merge:
|
|
ret void
|
|
}
|
|
|
|
; Check that a profitable transform is preferred over non-profitable.
|
|
define void @test_10(i32 %L, i1 %irrelevant_cond, i1 %infinite_loop_cond) {
|
|
; CHECK-LABEL: @test_10(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COND_0:%.*]] = icmp ugt i32 [[L:%.*]], 123
|
|
; CHECK-NEXT: [[COND_1:%.*]] = icmp ugt i32 [[L]], 456
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[IRRELEVANT_COND:%.*]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 [[INFINITE_LOOP_COND:%.*]], label [[LOOP]], label [[AFTER_LOOP:%.*]]
|
|
; CHECK: after_loop:
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = icmp uge i32 [[L]], 457
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 true, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !1
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cond_0 = icmp ugt i32 %L, 123
|
|
%cond_1 = icmp ugt i32 %L, 456
|
|
br label %loop
|
|
|
|
loop:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %irrelevant_cond) [ "deopt"() ]
|
|
br i1 %infinite_loop_cond, label %loop, label %after_loop
|
|
|
|
after_loop:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br i1 %cond_1, label %if.true, label %if.false, !prof !1
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
ret void
|
|
}
|
|
|
|
; Check that a profitable transform is preferred over non-profitable.
|
|
|
|
define void @test_10_not_taken(i32 %L, i1 %irrelevant_cond, i1 %infinite_loop_cond) {
|
|
; CHECK-LABEL: @test_10_not_taken(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COND_0:%.*]] = icmp ugt i32 [[L:%.*]], 123
|
|
; CHECK-NEXT: [[COND_1:%.*]] = icmp ule i32 [[L]], 456
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[IRRELEVANT_COND:%.*]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 [[INFINITE_LOOP_COND:%.*]], label [[LOOP]], label [[AFTER_LOOP:%.*]]
|
|
; CHECK: after_loop:
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = icmp uge i32 [[L]], 457
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br i1 false, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !2
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cond_0 = icmp ugt i32 %L, 123
|
|
%cond_1 = icmp ule i32 %L, 456
|
|
br label %loop
|
|
|
|
loop:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %irrelevant_cond) [ "deopt"() ]
|
|
br i1 %infinite_loop_cond, label %loop, label %after_loop
|
|
|
|
after_loop:
|
|
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
|
br i1 %cond_1, label %if.true, label %if.false, !prof !3
|
|
|
|
if.true:
|
|
call void @foo()
|
|
br label %merge
|
|
|
|
if.false:
|
|
br label %merge
|
|
|
|
merge:
|
|
ret void
|
|
}
|
|
|
|
!0 = !{!"branch_weights", i32 998, i32 1}
|
|
!1 = !{!"branch_weights", i32 999, i32 1}
|
|
!2 = !{!"branch_weights", i32 500, i32 500}
|
|
!3 = !{!"branch_weights", i32 1, i32 999}
|