blob: 72ef1c79f3a8e5a5d67727dd4d54996afd68c63b [file] [log] [blame]
; 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: {{.*}}