Files
clang-p2996/llvm/test/Transforms/InstCombine/unreachable-code.ll
Nikita Popov d01aec4c76 [InstCombine] Set dead phi inputs to poison in more cases
Set phi inputs to poison whenever we find a dead edge (either
during initial worklist population or the main InstCombine run),
instead of only doing this for successors of dead blocks.

This means that the phi operand is set to poison even if for
critical edges without an intermediate block.

There are quite a few test changes, because the pattern is fairly
common in vectorizer output, for cases where we know the vectorized
loop will be entered.
2023-08-01 11:53:47 +02:00

546 lines
12 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
; RUN: opt -S -passes=instcombine -instcombine-infinite-loop-threshold=2 < %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: {{.*}}