; 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
}
declare void @invoke(ptr)
declare i32 @__gxx_personality_v0(...)
define void @test(i1 %x) personality ptr @__gxx_personality_v0 {
; CHECK-LABEL: define void @test
; CHECK-SAME: (i1 [[X:%.*]]) personality ptr @__gxx_personality_v0 {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[X]], label [[IF_ELSE:%.*]], label [[CLEAN1:%.*]]
; CHECK: if.else:
; CHECK-NEXT: store i32 1, ptr undef, align 4
; CHECK-NEXT: invoke void @invoke(ptr poison)
; CHECK-NEXT: to label [[CONT:%.*]] unwind label [[LPAD5:%.*]]
; CHECK: cont:
; CHECK-NEXT: invoke void @invoke(ptr poison)
; CHECK-NEXT: to label [[CLEAN1]] unwind label [[LPAD6:%.*]]
; CHECK: lpad5:
; CHECK-NEXT: [[TMP0:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: br label [[CLEAN1]]
; CHECK: lpad6:
; CHECK-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: br label [[CLEAN2:%.*]]
; CHECK: clean1:
; CHECK-NEXT: ret void
; CHECK: clean2:
; CHECK-NEXT: ret void
;
entry:
%ref = alloca ptr
br i1 %x, label %if.else, label %clean1
if.else:
store i32 1, ptr undef
invoke void @invoke(ptr %ref)
to label %cont unwind label %lpad5
cont:
invoke void @invoke(ptr %ref)
to label %clean1 unwind label %lpad6
lpad5:
%13 = landingpad { ptr, i32 }
cleanup
br label %clean1
lpad6:
%14 = landingpad { ptr, i32 }
cleanup
br label %clean2
clean1:
ret void
clean2:
ret void
}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; DEFAULT_ITER: {{.*}}
; MAX1: {{.*}}