llvm/llvm/test/Transforms/InstCombine/unreachable-code.ll

; 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: {{.*}}