llvm.org GIT mirror llvm / e840344
[InstSimplify] Simplify saturating add/sub + icmp If a saturating add/sub has one constant operand, then we can determine the possible range of outputs it can produce, and simplify an icmp comparison based on that. The implementation is based on a similar existing mechanism for simplifying binary operator + icmps. Differential Revision: https://reviews.llvm.org/D55735 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@349369 91177308-0d34-0410-b5e6-96231b3b80d8 Nikita Popov 10 months ago
2 changed file(s) with 80 addition(s) and 42 deletion(s). Raw diff Collapse all Expand all
26292629 }
26302630 }
26312631
2632 /// Some intrinsics with a constant operand have an easy-to-compute range of
2633 /// outputs. This can be used to fold a comparison to always true or always
2634 /// false.
2635 static void setLimitsForIntrinsic(IntrinsicInst &II, APInt &Lower,
2636 APInt &Upper) {
2637 unsigned Width = Lower.getBitWidth();
2638 const APInt *C;
2639 switch (II.getIntrinsicID()) {
2640 case Intrinsic::uadd_sat:
2641 // uadd.sat(x, C) produces [C, UINT_MAX].
2642 if (match(II.getOperand(0), m_APInt(C)) ||
2643 match(II.getOperand(1), m_APInt(C)))
2644 Lower = *C;
2645 break;
2646 case Intrinsic::sadd_sat:
2647 if (match(II.getOperand(0), m_APInt(C)) ||
2648 match(II.getOperand(1), m_APInt(C))) {
2649 if (C->isNegative()) {
2650 // sadd.sat(x, -C) produces [SINT_MIN, SINT_MAX + (-C)].
2651 Lower = APInt::getSignedMinValue(Width);
2652 Upper = APInt::getSignedMaxValue(Width) + *C + 1;
2653 } else {
2654 // sadd.sat(x, +C) produces [SINT_MIN + C, SINT_MAX].
2655 Lower = APInt::getSignedMinValue(Width) + *C;
2656 Upper = APInt::getSignedMaxValue(Width) + 1;
2657 }
2658 }
2659 break;
2660 case Intrinsic::usub_sat:
2661 // usub.sat(C, x) produces [0, C].
2662 if (match(II.getOperand(0), m_APInt(C)))
2663 Upper = *C + 1;
2664 // usub.sat(x, C) produces [0, UINT_MAX - C].
2665 else if (match(II.getOperand(1), m_APInt(C)))
2666 Upper = APInt::getMaxValue(Width) - *C + 1;
2667 break;
2668 case Intrinsic::ssub_sat:
2669 if (match(II.getOperand(0), m_APInt(C))) {
2670 if (C->isNegative()) {
2671 // ssub.sat(-C, x) produces [SINT_MIN, -SINT_MIN + (-C)].
2672 Lower = APInt::getSignedMinValue(Width);
2673 Upper = *C - APInt::getSignedMinValue(Width) + 1;
2674 } else {
2675 // ssub.sat(+C, x) produces [-SINT_MAX + C, SINT_MAX].
2676 Lower = *C - APInt::getSignedMaxValue(Width);
2677 Upper = APInt::getSignedMaxValue(Width) + 1;
2678 }
2679 } else if (match(II.getOperand(1), m_APInt(C))) {
2680 if (C->isNegative()) {
2681 // ssub.sat(x, -C) produces [SINT_MIN - (-C), SINT_MAX]:
2682 Lower = APInt::getSignedMinValue(Width) - *C;
2683 Upper = APInt::getSignedMaxValue(Width) + 1;
2684 } else {
2685 // ssub.sat(x, +C) produces [SINT_MIN, SINT_MAX - C].
2686 Lower = APInt::getSignedMinValue(Width);
2687 Upper = APInt::getSignedMaxValue(Width) - *C + 1;
2688 }
2689 }
2690 break;
2691 default:
2692 break;
2693 }
2694 }
2695
26322696 static Value *simplifyICmpWithConstant(CmpInst::Predicate Pred, Value *LHS,
26332697 Value *RHS, const InstrInfoQuery &IIQ) {
26342698 Type *ITy = GetCompareTy(RHS); // The return type.
26622726 APInt Upper = APInt(Width, 0);
26632727 if (auto *BO = dyn_cast(LHS))
26642728 setLimitsForBinOp(*BO, Lower, Upper, IIQ);
2729 else if (auto *II = dyn_cast(LHS))
2730 setLimitsForIntrinsic(*II, Lower, Upper);
26652731
26662732 ConstantRange LHS_CR =
26672733 Lower != Upper ? ConstantRange(Lower, Upper) : ConstantRange(Width, true);
407407
408408 define i1 @uadd_icmp_op0_known(i8 %a) {
409409 ; CHECK-LABEL: @uadd_icmp_op0_known(
410 ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.uadd.sat.i8(i8 10, i8 [[A:%.*]])
411 ; CHECK-NEXT: [[C:%.*]] = icmp uge i8 [[B]], 10
412 ; CHECK-NEXT: ret i1 [[C]]
410 ; CHECK-NEXT: ret i1 true
413411 ;
414412 %b = call i8 @llvm.uadd.sat.i8(i8 10, i8 %a)
415413 %c = icmp uge i8 %b, 10
429427
430428 define i1 @uadd_icmp_op1_known(i8 %a) {
431429 ; CHECK-LABEL: @uadd_icmp_op1_known(
432 ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[A:%.*]], i8 10)
433 ; CHECK-NEXT: [[C:%.*]] = icmp uge i8 [[B]], 10
434 ; CHECK-NEXT: ret i1 [[C]]
430 ; CHECK-NEXT: ret i1 true
435431 ;
436432 %b = call i8 @llvm.uadd.sat.i8(i8 %a, i8 10)
437433 %c = icmp uge i8 %b, 10
451447
452448 define i1 @sadd_icmp_op0_pos_known(i8 %a) {
453449 ; CHECK-LABEL: @sadd_icmp_op0_pos_known(
454 ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.sadd.sat.i8(i8 10, i8 [[A:%.*]])
455 ; CHECK-NEXT: [[C:%.*]] = icmp sge i8 [[B]], -118
456 ; CHECK-NEXT: ret i1 [[C]]
450 ; CHECK-NEXT: ret i1 true
457451 ;
458452 %b = call i8 @llvm.sadd.sat.i8(i8 10, i8 %a)
459453 %c = icmp sge i8 %b, -118
473467
474468 define i1 @sadd_icmp_op0_neg_known(i8 %a) {
475469 ; CHECK-LABEL: @sadd_icmp_op0_neg_known(
476 ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.sadd.sat.i8(i8 -10, i8 [[A:%.*]])
477 ; CHECK-NEXT: [[C:%.*]] = icmp sle i8 [[B]], 117
478 ; CHECK-NEXT: ret i1 [[C]]
470 ; CHECK-NEXT: ret i1 true
479471 ;
480472 %b = call i8 @llvm.sadd.sat.i8(i8 -10, i8 %a)
481473 %c = icmp sle i8 %b, 117
495487
496488 define i1 @sadd_icmp_op1_pos_known(i8 %a) {
497489 ; CHECK-LABEL: @sadd_icmp_op1_pos_known(
498 ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[A:%.*]], i8 10)
499 ; CHECK-NEXT: [[C:%.*]] = icmp sge i8 [[B]], -118
500 ; CHECK-NEXT: ret i1 [[C]]
490 ; CHECK-NEXT: ret i1 true
501491 ;
502492 %b = call i8 @llvm.sadd.sat.i8(i8 %a, i8 10)
503493 %c = icmp sge i8 %b, -118
517507
518508 define i1 @sadd_icmp_op1_neg_known(i8 %a) {
519509 ; CHECK-LABEL: @sadd_icmp_op1_neg_known(
520 ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[A:%.*]], i8 -10)
521 ; CHECK-NEXT: [[C:%.*]] = icmp sle i8 [[B]], 117
522 ; CHECK-NEXT: ret i1 [[C]]
510 ; CHECK-NEXT: ret i1 true
523511 ;
524512 %b = call i8 @llvm.sadd.sat.i8(i8 %a, i8 -10)
525513 %c = icmp sle i8 %b, 117
539527
540528 define i1 @usub_icmp_op0_known(i8 %a) {
541529 ; CHECK-LABEL: @usub_icmp_op0_known(
542 ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.usub.sat.i8(i8 10, i8 [[A:%.*]])
543 ; CHECK-NEXT: [[C:%.*]] = icmp ule i8 [[B]], 10
544 ; CHECK-NEXT: ret i1 [[C]]
530 ; CHECK-NEXT: ret i1 true
545531 ;
546532 %b = call i8 @llvm.usub.sat.i8(i8 10, i8 %a)
547533 %c = icmp ule i8 %b, 10
561547
562548 define i1 @usub_icmp_op1_known(i8 %a) {
563549 ; CHECK-LABEL: @usub_icmp_op1_known(
564 ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 10)
565 ; CHECK-NEXT: [[C:%.*]] = icmp ule i8 [[B]], -11
566 ; CHECK-NEXT: ret i1 [[C]]
550 ; CHECK-NEXT: ret i1 true
567551 ;
568552 %b = call i8 @llvm.usub.sat.i8(i8 %a, i8 10)
569553 %c = icmp ule i8 %b, 245
583567
584568 define i1 @ssub_icmp_op0_pos_known(i8 %a) {
585569 ; CHECK-LABEL: @ssub_icmp_op0_pos_known(
586 ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.ssub.sat.i8(i8 10, i8 [[A:%.*]])
587 ; CHECK-NEXT: [[C:%.*]] = icmp sge i8 [[B]], -117
588 ; CHECK-NEXT: ret i1 [[C]]
570 ; CHECK-NEXT: ret i1 true
589571 ;
590572 %b = call i8 @llvm.ssub.sat.i8(i8 10, i8 %a)
591573 %c = icmp sge i8 %b, -117
605587
606588 define i1 @ssub_icmp_op0_neg_known(i8 %a) {
607589 ; CHECK-LABEL: @ssub_icmp_op0_neg_known(
608 ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.ssub.sat.i8(i8 -10, i8 [[A:%.*]])
609 ; CHECK-NEXT: [[C:%.*]] = icmp sle i8 [[B]], 118
610 ; CHECK-NEXT: ret i1 [[C]]
590 ; CHECK-NEXT: ret i1 true
611591 ;
612592 %b = call i8 @llvm.ssub.sat.i8(i8 -10, i8 %a)
613593 %c = icmp sle i8 %b, 118
628608 ; Peculiar case: ssub.sat(0, x) is never signed min.
629609 define i1 @ssub_icmp_op0_zero(i8 %a) {
630610 ; CHECK-LABEL: @ssub_icmp_op0_zero(
631 ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.ssub.sat.i8(i8 0, i8 [[A:%.*]])
632 ; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[B]], -128
633 ; CHECK-NEXT: ret i1 [[C]]
611 ; CHECK-NEXT: ret i1 true
634612 ;
635613 %b = call i8 @llvm.ssub.sat.i8(i8 0, i8 %a)
636614 %c = icmp ne i8 %b, -128
639617
640618 define i1 @ssub_icmp_op1_pos_known(i8 %a) {
641619 ; CHECK-LABEL: @ssub_icmp_op1_pos_known(
642 ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.ssub.sat.i8(i8 [[A:%.*]], i8 10)
643 ; CHECK-NEXT: [[C:%.*]] = icmp sle i8 [[B]], 117
644 ; CHECK-NEXT: ret i1 [[C]]
620 ; CHECK-NEXT: ret i1 true
645621 ;
646622 %b = call i8 @llvm.ssub.sat.i8(i8 %a, i8 10)
647623 %c = icmp sle i8 %b, 117
661637
662638 define i1 @ssub_icmp_op1_neg_known(i8 %a) {
663639 ; CHECK-LABEL: @ssub_icmp_op1_neg_known(
664 ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.ssub.sat.i8(i8 [[A:%.*]], i8 -10)
665 ; CHECK-NEXT: [[C:%.*]] = icmp sge i8 [[B]], -118
666 ; CHECK-NEXT: ret i1 [[C]]
640 ; CHECK-NEXT: ret i1 true
667641 ;
668642 %b = call i8 @llvm.ssub.sat.i8(i8 %a, i8 -10)
669643 %c = icmp sge i8 %b, -118
683657
684658 define i1 @ssub_icmp_op1_smin(i8 %a) {
685659 ; CHECK-LABEL: @ssub_icmp_op1_smin(
686 ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.ssub.sat.i8(i8 [[A:%.*]], i8 -128)
687 ; CHECK-NEXT: [[C:%.*]] = icmp sge i8 [[B]], 0
688 ; CHECK-NEXT: ret i1 [[C]]
660 ; CHECK-NEXT: ret i1 true
689661 ;
690662 %b = call i8 @llvm.ssub.sat.i8(i8 %a, i8 -128)
691663 %c = icmp sge i8 %b, 0