| ; 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(...) |