[llvm] r347770 - [InstCombine] Use known overflow information for saturating add/sub

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 28 08:36:59 PST 2018


Author: nikic
Date: Wed Nov 28 08:36:59 2018
New Revision: 347770

URL: http://llvm.org/viewvc/llvm-project?rev=347770&view=rev
Log:
[InstCombine] Use known overflow information for saturating add/sub

If ValueTracking can determine that the add/sub can newer overflow,
replace it with the corresponding nuw/nsw add/sub.

Additionally, for the unsigned case, if ValueTracking determines
that the add/sub always overflows, replace the result with the
saturation value.

This change is part of https://reviews.llvm.org/D54534.

Modified:
    llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp
    llvm/trunk/test/Transforms/InstCombine/saturating-add-sub.ll

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp?rev=347770&r1=347769&r2=347770&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp Wed Nov 28 08:36:59 2018
@@ -2065,7 +2065,45 @@ Instruction *InstCombiner::visitCallInst
   case Intrinsic::sadd_sat:
     if (Instruction *I = canonicalizeConstantArg0ToArg1(CI))
       return I;
+    LLVM_FALLTHROUGH;
+  case Intrinsic::usub_sat:
+  case Intrinsic::ssub_sat: {
+    Value *Arg0 = II->getArgOperand(0);
+    Value *Arg1 = II->getArgOperand(1);
+    Intrinsic::ID IID = II->getIntrinsicID();
+
+    // Make use of known overflow information.
+    OverflowResult OR;
+    switch (IID) {
+    default:
+      llvm_unreachable("Unexpected intrinsic!");
+    case Intrinsic::uadd_sat:
+      OR = computeOverflowForUnsignedAdd(Arg0, Arg1, II);
+      if (OR == OverflowResult::NeverOverflows)
+        return BinaryOperator::CreateNUWAdd(Arg0, Arg1);
+      if (OR == OverflowResult::AlwaysOverflows)
+        return replaceInstUsesWith(*II,
+                                   ConstantInt::getAllOnesValue(II->getType()));
+      break;
+    case Intrinsic::usub_sat:
+      OR = computeOverflowForUnsignedSub(Arg0, Arg1, II);
+      if (OR == OverflowResult::NeverOverflows)
+        return BinaryOperator::CreateNUWSub(Arg0, Arg1);
+      if (OR == OverflowResult::AlwaysOverflows)
+        return replaceInstUsesWith(*II,
+                                   ConstantInt::getNullValue(II->getType()));
+      break;
+    case Intrinsic::sadd_sat:
+      if (willNotOverflowSignedAdd(Arg0, Arg1, *II))
+        return BinaryOperator::CreateNSWAdd(Arg0, Arg1);
+      break;
+    case Intrinsic::ssub_sat:
+      if (willNotOverflowSignedSub(Arg0, Arg1, *II))
+        return BinaryOperator::CreateNSWSub(Arg0, Arg1);
+      break;
+    }
     break;
+  }
 
   case Intrinsic::minnum:
   case Intrinsic::maxnum:

Modified: llvm/trunk/test/Transforms/InstCombine/saturating-add-sub.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/saturating-add-sub.ll?rev=347770&r1=347769&r2=347770&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/saturating-add-sub.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/saturating-add-sub.ll Wed Nov 28 08:36:59 2018
@@ -178,9 +178,7 @@ define i8 @test_scalar_sadd_overflow(i8
 ; neg uadd neg always overflows.
 define i8 @test_scalar_uadd_neg_neg(i8 %a) {
 ; CHECK-LABEL: @test_scalar_uadd_neg_neg(
-; CHECK-NEXT:    [[A_NEG:%.*]] = or i8 [[A:%.*]], -128
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[A_NEG]], i8 -10)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 -1
 ;
   %a_neg = or i8 %a, -128
   %r = call i8 @llvm.uadd.sat.i8(i8 %a_neg, i8 -10)
@@ -189,9 +187,7 @@ define i8 @test_scalar_uadd_neg_neg(i8 %
 
 define <2 x i8> @test_vector_uadd_neg_neg(<2 x i8> %a) {
 ; CHECK-LABEL: @test_vector_uadd_neg_neg(
-; CHECK-NEXT:    [[A_NEG:%.*]] = or <2 x i8> [[A:%.*]], <i8 -128, i8 -128>
-; CHECK-NEXT:    [[R:%.*]] = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> [[A_NEG]], <2 x i8> <i8 -10, i8 -20>)
-; CHECK-NEXT:    ret <2 x i8> [[R]]
+; CHECK-NEXT:    ret <2 x i8> <i8 -1, i8 -1>
 ;
   %a_neg = or <2 x i8> %a, <i8 -128, i8 -128>
   %r = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %a_neg, <2 x i8> <i8 -10, i8 -20>)
@@ -202,7 +198,7 @@ define <2 x i8> @test_vector_uadd_neg_ne
 define i8 @test_scalar_uadd_nneg_nneg(i8 %a) {
 ; CHECK-LABEL: @test_scalar_uadd_nneg_nneg(
 ; CHECK-NEXT:    [[A_NNEG:%.*]] = and i8 [[A:%.*]], 127
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[A_NNEG]], i8 10)
+; CHECK-NEXT:    [[R:%.*]] = add nuw i8 [[A_NNEG]], 10
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %a_nneg = and i8 %a, 127
@@ -213,7 +209,7 @@ define i8 @test_scalar_uadd_nneg_nneg(i8
 define <2 x i8> @test_vector_uadd_nneg_nneg(<2 x i8> %a) {
 ; CHECK-LABEL: @test_vector_uadd_nneg_nneg(
 ; CHECK-NEXT:    [[A_NNEG:%.*]] = and <2 x i8> [[A:%.*]], <i8 127, i8 127>
-; CHECK-NEXT:    [[R:%.*]] = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> [[A_NNEG]], <2 x i8> <i8 10, i8 20>)
+; CHECK-NEXT:    [[R:%.*]] = add nuw <2 x i8> [[A_NNEG]], <i8 10, i8 20>
 ; CHECK-NEXT:    ret <2 x i8> [[R]]
 ;
   %a_nneg = and <2 x i8> %a, <i8 127, i8 127>
@@ -248,7 +244,7 @@ define <2 x i8> @test_vector_uadd_neg_nn
 define i8 @test_scalar_sadd_neg_nneg(i8 %a) {
 ; CHECK-LABEL: @test_scalar_sadd_neg_nneg(
 ; CHECK-NEXT:    [[A_NEG:%.*]] = or i8 [[A:%.*]], -128
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[A_NEG]], i8 10)
+; CHECK-NEXT:    [[R:%.*]] = add nsw i8 [[A_NEG]], 10
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %a_neg = or i8 %a, -128
@@ -259,7 +255,7 @@ define i8 @test_scalar_sadd_neg_nneg(i8
 define <2 x i8> @test_vector_sadd_neg_nneg(<2 x i8> %a) {
 ; CHECK-LABEL: @test_vector_sadd_neg_nneg(
 ; CHECK-NEXT:    [[A_NEG:%.*]] = or <2 x i8> [[A:%.*]], <i8 -128, i8 -128>
-; CHECK-NEXT:    [[R:%.*]] = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> [[A_NEG]], <2 x i8> <i8 10, i8 20>)
+; CHECK-NEXT:    [[R:%.*]] = add nsw <2 x i8> [[A_NEG]], <i8 10, i8 20>
 ; CHECK-NEXT:    ret <2 x i8> [[R]]
 ;
   %a_neg = or <2 x i8> %a, <i8 -128, i8 -128>
@@ -271,7 +267,7 @@ define <2 x i8> @test_vector_sadd_neg_nn
 define i8 @test_scalar_sadd_nneg_neg(i8 %a) {
 ; CHECK-LABEL: @test_scalar_sadd_nneg_neg(
 ; CHECK-NEXT:    [[A_NNEG:%.*]] = and i8 [[A:%.*]], 127
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[A_NNEG]], i8 -10)
+; CHECK-NEXT:    [[R:%.*]] = add nsw i8 [[A_NNEG]], -10
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %a_nneg = and i8 %a, 127
@@ -282,7 +278,7 @@ define i8 @test_scalar_sadd_nneg_neg(i8
 define <2 x i8> @test_vector_sadd_nneg_neg(<2 x i8> %a) {
 ; CHECK-LABEL: @test_vector_sadd_nneg_neg(
 ; CHECK-NEXT:    [[A_NNEG:%.*]] = and <2 x i8> [[A:%.*]], <i8 127, i8 127>
-; CHECK-NEXT:    [[R:%.*]] = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> [[A_NNEG]], <2 x i8> <i8 -10, i8 -20>)
+; CHECK-NEXT:    [[R:%.*]] = add nsw <2 x i8> [[A_NNEG]], <i8 -10, i8 -20>
 ; CHECK-NEXT:    ret <2 x i8> [[R]]
 ;
   %a_nneg = and <2 x i8> %a, <i8 127, i8 127>
@@ -557,7 +553,7 @@ define <2 x i8> @test_vector_usub_nneg_n
 define i8 @test_scalar_usub_neg_nneg(i8 %a) {
 ; CHECK-LABEL: @test_scalar_usub_neg_nneg(
 ; CHECK-NEXT:    [[A_NEG:%.*]] = or i8 [[A:%.*]], -128
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[A_NEG]], i8 10)
+; CHECK-NEXT:    [[R:%.*]] = add i8 [[A_NEG]], -10
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %a_neg = or i8 %a, -128
@@ -568,7 +564,7 @@ define i8 @test_scalar_usub_neg_nneg(i8
 define <2 x i8> @test_vector_usub_neg_nneg(<2 x i8> %a) {
 ; CHECK-LABEL: @test_vector_usub_neg_nneg(
 ; CHECK-NEXT:    [[A_NEG:%.*]] = or <2 x i8> [[A:%.*]], <i8 -128, i8 -128>
-; CHECK-NEXT:    [[R:%.*]] = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[A_NEG]], <2 x i8> <i8 10, i8 20>)
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i8> [[A_NEG]], <i8 -10, i8 -20>
 ; CHECK-NEXT:    ret <2 x i8> [[R]]
 ;
   %a_neg = or <2 x i8> %a, <i8 -128, i8 -128>
@@ -603,7 +599,7 @@ define <2 x i8> @test_vector_usub_nneg_n
 define i8 @test_scalar_ssub_neg_neg(i8 %a) {
 ; CHECK-LABEL: @test_scalar_ssub_neg_neg(
 ; CHECK-NEXT:    [[A_NEG:%.*]] = or i8 [[A:%.*]], -128
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ssub.sat.i8(i8 [[A_NEG]], i8 -10)
+; CHECK-NEXT:    [[R:%.*]] = add nsw i8 [[A_NEG]], 10
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %a_neg = or i8 %a, -128
@@ -614,7 +610,7 @@ define i8 @test_scalar_ssub_neg_neg(i8 %
 define <2 x i8> @test_vector_ssub_neg_neg(<2 x i8> %a) {
 ; CHECK-LABEL: @test_vector_ssub_neg_neg(
 ; CHECK-NEXT:    [[A_NEG:%.*]] = or <2 x i8> [[A:%.*]], <i8 -128, i8 -128>
-; CHECK-NEXT:    [[R:%.*]] = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> [[A_NEG]], <2 x i8> <i8 -10, i8 -20>)
+; CHECK-NEXT:    [[R:%.*]] = add nsw <2 x i8> [[A_NEG]], <i8 10, i8 20>
 ; CHECK-NEXT:    ret <2 x i8> [[R]]
 ;
   %a_neg = or <2 x i8> %a, <i8 -128, i8 -128>
@@ -626,7 +622,7 @@ define <2 x i8> @test_vector_ssub_neg_ne
 define i8 @test_scalar_ssub_nneg_nneg(i8 %a) {
 ; CHECK-LABEL: @test_scalar_ssub_nneg_nneg(
 ; CHECK-NEXT:    [[A_NNEG:%.*]] = and i8 [[A:%.*]], 127
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ssub.sat.i8(i8 [[A_NNEG]], i8 10)
+; CHECK-NEXT:    [[R:%.*]] = add nsw i8 [[A_NNEG]], -10
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %a_nneg = and i8 %a, 127
@@ -637,7 +633,7 @@ define i8 @test_scalar_ssub_nneg_nneg(i8
 define <2 x i8> @test_vector_ssub_nneg_nneg(<2 x i8> %a) {
 ; CHECK-LABEL: @test_vector_ssub_nneg_nneg(
 ; CHECK-NEXT:    [[A_NNEG:%.*]] = and <2 x i8> [[A:%.*]], <i8 127, i8 127>
-; CHECK-NEXT:    [[R:%.*]] = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> [[A_NNEG]], <2 x i8> <i8 10, i8 20>)
+; CHECK-NEXT:    [[R:%.*]] = add nsw <2 x i8> [[A_NNEG]], <i8 -10, i8 -20>
 ; CHECK-NEXT:    ret <2 x i8> [[R]]
 ;
   %a_nneg = and <2 x i8> %a, <i8 127, i8 127>




More information about the llvm-commits mailing list