
If we switch over ucmp/scmp and have two switch cases going to the same destination, we can convert into icmp+br. Fixes https://github.com/llvm/llvm-project/issues/105632.
709 lines
17 KiB
LLVM
709 lines
17 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
|
|
; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
|
|
|
|
define void @ucmp_gt1(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt1(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[BB1:.*]], label %[[BB2:.*]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %bb1 [
|
|
i8 -1, label %bb2
|
|
i8 0, label %bb2
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
|
|
define void @ucmp_gt2(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt2(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[BB1:.*]], label %[[BB2:.*]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %bb1 [
|
|
i8 0, label %bb2
|
|
i8 -1, label %bb2
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
|
|
define void @ucmp_lt1(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_lt1(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[BB2:.*]], label %[[BB1:.*]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %bb2 [
|
|
i8 1, label %bb1
|
|
i8 0, label %bb1
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
|
|
define void @ucmp_lt2(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_lt2(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[BB2:.*]], label %[[BB1:.*]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %bb2 [
|
|
i8 0, label %bb1
|
|
i8 1, label %bb1
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
|
|
define void @ucmp_eq1(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_eq1(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[BB1:.*]], label %[[BB2:.*]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %bb1 [
|
|
i8 -1, label %bb2
|
|
i8 1, label %bb2
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
|
|
define void @ucmp_eq2(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_eq2(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[BB1:.*]], label %[[BB2:.*]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %bb1 [
|
|
i8 1, label %bb2
|
|
i8 -1, label %bb2
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
|
|
define void @scmp_gt1(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @scmp_gt1(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[BB1:.*]], label %[[BB2:.*]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.scmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %bb1 [
|
|
i8 -1, label %bb2
|
|
i8 0, label %bb2
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
|
|
define void @scmp_gt2(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @scmp_gt2(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[BB1:.*]], label %[[BB2:.*]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.scmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %bb1 [
|
|
i8 0, label %bb2
|
|
i8 -1, label %bb2
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
|
|
define void @ucmp_gt_multiuse(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt_multiuse(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A]], i32 [[B]])
|
|
; CHECK-NEXT: call void @use(i8 [[RES]])
|
|
; CHECK-NEXT: switch i8 [[RES]], label %[[BB1:.*]] [
|
|
; CHECK-NEXT: i8 -1, label %[[BB2:.*]]
|
|
; CHECK-NEXT: i8 0, label %[[BB2]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
call void @use(i8 %res)
|
|
switch i8 %res, label %bb1 [
|
|
i8 -1, label %bb2
|
|
i8 0, label %bb2
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
|
|
define i32 @ucmp_gt_phi(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define i32 @ucmp_gt_phi(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*]]:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label %[[BB1:.*]], label %[[BB2:.*]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, %[[BB1]] ], [ 1, %[[ENTRY]] ]
|
|
; CHECK-NEXT: ret i32 [[PHI]]
|
|
;
|
|
entry:
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %bb1 [
|
|
i8 -1, label %bb2
|
|
i8 0, label %bb2
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
%phi = phi i32 [ 0, %bb1 ], [ 1, %entry ], [ 1, %entry ]
|
|
ret i32 %phi
|
|
}
|
|
|
|
define void @ucmp_gt_extra_case(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt_extra_case(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A]], i32 [[B]])
|
|
; CHECK-NEXT: switch i8 [[RES]], label %[[BB1:.*]] [
|
|
; CHECK-NEXT: i8 -1, label %[[BB2:.*]]
|
|
; CHECK-NEXT: i8 0, label %[[BB2]]
|
|
; CHECK-NEXT: i8 1, label %[[BB2]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %bb1 [
|
|
i8 -1, label %bb2
|
|
i8 0, label %bb2
|
|
i8 1, label %bb2
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
|
|
define void @ucmp_gt_wrong_case(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt_wrong_case(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A]], i32 [[B]])
|
|
; CHECK-NEXT: switch i8 [[RES]], label %[[BB1:.*]] [
|
|
; CHECK-NEXT: i8 -2, label %[[BB2:.*]]
|
|
; CHECK-NEXT: i8 0, label %[[BB2]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %bb1 [
|
|
i8 -2, label %bb2
|
|
i8 0, label %bb2
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
|
|
define void @ucmp_gt_not_same_succ(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt_not_same_succ(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A]], i32 [[B]])
|
|
; CHECK-NEXT: switch i8 [[RES]], label %[[BB1:.*]] [
|
|
; CHECK-NEXT: i8 -1, label %[[BB2:.*]]
|
|
; CHECK-NEXT: i8 0, label %[[BB3:.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB3]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %bb1 [
|
|
i8 -1, label %bb2
|
|
i8 0, label %bb3
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb3:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
|
|
define void @ucmp_gt_unpredictable(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt_unpredictable(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[BB1:.*]], label %[[BB2:.*]], !unpredictable [[META0:![0-9]+]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %bb1 [
|
|
i8 -1, label %bb2
|
|
i8 0, label %bb2
|
|
], !unpredictable !{}
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
|
|
define void @ucmp_gt_weights(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt_weights(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[BB1:.*]], label %[[BB2:.*]], !prof [[PROF1:![0-9]+]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %bb1 [
|
|
i8 -1, label %bb2
|
|
i8 0, label %bb2
|
|
], !prof !{!"branch_weights", i32 5, i32 10, i32 20}
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
|
|
define void @ucmp_gt_unreachable(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt_unreachable(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[BB1:.*]], label %[[BB2:.*]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %unreachable [
|
|
i8 -1, label %bb2
|
|
i8 0, label %bb2
|
|
i8 1, label %bb1
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
|
|
unreachable:
|
|
unreachable
|
|
}
|
|
|
|
define void @ucmp_lt_unreachable(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_lt_unreachable(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[BB1:.*]], label %[[BB2:.*]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %unreachable [
|
|
i8 -1, label %bb1
|
|
i8 0, label %bb2
|
|
i8 1, label %bb2
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
|
|
unreachable:
|
|
unreachable
|
|
}
|
|
|
|
define void @ucmp_eq_unreachable(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_eq_unreachable(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[BB1:.*]], label %[[BB2:.*]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %unreachable [
|
|
i8 -1, label %bb2
|
|
i8 0, label %bb1
|
|
i8 1, label %bb2
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
|
|
unreachable:
|
|
unreachable
|
|
}
|
|
|
|
define void @ucmp_gt_unreachable_multi_edge(i8 %x, i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt_unreachable_multi_edge(
|
|
; CHECK-SAME: i8 [[X:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*:]]
|
|
; CHECK-NEXT: switch i8 [[X]], label %[[UNREACHABLE:.*]] [
|
|
; CHECK-NEXT: i8 0, label %[[SW:.*]]
|
|
; CHECK-NEXT: i8 1, label %[[BB1:.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: [[SW]]:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label %[[BB1]], label %[[BB2:.*]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: [[UNREACHABLE]]:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
entry:
|
|
switch i8 %x, label %unreachable [
|
|
i8 0, label %sw
|
|
i8 1, label %bb1
|
|
]
|
|
|
|
sw:
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %unreachable [
|
|
i8 -1, label %bb2
|
|
i8 0, label %bb2
|
|
i8 1, label %bb1
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
|
|
unreachable:
|
|
%phi = phi i32 [ 0, %entry ], [ 1, %sw ]
|
|
unreachable
|
|
}
|
|
|
|
define void @ucmp_gt_unreachable_wrong_case(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt_unreachable_wrong_case(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A]], i32 [[B]])
|
|
; CHECK-NEXT: switch i8 [[RES]], label %[[UNREACHABLE:.*]] [
|
|
; CHECK-NEXT: i8 -2, label %[[BB2:.*]]
|
|
; CHECK-NEXT: i8 0, label %[[BB2]]
|
|
; CHECK-NEXT: i8 1, label %[[BB1:.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: [[UNREACHABLE]]:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %unreachable [
|
|
i8 -2, label %bb2
|
|
i8 0, label %bb2
|
|
i8 1, label %bb1
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
|
|
unreachable:
|
|
unreachable
|
|
}
|
|
|
|
define void @ucmp_gt_unreachable_no_two_equal_cases(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt_unreachable_no_two_equal_cases(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A]], i32 [[B]])
|
|
; CHECK-NEXT: switch i8 [[RES]], label %[[UNREACHABLE:.*]] [
|
|
; CHECK-NEXT: i8 -1, label %[[BB3:.*]]
|
|
; CHECK-NEXT: i8 0, label %[[BB2:.*]]
|
|
; CHECK-NEXT: i8 1, label %[[BB1:.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB3]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: [[UNREACHABLE]]:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %unreachable [
|
|
i8 -1, label %bb3
|
|
i8 0, label %bb2
|
|
i8 1, label %bb1
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb3:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
|
|
unreachable:
|
|
unreachable
|
|
}
|
|
|
|
define void @ucmp_gt_unreachable_three_equal_cases(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt_unreachable_three_equal_cases(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[BB1:.*:]]
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %unreachable [
|
|
i8 -1, label %bb1
|
|
i8 0, label %bb1
|
|
i8 1, label %bb1
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
ret void
|
|
|
|
unreachable:
|
|
unreachable
|
|
}
|
|
|
|
define void @ucmp_gt_unreachable_default_not_unreachable(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt_unreachable_default_not_unreachable(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A]], i32 [[B]])
|
|
; CHECK-NEXT: switch i8 [[RES]], label %[[NOT_UNREACHABLE:.*]] [
|
|
; CHECK-NEXT: i8 -1, label %[[BB2:.*]]
|
|
; CHECK-NEXT: i8 0, label %[[BB2]]
|
|
; CHECK-NEXT: i8 1, label %[[BB1:.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: [[NOT_UNREACHABLE]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %not.unreachable [
|
|
i8 -1, label %bb2
|
|
i8 0, label %bb2
|
|
i8 1, label %bb1
|
|
]
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
|
|
not.unreachable:
|
|
call void @foo()
|
|
br label %bb2
|
|
}
|
|
|
|
define void @ucmp_gt_unreachable_weights(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define void @ucmp_gt_unreachable_weights(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[A]], [[B]]
|
|
; CHECK-NEXT: br i1 [[TMP1]], label %[[BB1:.*]], label %[[BB2:.*]], !prof [[PROF1]]
|
|
; CHECK: [[BB1]]:
|
|
; CHECK-NEXT: call void @foo()
|
|
; CHECK-NEXT: br label %[[BB2]]
|
|
; CHECK: [[BB2]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%res = call i8 @llvm.ucmp.i8.i32(i32 %a, i32 %b)
|
|
switch i8 %res, label %unreachable [
|
|
i8 -1, label %bb2
|
|
i8 0, label %bb2
|
|
i8 1, label %bb1
|
|
], !prof !{!"branch_weights", i32 0, i32 10, i32 20, i32 5}
|
|
|
|
bb1:
|
|
call void @foo()
|
|
br label %bb2
|
|
|
|
bb2:
|
|
ret void
|
|
|
|
unreachable:
|
|
unreachable
|
|
}
|
|
|
|
declare void @use(i8)
|
|
declare void @foo()
|
|
;.
|
|
; CHECK: [[META0]] = !{}
|
|
; CHECK: [[PROF1]] = !{!"branch_weights", i32 5, i32 30}
|
|
;.
|