We cannot calculate the weights of the switch precisely, but we do know the probability of the default branch. We then split equally the remaining probability over the rest of the cases. If we did nothing, the static estimation could be considerably poorer. Issue #147390
1329 lines
41 KiB
LLVM
1329 lines
41 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
|
|
; RUN: opt -S -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -switch-range-to-icmp < %s | FileCheck %s
|
|
; RUN: opt -S -data-layout="p:32:32-p1:16:16" -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -switch-range-to-icmp < %s | FileCheck -check-prefix=CHECK -check-prefix=DL %s
|
|
|
|
declare void @foo1()
|
|
|
|
declare void @foo2()
|
|
|
|
define void @test1(i32 %V) !prof !0 {
|
|
; CHECK-LABEL: @test1(
|
|
; CHECK-NEXT: switch i32 [[V:%.*]], label [[F:%.*]] [
|
|
; CHECK-NEXT: i32 17, label [[T:%.*]]
|
|
; CHECK-NEXT: i32 4, label [[T]]
|
|
; CHECK-NEXT: ], !prof [[PROF1:![0-9]+]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: T:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
|
|
; CHECK: F:
|
|
; CHECK-NEXT: call void @foo2()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%C1 = icmp eq i32 %V, 4 ; <i1> [#uses=1]
|
|
%C2 = icmp eq i32 %V, 17 ; <i1> [#uses=1]
|
|
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
|
|
br i1 %CN, label %T, label %F, !prof !1
|
|
T: ; preds = %0
|
|
call void @foo1( )
|
|
ret void
|
|
F: ; preds = %0
|
|
call void @foo2( )
|
|
ret void
|
|
}
|
|
|
|
define void @test1_select(i32 %V) {
|
|
; CHECK-LABEL: @test1_select(
|
|
; CHECK-NEXT: switch i32 [[V:%.*]], label [[F:%.*]] [
|
|
; CHECK-NEXT: i32 17, label [[T:%.*]]
|
|
; CHECK-NEXT: i32 4, label [[T]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: T:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
|
|
; CHECK: F:
|
|
; CHECK-NEXT: call void @foo2()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%C1 = icmp eq i32 %V, 4
|
|
%C2 = icmp eq i32 %V, 17
|
|
%CN = select i1 %C1, i1 true, i1 %C2
|
|
br i1 %CN, label %T, label %F
|
|
T:
|
|
call void @foo1( )
|
|
ret void
|
|
F:
|
|
call void @foo2( )
|
|
ret void
|
|
}
|
|
|
|
define void @test1_ptr(ptr %V) {
|
|
; DL-LABEL: @test1_ptr(
|
|
; DL-NEXT: [[MAGICPTR:%.*]] = ptrtoint ptr [[V:%.*]] to i32
|
|
; DL-NEXT: switch i32 [[MAGICPTR]], label [[F:%.*]] [
|
|
; DL-NEXT: i32 17, label [[T:%.*]]
|
|
; DL-NEXT: i32 4, label [[T]]
|
|
; DL-NEXT: ]
|
|
; DL: common.ret:
|
|
; DL-NEXT: ret void
|
|
; DL: T:
|
|
; DL-NEXT: call void @foo1()
|
|
; DL-NEXT: br label [[COMMON_RET:%.*]]
|
|
; DL: F:
|
|
; DL-NEXT: call void @foo2()
|
|
; DL-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%C1 = icmp eq ptr %V, inttoptr (i32 4 to ptr)
|
|
%C2 = icmp eq ptr %V, inttoptr (i32 17 to ptr)
|
|
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
|
|
br i1 %CN, label %T, label %F
|
|
T: ; preds = %0
|
|
call void @foo1( )
|
|
ret void
|
|
F: ; preds = %0
|
|
call void @foo2( )
|
|
ret void
|
|
}
|
|
|
|
define void @test1_ptr_as1(ptr addrspace(1) %V) {
|
|
; DL-LABEL: @test1_ptr_as1(
|
|
; DL-NEXT: [[MAGICPTR:%.*]] = ptrtoint ptr addrspace(1) [[V:%.*]] to i16
|
|
; DL-NEXT: switch i16 [[MAGICPTR]], label [[F:%.*]] [
|
|
; DL-NEXT: i16 17, label [[T:%.*]]
|
|
; DL-NEXT: i16 4, label [[T]]
|
|
; DL-NEXT: ]
|
|
; DL: common.ret:
|
|
; DL-NEXT: ret void
|
|
; DL: T:
|
|
; DL-NEXT: call void @foo1()
|
|
; DL-NEXT: br label [[COMMON_RET:%.*]]
|
|
; DL: F:
|
|
; DL-NEXT: call void @foo2()
|
|
; DL-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%C1 = icmp eq ptr addrspace(1) %V, inttoptr (i32 4 to ptr addrspace(1))
|
|
%C2 = icmp eq ptr addrspace(1) %V, inttoptr (i32 17 to ptr addrspace(1))
|
|
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
|
|
br i1 %CN, label %T, label %F
|
|
T: ; preds = %0
|
|
call void @foo1( )
|
|
ret void
|
|
F: ; preds = %0
|
|
call void @foo2( )
|
|
ret void
|
|
}
|
|
|
|
define void @test2(i32 %V) !prof !0 {
|
|
; CHECK-LABEL: @test2(
|
|
; CHECK-NEXT: switch i32 [[V:%.*]], label [[T:%.*]] [
|
|
; CHECK-NEXT: i32 17, label [[F:%.*]]
|
|
; CHECK-NEXT: i32 4, label [[F]]
|
|
; CHECK-NEXT: ], !prof [[PROF2:![0-9]+]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: T:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
|
|
; CHECK: F:
|
|
; CHECK-NEXT: call void @foo2()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%C1 = icmp ne i32 %V, 4 ; <i1> [#uses=1]
|
|
%C2 = icmp ne i32 %V, 17 ; <i1> [#uses=1]
|
|
%CN = and i1 %C1, %C2 ; <i1> [#uses=1]
|
|
br i1 %CN, label %T, label %F, !prof !1
|
|
T: ; preds = %0
|
|
call void @foo1( )
|
|
ret void
|
|
F: ; preds = %0
|
|
call void @foo2( )
|
|
ret void
|
|
}
|
|
|
|
define void @test2_select(i32 %V) {
|
|
; CHECK-LABEL: @test2_select(
|
|
; CHECK-NEXT: switch i32 [[V:%.*]], label [[T:%.*]] [
|
|
; CHECK-NEXT: i32 17, label [[F:%.*]]
|
|
; CHECK-NEXT: i32 4, label [[F]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: T:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
|
|
; CHECK: F:
|
|
; CHECK-NEXT: call void @foo2()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%C1 = icmp ne i32 %V, 4
|
|
%C2 = icmp ne i32 %V, 17
|
|
%CN = select i1 %C1, i1 %C2, i1 false
|
|
br i1 %CN, label %T, label %F
|
|
T:
|
|
call void @foo1( )
|
|
ret void
|
|
F:
|
|
call void @foo2( )
|
|
ret void
|
|
}
|
|
|
|
define void @test3(i32 %V) {
|
|
; CHECK-LABEL: @test3(
|
|
; CHECK-NEXT: switch i32 [[V:%.*]], label [[F:%.*]] [
|
|
; CHECK-NEXT: i32 4, label [[T:%.*]]
|
|
; CHECK-NEXT: i32 17, label [[T]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: T:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
|
|
; CHECK: F:
|
|
; CHECK-NEXT: call void @foo2()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%C1 = icmp eq i32 %V, 4 ; <i1> [#uses=1]
|
|
br i1 %C1, label %T, label %N
|
|
N: ; preds = %0
|
|
%C2 = icmp eq i32 %V, 17 ; <i1> [#uses=1]
|
|
br i1 %C2, label %T, label %F
|
|
T: ; preds = %N, %0
|
|
call void @foo1( )
|
|
ret void
|
|
F: ; preds = %N
|
|
call void @foo2( )
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
define i32 @test4(i8 zeroext %c) nounwind ssp noredzone {
|
|
; CHECK-LABEL: @test4(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: switch i8 [[C:%.*]], label [[LOR_RHS:%.*]] [
|
|
; CHECK-NEXT: i8 62, label [[LOR_END:%.*]]
|
|
; CHECK-NEXT: i8 34, label [[LOR_END]]
|
|
; CHECK-NEXT: i8 92, label [[LOR_END]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: lor.rhs:
|
|
; CHECK-NEXT: br label [[LOR_END]]
|
|
; CHECK: lor.end:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ false, [[LOR_RHS]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ]
|
|
; CHECK-NEXT: [[LOR_EXT:%.*]] = zext i1 [[TMP0]] to i32
|
|
; CHECK-NEXT: ret i32 [[LOR_EXT]]
|
|
;
|
|
entry:
|
|
%cmp = icmp eq i8 %c, 62
|
|
br i1 %cmp, label %lor.end, label %lor.lhs.false
|
|
|
|
lor.lhs.false: ; preds = %entry
|
|
%cmp4 = icmp eq i8 %c, 34
|
|
br i1 %cmp4, label %lor.end, label %lor.rhs
|
|
|
|
lor.rhs: ; preds = %lor.lhs.false
|
|
%cmp8 = icmp eq i8 %c, 92
|
|
br label %lor.end
|
|
|
|
lor.end: ; preds = %lor.rhs, %lor.lhs.false, %entry
|
|
%0 = phi i1 [ true, %lor.lhs.false ], [ true, %entry ], [ %cmp8, %lor.rhs ]
|
|
%lor.ext = zext i1 %0 to i32
|
|
ret i32 %lor.ext
|
|
|
|
}
|
|
|
|
define i32 @test5(i8 zeroext %c) nounwind ssp noredzone {
|
|
; CHECK-LABEL: @test5(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: switch i8 [[C:%.*]], label [[LOR_RHS:%.*]] [
|
|
; CHECK-NEXT: i8 62, label [[LOR_END:%.*]]
|
|
; CHECK-NEXT: i8 34, label [[LOR_END]]
|
|
; CHECK-NEXT: i8 92, label [[LOR_END]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: lor.rhs:
|
|
; CHECK-NEXT: br label [[LOR_END]]
|
|
; CHECK: lor.end:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ false, [[LOR_RHS]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ]
|
|
; CHECK-NEXT: [[LOR_EXT:%.*]] = zext i1 [[TMP0]] to i32
|
|
; CHECK-NEXT: ret i32 [[LOR_EXT]]
|
|
;
|
|
entry:
|
|
switch i8 %c, label %lor.rhs [
|
|
i8 62, label %lor.end
|
|
i8 34, label %lor.end
|
|
i8 92, label %lor.end
|
|
]
|
|
|
|
lor.rhs: ; preds = %entry
|
|
%V = icmp eq i8 %c, 92
|
|
br label %lor.end
|
|
|
|
lor.end: ; preds = %entry, %entry, %entry, %lor.rhs
|
|
%0 = phi i1 [ true, %entry ], [ %V, %lor.rhs ], [ true, %entry ], [ true, %entry ]
|
|
%lor.ext = zext i1 %0 to i32
|
|
ret i32 %lor.ext
|
|
}
|
|
|
|
|
|
define i1 @test6(ptr %I) {
|
|
; CHECK-LABEL: @test6(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP_1_I:%.*]] = getelementptr { i32, i32 }, ptr [[I:%.*]], i64 0, i32 1
|
|
; CHECK-NEXT: [[TMP_2_I:%.*]] = load i32, ptr [[TMP_1_I]], align 4
|
|
; CHECK-NEXT: [[TMP_2_I_OFF:%.*]] = add i32 [[TMP_2_I]], -14
|
|
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[TMP_2_I_OFF]], 6
|
|
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[SWITCH]], i1 true, i1 false
|
|
; CHECK-NEXT: ret i1 [[SPEC_SELECT]]
|
|
;
|
|
entry:
|
|
%tmp.1.i = getelementptr { i32, i32 }, ptr %I, i64 0, i32 1 ; <ptr> [#uses=1]
|
|
%tmp.2.i = load i32, ptr %tmp.1.i ; <i32> [#uses=6]
|
|
%tmp.2 = icmp eq i32 %tmp.2.i, 14 ; <i1> [#uses=1]
|
|
br i1 %tmp.2, label %shortcirc_done.4, label %shortcirc_next.0
|
|
shortcirc_next.0: ; preds = %entry
|
|
%tmp.6 = icmp eq i32 %tmp.2.i, 15 ; <i1> [#uses=1]
|
|
br i1 %tmp.6, label %shortcirc_done.4, label %shortcirc_next.1
|
|
shortcirc_next.1: ; preds = %shortcirc_next.0
|
|
%tmp.11 = icmp eq i32 %tmp.2.i, 16 ; <i1> [#uses=1]
|
|
br i1 %tmp.11, label %shortcirc_done.4, label %shortcirc_next.2
|
|
shortcirc_next.2: ; preds = %shortcirc_next.1
|
|
%tmp.16 = icmp eq i32 %tmp.2.i, 17 ; <i1> [#uses=1]
|
|
br i1 %tmp.16, label %shortcirc_done.4, label %shortcirc_next.3
|
|
shortcirc_next.3: ; preds = %shortcirc_next.2
|
|
%tmp.21 = icmp eq i32 %tmp.2.i, 18 ; <i1> [#uses=1]
|
|
br i1 %tmp.21, label %shortcirc_done.4, label %shortcirc_next.4
|
|
shortcirc_next.4: ; preds = %shortcirc_next.3
|
|
%tmp.26 = icmp eq i32 %tmp.2.i, 19 ; <i1> [#uses=1]
|
|
br label %UnifiedReturnBlock
|
|
shortcirc_done.4: ; preds = %shortcirc_next.3, %shortcirc_next.2, %shortcirc_next.1, %shortcirc_next.0, %entry
|
|
br label %UnifiedReturnBlock
|
|
UnifiedReturnBlock: ; preds = %shortcirc_done.4, %shortcirc_next.4
|
|
%UnifiedRetVal = phi i1 [ %tmp.26, %shortcirc_next.4 ], [ true, %shortcirc_done.4 ] ; <i1> [#uses=1]
|
|
ret i1 %UnifiedRetVal
|
|
|
|
}
|
|
|
|
define void @test7(i8 zeroext %c, i32 %x) nounwind ssp noredzone {
|
|
; CHECK-LABEL: @test7(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 32
|
|
; CHECK-NEXT: [[TMP0:%.*]] = freeze i1 [[CMP]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]]
|
|
; CHECK: switch.early.test:
|
|
; CHECK-NEXT: switch i8 [[C:%.*]], label [[COMMON_RET:%.*]] [
|
|
; CHECK-NEXT: i8 99, label [[IF_THEN]]
|
|
; CHECK-NEXT: i8 97, label [[IF_THEN]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: tail call void @foo1() #[[ATTR2:[0-9]+]]
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
entry:
|
|
%cmp = icmp ult i32 %x, 32
|
|
%cmp4 = icmp eq i8 %c, 97
|
|
%or.cond = or i1 %cmp, %cmp4
|
|
%cmp9 = icmp eq i8 %c, 99
|
|
%or.cond11 = or i1 %or.cond, %cmp9
|
|
br i1 %or.cond11, label %if.then, label %if.end
|
|
|
|
if.then: ; preds = %entry
|
|
tail call void @foo1() nounwind noredzone
|
|
ret void
|
|
|
|
if.end: ; preds = %entry
|
|
ret void
|
|
|
|
}
|
|
|
|
define i32 @test8(i8 zeroext %c, i32 %x, i1 %C) nounwind ssp noredzone {
|
|
; CHECK-LABEL: @test8(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[N:%.*]], label [[IF_THEN:%.*]]
|
|
; CHECK: N:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 32
|
|
; CHECK-NEXT: [[TMP0:%.*]] = freeze i1 [[CMP]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN]], label [[SWITCH_EARLY_TEST:%.*]]
|
|
; CHECK: switch.early.test:
|
|
; CHECK-NEXT: switch i8 [[C:%.*]], label [[COMMON_RET:%.*]] [
|
|
; CHECK-NEXT: i8 99, label [[IF_THEN]]
|
|
; CHECK-NEXT: i8 97, label [[IF_THEN]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[A:%.*]], [[IF_THEN]] ], [ 0, [[SWITCH_EARLY_TEST]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: [[A]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 42, [[SWITCH_EARLY_TEST]] ], [ 42, [[N]] ], [ 42, [[SWITCH_EARLY_TEST]] ]
|
|
; CHECK-NEXT: tail call void @foo1() #[[ATTR2]]
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
entry:
|
|
br i1 %C, label %N, label %if.then
|
|
N:
|
|
%cmp = icmp ult i32 %x, 32
|
|
%cmp4 = icmp eq i8 %c, 97
|
|
%or.cond = or i1 %cmp, %cmp4
|
|
%cmp9 = icmp eq i8 %c, 99
|
|
%or.cond11 = or i1 %or.cond, %cmp9
|
|
br i1 %or.cond11, label %if.then, label %if.end
|
|
|
|
if.then: ; preds = %entry
|
|
%A = phi i32 [0, %entry], [42, %N]
|
|
tail call void @foo1() nounwind noredzone
|
|
ret i32 %A
|
|
|
|
if.end: ; preds = %entry
|
|
ret i32 0
|
|
|
|
}
|
|
|
|
;; This is "Example 7" from http://blog.regehr.org/archives/320
|
|
define i32 @test9(i8 zeroext %c) nounwind ssp noredzone {
|
|
; CHECK-LABEL: @test9(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[C:%.*]], 33
|
|
; CHECK-NEXT: [[TMP0:%.*]] = freeze i1 [[CMP]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[LOR_END:%.*]], label [[SWITCH_EARLY_TEST:%.*]]
|
|
; CHECK: switch.early.test:
|
|
; CHECK-NEXT: switch i8 [[C]], label [[LOR_RHS:%.*]] [
|
|
; CHECK-NEXT: i8 92, label [[LOR_END]]
|
|
; CHECK-NEXT: i8 62, label [[LOR_END]]
|
|
; CHECK-NEXT: i8 60, label [[LOR_END]]
|
|
; CHECK-NEXT: i8 59, label [[LOR_END]]
|
|
; CHECK-NEXT: i8 58, label [[LOR_END]]
|
|
; CHECK-NEXT: i8 46, label [[LOR_END]]
|
|
; CHECK-NEXT: i8 44, label [[LOR_END]]
|
|
; CHECK-NEXT: i8 34, label [[LOR_END]]
|
|
; CHECK-NEXT: i8 39, label [[LOR_END]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: lor.rhs:
|
|
; CHECK-NEXT: br label [[LOR_END]]
|
|
; CHECK: lor.end:
|
|
; CHECK-NEXT: [[TMP1:%.*]] = phi i1 [ true, [[SWITCH_EARLY_TEST]] ], [ false, [[LOR_RHS]] ], [ true, [[ENTRY:%.*]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ]
|
|
; CHECK-NEXT: [[CONV46:%.*]] = zext i1 [[TMP1]] to i32
|
|
; CHECK-NEXT: ret i32 [[CONV46]]
|
|
;
|
|
entry:
|
|
%cmp = icmp ult i8 %c, 33
|
|
br i1 %cmp, label %lor.end, label %lor.lhs.false
|
|
|
|
lor.lhs.false: ; preds = %entry
|
|
%cmp4 = icmp eq i8 %c, 46
|
|
br i1 %cmp4, label %lor.end, label %lor.lhs.false6
|
|
|
|
lor.lhs.false6: ; preds = %lor.lhs.false
|
|
%cmp9 = icmp eq i8 %c, 44
|
|
br i1 %cmp9, label %lor.end, label %lor.lhs.false11
|
|
|
|
lor.lhs.false11: ; preds = %lor.lhs.false6
|
|
%cmp14 = icmp eq i8 %c, 58
|
|
br i1 %cmp14, label %lor.end, label %lor.lhs.false16
|
|
|
|
lor.lhs.false16: ; preds = %lor.lhs.false11
|
|
%cmp19 = icmp eq i8 %c, 59
|
|
br i1 %cmp19, label %lor.end, label %lor.lhs.false21
|
|
|
|
lor.lhs.false21: ; preds = %lor.lhs.false16
|
|
%cmp24 = icmp eq i8 %c, 60
|
|
br i1 %cmp24, label %lor.end, label %lor.lhs.false26
|
|
|
|
lor.lhs.false26: ; preds = %lor.lhs.false21
|
|
%cmp29 = icmp eq i8 %c, 62
|
|
br i1 %cmp29, label %lor.end, label %lor.lhs.false31
|
|
|
|
lor.lhs.false31: ; preds = %lor.lhs.false26
|
|
%cmp34 = icmp eq i8 %c, 34
|
|
br i1 %cmp34, label %lor.end, label %lor.lhs.false36
|
|
|
|
lor.lhs.false36: ; preds = %lor.lhs.false31
|
|
%cmp39 = icmp eq i8 %c, 92
|
|
br i1 %cmp39, label %lor.end, label %lor.rhs
|
|
|
|
lor.rhs: ; preds = %lor.lhs.false36
|
|
%cmp43 = icmp eq i8 %c, 39
|
|
br label %lor.end
|
|
|
|
lor.end: ; preds = %lor.rhs, %lor.lhs.false36, %lor.lhs.false31, %lor.lhs.false26, %lor.lhs.false21, %lor.lhs.false16, %lor.lhs.false11, %lor.lhs.false6, %lor.lhs.false, %entry
|
|
%0 = phi i1 [ true, %lor.lhs.false36 ], [ true, %lor.lhs.false31 ], [ true, %lor.lhs.false26 ], [ true, %lor.lhs.false21 ], [ true, %lor.lhs.false16 ], [ true, %lor.lhs.false11 ], [ true, %lor.lhs.false6 ], [ true, %lor.lhs.false ], [ true, %entry ], [ %cmp43, %lor.rhs ]
|
|
%conv46 = zext i1 %0 to i32
|
|
ret i32 %conv46
|
|
|
|
|
|
}
|
|
|
|
define i32 @test10(i32 %mode, i1 %Cond) {
|
|
; CHECK-LABEL: @test10(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[COND:%.*]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]]
|
|
; CHECK: switch.early.test:
|
|
; CHECK-NEXT: switch i32 [[MODE:%.*]], label [[T:%.*]] [
|
|
; CHECK-NEXT: i32 51, label [[F]]
|
|
; CHECK-NEXT: i32 0, label [[F]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 123, [[T]] ], [ 324, [[F]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
; CHECK: T:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
|
|
; CHECK: F:
|
|
; CHECK-NEXT: call void @foo2()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%A = icmp ne i32 %mode, 0
|
|
%B = icmp ne i32 %mode, 51
|
|
%C = and i1 %A, %B
|
|
%D = and i1 %C, %Cond
|
|
br i1 %D, label %T, label %F
|
|
T:
|
|
call void @foo1()
|
|
ret i32 123
|
|
F:
|
|
call void @foo2()
|
|
ret i32 324
|
|
|
|
}
|
|
|
|
define i32 @test10_select(i32 %mode, i1 %Cond) {
|
|
; CHECK-LABEL: @test10_select(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[COND:%.*]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]]
|
|
; CHECK: switch.early.test:
|
|
; CHECK-NEXT: switch i32 [[MODE:%.*]], label [[T:%.*]] [
|
|
; CHECK-NEXT: i32 51, label [[F]]
|
|
; CHECK-NEXT: i32 0, label [[F]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 123, [[T]] ], [ 324, [[F]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
; CHECK: T:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
|
|
; CHECK: F:
|
|
; CHECK-NEXT: call void @foo2()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%A = icmp ne i32 %mode, 0
|
|
%B = icmp ne i32 %mode, 51
|
|
%C = select i1 %A, i1 %B, i1 false
|
|
%D = select i1 %C, i1 %Cond, i1 false
|
|
br i1 %D, label %T, label %F
|
|
T:
|
|
call void @foo1()
|
|
ret i32 123
|
|
F:
|
|
call void @foo2()
|
|
ret i32 324
|
|
|
|
}
|
|
|
|
; TODO: %Cond doesn't need freeze
|
|
define i32 @test10_select_and(i32 %mode, i1 %Cond) {
|
|
; CHECK-LABEL: @test10_select_and(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[COND:%.*]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]]
|
|
; CHECK: switch.early.test:
|
|
; CHECK-NEXT: switch i32 [[MODE:%.*]], label [[T:%.*]] [
|
|
; CHECK-NEXT: i32 51, label [[F]]
|
|
; CHECK-NEXT: i32 0, label [[F]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 123, [[T]] ], [ 324, [[F]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
; CHECK: T:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
|
|
; CHECK: F:
|
|
; CHECK-NEXT: call void @foo2()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%A = icmp ne i32 %mode, 0
|
|
%B = icmp ne i32 %mode, 51
|
|
%C = select i1 %A, i1 %B, i1 false
|
|
%D = and i1 %C, %Cond
|
|
br i1 %D, label %T, label %F
|
|
T:
|
|
call void @foo1()
|
|
ret i32 123
|
|
F:
|
|
call void @foo2()
|
|
ret i32 324
|
|
|
|
}
|
|
|
|
define i32 @test10_select_nofreeze(i32 %mode, i1 noundef %Cond) {
|
|
; CHECK-LABEL: @test10_select_nofreeze(
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]]
|
|
; CHECK: switch.early.test:
|
|
; CHECK-NEXT: switch i32 [[MODE:%.*]], label [[T:%.*]] [
|
|
; CHECK-NEXT: i32 51, label [[F]]
|
|
; CHECK-NEXT: i32 0, label [[F]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 123, [[T]] ], [ 324, [[F]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
; CHECK: T:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
|
|
; CHECK: F:
|
|
; CHECK-NEXT: call void @foo2()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%A = icmp ne i32 %mode, 0
|
|
%B = icmp ne i32 %mode, 51
|
|
%C = select i1 %A, i1 %B, i1 false
|
|
%D = select i1 %C, i1 %Cond, i1 false
|
|
br i1 %D, label %T, label %F
|
|
T:
|
|
call void @foo1()
|
|
ret i32 123
|
|
F:
|
|
call void @foo2()
|
|
ret i32 324
|
|
|
|
}
|
|
|
|
; PR8780
|
|
define i32 @test11(i32 %bar) nounwind {
|
|
; CHECK-LABEL: @test11(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: switch i32 [[BAR:%.*]], label [[IF_END:%.*]] [
|
|
; CHECK-NEXT: i32 55, label [[RETURN:%.*]]
|
|
; CHECK-NEXT: i32 53, label [[RETURN]]
|
|
; CHECK-NEXT: i32 35, label [[RETURN]]
|
|
; CHECK-NEXT: i32 24, label [[RETURN]]
|
|
; CHECK-NEXT: i32 23, label [[RETURN]]
|
|
; CHECK-NEXT: i32 12, label [[RETURN]]
|
|
; CHECK-NEXT: i32 4, label [[RETURN]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: if.end:
|
|
; CHECK-NEXT: br label [[RETURN]]
|
|
; CHECK: return:
|
|
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ 0, [[IF_END]] ], [ 1, [[ENTRY:%.*]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ]
|
|
; CHECK-NEXT: ret i32 [[RETVAL_0]]
|
|
;
|
|
entry:
|
|
%cmp = icmp eq i32 %bar, 4
|
|
%cmp2 = icmp eq i32 %bar, 35
|
|
%or.cond = or i1 %cmp, %cmp2
|
|
%cmp5 = icmp eq i32 %bar, 53
|
|
%or.cond1 = or i1 %or.cond, %cmp5
|
|
%cmp8 = icmp eq i32 %bar, 24
|
|
%or.cond2 = or i1 %or.cond1, %cmp8
|
|
%cmp11 = icmp eq i32 %bar, 23
|
|
%or.cond3 = or i1 %or.cond2, %cmp11
|
|
%cmp14 = icmp eq i32 %bar, 55
|
|
%or.cond4 = or i1 %or.cond3, %cmp14
|
|
%cmp17 = icmp eq i32 %bar, 12
|
|
%or.cond5 = or i1 %or.cond4, %cmp17
|
|
%cmp20 = icmp eq i32 %bar, 35
|
|
%or.cond6 = or i1 %or.cond5, %cmp20
|
|
br i1 %or.cond6, label %if.then, label %if.end
|
|
|
|
if.then: ; preds = %entry
|
|
br label %return
|
|
|
|
if.end: ; preds = %entry
|
|
br label %return
|
|
|
|
return: ; preds = %if.end, %if.then
|
|
%retval.0 = phi i32 [ 1, %if.then ], [ 0, %if.end ]
|
|
ret i32 %retval.0
|
|
|
|
}
|
|
|
|
define void @test12() nounwind {
|
|
; CHECK-LABEL: @test12(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[A_OLD:%.*]] = icmp eq i32 undef, undef
|
|
; CHECK-NEXT: br i1 [[A_OLD]], label [[BB55_US_US:%.*]], label [[MALFORMED:%.*]]
|
|
; CHECK: bb55.us.us:
|
|
; CHECK-NEXT: [[B:%.*]] = icmp ugt i32 undef, undef
|
|
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 undef, undef
|
|
; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[B]], [[A]]
|
|
; CHECK-NEXT: br i1 [[OR_COND]], label [[BB55_US_US]], label [[MALFORMED]]
|
|
; CHECK: malformed:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %bb49.us.us
|
|
|
|
bb49.us.us:
|
|
%A = icmp eq i32 undef, undef
|
|
br i1 %A, label %bb55.us.us, label %malformed
|
|
|
|
bb48.us.us:
|
|
%B = icmp ugt i32 undef, undef
|
|
br i1 %B, label %bb55.us.us, label %bb49.us.us
|
|
|
|
bb55.us.us:
|
|
br label %bb48.us.us
|
|
|
|
malformed:
|
|
ret void
|
|
|
|
}
|
|
|
|
; test13 - handle switch formation with ult.
|
|
define void @test13(i32 %x) nounwind ssp noredzone {
|
|
; CHECK-LABEL: @test13(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: switch i32 [[X:%.*]], label [[IF_END:%.*]] [
|
|
; CHECK-NEXT: i32 6, label [[IF_THEN:%.*]]
|
|
; CHECK-NEXT: i32 4, label [[IF_THEN]]
|
|
; CHECK-NEXT: i32 3, label [[IF_THEN]]
|
|
; CHECK-NEXT: i32 1, label [[IF_THEN]]
|
|
; CHECK-NEXT: i32 0, label [[IF_THEN]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: call void @foo1() #[[ATTR3:[0-9]+]]
|
|
; CHECK-NEXT: br label [[IF_END]]
|
|
; CHECK: if.end:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp = icmp ult i32 %x, 2
|
|
br i1 %cmp, label %if.then, label %lor.lhs.false3
|
|
|
|
lor.lhs.false3: ; preds = %lor.lhs.false
|
|
%cmp5 = icmp eq i32 %x, 3
|
|
br i1 %cmp5, label %if.then, label %lor.lhs.false6
|
|
|
|
lor.lhs.false6: ; preds = %lor.lhs.false3
|
|
%cmp8 = icmp eq i32 %x, 4
|
|
br i1 %cmp8, label %if.then, label %lor.lhs.false9
|
|
|
|
lor.lhs.false9: ; preds = %lor.lhs.false6
|
|
%cmp11 = icmp eq i32 %x, 6
|
|
br i1 %cmp11, label %if.then, label %if.end
|
|
|
|
if.then: ; preds = %lor.lhs.false9, %lor.lhs.false6, %lor.lhs.false3, %lor.lhs.false, %entry
|
|
call void @foo1() noredzone
|
|
br label %if.end
|
|
|
|
if.end: ; preds = %if.then, %lor.lhs.false9
|
|
ret void
|
|
}
|
|
|
|
; test14 - handle switch formation with ult.
|
|
define void @test14(i32 %x) nounwind ssp noredzone {
|
|
; CHECK-LABEL: @test14(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: switch i32 [[X:%.*]], label [[IF_END:%.*]] [
|
|
; CHECK-NEXT: i32 6, label [[IF_THEN:%.*]]
|
|
; CHECK-NEXT: i32 4, label [[IF_THEN]]
|
|
; CHECK-NEXT: i32 3, label [[IF_THEN]]
|
|
; CHECK-NEXT: i32 2, label [[IF_THEN]]
|
|
; CHECK-NEXT: i32 1, label [[IF_THEN]]
|
|
; CHECK-NEXT: i32 0, label [[IF_THEN]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: call void @foo1() #[[ATTR3]]
|
|
; CHECK-NEXT: br label [[IF_END]]
|
|
; CHECK: if.end:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp = icmp ugt i32 %x, 2
|
|
br i1 %cmp, label %lor.lhs.false3, label %if.then
|
|
|
|
lor.lhs.false3: ; preds = %lor.lhs.false
|
|
%cmp5 = icmp ne i32 %x, 3
|
|
br i1 %cmp5, label %lor.lhs.false6, label %if.then
|
|
|
|
lor.lhs.false6: ; preds = %lor.lhs.false3
|
|
%cmp8 = icmp ne i32 %x, 4
|
|
br i1 %cmp8, label %lor.lhs.false9, label %if.then
|
|
|
|
lor.lhs.false9: ; preds = %lor.lhs.false6
|
|
%cmp11 = icmp ne i32 %x, 6
|
|
br i1 %cmp11, label %if.end, label %if.then
|
|
|
|
if.then: ; preds = %lor.lhs.false9, %lor.lhs.false6, %lor.lhs.false3, %lor.lhs.false, %entry
|
|
call void @foo1() noredzone
|
|
br label %if.end
|
|
|
|
if.end: ; preds = %if.then, %lor.lhs.false9
|
|
ret void
|
|
}
|
|
|
|
; Don't crash on ginormous ranges.
|
|
define void @test15(i128 %x) nounwind {
|
|
; CHECK-LABEL: @test15(
|
|
; CHECK-NEXT: if.end:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i128 [[X:%.*]], 2
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%cmp = icmp ugt i128 %x, 2
|
|
br i1 %cmp, label %if.end, label %lor.false
|
|
|
|
lor.false:
|
|
%cmp2 = icmp ne i128 %x, 100000000000000000000
|
|
br i1 %cmp2, label %if.end, label %if.then
|
|
|
|
if.then:
|
|
call void @foo1() noredzone
|
|
br label %if.end
|
|
|
|
if.end:
|
|
ret void
|
|
|
|
}
|
|
|
|
; PR8675
|
|
; rdar://5134905
|
|
define zeroext i1 @test16(i32 %x) nounwind {
|
|
; CHECK-LABEL: @test16(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], -1
|
|
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[X_OFF]], 3
|
|
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[SWITCH]], i1 true, i1 false
|
|
; CHECK-NEXT: ret i1 [[SPEC_SELECT]]
|
|
;
|
|
entry:
|
|
%cmp.i = icmp eq i32 %x, 1
|
|
br i1 %cmp.i, label %lor.end, label %lor.lhs.false
|
|
|
|
lor.lhs.false:
|
|
%cmp.i2 = icmp eq i32 %x, 2
|
|
br i1 %cmp.i2, label %lor.end, label %lor.rhs
|
|
|
|
lor.rhs:
|
|
%cmp.i1 = icmp eq i32 %x, 3
|
|
br label %lor.end
|
|
|
|
lor.end:
|
|
%0 = phi i1 [ true, %lor.lhs.false ], [ true, %entry ], [ %cmp.i1, %lor.rhs ]
|
|
ret i1 %0
|
|
}
|
|
|
|
; Check that we don't turn an icmp into a switch where it's not useful.
|
|
define void @test17(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test17(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 3
|
|
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[Y:%.*]], 2
|
|
; CHECK-NEXT: [[OR_COND775:%.*]] = or i1 [[CMP]], [[SWITCH]]
|
|
; CHECK-NEXT: br i1 [[OR_COND775]], label [[LOR_LHS_FALSE8:%.*]], label [[COMMON_RET:%.*]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: lor.lhs.false8:
|
|
; CHECK-NEXT: tail call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%cmp = icmp ult i32 %x, 3
|
|
%switch = icmp ult i32 %y, 2
|
|
%or.cond775 = or i1 %cmp, %switch
|
|
br i1 %or.cond775, label %lor.lhs.false8, label %return
|
|
|
|
lor.lhs.false8:
|
|
tail call void @foo1()
|
|
ret void
|
|
|
|
return:
|
|
ret void
|
|
|
|
}
|
|
|
|
define void @test17_select(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test17_select(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 3
|
|
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[Y:%.*]], 2
|
|
; CHECK-NEXT: [[OR_COND775:%.*]] = select i1 [[CMP]], i1 true, i1 [[SWITCH]]
|
|
; CHECK-NEXT: br i1 [[OR_COND775]], label [[LOR_LHS_FALSE8:%.*]], label [[COMMON_RET:%.*]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: lor.lhs.false8:
|
|
; CHECK-NEXT: tail call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%cmp = icmp ult i32 %x, 3
|
|
%switch = icmp ult i32 %y, 2
|
|
%or.cond775 = select i1 %cmp, i1 true, i1 %switch
|
|
br i1 %or.cond775, label %lor.lhs.false8, label %return
|
|
|
|
lor.lhs.false8:
|
|
tail call void @foo1()
|
|
ret void
|
|
|
|
return:
|
|
ret void
|
|
|
|
}
|
|
|
|
define void @test18(i32 %arg) {
|
|
; CHECK-LABEL: @test18(
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[ARG_OFF:%.*]] = add i32 [[ARG:%.*]], -8
|
|
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[ARG_OFF]], 11
|
|
; CHECK-NEXT: br i1 [[SWITCH]], label [[BB19:%.*]], label [[BB20:%.*]]
|
|
; CHECK: bb19:
|
|
; CHECK-NEXT: tail call void @foo1()
|
|
; CHECK-NEXT: br label [[BB20]]
|
|
; CHECK: bb20:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
bb:
|
|
%tmp = and i32 %arg, -2
|
|
%tmp1 = icmp eq i32 %tmp, 8
|
|
%tmp2 = icmp eq i32 %arg, 10
|
|
%tmp3 = or i1 %tmp1, %tmp2
|
|
%tmp4 = icmp eq i32 %arg, 11
|
|
%tmp5 = or i1 %tmp3, %tmp4
|
|
%tmp6 = icmp eq i32 %arg, 12
|
|
%tmp7 = or i1 %tmp5, %tmp6
|
|
br i1 %tmp7, label %bb19, label %bb8
|
|
|
|
bb8: ; preds = %bb
|
|
%tmp9 = add i32 %arg, -13
|
|
%tmp10 = icmp ult i32 %tmp9, 2
|
|
%tmp11 = icmp eq i32 %arg, 16
|
|
%tmp12 = or i1 %tmp10, %tmp11
|
|
%tmp13 = icmp eq i32 %arg, 17
|
|
%tmp14 = or i1 %tmp12, %tmp13
|
|
%tmp15 = icmp eq i32 %arg, 18
|
|
%tmp16 = or i1 %tmp14, %tmp15
|
|
%tmp17 = icmp eq i32 %arg, 15
|
|
%tmp18 = or i1 %tmp16, %tmp17
|
|
br i1 %tmp18, label %bb19, label %bb20
|
|
|
|
bb19: ; preds = %bb8, %bb
|
|
tail call void @foo1()
|
|
br label %bb20
|
|
|
|
bb20: ; preds = %bb19, %bb8
|
|
ret void
|
|
|
|
}
|
|
|
|
define void @PR26323(i1 %tobool23, i32 %tmp3) {
|
|
; CHECK-LABEL: @PR26323(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TOBOOL5:%.*]] = icmp ne i32 [[TMP3:%.*]], 0
|
|
; CHECK-NEXT: [[NEG14:%.*]] = and i32 [[TMP3]], -2
|
|
; CHECK-NEXT: [[CMP17:%.*]] = icmp ne i32 [[NEG14]], -1
|
|
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[TOBOOL5]], [[TOBOOL23:%.*]]
|
|
; CHECK-NEXT: [[OR_COND1:%.*]] = and i1 [[CMP17]], [[OR_COND]]
|
|
; CHECK-NEXT: br i1 [[OR_COND1]], label [[IF_END29:%.*]], label [[IF_THEN27:%.*]]
|
|
; CHECK: if.then27:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: if.end29:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%tobool5 = icmp ne i32 %tmp3, 0
|
|
%neg14 = and i32 %tmp3, -2
|
|
%cmp17 = icmp ne i32 %neg14, -1
|
|
%or.cond = and i1 %tobool5, %tobool23
|
|
%or.cond1 = and i1 %cmp17, %or.cond
|
|
br i1 %or.cond1, label %if.end29, label %if.then27
|
|
|
|
if.then27: ; preds = %entry
|
|
call void @foo1()
|
|
unreachable
|
|
|
|
if.end29: ; preds = %entry
|
|
ret void
|
|
}
|
|
|
|
; Form a switch when and'ing a negated power of two
|
|
define void @test19(i32 %arg) {
|
|
; CHECK-LABEL: @test19(
|
|
; CHECK-NEXT: switch i32 [[ARG:%.*]], label [[COMMON_RET:%.*]] [
|
|
; CHECK-NEXT: i32 32, label [[IF:%.*]]
|
|
; CHECK-NEXT: i32 13, label [[IF]]
|
|
; CHECK-NEXT: i32 12, label [[IF]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%and = and i32 %arg, -2
|
|
%cmp1 = icmp eq i32 %and, 12
|
|
%cmp2 = icmp eq i32 %arg, 32
|
|
%pred = or i1 %cmp1, %cmp2
|
|
br i1 %pred, label %if, label %else
|
|
|
|
if:
|
|
call void @foo1()
|
|
ret void
|
|
|
|
else:
|
|
ret void
|
|
}
|
|
|
|
define void @test19_select(i32 %arg) {
|
|
; CHECK-LABEL: @test19_select(
|
|
; CHECK-NEXT: switch i32 [[ARG:%.*]], label [[COMMON_RET:%.*]] [
|
|
; CHECK-NEXT: i32 32, label [[IF:%.*]]
|
|
; CHECK-NEXT: i32 13, label [[IF]]
|
|
; CHECK-NEXT: i32 12, label [[IF]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%and = and i32 %arg, -2
|
|
%cmp1 = icmp eq i32 %and, 12
|
|
%cmp2 = icmp eq i32 %arg, 32
|
|
%pred = select i1 %cmp1, i1 true, i1 %cmp2
|
|
br i1 %pred, label %if, label %else
|
|
|
|
if:
|
|
call void @foo1()
|
|
ret void
|
|
|
|
else:
|
|
ret void
|
|
}
|
|
|
|
; Since %cmp1 is always false, a switch is never formed
|
|
define void @test20(i32 %arg) {
|
|
; CHECK-LABEL: @test20(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[ARG:%.*]], -2
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[AND]], 13
|
|
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[ARG]], 32
|
|
; CHECK-NEXT: [[PRED:%.*]] = or i1 [[CMP1]], [[CMP2]]
|
|
; CHECK-NEXT: br i1 [[PRED]], label [[IF:%.*]], label [[COMMON_RET:%.*]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%and = and i32 %arg, -2
|
|
%cmp1 = icmp eq i32 %and, 13
|
|
%cmp2 = icmp eq i32 %arg, 32
|
|
%pred = or i1 %cmp1, %cmp2
|
|
br i1 %pred, label %if, label %else
|
|
|
|
if:
|
|
call void @foo1()
|
|
ret void
|
|
|
|
else:
|
|
ret void
|
|
}
|
|
|
|
; Form a switch when or'ing a power of two
|
|
define void @test21(i32 %arg) {
|
|
; CHECK-LABEL: @test21(
|
|
; CHECK-NEXT: switch i32 [[ARG:%.*]], label [[IF:%.*]] [
|
|
; CHECK-NEXT: i32 32, label [[COMMON_RET:%.*]]
|
|
; CHECK-NEXT: i32 13, label [[COMMON_RET]]
|
|
; CHECK-NEXT: i32 12, label [[COMMON_RET]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%and = or i32 %arg, 1
|
|
%cmp1 = icmp ne i32 %and, 13
|
|
%cmp2 = icmp ne i32 %arg, 32
|
|
%pred = and i1 %cmp1, %cmp2
|
|
br i1 %pred, label %if, label %else
|
|
|
|
if:
|
|
call void @foo1()
|
|
ret void
|
|
|
|
else:
|
|
ret void
|
|
}
|
|
|
|
; Since %cmp1 is always false, a switch is never formed
|
|
define void @test22(i32 %arg) {
|
|
; CHECK-LABEL: @test22(
|
|
; CHECK-NEXT: [[AND:%.*]] = or i32 [[ARG:%.*]], 1
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[AND]], 12
|
|
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[ARG]], 32
|
|
; CHECK-NEXT: [[PRED:%.*]] = and i1 [[CMP1]], [[CMP2]]
|
|
; CHECK-NEXT: br i1 [[PRED]], label [[IF:%.*]], label [[COMMON_RET:%.*]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%and = or i32 %arg, 1
|
|
%cmp1 = icmp ne i32 %and, 12
|
|
%cmp2 = icmp ne i32 %arg, 32
|
|
%pred = and i1 %cmp1, %cmp2
|
|
br i1 %pred, label %if, label %else
|
|
|
|
if:
|
|
call void @foo1()
|
|
ret void
|
|
|
|
else:
|
|
ret void
|
|
}
|
|
|
|
define void @trunc_nuw_i1_condition(i32 %V) {
|
|
; CHECK-LABEL: @trunc_nuw_i1_condition(
|
|
; CHECK-NEXT: switch i32 [[V:%.*]], label [[F:%.*]] [
|
|
; CHECK-NEXT: i32 2, label [[T:%.*]]
|
|
; CHECK-NEXT: i32 0, label [[T]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: T:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
|
|
; CHECK: F:
|
|
; CHECK-NEXT: call void @foo2()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%C1 = icmp eq i32 %V, 2
|
|
br i1 %C1, label %T, label %N
|
|
N:
|
|
%C2 = trunc nuw i32 %V to i1
|
|
br i1 %C2, label %F, label %T
|
|
T:
|
|
call void @foo1( )
|
|
ret void
|
|
F:
|
|
call void @foo2( )
|
|
ret void
|
|
}
|
|
|
|
define void @neg_trunc_i1_condition(i32 %V) {
|
|
; CHECK-LABEL: @neg_trunc_i1_condition(
|
|
; CHECK-NEXT: [[C1:%.*]] = icmp ne i32 [[V:%.*]], 2
|
|
; CHECK-NEXT: [[C2:%.*]] = trunc i32 [[V]] to i1
|
|
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C1]], [[C2]]
|
|
; CHECK-NEXT: br i1 [[OR_COND]], label [[F:%.*]], label [[T:%.*]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: T:
|
|
; CHECK-NEXT: call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
|
|
; CHECK: F:
|
|
; CHECK-NEXT: call void @foo2()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%C1 = icmp eq i32 %V, 2
|
|
br i1 %C1, label %T, label %N
|
|
N:
|
|
%C2 = trunc i32 %V to i1
|
|
br i1 %C2, label %F, label %T
|
|
T:
|
|
call void @foo1( )
|
|
ret void
|
|
F:
|
|
call void @foo2( )
|
|
ret void
|
|
}
|
|
|
|
define void @extra_cond_is_eq_cmp(i8 %c, i32 %x) {
|
|
; CHECK-LABEL: @extra_cond_is_eq_cmp(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 32
|
|
; CHECK-NEXT: [[TMP0:%.*]] = freeze i1 [[CMP]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]]
|
|
; CHECK: switch.early.test:
|
|
; CHECK-NEXT: switch i8 [[C:%.*]], label [[COMMON_RET:%.*]] [
|
|
; CHECK-NEXT: i8 99, label [[IF_THEN]]
|
|
; CHECK-NEXT: i8 97, label [[IF_THEN]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: tail call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
entry:
|
|
%cmp = icmp eq i32 %x, 32
|
|
%cmp4 = icmp eq i8 %c, 97
|
|
%or.cond = or i1 %cmp, %cmp4
|
|
%cmp9 = icmp eq i8 %c, 99
|
|
%or.cond11 = or i1 %or.cond, %cmp9
|
|
br i1 %or.cond11, label %if.then, label %if.end
|
|
|
|
if.then:
|
|
tail call void @foo1()
|
|
ret void
|
|
|
|
if.end:
|
|
ret void
|
|
|
|
}
|
|
|
|
define void @extra_cond_is_eq_cmp_c(i8 %c, i32 %x) {
|
|
; CHECK-LABEL: @extra_cond_is_eq_cmp_c(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 32
|
|
; CHECK-NEXT: [[TMP0:%.*]] = freeze i1 [[CMP]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]]
|
|
; CHECK: switch.early.test:
|
|
; CHECK-NEXT: switch i8 [[C:%.*]], label [[COMMON_RET:%.*]] [
|
|
; CHECK-NEXT: i8 99, label [[IF_THEN]]
|
|
; CHECK-NEXT: i8 97, label [[IF_THEN]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: tail call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
entry:
|
|
%cmp = icmp eq i32 %x, 32
|
|
%cmp4 = icmp eq i8 %c, 97
|
|
%or.cond = or i1 %cmp4, %cmp
|
|
%cmp9 = icmp eq i8 %c, 99
|
|
%or.cond11 = or i1 %or.cond, %cmp9
|
|
br i1 %or.cond11, label %if.then, label %if.end
|
|
|
|
if.then:
|
|
tail call void @foo1()
|
|
ret void
|
|
|
|
if.end:
|
|
ret void
|
|
|
|
}
|
|
|
|
define void @and_chain_trunc_nuw_i1_condition(i8 %x) {
|
|
; CHECK-LABEL: @and_chain_trunc_nuw_i1_condition(
|
|
; CHECK-NEXT: switch i8 [[X:%.*]], label [[IF_THEN:%.*]] [
|
|
; CHECK-NEXT: i8 4, label [[COMMON_RET:%.*]]
|
|
; CHECK-NEXT: i8 3, label [[COMMON_RET]]
|
|
; CHECK-NEXT: i8 2, label [[COMMON_RET]]
|
|
; CHECK-NEXT: i8 0, label [[COMMON_RET]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: tail call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%add = add nsw i8 %x, -2
|
|
%icmp = icmp ugt i8 %add, 2
|
|
%trunc = trunc nuw i8 %x to i1
|
|
%and = select i1 %icmp, i1 %trunc, i1 false
|
|
br i1 %and, label %if.then, label %if.end
|
|
if.then:
|
|
tail call void @foo1()
|
|
ret void
|
|
if.end:
|
|
ret void
|
|
}
|
|
|
|
define void @or_chain_trunc_nuw_i1_condition(i8 %x) {
|
|
; CHECK-LABEL: @or_chain_trunc_nuw_i1_condition(
|
|
; CHECK-NEXT: [[X_OFF:%.*]] = add i8 [[X:%.*]], -1
|
|
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[X_OFF]], 2
|
|
; CHECK-NEXT: br i1 [[SWITCH]], label [[IF_THEN:%.*]], label [[COMMON_RET:%.*]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: tail call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%icmp = icmp eq i8 %x, 2
|
|
%trunc = trunc nuw i8 %x to i1
|
|
%or = select i1 %icmp, i1 true, i1 %trunc
|
|
br i1 %or, label %if.then, label %if.end
|
|
if.then:
|
|
tail call void @foo1()
|
|
ret void
|
|
if.end:
|
|
ret void
|
|
}
|
|
|
|
define void @neg_and_chain_trunc_i1_condition(i8 %x) {
|
|
; CHECK-LABEL: @neg_and_chain_trunc_i1_condition(
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[X:%.*]], -2
|
|
; CHECK-NEXT: [[ICMP:%.*]] = icmp ugt i8 [[ADD]], 2
|
|
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[X]] to i1
|
|
; CHECK-NEXT: [[AND:%.*]] = select i1 [[ICMP]], i1 [[TRUNC]], i1 false
|
|
; CHECK-NEXT: br i1 [[AND]], label [[IF_THEN:%.*]], label [[COMMON_RET:%.*]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: tail call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%add = add nsw i8 %x, -2
|
|
%icmp = icmp ugt i8 %add, 2
|
|
%trunc = trunc i8 %x to i1
|
|
%and = select i1 %icmp, i1 %trunc, i1 false
|
|
br i1 %and, label %if.then, label %if.end
|
|
if.then:
|
|
tail call void @foo1()
|
|
ret void
|
|
if.end:
|
|
ret void
|
|
}
|
|
|
|
define void @and_chain_trunc_nuw_not_i1_condition(i8 %x) {
|
|
; CHECK-LABEL: @and_chain_trunc_nuw_not_i1_condition(
|
|
; CHECK-NEXT: [[X_OFF:%.*]] = add i8 [[X:%.*]], -1
|
|
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[X_OFF]], 4
|
|
; CHECK-NEXT: br i1 [[SWITCH]], label [[COMMON_RET:%.*]], label [[IF_THEN:%.*]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: tail call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%add = add nsw i8 %x, -2
|
|
%icmp = icmp ugt i8 %add, 2
|
|
%trunc = trunc nuw i8 %x to i1
|
|
%not = xor i1 %trunc, true
|
|
%and = select i1 %icmp, i1 %not, i1 false
|
|
br i1 %and, label %if.then, label %if.end
|
|
if.then:
|
|
tail call void @foo1()
|
|
ret void
|
|
if.end:
|
|
ret void
|
|
}
|
|
|
|
define void @or_chain_trunc_nuw_not_i1_condition(i8 %x) {
|
|
; CHECK-LABEL: @or_chain_trunc_nuw_not_i1_condition(
|
|
; CHECK-NEXT: switch i8 [[X:%.*]], label [[COMMON_RET:%.*]] [
|
|
; CHECK-NEXT: i8 2, label [[IF_THEN:%.*]]
|
|
; CHECK-NEXT: i8 0, label [[IF_THEN]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: tail call void @foo1()
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
%icmp = icmp eq i8 %x, 2
|
|
%trunc = trunc nuw i8 %x to i1
|
|
%not = xor i1 %trunc, true
|
|
%or = select i1 %icmp, i1 true, i1 %not
|
|
br i1 %or, label %if.then, label %if.end
|
|
if.then:
|
|
tail call void @foo1()
|
|
ret void
|
|
if.end:
|
|
ret void
|
|
}
|
|
|
|
!0 = !{!"function_entry_count", i32 100}
|
|
!1 = !{!"branch_weights", i32 6, i32 10}
|
|
;.
|
|
; DL: attributes #[[ATTR0:[0-9]+]] = { noredzone nounwind ssp }
|
|
; DL: attributes #[[ATTR1:[0-9]+]] = { nounwind }
|
|
; DL: attributes #[[ATTR2]] = { noredzone nounwind }
|
|
; DL: attributes #[[ATTR3]] = { noredzone }
|
|
;.
|
|
; DL: [[META0:![0-9]+]] = !{!"function_entry_count", i32 100}
|
|
; DL: [[PROF1]] = !{!"branch_weights", i32 10, i32 3, i32 3}
|
|
; DL: [[PROF2]] = !{!"branch_weights", i32 6, i32 5, i32 5}
|
|
;.
|