545 lines
12 KiB
LLVM
545 lines
12 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
|
; RUN: opt -S -passes=instcombine < %s | FileCheck %s --check-prefixes=CHECK,DEFAULT_ITER
|
|
; RUN: opt -S -passes='instcombine<max-iterations=1>' < %s | FileCheck %s --check-prefixes=CHECK,MAX1
|
|
|
|
declare void @dummy()
|
|
declare void @llvm.assume(i1)
|
|
|
|
define i32 @br_true(i1 %x) {
|
|
; CHECK-LABEL: define i32 @br_true
|
|
; CHECK-SAME: (i1 [[X:%.*]]) {
|
|
; CHECK-NEXT: br i1 true, label [[IF:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: br label [[JOIN:%.*]]
|
|
; CHECK: else:
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: ret i32 1
|
|
;
|
|
%c = or i1 %x, true
|
|
br i1 %c, label %if, label %else
|
|
|
|
if:
|
|
call void @dummy()
|
|
br label %join
|
|
|
|
else:
|
|
call void @dummy()
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi i32 [ 1, %if ], [ 2, %else ]
|
|
ret i32 %phi
|
|
}
|
|
|
|
define i32 @br_false(i1 %x) {
|
|
; CHECK-LABEL: define i32 @br_false
|
|
; CHECK-SAME: (i1 [[X:%.*]]) {
|
|
; CHECK-NEXT: br i1 false, label [[IF:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: br label [[JOIN:%.*]]
|
|
; CHECK: else:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: ret i32 2
|
|
;
|
|
%c = and i1 %x, false
|
|
br i1 %c, label %if, label %else
|
|
|
|
if:
|
|
call void @dummy()
|
|
br label %join
|
|
|
|
else:
|
|
call void @dummy()
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi i32 [ 1, %if ], [ 2, %else ]
|
|
ret i32 %phi
|
|
}
|
|
|
|
define i32 @br_undef(i1 %x) {
|
|
; CHECK-LABEL: define i32 @br_undef
|
|
; CHECK-SAME: (i1 [[X:%.*]]) {
|
|
; CHECK-NEXT: br i1 undef, label [[IF:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: br label [[JOIN:%.*]]
|
|
; CHECK: else:
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: ret i32 poison
|
|
;
|
|
%c = xor i1 %x, undef
|
|
br i1 %c, label %if, label %else
|
|
|
|
if:
|
|
call void @dummy()
|
|
br label %join
|
|
|
|
else:
|
|
call void @dummy()
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi i32 [ 1, %if ], [ 2, %else ]
|
|
ret i32 %phi
|
|
}
|
|
|
|
define i32 @br_true_phi_with_repeated_preds(i1 %x) {
|
|
; CHECK-LABEL: define i32 @br_true_phi_with_repeated_preds
|
|
; CHECK-SAME: (i1 [[X:%.*]]) {
|
|
; CHECK-NEXT: br i1 true, label [[IF:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: br label [[JOIN:%.*]]
|
|
; CHECK: else:
|
|
; CHECK-NEXT: br i1 false, label [[JOIN]], label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: ret i32 1
|
|
;
|
|
%c = or i1 %x, true
|
|
br i1 %c, label %if, label %else
|
|
|
|
if:
|
|
call void @dummy()
|
|
br label %join
|
|
|
|
else:
|
|
br i1 false, label %join, label %join
|
|
|
|
join:
|
|
%phi = phi i32 [ 1, %if ], [ 2, %else ], [ 2, %else ]
|
|
ret i32 %phi
|
|
}
|
|
|
|
define i32 @br_true_const_phi_direct_edge(i1 %x) {
|
|
; CHECK-LABEL: define i32 @br_true_const_phi_direct_edge
|
|
; CHECK-SAME: (i1 [[X:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 true, label [[IF:%.*]], label [[JOIN:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: ret i32 2
|
|
;
|
|
entry:
|
|
br i1 true, label %if, label %join
|
|
|
|
if:
|
|
call void @dummy()
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi i32 [ 1, %entry ], [ 2, %if ]
|
|
ret i32 %phi
|
|
}
|
|
|
|
define i32 @br_true_var_phi_direct_edge(i1 %x) {
|
|
; CHECK-LABEL: define i32 @br_true_var_phi_direct_edge
|
|
; CHECK-SAME: (i1 [[X:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 true, label [[IF:%.*]], label [[JOIN:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: ret i32 2
|
|
;
|
|
entry:
|
|
%c = or i1 %x, true
|
|
br i1 %c, label %if, label %join
|
|
|
|
if:
|
|
call void @dummy()
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi i32 [ 1, %entry ], [ 2, %if ]
|
|
ret i32 %phi
|
|
}
|
|
|
|
define void @switch_case(i32 %x) {
|
|
; CHECK-LABEL: define void @switch_case
|
|
; CHECK-SAME: (i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: switch i32 0, label [[DEFAULT:%.*]] [
|
|
; CHECK-NEXT: i32 0, label [[CASE0:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: case0:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: default:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%v = and i32 %x, 0
|
|
switch i32 %v, label %default [
|
|
i32 0, label %case0
|
|
]
|
|
|
|
case0:
|
|
call void @dummy()
|
|
ret void
|
|
|
|
default:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @switch_default(i32 %x) {
|
|
; CHECK-LABEL: define void @switch_default
|
|
; CHECK-SAME: (i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: switch i32 -1, label [[DEFAULT:%.*]] [
|
|
; CHECK-NEXT: i32 0, label [[CASE0:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: case0:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: default:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%v = or i32 %x, -1
|
|
switch i32 %v, label %default [
|
|
i32 0, label %case0
|
|
]
|
|
|
|
case0:
|
|
call void @dummy()
|
|
ret void
|
|
|
|
default:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @switch_undef(i32 %x) {
|
|
; CHECK-LABEL: define void @switch_undef
|
|
; CHECK-SAME: (i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: switch i32 undef, label [[DEFAULT:%.*]] [
|
|
; CHECK-NEXT: i32 0, label [[CASE0:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: case0:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: default:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%v = xor i32 %x, undef
|
|
switch i32 %v, label %default [
|
|
i32 0, label %case0
|
|
]
|
|
|
|
case0:
|
|
call void @dummy()
|
|
ret void
|
|
|
|
default:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @non_term_unreachable() {
|
|
; CHECK-LABEL: define void @non_term_unreachable() {
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: store i1 true, ptr poison, align 1
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @dummy()
|
|
call void @dummy() nounwind willreturn
|
|
store i1 true, ptr poison
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define i32 @non_term_unreachable_phi(i1 %c) {
|
|
; CHECK-LABEL: define i32 @non_term_unreachable_phi
|
|
; CHECK-SAME: (i1 [[C:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: store i1 true, ptr poison, align 1
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: ret i32 2
|
|
;
|
|
entry:
|
|
br i1 %c, label %if, label %join
|
|
|
|
if:
|
|
store i1 true, ptr poison
|
|
call void @dummy()
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi i32 [ 1, %if], [ 2, %entry ]
|
|
ret i32 %phi
|
|
}
|
|
|
|
define void @non_term_unreachable_following_blocks() {
|
|
; CHECK-LABEL: define void @non_term_unreachable_following_blocks() {
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: store i1 true, ptr poison, align 1
|
|
; CHECK-NEXT: br label [[SPLIT:%.*]]
|
|
; CHECK: split:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
;
|
|
call void @dummy()
|
|
store i1 true, ptr poison
|
|
call void @dummy()
|
|
br label %split
|
|
|
|
split:
|
|
call void @dummy()
|
|
br label %loop
|
|
|
|
loop:
|
|
call void @dummy()
|
|
br label %loop
|
|
}
|
|
|
|
define void @br_not_into_loop(i1 %x) {
|
|
; CHECK-LABEL: define void @br_not_into_loop
|
|
; CHECK-SAME: (i1 [[X:%.*]]) {
|
|
; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%c = or i1 %x, true
|
|
br i1 %c, label %exit, label %loop
|
|
|
|
loop:
|
|
call void @dummy()
|
|
br label %loop
|
|
|
|
exit:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @br_into_loop(i1 %x) {
|
|
; CHECK-LABEL: define void @br_into_loop
|
|
; CHECK-SAME: (i1 [[X:%.*]]) {
|
|
; CHECK-NEXT: br i1 true, label [[LOOP:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%c = or i1 %x, true
|
|
br i1 %c, label %loop, label %exit
|
|
|
|
loop:
|
|
call void @dummy()
|
|
br label %loop
|
|
|
|
exit:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @two_br_not_into_loop(i1 %x) {
|
|
; CHECK-LABEL: define void @two_br_not_into_loop
|
|
; CHECK-SAME: (i1 [[X:%.*]]) {
|
|
; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[LOOP:%.*]]
|
|
; CHECK: bb2:
|
|
; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[LOOP]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%c = or i1 %x, true
|
|
br i1 %c, label %bb2, label %loop
|
|
|
|
bb2:
|
|
%c2 = or i1 %x, true
|
|
br i1 %c2, label %exit, label %loop
|
|
|
|
loop:
|
|
call void @dummy()
|
|
br label %loop
|
|
|
|
exit:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @one_br_into_loop_one_not(i1 %x, i1 %c2) {
|
|
; CHECK-LABEL: define void @one_br_into_loop_one_not
|
|
; CHECK-SAME: (i1 [[X:%.*]], i1 [[C2:%.*]]) {
|
|
; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[LOOP:%.*]]
|
|
; CHECK: bb2:
|
|
; CHECK-NEXT: br i1 [[C2]], label [[EXIT:%.*]], label [[LOOP]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%c = or i1 %x, true
|
|
br i1 %c, label %bb2, label %loop
|
|
|
|
bb2:
|
|
br i1 %c2, label %exit, label %loop
|
|
|
|
loop:
|
|
call void @dummy()
|
|
br label %loop
|
|
|
|
exit:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @two_br_not_into_loop_with_split(i1 %x) {
|
|
; CHECK-LABEL: define void @two_br_not_into_loop_with_split
|
|
; CHECK-SAME: (i1 [[X:%.*]]) {
|
|
; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[SPLIT1:%.*]]
|
|
; CHECK: bb2:
|
|
; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[SPLIT2:%.*]]
|
|
; CHECK: split1:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: split2:
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%c = or i1 %x, true
|
|
br i1 %c, label %bb2, label %split1
|
|
|
|
bb2:
|
|
%c2 = or i1 %x, true
|
|
br i1 %c2, label %exit, label %split2
|
|
|
|
split1:
|
|
call void @dummy()
|
|
br label %loop
|
|
|
|
split2:
|
|
call void @dummy()
|
|
br label %loop
|
|
|
|
loop:
|
|
call void @dummy()
|
|
br label %loop
|
|
|
|
exit:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @irreducible() {
|
|
; CHECK-LABEL: define void @irreducible() {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 false, label [[LOOP2:%.*]], label [[LOOP1:%.*]]
|
|
; CHECK: loop1:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: br label [[LOOP2]]
|
|
; CHECK: loop2:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[LOOP1]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br i1 false, label %loop2, label %loop1
|
|
|
|
loop1:
|
|
call void @dummy()
|
|
br label %loop2
|
|
|
|
loop2:
|
|
call void @dummy()
|
|
br i1 true, label %exit, label %loop1
|
|
|
|
exit:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @really_unreachable() {
|
|
; CHECK-LABEL: define void @really_unreachable() {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: unreachable:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
ret void
|
|
|
|
unreachable:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @really_unreachable_predecessor() {
|
|
; CHECK-LABEL: define void @really_unreachable_predecessor() {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 false, label [[BB:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: unreachable:
|
|
; CHECK-NEXT: br label [[BB]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br i1 false, label %bb, label %exit
|
|
|
|
unreachable:
|
|
call void @dummy()
|
|
br label %bb
|
|
|
|
bb:
|
|
call void @dummy()
|
|
ret void
|
|
|
|
exit:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define i32 @pr64235() {
|
|
; CHECK-LABEL: define i32 @pr64235() {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 false, label [[BB:%.*]], label [[BB3:%.*]]
|
|
; CHECK: bb3:
|
|
; CHECK-NEXT: store i1 true, ptr poison, align 1
|
|
; CHECK-NEXT: br label [[BB2:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: br label [[BB2]]
|
|
; CHECK: bb2:
|
|
; CHECK-NEXT: br label [[BB]]
|
|
;
|
|
entry:
|
|
br i1 false, label %bb, label %bb3
|
|
|
|
bb3:
|
|
call void @llvm.assume(i1 false)
|
|
br label %bb2
|
|
|
|
bb:
|
|
br label %bb2
|
|
|
|
bb2:
|
|
call void @llvm.assume(i1 false)
|
|
br label %bb
|
|
}
|
|
|
|
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
|
|
; DEFAULT_ITER: {{.*}}
|
|
; MAX1: {{.*}}
|