llvm/llvm/test/Transforms/InstCombine/sink_to_unreachable.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=instcombine -S < %s | FileCheck %s

declare void @use(i32 %x)
declare i1 @cond()

define void @test_01(i32 %x, i32 %y) {
; CHECK-LABEL: @test_01(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[C2:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    br i1 [[C2]], label [[EXIT:%.*]], label [[UNREACHED:%.*]]
; CHECK:       unreached:
; CHECK-NEXT:    [[COMPARATOR:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT:    call void @use(i32 [[COMPARATOR]])
; CHECK-NEXT:    unreachable
; CHECK:       exit:
; CHECK-NEXT:    ret void
;
entry:
  %c1 = icmp eq i32 %x, %y
  %c2 = icmp slt i32 %x, %y
  %signed = select i1 %c2, i32 -1, i32 1
  %comparator = select i1 %c1, i32 0, i32 %signed
  br i1 %c2, label %exit, label %unreached

unreached:
  call void @use(i32 %comparator)
  unreachable

exit:
  ret void
}


define void @test_02(i32 %x, i32 %y) {
; CHECK-LABEL: @test_02(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[C2:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    br i1 [[C2]], label [[EXIT:%.*]], label [[MEDIUM:%.*]]
; CHECK:       medium:
; CHECK-NEXT:    [[C3:%.*]] = icmp sgt i32 [[X]], [[Y]]
; CHECK-NEXT:    br i1 [[C3]], label [[EXIT]], label [[UNREACHED:%.*]]
; CHECK:       unreached:
; CHECK-NEXT:    [[COMPARATOR:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT:    call void @use(i32 [[COMPARATOR]])
; CHECK-NEXT:    unreachable
; CHECK:       exit:
; CHECK-NEXT:    ret void
;
entry:
  %c1 = icmp eq i32 %x, %y
  %c2 = icmp slt i32 %x, %y
  %signed = select i1 %c2, i32 -1, i32 1
  %comparator = select i1 %c1, i32 0, i32 %signed
  br i1 %c2, label %exit, label %medium

medium:
  %c3 = icmp sgt i32 %x, %y
  br i1 %c3, label %exit, label %unreached

unreached:
  call void @use(i32 %comparator)
  unreachable

exit:
  ret void
}

define i32 @test_03(i32 %x, i32 %y) {
; CHECK-LABEL: @test_03(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[C2:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    br i1 [[C2]], label [[EXIT:%.*]], label [[MEDIUM:%.*]]
; CHECK:       medium:
; CHECK-NEXT:    [[C3:%.*]] = icmp sgt i32 [[X]], [[Y]]
; CHECK-NEXT:    br i1 [[C3]], label [[EXIT]], label [[UNREACHED:%.*]]
; CHECK:       unreached:
; CHECK-NEXT:    [[COMPARATOR:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT:    ret i32 [[COMPARATOR]]
; CHECK:       exit:
; CHECK-NEXT:    ret i32 0
;
entry:
  %c1 = icmp eq i32 %x, %y
  %c2 = icmp slt i32 %x, %y
  %signed = select i1 %c2, i32 -1, i32 1
  %comparator = select i1 %c1, i32 0, i32 %signed
  br i1 %c2, label %exit, label %medium

medium:
  %c3 = icmp sgt i32 %x, %y
  br i1 %c3, label %exit, label %unreached

unreached:
  ret i32 %comparator

exit:
  ret i32 0
}

define i32 @test_04(i32 %x, i1 %c) {
; CHECK-LABEL: @test_04(
; CHECK-NEXT:  bb0:
; CHECK-NEXT:    br i1 [[C:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK:       bb1:
; CHECK-NEXT:    br label [[BB3:%.*]]
; CHECK:       bb2:
; CHECK-NEXT:    br label [[BB3]]
; CHECK:       bb3:
; CHECK-NEXT:    [[P:%.*]] = phi i32 [ 0, [[BB1]] ], [ 1, [[BB2]] ]
; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], 1
; CHECK-NEXT:    [[R:%.*]] = add i32 [[P]], [[A]]
; CHECK-NEXT:    ret i32 [[R]]
;
bb0:
  %a = add i32 %x, 1
  br i1 %c, label %bb1, label %bb2
bb1:
  br label %bb3
bb2:
  br label %bb3
bb3:
  %p = phi i32 [0, %bb1], [1, %bb2]
  %r = add i32 %p, %a
  ret i32 %r
}

; Do not sink into a potentially hotter block.
define i32 @test_05_neg(i32 %x, i1 %cond) {
; CHECK-LABEL: @test_05_neg(
; CHECK-NEXT:  bb0:
; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], 1
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK:       bb1:
; CHECK-NEXT:    br label [[BB3:%.*]]
; CHECK:       bb2:
; CHECK-NEXT:    [[CALL:%.*]] = call i1 @cond()
; CHECK-NEXT:    br i1 [[CALL]], label [[BB2]], label [[BB3]]
; CHECK:       bb3:
; CHECK-NEXT:    [[P:%.*]] = phi i32 [ 0, [[BB1]] ], [ [[A]], [[BB2]] ]
; CHECK-NEXT:    ret i32 [[P]]
;
bb0:
  %a = add i32 %x, 1
  br i1 %cond, label %bb1, label %bb2
bb1:
  br label %bb3
bb2:
  %call = call i1 @cond()
  br i1 %call, label %bb2, label %bb3
bb3:
  %p = phi i32 [0, %bb1], [%a, %bb2]
  ret i32 %p
}

define i1 @sink_to_unreachable_ret(i16 %X)  {
; CHECK-LABEL: @sink_to_unreachable_ret(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
; CHECK:       unreach:
; CHECK-NEXT:    ret i1 poison
;
entry:
  br label %loop

loop:
  %p = icmp sgt i16 %X, 16
  br i1 true, label %loop, label %unreach

unreach:
  ret i1 %p
}

define void @sink_to_unreachable_condbr(i16 %X)  {
; CHECK-LABEL: @sink_to_unreachable_condbr(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
; CHECK:       unreach:
; CHECK-NEXT:    br i1 poison, label [[DUMMY:%.*]], label [[LOOP]]
; CHECK:       dummy:
; CHECK-NEXT:    unreachable
;
entry:
  br label %loop

loop:
  %p = icmp sgt i16 %X, 16
  br i1 true, label %loop, label %unreach

unreach:
  br i1 %p, label %dummy, label %loop

dummy:
  unreachable
}

define void @sink_to_unreachable_switch(i16 %X)  {
; CHECK-LABEL: @sink_to_unreachable_switch(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
; CHECK:       unreach:
; CHECK-NEXT:    switch i16 poison, label [[UNREACH_RET:%.*]] [
; CHECK-NEXT:    ]
; CHECK:       unreach.ret:
; CHECK-NEXT:    unreachable
;
entry:
  br label %loop

loop:
  %quantum = srem i16 %X, 32
  br i1 true, label %loop, label %unreach

unreach:
  switch i16 %quantum, label %unreach.ret []

unreach.ret:
  unreachable
}

define void @sink_to_unreachable_indirectbr(ptr %Ptr)  {
; CHECK-LABEL: @sink_to_unreachable_indirectbr(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
; CHECK:       unreach:
; CHECK-NEXT:    indirectbr ptr poison, [label %loop]
;
entry:
  br label %loop

loop:
  %gep = getelementptr inbounds ptr, ptr %Ptr, i16 1
  br i1 true, label %loop, label %unreach

unreach:
  indirectbr ptr %gep, [label %loop]
}

define void @sink_to_unreachable_invoke(ptr %Ptr) personality ptr @__CxxFrameHandler3 {
; CHECK-LABEL: @sink_to_unreachable_invoke(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
; CHECK:       unreach:
; CHECK-NEXT:    invoke void poison(i1 false)
; CHECK-NEXT:            to label [[DUMMY:%.*]] unwind label [[ICATCH_DISPATCH:%.*]]
; CHECK:       unreach2:
; CHECK-NEXT:    invoke void @__CxxFrameHandler3(ptr poison)
; CHECK-NEXT:            to label [[DUMMY]] unwind label [[ICATCH_DISPATCH]]
; CHECK:       unreach3:
; CHECK-NEXT:    [[CLEAN:%.*]] = cleanuppad within none []
; CHECK-NEXT:    invoke void @__CxxFrameHandler3(ptr poison) [ "funclet"(token [[CLEAN]]) ]
; CHECK-NEXT:            to label [[DUMMY]] unwind label [[ICATCH_DISPATCH]]
; CHECK:       icatch.dispatch:
; CHECK-NEXT:    [[TMP1:%.*]] = catchswitch within none [label %icatch] unwind to caller
; CHECK:       icatch:
; CHECK-NEXT:    [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null, i32 64, ptr null]
; CHECK-NEXT:    catchret from [[TMP2]] to label [[DUMMY2:%.*]]
; CHECK:       dummy:
; CHECK-NEXT:    ret void
; CHECK:       dummy2:
; CHECK-NEXT:    ret void
;
entry:
  br label %loop

loop:
  %gep = getelementptr inbounds ptr, ptr %Ptr, i16 1
  br i1 true, label %loop, label %unreach

unreach:
  invoke void %gep(i1 false)
  to label %dummy unwind label %icatch.dispatch

unreach2:
  invoke void @__CxxFrameHandler3(ptr %gep)
  to label %dummy unwind label %icatch.dispatch

unreach3:
  %clean = cleanuppad within none []
  invoke void @__CxxFrameHandler3(ptr %gep) [ "funclet"(token %clean) ]
  to label %dummy unwind label %icatch.dispatch

icatch.dispatch:
  %tmp1 = catchswitch within none [label %icatch] unwind to caller

icatch:
  %tmp2 = catchpad within %tmp1 [ptr null, i32 64, ptr null]
  catchret from %tmp2 to label %dummy2

dummy:
  ret void

dummy2:
  ret void
}

declare void @may_throw()
declare i32 @__CxxFrameHandler3(...)