| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s |
| |
| declare void @llvm.assume(i1) |
| declare i8 @llvm.umin(i8, i8) |
| declare i8 @llvm.umax(i8, i8) |
| declare i8 @llvm.smin(i8, i8) |
| declare i8 @llvm.smax(i8, i8) |
| |
| ; If we don't know anything about the arguments, we can't do anything. |
| |
| define i8 @test0(i8 %x, i8 %y) { |
| ; CHECK-LABEL: @test0( |
| ; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.umin.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) |
| ; CHECK-NEXT: ret i8 [[R]] |
| ; |
| %r = call i8 @llvm.umin(i8 %x, i8 %y) |
| ret i8 %r |
| } |
| define i8 @test1(i8 %x, i8 %y) { |
| ; CHECK-LABEL: @test1( |
| ; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.umax.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) |
| ; CHECK-NEXT: ret i8 [[R]] |
| ; |
| %r = call i8 @llvm.umax(i8 %x, i8 %y) |
| ret i8 %r |
| } |
| define i8 @test2(i8 %x, i8 %y) { |
| ; CHECK-LABEL: @test2( |
| ; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) |
| ; CHECK-NEXT: ret i8 [[R]] |
| ; |
| %r = call i8 @llvm.smin(i8 %x, i8 %y) |
| ret i8 %r |
| } |
| define i8 @test3(i8 %x, i8 %y) { |
| ; CHECK-LABEL: @test3( |
| ; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) |
| ; CHECK-NEXT: ret i8 [[R]] |
| ; |
| %r = call i8 @llvm.smax(i8 %x, i8 %y) |
| ret i8 %r |
| } |
| |
| ; However, if we do know the ranges of arguments, we sometimes can tell that either one is always picked. |
| |
| define i8 @test4(i8 %x) { |
| ; CHECK-LABEL: @test4( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp ule i8 [[X:%.*]], 43 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 42) |
| ; CHECK-NEXT: ret i8 [[R]] |
| ; |
| %lim = icmp ule i8 %x, 43 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.umin(i8 %x, i8 42) |
| ret i8 %r |
| } |
| define i8 @test5(i8 %x) { |
| ; CHECK-LABEL: @test5( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp ule i8 [[X:%.*]], 42 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: ret i8 [[X]] |
| ; |
| %lim = icmp ule i8 %x, 42 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.umin(i8 %x, i8 42) |
| ret i8 %r |
| } |
| define i8 @test6(i8 %x) { |
| ; CHECK-LABEL: @test6( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp uge i8 [[X:%.*]], 42 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: ret i8 42 |
| ; |
| %lim = icmp uge i8 %x, 42 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.umin(i8 %x, i8 42) |
| ret i8 %r |
| } |
| define i8 @test7(i8 %x) { |
| ; CHECK-LABEL: @test7( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp uge i8 [[X:%.*]], 41 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 42) |
| ; CHECK-NEXT: ret i8 [[R]] |
| ; |
| %lim = icmp uge i8 %x, 41 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.umin(i8 %x, i8 42) |
| ret i8 %r |
| } |
| |
| define i8 @test8(i8 %x) { |
| ; CHECK-LABEL: @test8( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp uge i8 [[X:%.*]], 41 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 42) |
| ; CHECK-NEXT: ret i8 [[R]] |
| ; |
| %lim = icmp uge i8 %x, 41 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.umax(i8 %x, i8 42) |
| ret i8 %r |
| } |
| define i8 @test9(i8 %x) { |
| ; CHECK-LABEL: @test9( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp uge i8 [[X:%.*]], 42 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: ret i8 [[X]] |
| ; |
| %lim = icmp uge i8 %x, 42 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.umax(i8 %x, i8 42) |
| ret i8 %r |
| } |
| define i8 @test10(i8 %x) { |
| ; CHECK-LABEL: @test10( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp ule i8 [[X:%.*]], 42 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: ret i8 42 |
| ; |
| %lim = icmp ule i8 %x, 42 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.umax(i8 %x, i8 42) |
| ret i8 %r |
| } |
| define i8 @test11(i8 %x) { |
| ; CHECK-LABEL: @test11( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp ule i8 [[X:%.*]], 43 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 42) |
| ; CHECK-NEXT: ret i8 [[R]] |
| ; |
| %lim = icmp ule i8 %x, 43 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.umax(i8 %x, i8 42) |
| ret i8 %r |
| } |
| |
| define i8 @test12(i8 %x) { |
| ; CHECK-LABEL: @test12( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp sle i8 [[X:%.*]], 43 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 42) |
| ; CHECK-NEXT: ret i8 [[R]] |
| ; |
| %lim = icmp sle i8 %x, 43 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.smin(i8 %x, i8 42) |
| ret i8 %r |
| } |
| define i8 @test13(i8 %x) { |
| ; CHECK-LABEL: @test13( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp sle i8 [[X:%.*]], 42 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: ret i8 [[X]] |
| ; |
| %lim = icmp sle i8 %x, 42 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.smin(i8 %x, i8 42) |
| ret i8 %r |
| } |
| define i8 @test14(i8 %x) { |
| ; CHECK-LABEL: @test14( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 42 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: ret i8 42 |
| ; |
| %lim = icmp sge i8 %x, 42 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.smin(i8 %x, i8 42) |
| ret i8 %r |
| } |
| define i8 @test15(i8 %x) { |
| ; CHECK-LABEL: @test15( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 42) |
| ; CHECK-NEXT: ret i8 [[TMP1]] |
| ; |
| %lim = icmp sge i8 %x, 41 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.smin(i8 %x, i8 42) |
| ret i8 %r |
| } |
| |
| define i8 @test16(i8 %x) { |
| ; CHECK-LABEL: @test16( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 42) |
| ; CHECK-NEXT: ret i8 [[TMP1]] |
| ; |
| %lim = icmp sge i8 %x, 41 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.smax(i8 %x, i8 42) |
| ret i8 %r |
| } |
| define i8 @test17(i8 %x) { |
| ; CHECK-LABEL: @test17( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 42 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: ret i8 [[X]] |
| ; |
| %lim = icmp sge i8 %x, 42 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.smax(i8 %x, i8 42) |
| ret i8 %r |
| } |
| define i8 @test18(i8 %x) { |
| ; CHECK-LABEL: @test18( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp sle i8 [[X:%.*]], 42 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: ret i8 42 |
| ; |
| %lim = icmp sle i8 %x, 42 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.smax(i8 %x, i8 42) |
| ret i8 %r |
| } |
| define i8 @test19(i8 %x) { |
| ; CHECK-LABEL: @test19( |
| ; CHECK-NEXT: [[LIM:%.*]] = icmp sle i8 [[X:%.*]], 43 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]]) |
| ; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 42) |
| ; CHECK-NEXT: ret i8 [[R]] |
| ; |
| %lim = icmp sle i8 %x, 43 |
| call void @llvm.assume(i1 %lim) |
| %r = call i8 @llvm.smax(i8 %x, i8 42) |
| ret i8 %r |
| } |
| |
| declare void @body(i32) |
| |
| define void @test_bidirectional() { |
| ; CHECK-LABEL: @test_bidirectional( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[INDVAR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ] |
| ; CHECK-NEXT: call void @body(i32 65535) |
| ; CHECK-NEXT: [[INC]] = add nsw i32 [[INDVAR]], 1 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INDVAR]], 65535 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %for.body |
| |
| for.body: |
| %indvar = phi i32 [ 0, %entry ], [ %inc, %for.body ] |
| %smax = call i32 @llvm.smax.i32(i32 %indvar, i32 65535) |
| call void @body(i32 %smax) |
| %inc = add nsw i32 %indvar, 1 |
| %cmp = icmp slt i32 %indvar, 65535 |
| br i1 %cmp, label %for.body, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define i64 @test_at_use(i1 %cond, i64 %x) { |
| ; CHECK-LABEL: @test_at_use( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[IF_END:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[X:%.*]], 0 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: ret i64 0 |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[PHI:%.*]] = phi i64 [ [[X]], [[BB1]] ], [ 0, [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: ret i64 [[PHI]] |
| ; |
| entry: |
| br i1 %cond, label %bb1, label %if.end |
| |
| bb1: |
| %val = call i64 @llvm.smax.i64(i64 %x, i64 -1) |
| %cmp = icmp slt i64 %x, 0 |
| br i1 %cmp, label %if.then, label %if.end |
| |
| if.then: |
| ret i64 0 |
| |
| if.end: |
| %phi = phi i64 [%val, %bb1], [0, %entry] |
| ret i64 %phi |
| } |
| |
| define i8 @test_smax_to_umax_nneg(i8 %a, i8 %b) { |
| ; CHECK-LABEL: @test_smax_to_umax_nneg( |
| ; CHECK-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127 |
| ; CHECK-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127 |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[NNEG_A]], i8 [[NNEG_B]]) |
| ; CHECK-NEXT: ret i8 [[TMP1]] |
| ; |
| %nneg_a = and i8 %a, 127 |
| %nneg_b = and i8 %b, 127 |
| %ret = call i8 @llvm.smax.i8(i8 %nneg_a, i8 %nneg_b) |
| ret i8 %ret |
| } |
| |
| define i8 @test_smax_to_umax_neg(i8 %a, i8 %b) { |
| ; CHECK-LABEL: @test_smax_to_umax_neg( |
| ; CHECK-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128 |
| ; CHECK-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128 |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[NEG_A]], i8 [[NEG_B]]) |
| ; CHECK-NEXT: ret i8 [[TMP1]] |
| ; |
| %neg_a = or i8 %a, 128 |
| %neg_b = or i8 %b, 128 |
| %ret = call i8 @llvm.smax.i8(i8 %neg_a, i8 %neg_b) |
| ret i8 %ret |
| } |
| |
| define i8 @test_smin_to_umin_nneg(i8 %a, i8 %b) { |
| ; CHECK-LABEL: @test_smin_to_umin_nneg( |
| ; CHECK-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127 |
| ; CHECK-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127 |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[NNEG_A]], i8 [[NNEG_B]]) |
| ; CHECK-NEXT: ret i8 [[TMP1]] |
| ; |
| %nneg_a = and i8 %a, 127 |
| %nneg_b = and i8 %b, 127 |
| %ret = call i8 @llvm.smin.i8(i8 %nneg_a, i8 %nneg_b) |
| ret i8 %ret |
| } |
| |
| define i8 @test_smin_to_umin_neg(i8 %a, i8 %b) { |
| ; CHECK-LABEL: @test_smin_to_umin_neg( |
| ; CHECK-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128 |
| ; CHECK-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128 |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[NEG_A]], i8 [[NEG_B]]) |
| ; CHECK-NEXT: ret i8 [[TMP1]] |
| ; |
| %neg_a = or i8 %a, 128 |
| %neg_b = or i8 %b, 128 |
| %ret = call i8 @llvm.smin.i8(i8 %neg_a, i8 %neg_b) |
| ret i8 %ret |
| } |
| |
| define i8 @test_umax_nneg(i8 %a, i8 %b) { |
| ; CHECK-LABEL: @test_umax_nneg( |
| ; CHECK-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127 |
| ; CHECK-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127 |
| ; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.umax.i8(i8 [[NNEG_A]], i8 [[NNEG_B]]) |
| ; CHECK-NEXT: ret i8 [[RET]] |
| ; |
| %nneg_a = and i8 %a, 127 |
| %nneg_b = and i8 %b, 127 |
| %ret = call i8 @llvm.umax.i8(i8 %nneg_a, i8 %nneg_b) |
| ret i8 %ret |
| } |