diff --git a/llvm/test/Analysis/ValueTracking/knownbits-sat-addsub.ll b/llvm/test/Analysis/ValueTracking/knownbits-sat-addsub.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/ValueTracking/knownbits-sat-addsub.ll @@ -0,0 +1,219 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -passes=instsimplify -S < %s | FileCheck %s + +declare i8 @llvm.sadd.sat.i8(i8, i8) +declare i8 @llvm.ssub.sat.i8(i8, i8) +declare i8 @llvm.uadd.sat.i8(i8, i8) +declare i8 @llvm.usub.sat.i8(i8, i8) + +define i1 @uadd_sat_overflow(i8 %x, i8 %y) { +; CHECK-LABEL: @uadd_sat_overflow( +; CHECK-NEXT: [[LHS:%.*]] = or i8 [[X:%.*]], -128 +; CHECK-NEXT: [[RHS:%.*]] = or i8 [[Y:%.*]], -128 +; CHECK-NEXT: [[EXP:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[LHS]], i8 [[RHS]]) +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[EXP]], -2 +; CHECK-NEXT: ret i1 [[R]] +; + %lhs = or i8 %x, 128 + %rhs = or i8 %y, 128 + %exp = call i8 @llvm.uadd.sat.i8(i8 %lhs, i8 %rhs) + %r = icmp eq i8 %exp, 254 + ret i1 %r +} + +define i1 @uadd_sat_overflow_fail(i8 %x, i8 %y) { +; CHECK-LABEL: @uadd_sat_overflow_fail( +; CHECK-NEXT: [[LHS:%.*]] = or i8 [[X:%.*]], -128 +; CHECK-NEXT: [[RHS:%.*]] = or i8 [[Y:%.*]], 126 +; CHECK-NEXT: [[EXP:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[LHS]], i8 [[RHS]]) +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[EXP]], -2 +; CHECK-NEXT: ret i1 [[R]] +; + %lhs = or i8 %x, 128 + %rhs = or i8 %y, 126 + %exp = call i8 @llvm.uadd.sat.i8(i8 %lhs, i8 %rhs) + %r = icmp eq i8 %exp, 254 + ret i1 %r +} + +define i1 @usub_sat_overflow(i8 %x, i8 %y) { +; CHECK-LABEL: @usub_sat_overflow( +; CHECK-NEXT: [[LHS:%.*]] = and i8 [[X:%.*]], 127 +; CHECK-NEXT: [[RHS:%.*]] = or i8 [[Y:%.*]], -128 +; CHECK-NEXT: [[EXP:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[LHS]], i8 [[RHS]]) +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[EXP]], 1 +; CHECK-NEXT: ret i1 [[R]] +; + %lhs = and i8 %x, 127 + %rhs = or i8 %y, 128 + %exp = call i8 @llvm.usub.sat.i8(i8 %lhs, i8 %rhs) + %r = icmp eq i8 %exp, 1 + ret i1 %r +} + +define i1 @usub_sat_overflow_fail(i8 %x, i8 %y) { +; CHECK-LABEL: @usub_sat_overflow_fail( +; CHECK-NEXT: [[LHS:%.*]] = and i8 [[X:%.*]], 127 +; CHECK-NEXT: [[RHS:%.*]] = or i8 [[Y:%.*]], 126 +; CHECK-NEXT: [[EXP:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[LHS]], i8 [[RHS]]) +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[EXP]], 1 +; CHECK-NEXT: ret i1 [[R]] +; + %lhs = and i8 %x, 127 + %rhs = or i8 %y, 126 + %exp = call i8 @llvm.usub.sat.i8(i8 %lhs, i8 %rhs) + %r = icmp eq i8 %exp, 1 + ret i1 %r +} + +define i1 @sadd_sat_overflow_pos(i8 %x, i8 %y) { +; CHECK-LABEL: @sadd_sat_overflow_pos( +; CHECK-NEXT: [[XX:%.*]] = and i8 [[X:%.*]], 127 +; CHECK-NEXT: [[YY:%.*]] = and i8 [[Y:%.*]], 127 +; CHECK-NEXT: [[LHS:%.*]] = or i8 [[XX]], 64 +; CHECK-NEXT: [[RHS:%.*]] = or i8 [[YY]], 65 +; CHECK-NEXT: [[EXP:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[LHS]], i8 [[RHS]]) +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[EXP]], -128 +; CHECK-NEXT: ret i1 [[R]] +; + %xx = and i8 %x, 127 + %yy = and i8 %y, 127 + %lhs = or i8 %xx, 64 + %rhs = or i8 %yy, 65 + %exp = call i8 @llvm.sadd.sat.i8(i8 %lhs, i8 %rhs) + %r = icmp eq i8 %exp, 128 + ret i1 %r +} + +define i1 @sadd_sat_low_bits(i8 %x, i8 %y) { +; CHECK-LABEL: @sadd_sat_low_bits( +; CHECK-NEXT: [[XX:%.*]] = and i8 [[X:%.*]], 15 +; CHECK-NEXT: [[YY:%.*]] = and i8 [[Y:%.*]], 15 +; CHECK-NEXT: [[LHS:%.*]] = or i8 [[XX]], 1 +; CHECK-NEXT: [[RHS:%.*]] = and i8 [[YY]], -2 +; CHECK-NEXT: [[EXP:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[LHS]], i8 [[RHS]]) +; CHECK-NEXT: [[AND:%.*]] = and i8 [[EXP]], 1 +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND]], 0 +; CHECK-NEXT: ret i1 [[R]] +; + %xx = and i8 %x, 15 + %yy = and i8 %y, 15 + %lhs = or i8 %xx, 1 + %rhs = and i8 %yy, -2 + %exp = call i8 @llvm.sadd.sat.i8(i8 %lhs, i8 %rhs) + %and = and i8 %exp, 1 + %r = icmp eq i8 %and, 0 + ret i1 %r +} + +define i1 @sadd_sat_fail_may_overflow(i8 %x, i8 %y) { +; CHECK-LABEL: @sadd_sat_fail_may_overflow( +; CHECK-NEXT: [[LHS:%.*]] = or i8 [[X:%.*]], 1 +; CHECK-NEXT: [[RHS:%.*]] = and i8 [[Y:%.*]], -2 +; CHECK-NEXT: [[EXP:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[LHS]], i8 [[RHS]]) +; CHECK-NEXT: [[AND:%.*]] = and i8 [[EXP]], 1 +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND]], 0 +; CHECK-NEXT: ret i1 [[R]] +; + %lhs = or i8 %x, 1 + %rhs = and i8 %y, -2 + %exp = call i8 @llvm.sadd.sat.i8(i8 %lhs, i8 %rhs) + %and = and i8 %exp, 1 + %r = icmp eq i8 %and, 0 + ret i1 %r +} + +define i1 @sadd_sat_overflow_neg(i8 %x, i8 %y) { +; CHECK-LABEL: @sadd_sat_overflow_neg( +; CHECK-NEXT: [[LHS:%.*]] = or i8 [[X:%.*]], -64 +; CHECK-NEXT: [[RHS:%.*]] = or i8 [[Y:%.*]], -65 +; CHECK-NEXT: [[EXP:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[LHS]], i8 [[RHS]]) +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[EXP]], 127 +; CHECK-NEXT: ret i1 [[R]] +; + %lhs = or i8 %x, 192 + %rhs = or i8 %y, 191 + %exp = call i8 @llvm.sadd.sat.i8(i8 %lhs, i8 %rhs) + %r = icmp eq i8 %exp, 127 + ret i1 %r +} + +define i1 @ssub_sat_overflow_neg(i8 %x, i8 %y) { +; CHECK-LABEL: @ssub_sat_overflow_neg( +; CHECK-NEXT: [[XX:%.*]] = and i8 [[X:%.*]], 112 +; CHECK-NEXT: [[YY:%.*]] = and i8 [[Y:%.*]], 127 +; CHECK-NEXT: [[LHS:%.*]] = or i8 [[XX]], -128 +; CHECK-NEXT: [[RHS:%.*]] = or i8 [[YY]], 126 +; CHECK-NEXT: [[EXP:%.*]] = call i8 @llvm.ssub.sat.i8(i8 [[LHS]], i8 [[RHS]]) +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[EXP]], 32 +; CHECK-NEXT: ret i1 [[R]] +; + %xx = and i8 %x, 112 + %yy = and i8 %y, 127 + %lhs = or i8 %xx, 128 + %rhs = or i8 %yy, 126 + %exp = call i8 @llvm.ssub.sat.i8(i8 %lhs, i8 %rhs) + %r = icmp eq i8 %exp, 32 + ret i1 %r +} + +define i1 @ssub_sat_low_bits(i8 %x, i8 %y) { +; CHECK-LABEL: @ssub_sat_low_bits( +; CHECK-NEXT: [[XX:%.*]] = and i8 [[X:%.*]], 15 +; CHECK-NEXT: [[YY:%.*]] = and i8 [[Y:%.*]], 15 +; CHECK-NEXT: [[LHS:%.*]] = or i8 [[XX]], 17 +; CHECK-NEXT: [[RHS:%.*]] = and i8 [[YY]], -2 +; CHECK-NEXT: [[EXP:%.*]] = call i8 @llvm.ssub.sat.i8(i8 [[LHS]], i8 [[RHS]]) +; CHECK-NEXT: [[AND:%.*]] = and i8 [[EXP]], 1 +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND]], 0 +; CHECK-NEXT: ret i1 [[R]] +; + %xx = and i8 %x, 15 + %yy = and i8 %y, 15 + %lhs = or i8 %xx, 17 + %rhs = and i8 %yy, -2 + %exp = call i8 @llvm.ssub.sat.i8(i8 %lhs, i8 %rhs) + %and = and i8 %exp, 1 + %r = icmp eq i8 %and, 0 + ret i1 %r +} + +define i1 @ssub_sat_fail_may_overflow(i8 %x, i8 %y) { +; CHECK-LABEL: @ssub_sat_fail_may_overflow( +; CHECK-NEXT: [[XX:%.*]] = and i8 [[X:%.*]], 15 +; CHECK-NEXT: [[YY:%.*]] = and i8 [[Y:%.*]], 15 +; CHECK-NEXT: [[LHS:%.*]] = or i8 [[XX]], 1 +; CHECK-NEXT: [[RHS:%.*]] = and i8 [[YY]], -2 +; CHECK-NEXT: [[EXP:%.*]] = call i8 @llvm.ssub.sat.i8(i8 [[LHS]], i8 [[RHS]]) +; CHECK-NEXT: [[AND:%.*]] = and i8 [[EXP]], 1 +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND]], 0 +; CHECK-NEXT: ret i1 [[R]] +; + %xx = and i8 %x, 15 + %yy = and i8 %y, 15 + %lhs = or i8 %xx, 1 + %rhs = and i8 %yy, -2 + %exp = call i8 @llvm.ssub.sat.i8(i8 %lhs, i8 %rhs) + %and = and i8 %exp, 1 + %r = icmp eq i8 %and, 0 + ret i1 %r +} + +define i1 @ssub_sat_overflow_pos(i8 %x, i8 %y) { +; CHECK-LABEL: @ssub_sat_overflow_pos( +; CHECK-NEXT: [[XX:%.*]] = and i8 [[X:%.*]], 24 +; CHECK-NEXT: [[YY:%.*]] = and i8 [[Y:%.*]], 3 +; CHECK-NEXT: [[LHS:%.*]] = or i8 [[XX]], 8 +; CHECK-NEXT: [[RHS:%.*]] = or i8 [[YY]], -128 +; CHECK-NEXT: [[EXP:%.*]] = call i8 @llvm.ssub.sat.i8(i8 [[LHS]], i8 [[RHS]]) +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[EXP]], -128 +; CHECK-NEXT: ret i1 [[R]] +; + %xx = and i8 %x, 24 + %yy = and i8 %y, 3 + %lhs = or i8 %xx, 8 + %rhs = or i8 %yy, 128 + %exp = call i8 @llvm.ssub.sat.i8(i8 %lhs, i8 %rhs) + %r = icmp eq i8 %exp, 128 + ret i1 %r +}