Jump threading can replace select and unconditional branch with conditional branch, but when doing so loses profile information. This destructive transform can eventually lead to a performance degradation due to folding of branches in shouldFoldCondBranchesToCommonDestination as branch probabilities are no longer known. The first version was reverted due to assert caused by i32 overflow, fixed in this version. Patch by Roman Paukner! Differential Revision: https://reviews.llvm.org/D138132 Reviewed By: mkazantsev
676 lines
24 KiB
LLVM
676 lines
24 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
|
|
; RUN: opt -S -passes=jump-threading -debug-only=branch-prob < %s 2>&1 | FileCheck %s
|
|
; REQUIRES: asserts
|
|
|
|
; CHECK-LABEL: ---- Branch Probability Info : unfold1 ----
|
|
; CHECK: set edge cond.false -> 0 successor probability to 0x20000000 / 0x80000000 = 25.00%
|
|
; CHECK: set edge cond.false -> 1 successor probability to 0x60000000 / 0x80000000 = 75.00%
|
|
; CHECK-LABEL: ---- Branch Probability Info : unfold2 ----
|
|
; CHECK: set edge cond.false -> 0 successor probability to 0x20000000 / 0x80000000 = 25.00%
|
|
; CHECK: set edge cond.false -> 1 successor probability to 0x60000000 / 0x80000000 = 75.00%
|
|
|
|
declare void @foo()
|
|
declare void @bar()
|
|
declare void @baz()
|
|
declare void @quux()
|
|
|
|
|
|
; Jump threading of branch with select as condition.
|
|
; Mostly theoretical since instruction combining simplifies all selects of
|
|
; booleans where at least one operand is true/false/undef.
|
|
|
|
;.
|
|
; CHECK: @[[ANCHOR:[a-zA-Z0-9_$"\\.-]+]] = constant [3 x ptr] [ptr blockaddress(@test_indirectbr, [[L1:%.*]]), ptr inttoptr (i32 1 to ptr), ptr blockaddress(@test_indirectbr, [[L3:%.*]])]
|
|
;.
|
|
define void @test_br(i1 %cond, i1 %value) nounwind {
|
|
; CHECK-LABEL: @test_br(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[L1:%.*]], label [[L0:%.*]]
|
|
; CHECK: L0:
|
|
; CHECK-NEXT: call void @baz()
|
|
; CHECK-NEXT: [[EXPR:%.*]] = select i1 [[COND]], i1 true, i1 [[VALUE:%.*]]
|
|
; CHECK-NEXT: br i1 [[EXPR]], label [[L1]], label [[L2:%.*]]
|
|
; CHECK: L1:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: L2:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br i1 %cond, label %L0, label %L3
|
|
L0:
|
|
%expr = select i1 %cond, i1 true, i1 %value
|
|
br i1 %expr, label %L1, label %L2
|
|
|
|
L1:
|
|
call void @foo()
|
|
ret void
|
|
L2:
|
|
call void @bar()
|
|
ret void
|
|
L3:
|
|
call void @baz()
|
|
br label %L0
|
|
}
|
|
|
|
|
|
; Jump threading of switch with select as condition.
|
|
|
|
define void @test_switch(i1 %cond, i8 %value) nounwind {
|
|
; CHECK-LABEL: @test_switch(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[L1:%.*]], label [[L0:%.*]]
|
|
; CHECK: L0:
|
|
; CHECK-NEXT: call void @quux()
|
|
; CHECK-NEXT: [[EXPR:%.*]] = select i1 [[COND]], i8 1, i8 [[VALUE:%.*]]
|
|
; CHECK-NEXT: switch i8 [[EXPR]], label [[L3:%.*]] [
|
|
; CHECK-NEXT: i8 1, label [[L1]]
|
|
; CHECK-NEXT: i8 2, label [[L2:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: L1:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: L2:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: L3:
|
|
; CHECK-NEXT: call void @baz()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br i1 %cond, label %L0, label %L4
|
|
L0:
|
|
%expr = select i1 %cond, i8 1, i8 %value
|
|
switch i8 %expr, label %L3 [i8 1, label %L1 i8 2, label %L2]
|
|
|
|
L1:
|
|
call void @foo()
|
|
ret void
|
|
L2:
|
|
call void @bar()
|
|
ret void
|
|
L3:
|
|
call void @baz()
|
|
ret void
|
|
L4:
|
|
call void @quux()
|
|
br label %L0
|
|
}
|
|
|
|
; Make sure the blocks in the indirectbr test aren't trivially removable as
|
|
; successors by taking their addresses.
|
|
@anchor = constant [3 x ptr] [
|
|
ptr blockaddress(@test_indirectbr, %L1),
|
|
ptr blockaddress(@test_indirectbr, %L2),
|
|
ptr blockaddress(@test_indirectbr, %L3)
|
|
]
|
|
|
|
|
|
; Jump threading of indirectbr with select as address.
|
|
|
|
define void @test_indirectbr(i1 %cond, ptr %address) nounwind {
|
|
; CHECK-LABEL: @test_indirectbr(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[L1:%.*]], label [[L3:%.*]]
|
|
; CHECK: L1:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: L3:
|
|
; CHECK-NEXT: call void @baz()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br i1 %cond, label %L0, label %L3
|
|
L0:
|
|
%indirect.goto.dest = select i1 %cond, ptr blockaddress(@test_indirectbr, %L1), ptr %address
|
|
indirectbr ptr %indirect.goto.dest, [label %L1, label %L2, label %L3]
|
|
|
|
L1:
|
|
call void @foo()
|
|
ret void
|
|
L2:
|
|
call void @bar()
|
|
ret void
|
|
L3:
|
|
call void @baz()
|
|
ret void
|
|
}
|
|
|
|
|
|
; Jump threading of indirectbr with select as address. Test increased
|
|
; duplication threshold for cases where indirectbr is being threaded
|
|
; through.
|
|
|
|
define void @test_indirectbr_thresh(i1 %cond, ptr %address) nounwind {
|
|
; CHECK-LABEL: @test_indirectbr_thresh(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[L1:%.*]], label [[L3:%.*]]
|
|
; CHECK: L1:
|
|
; CHECK-NEXT: call void @quux()
|
|
; CHECK-NEXT: call void @quux()
|
|
; CHECK-NEXT: call void @quux()
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: L3:
|
|
; CHECK-NEXT: call void @baz()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br i1 %cond, label %L0, label %L3
|
|
L0:
|
|
%indirect.goto.dest = select i1 %cond, ptr blockaddress(@test_indirectbr_thresh, %L1), ptr %address
|
|
call void @quux()
|
|
call void @quux()
|
|
call void @quux()
|
|
indirectbr ptr %indirect.goto.dest, [label %L1, label %L2, label %L3]
|
|
|
|
L1:
|
|
call void @foo()
|
|
ret void
|
|
L2:
|
|
call void @bar()
|
|
ret void
|
|
L3:
|
|
call void @baz()
|
|
ret void
|
|
}
|
|
|
|
|
|
; A more complicated case: the condition is a select based on a comparison.
|
|
|
|
define void @test_switch_cmp(i1 %cond, i32 %val, i8 %value) nounwind {
|
|
; CHECK-LABEL: @test_switch_cmp(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[L0:%.*]], label [[L0_THREAD:%.*]]
|
|
; CHECK: L0:
|
|
; CHECK-NEXT: [[VAL_PHI:%.*]] = phi i32 [ [[VAL:%.*]], [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[VAL_PHI]], 0
|
|
; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[CMP]]
|
|
; CHECK-NEXT: br i1 [[COND_FR]], label [[L1:%.*]], label [[TMP0:%.*]]
|
|
; CHECK: 0:
|
|
; CHECK-NEXT: [[TMP1:%.*]] = phi i8 [ [[VALUE:%.*]], [[L0]] ]
|
|
; CHECK-NEXT: switch i8 [[TMP1]], label [[L3:%.*]] [
|
|
; CHECK-NEXT: i8 1, label [[L1]]
|
|
; CHECK-NEXT: i8 2, label [[L2:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: L1:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: L2:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: L3:
|
|
; CHECK-NEXT: call void @baz()
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: L0.thread:
|
|
; CHECK-NEXT: call void @quux()
|
|
; CHECK-NEXT: br label [[L1]]
|
|
;
|
|
entry:
|
|
br i1 %cond, label %L0, label %L4
|
|
L0:
|
|
%val.phi = phi i32 [%val, %entry], [-1, %L4]
|
|
%cmp = icmp slt i32 %val.phi, 0
|
|
%expr = select i1 %cmp, i8 1, i8 %value
|
|
switch i8 %expr, label %L3 [i8 1, label %L1 i8 2, label %L2]
|
|
|
|
L1:
|
|
call void @foo()
|
|
ret void
|
|
L2:
|
|
call void @bar()
|
|
ret void
|
|
L3:
|
|
call void @baz()
|
|
ret void
|
|
L4:
|
|
call void @quux()
|
|
br label %L0
|
|
}
|
|
|
|
; Make sure the edge value of %0 from entry to L2 includes 0 and L3 is
|
|
; reachable.
|
|
define void @test_switch_default(ptr nocapture %status) nounwind {
|
|
; CHECK-LABEL: @test_switch_default(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[STATUS:%.*]], align 4
|
|
; CHECK-NEXT: switch i32 [[TMP0]], label [[L2:%.*]] [
|
|
; CHECK-NEXT: i32 5061, label [[L2_THREAD:%.*]]
|
|
; CHECK-NEXT: i32 0, label [[L2]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: L2.thread:
|
|
; CHECK-NEXT: store i32 10025, ptr [[STATUS]], align 4
|
|
; CHECK-NEXT: br label [[L4:%.*]]
|
|
; CHECK: L2:
|
|
; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[TMP0]], [[ENTRY:%.*]] ], [ [[TMP0]], [[ENTRY]] ]
|
|
; CHECK-NEXT: [[CMP57_I:%.*]] = icmp eq i32 [[TMP1]], 0
|
|
; CHECK-NEXT: br i1 [[CMP57_I]], label [[L3:%.*]], label [[L4]]
|
|
; CHECK: L3:
|
|
; CHECK-NEXT: store i32 10000, ptr [[STATUS]], align 4
|
|
; CHECK-NEXT: br label [[L4]]
|
|
; CHECK: L4:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%0 = load i32, ptr %status, align 4
|
|
switch i32 %0, label %L2 [
|
|
i32 5061, label %L1
|
|
i32 0, label %L2
|
|
]
|
|
|
|
L1:
|
|
store i32 10025, ptr %status, align 4
|
|
br label %L2
|
|
|
|
L2:
|
|
%1 = load i32, ptr %status, align 4
|
|
%cmp57.i = icmp eq i32 %1, 0
|
|
br i1 %cmp57.i, label %L3, label %L4
|
|
|
|
L3:
|
|
store i32 10000, ptr %status, align 4
|
|
br label %L4
|
|
|
|
L4:
|
|
ret void
|
|
}
|
|
|
|
define void @unfold1(double %x, double %y) nounwind !prof !1 {
|
|
; CHECK-LABEL: @unfold1(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[SUB:%.*]] = fsub double [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt double [[SUB]], 1.000000e+01
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[COND_END4:%.*]], label [[COND_FALSE:%.*]]
|
|
; CHECK: cond.false:
|
|
; CHECK-NEXT: [[ADD:%.*]] = fadd double [[X]], [[Y]]
|
|
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt double [[ADD]], 1.000000e+01
|
|
; CHECK-NEXT: br i1 [[CMP1]], label [[COND_END4]], label [[IF_THEN:%.*]], !prof [[PROF1:![0-9]+]]
|
|
; CHECK: cond.end4:
|
|
; CHECK-NEXT: [[COND5:%.*]] = phi double [ [[SUB]], [[ENTRY:%.*]] ], [ [[ADD]], [[COND_FALSE]] ]
|
|
; CHECK-NEXT: [[CMP6:%.*]] = fcmp oeq double [[COND5]], 0.000000e+00
|
|
; CHECK-NEXT: br i1 [[CMP6]], label [[IF_THEN]], label [[IF_END:%.*]]
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[IF_END]]
|
|
; CHECK: if.end:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%sub = fsub double %x, %y
|
|
%cmp = fcmp ogt double %sub, 1.000000e+01
|
|
br i1 %cmp, label %cond.end4, label %cond.false
|
|
|
|
cond.false: ; preds = %entry
|
|
%add = fadd double %x, %y
|
|
%cmp1 = fcmp ogt double %add, 1.000000e+01
|
|
%add. = select i1 %cmp1, double %add, double 0.000000e+00, !prof !0
|
|
br label %cond.end4
|
|
|
|
cond.end4: ; preds = %entry, %cond.false
|
|
%cond5 = phi double [ %add., %cond.false ], [ %sub, %entry ]
|
|
%cmp6 = fcmp oeq double %cond5, 0.000000e+00
|
|
br i1 %cmp6, label %if.then, label %if.end
|
|
|
|
if.then: ; preds = %cond.end4
|
|
call void @foo()
|
|
br label %if.end
|
|
|
|
if.end: ; preds = %if.then, %cond.end4
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
define void @unfold2(i32 %x, i32 %y) nounwind !prof !1 {
|
|
; CHECK-LABEL: @unfold2(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[SUB]], 10
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[IF_END:%.*]], label [[COND_FALSE:%.*]]
|
|
; CHECK: cond.false:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[ADD]], 10
|
|
; CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN:%.*]], label [[COND_END4:%.*]], !prof [[PROF1]]
|
|
; CHECK: cond.end4:
|
|
; CHECK-NEXT: [[COND5:%.*]] = phi i32 [ [[ADD]], [[COND_FALSE]] ]
|
|
; CHECK-NEXT: [[CMP6:%.*]] = icmp eq i32 [[COND5]], 0
|
|
; CHECK-NEXT: br i1 [[CMP6]], label [[IF_THEN]], label [[IF_END]]
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[IF_END]]
|
|
; CHECK: if.end:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%sub = sub nsw i32 %x, %y
|
|
%cmp = icmp sgt i32 %sub, 10
|
|
br i1 %cmp, label %cond.end4, label %cond.false
|
|
|
|
cond.false: ; preds = %entry
|
|
%add = add nsw i32 %x, %y
|
|
%cmp1 = icmp sgt i32 %add, 10
|
|
%add. = select i1 %cmp1, i32 0, i32 %add, !prof !0
|
|
br label %cond.end4
|
|
|
|
cond.end4: ; preds = %entry, %cond.false
|
|
%cond5 = phi i32 [ %add., %cond.false ], [ %sub, %entry ]
|
|
%cmp6 = icmp eq i32 %cond5, 0
|
|
br i1 %cmp6, label %if.then, label %if.end
|
|
|
|
if.then: ; preds = %cond.end4
|
|
call void @foo()
|
|
br label %if.end
|
|
|
|
if.end: ; preds = %if.then, %cond.end4
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
define i32 @unfold3(i32 %u, i32 %v, i32 %w, i32 %x, i32 %y, i32 %z, i32 %j) nounwind {
|
|
; CHECK-LABEL: @unfold3(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ADD3:%.*]] = add nsw i32 [[J:%.*]], 2
|
|
; CHECK-NEXT: [[CMP_I:%.*]] = icmp slt i32 [[U:%.*]], [[V:%.*]]
|
|
; CHECK-NEXT: br i1 [[CMP_I]], label [[DOTEXIT_THREAD4:%.*]], label [[COND_FALSE_I:%.*]]
|
|
; CHECK: cond.false.i:
|
|
; CHECK-NEXT: [[CMP4_I:%.*]] = icmp sgt i32 [[U]], [[V]]
|
|
; CHECK-NEXT: br i1 [[CMP4_I]], label [[DOTEXIT_THREAD:%.*]], label [[COND_FALSE_6_I:%.*]]
|
|
; CHECK: cond.false.6.i:
|
|
; CHECK-NEXT: [[CMP8_I:%.*]] = icmp slt i32 [[W:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: br i1 [[CMP8_I]], label [[DOTEXIT_THREAD4]], label [[COND_FALSE_10_I:%.*]]
|
|
; CHECK: cond.false.10.i:
|
|
; CHECK-NEXT: [[CMP13_I:%.*]] = icmp sgt i32 [[W]], [[X]]
|
|
; CHECK-NEXT: br i1 [[CMP13_I]], label [[DOTEXIT_THREAD]], label [[DOTEXIT:%.*]]
|
|
; CHECK: .exit:
|
|
; CHECK-NEXT: [[PHITMP:%.*]] = icmp sge i32 [[Y:%.*]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[PHITMP]]
|
|
; CHECK-NEXT: br i1 [[COND_FR]], label [[DOTEXIT_THREAD]], label [[DOTEXIT_THREAD4]]
|
|
; CHECK: .exit.thread:
|
|
; CHECK-NEXT: br label [[DOTEXIT_THREAD4]]
|
|
; CHECK: .exit.thread4:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ [[J]], [[DOTEXIT_THREAD]] ], [ [[ADD3]], [[DOTEXIT]] ], [ [[ADD3]], [[ENTRY:%.*]] ], [ [[ADD3]], [[COND_FALSE_6_I]] ]
|
|
; CHECK-NEXT: ret i32 [[TMP0]]
|
|
;
|
|
entry:
|
|
%add3 = add nsw i32 %j, 2
|
|
%cmp.i = icmp slt i32 %u, %v
|
|
br i1 %cmp.i, label %.exit, label %cond.false.i
|
|
|
|
cond.false.i: ; preds = %entry
|
|
%cmp4.i = icmp sgt i32 %u, %v
|
|
br i1 %cmp4.i, label %.exit, label %cond.false.6.i
|
|
|
|
cond.false.6.i: ; preds = %cond.false.i
|
|
%cmp8.i = icmp slt i32 %w, %x
|
|
br i1 %cmp8.i, label %.exit, label %cond.false.10.i
|
|
|
|
cond.false.10.i: ; preds = %cond.false.6.i
|
|
%cmp13.i = icmp sgt i32 %w, %x
|
|
br i1 %cmp13.i, label %.exit, label %cond.false.15.i
|
|
|
|
cond.false.15.i: ; preds = %cond.false.10.i
|
|
%phitmp = icmp sge i32 %y, %z
|
|
br label %.exit
|
|
|
|
.exit: ; preds = %entry, %cond.false.i, %cond.false.6.i, %cond.false.10.i, %cond.false.15.i
|
|
%cond23.i = phi i1 [ false, %entry ], [ true, %cond.false.i ], [ false, %cond.false.6.i ], [ %phitmp, %cond.false.15.i ], [ true, %cond.false.10.i ]
|
|
%j.add3 = select i1 %cond23.i, i32 %j, i32 %add3
|
|
ret i32 %j.add3
|
|
|
|
}
|
|
|
|
define i32 @unfold4(i32 %u, i32 %v, i32 %w, i32 %x, i32 %y, i32 %z, i32 %j) nounwind {
|
|
; CHECK-LABEL: @unfold4(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ADD3:%.*]] = add nsw i32 [[J:%.*]], 2
|
|
; CHECK-NEXT: [[CMP_I:%.*]] = icmp slt i32 [[U:%.*]], [[V:%.*]]
|
|
; CHECK-NEXT: br i1 [[CMP_I]], label [[DOTEXIT_THREAD:%.*]], label [[COND_FALSE_I:%.*]]
|
|
; CHECK: cond.false.i:
|
|
; CHECK-NEXT: [[CMP4_I:%.*]] = icmp sgt i32 [[U]], [[V]]
|
|
; CHECK-NEXT: br i1 [[CMP4_I]], label [[DOTEXIT_THREAD5:%.*]], label [[COND_FALSE_6_I:%.*]]
|
|
; CHECK: cond.false.6.i:
|
|
; CHECK-NEXT: [[CMP8_I:%.*]] = icmp slt i32 [[W:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: br i1 [[CMP8_I]], label [[DOTEXIT_THREAD]], label [[COND_FALSE_10_I:%.*]]
|
|
; CHECK: cond.false.10.i:
|
|
; CHECK-NEXT: [[CMP13_I:%.*]] = icmp sgt i32 [[W]], [[X]]
|
|
; CHECK-NEXT: br i1 [[CMP13_I]], label [[DOTEXIT_THREAD5]], label [[DOTEXIT:%.*]]
|
|
; CHECK: .exit:
|
|
; CHECK-NEXT: [[CMP19_I:%.*]] = icmp sge i32 [[Y:%.*]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP19_I]] to i32
|
|
; CHECK-NEXT: [[LNOT_I18:%.*]] = icmp eq i32 [[CONV]], 1
|
|
; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[LNOT_I18]]
|
|
; CHECK-NEXT: br i1 [[COND_FR]], label [[DOTEXIT_THREAD]], label [[DOTEXIT_THREAD5]]
|
|
; CHECK: .exit.thread:
|
|
; CHECK-NEXT: br label [[DOTEXIT_THREAD5]]
|
|
; CHECK: .exit.thread5:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ [[J]], [[DOTEXIT_THREAD]] ], [ [[ADD3]], [[DOTEXIT]] ], [ [[ADD3]], [[COND_FALSE_I]] ], [ [[ADD3]], [[COND_FALSE_10_I]] ]
|
|
; CHECK-NEXT: ret i32 [[TMP0]]
|
|
;
|
|
entry:
|
|
%add3 = add nsw i32 %j, 2
|
|
%cmp.i = icmp slt i32 %u, %v
|
|
br i1 %cmp.i, label %.exit, label %cond.false.i
|
|
|
|
cond.false.i: ; preds = %entry
|
|
%cmp4.i = icmp sgt i32 %u, %v
|
|
br i1 %cmp4.i, label %.exit, label %cond.false.6.i
|
|
|
|
cond.false.6.i: ; preds = %cond.false.i
|
|
%cmp8.i = icmp slt i32 %w, %x
|
|
br i1 %cmp8.i, label %.exit, label %cond.false.10.i
|
|
|
|
cond.false.10.i: ; preds = %cond.false.6.i
|
|
%cmp13.i = icmp sgt i32 %w, %x
|
|
br i1 %cmp13.i, label %.exit, label %cond.false.15.i
|
|
|
|
cond.false.15.i: ; preds = %cond.false.10.i
|
|
%cmp19.i = icmp sge i32 %y, %z
|
|
%conv = zext i1 %cmp19.i to i32
|
|
br label %.exit
|
|
|
|
.exit: ; preds = %entry, %cond.false.i, %cond.false.6.i, %cond.false.10.i, %cond.false.15.i
|
|
%cond23.i = phi i32 [ 1, %entry ], [ 0, %cond.false.i ], [ 1, %cond.false.6.i ], [ %conv, %cond.false.15.i ], [ 0, %cond.false.10.i ]
|
|
%lnot.i18 = icmp eq i32 %cond23.i, 1
|
|
%j.add3 = select i1 %lnot.i18, i32 %j, i32 %add3
|
|
ret i32 %j.add3
|
|
|
|
}
|
|
|
|
define i32 @unfold5(i32 %u, i32 %v, i32 %w, i32 %x, i32 %y, i32 %z, i32 %j) nounwind {
|
|
; CHECK-LABEL: @unfold5(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ADD3:%.*]] = add nsw i32 [[J:%.*]], 2
|
|
; CHECK-NEXT: [[CMP_I:%.*]] = icmp slt i32 [[U:%.*]], [[V:%.*]]
|
|
; CHECK-NEXT: br i1 [[CMP_I]], label [[DOTEXIT:%.*]], label [[COND_FALSE_I:%.*]]
|
|
; CHECK: cond.false.i:
|
|
; CHECK-NEXT: [[CMP4_I:%.*]] = icmp sgt i32 [[U]], [[V]]
|
|
; CHECK-NEXT: br i1 [[CMP4_I]], label [[DOTEXIT]], label [[COND_FALSE_6_I:%.*]]
|
|
; CHECK: cond.false.6.i:
|
|
; CHECK-NEXT: [[CMP8_I:%.*]] = icmp slt i32 [[W:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: br i1 [[CMP8_I]], label [[DOTEXIT]], label [[COND_FALSE_10_I:%.*]]
|
|
; CHECK: cond.false.10.i:
|
|
; CHECK-NEXT: [[CMP13_I:%.*]] = icmp sgt i32 [[W]], [[X]]
|
|
; CHECK-NEXT: br i1 [[CMP13_I]], label [[DOTEXIT]], label [[COND_FALSE_15_I:%.*]]
|
|
; CHECK: cond.false.15.i:
|
|
; CHECK-NEXT: [[CMP19_I:%.*]] = icmp sge i32 [[Y:%.*]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP19_I]] to i32
|
|
; CHECK-NEXT: br label [[DOTEXIT]]
|
|
; CHECK: .exit:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ [[J]], [[COND_FALSE_10_I]] ], [ [[CONV]], [[COND_FALSE_15_I]] ], [ 1, [[COND_FALSE_6_I]] ], [ 3, [[COND_FALSE_I]] ], [ 2, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: ret i32 [[TMP0]]
|
|
;
|
|
entry:
|
|
%add3 = add nsw i32 %j, 2
|
|
%cmp.i = icmp slt i32 %u, %v
|
|
br i1 %cmp.i, label %.exit, label %cond.false.i
|
|
|
|
cond.false.i: ; preds = %entry
|
|
%cmp4.i = icmp sgt i32 %u, %v
|
|
br i1 %cmp4.i, label %.exit, label %cond.false.6.i
|
|
|
|
cond.false.6.i: ; preds = %cond.false.i
|
|
%cmp8.i = icmp slt i32 %w, %x
|
|
br i1 %cmp8.i, label %.exit, label %cond.false.10.i
|
|
|
|
cond.false.10.i: ; preds = %cond.false.6.i
|
|
%cmp13.i = icmp sgt i32 %w, %x
|
|
br i1 %cmp13.i, label %.exit, label %cond.false.15.i
|
|
|
|
cond.false.15.i: ; preds = %cond.false.10.i
|
|
%cmp19.i = icmp sge i32 %y, %z
|
|
%conv = zext i1 %cmp19.i to i32
|
|
br label %.exit
|
|
|
|
.exit: ; preds = %entry, %cond.false.i, %cond.false.6.i, %cond.false.10.i, %cond.false.15.i
|
|
%cond23.i = phi i32 [ 2, %entry ], [ 3, %cond.false.i ], [ 1, %cond.false.6.i ], [ %conv, %cond.false.15.i ], [ 7, %cond.false.10.i ]
|
|
%lnot.i18 = icmp sgt i32 %cond23.i, 5
|
|
%j.add3 = select i1 %lnot.i18, i32 %j, i32 %cond23.i
|
|
ret i32 %j.add3
|
|
|
|
}
|
|
|
|
; When a select has a constant operand in one branch, and it feeds a phi node
|
|
; and the phi node feeds a switch we unfold the select
|
|
define void @test_func(ptr nocapture readonly %a, ptr nocapture readonly %b, ptr nocapture readonly %c, i32 %n) local_unnamed_addr #0 {
|
|
; CHECK-LABEL: @test_func(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[FOR_COND:%.*]]
|
|
; CHECK: for.cond:
|
|
; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[SW_DEFAULT:%.*]] ]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]
|
|
; CHECK: for.cond.cleanup:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[I_0]] to i64
|
|
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[A:%.*]], i64 [[TMP0]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP1]], 4
|
|
; CHECK-NEXT: br i1 [[CMP1]], label [[LAND_LHS_TRUE:%.*]], label [[IF_END:%.*]]
|
|
; CHECK: land.lhs.true:
|
|
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds i32, ptr [[B:%.*]], i64 [[TMP0]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX3]], align 4
|
|
; CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds i32, ptr [[C:%.*]], i64 [[TMP0]]
|
|
; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ARRAYIDX5]], align 4
|
|
; CHECK-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP2]], [[TMP3]]
|
|
; CHECK-NEXT: br i1 [[CMP6]], label [[SW_BB:%.*]], label [[SW_BB7:%.*]]
|
|
; CHECK: if.end:
|
|
; CHECK-NEXT: [[LOCAL_VAR_0:%.*]] = phi i32 [ [[TMP1]], [[FOR_BODY]] ]
|
|
; CHECK-NEXT: switch i32 [[LOCAL_VAR_0]], label [[SW_DEFAULT]] [
|
|
; CHECK-NEXT: i32 2, label [[SW_BB]]
|
|
; CHECK-NEXT: i32 4, label [[SW_BB7]]
|
|
; CHECK-NEXT: i32 5, label [[SW_BB8:%.*]]
|
|
; CHECK-NEXT: i32 7, label [[SW_BB9:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: sw.bb:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label [[SW_BB7]]
|
|
; CHECK: sw.bb7:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[SW_BB8]]
|
|
; CHECK: sw.bb8:
|
|
; CHECK-NEXT: call void @baz()
|
|
; CHECK-NEXT: br label [[SW_BB9]]
|
|
; CHECK: sw.bb9:
|
|
; CHECK-NEXT: call void @quux()
|
|
; CHECK-NEXT: br label [[SW_DEFAULT]]
|
|
; CHECK: sw.default:
|
|
; CHECK-NEXT: call void @baz()
|
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_0]], 1
|
|
; CHECK-NEXT: br label [[FOR_COND]]
|
|
;
|
|
entry:
|
|
br label %for.cond
|
|
|
|
for.cond: ; preds = %sw.default, %entry
|
|
%i.0 = phi i32 [ 0, %entry ], [ %inc, %sw.default ]
|
|
%cmp = icmp slt i32 %i.0, %n
|
|
br i1 %cmp, label %for.body, label %for.cond.cleanup
|
|
|
|
for.cond.cleanup: ; preds = %for.cond
|
|
ret void
|
|
|
|
for.body: ; preds = %for.cond
|
|
%0 = zext i32 %i.0 to i64
|
|
%arrayidx = getelementptr inbounds i32, ptr %a, i64 %0
|
|
%1 = load i32, ptr %arrayidx, align 4
|
|
%cmp1 = icmp eq i32 %1, 4
|
|
br i1 %cmp1, label %land.lhs.true, label %if.end
|
|
|
|
land.lhs.true: ; preds = %for.body
|
|
%arrayidx3 = getelementptr inbounds i32, ptr %b, i64 %0
|
|
%2 = load i32, ptr %arrayidx3, align 4
|
|
%arrayidx5 = getelementptr inbounds i32, ptr %c, i64 %0
|
|
%3 = load i32, ptr %arrayidx5, align 4
|
|
%cmp6 = icmp eq i32 %2, %3
|
|
%spec.select = select i1 %cmp6, i32 2, i32 4
|
|
br label %if.end
|
|
|
|
if.end: ; preds = %land.lhs.true, %for.body
|
|
%local_var.0 = phi i32 [ %1, %for.body ], [ %spec.select, %land.lhs.true ]
|
|
switch i32 %local_var.0, label %sw.default [
|
|
i32 2, label %sw.bb
|
|
i32 4, label %sw.bb7
|
|
i32 5, label %sw.bb8
|
|
i32 7, label %sw.bb9
|
|
]
|
|
|
|
sw.bb: ; preds = %if.end
|
|
call void @foo()
|
|
br label %sw.bb7
|
|
|
|
sw.bb7: ; preds = %if.end, %sw.bb
|
|
call void @bar()
|
|
br label %sw.bb8
|
|
|
|
sw.bb8: ; preds = %if.end, %sw.bb7
|
|
call void @baz()
|
|
br label %sw.bb9
|
|
|
|
sw.bb9: ; preds = %if.end, %sw.bb8
|
|
call void @quux()
|
|
br label %sw.default
|
|
|
|
sw.default: ; preds = %if.end, %sw.bb9
|
|
call void @baz()
|
|
%inc = add nuw nsw i32 %i.0, 1
|
|
br label %for.cond
|
|
}
|
|
|
|
define i32 @TryToUnfoldSelectInCurrBB(i1 %b, i1 %ui, i32 %s, i1 %x) {
|
|
; CHECK-LABEL: @TryToUnfoldSelectInCurrBB(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF_END_THREAD:%.*]], label [[IF_END:%.*]]
|
|
; CHECK: if.end:
|
|
; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[X:%.*]]
|
|
; CHECK-NEXT: br i1 [[COND_FR]], label [[TMP0:%.*]], label [[IF_END_THREAD]]
|
|
; CHECK: 0:
|
|
; CHECK-NEXT: br label [[IF_END_THREAD]]
|
|
; CHECK: if.end.thread:
|
|
; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[S:%.*]], [[TMP0]] ], [ 42, [[IF_END]] ], [ 42, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: ret i32 [[TMP1]]
|
|
;
|
|
entry:
|
|
br i1 %b, label %if.end, label %if.else
|
|
|
|
if.else:
|
|
br label %if.end
|
|
|
|
if.end:
|
|
%v = phi i1 [ %x, %if.else ], [ false, %entry ]
|
|
%v1 = select i1 %v, i32 %s, i32 42
|
|
ret i32 %v1
|
|
}
|
|
|
|
; branch_weights overflowing uint32_t
|
|
!0 = !{!"branch_weights", i64 1073741824, i64 3221225472}
|
|
!1 = !{!"function_entry_count", i64 1984}
|
|
;.
|
|
; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind }
|
|
;.
|
|
; CHECK: [[META0:![0-9]+]] = !{!"function_entry_count", i64 1984}
|
|
; CHECK: [[PROF1]] = !{!"branch_weights", i64 1073741824, i64 3221225472}
|
|
;.
|