[llvm] c329a47 - [CVP] @llvm.abs() handling

Roman Lebedev via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 10 06:47:53 PDT 2021


Author: Roman Lebedev
Date: 2021-04-10T16:47:31+03:00
New Revision: c329a47d9ed77512493f787520317e3f51be3387

URL: https://github.com/llvm/llvm-project/commit/c329a47d9ed77512493f787520317e3f51be3387
DIFF: https://github.com/llvm/llvm-project/commit/c329a47d9ed77512493f787520317e3f51be3387.diff

LOG: [CVP] @llvm.abs() handling

Iff we know the sigdness domain of the argument,
we can either skip @llvm.abs, or do negation directly.

Notably, INT_MIN can belong to either domain:
* X u<= INT_MIN --> X  is always fine
  https://alive2.llvm.org/ce/z/QB8j-C https://alive2.llvm.org/ce/z/7sFKpS
* X s<= 0 --> -X  is always fine
  https://alive2.llvm.org/ce/z/QbGSyq https://alive2.llvm.org/ce/z/APsN84

If all else fails, try to inferr NSW flag:
https://alive2.llvm.org/ce/z/qCJfYm

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
    llvm/test/Transforms/CorrelatedValuePropagation/abs.ll
    llvm/test/Transforms/CorrelatedValuePropagation/minmaxabs.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
index 02d2bacabecb3..e84f6eb63da5c 100644
--- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
+++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
@@ -82,6 +82,7 @@ STATISTIC(NumMulNUW,    "Number of no-unsigned-wrap deductions for mul");
 STATISTIC(NumShlNW,     "Number of no-wrap deductions for shl");
 STATISTIC(NumShlNSW,    "Number of no-signed-wrap deductions for shl");
 STATISTIC(NumShlNUW,    "Number of no-unsigned-wrap deductions for shl");
+STATISTIC(NumAbs,       "Number of llvm.abs intrinsics removed");
 STATISTIC(NumOverflows, "Number of overflow checks removed");
 STATISTIC(NumSaturating,
     "Number of saturating arithmetics converted to normal arithmetics");
@@ -442,6 +443,61 @@ static void setDeducedOverflowingFlags(Value *V, Instruction::BinaryOps Opcode,
 
 static bool processBinOp(BinaryOperator *BinOp, LazyValueInfo *LVI);
 
+// See if @llvm.abs argument is alays positive/negative, and simplify.
+// Notably, INT_MIN can belong to either range, regardless of the NSW,
+// because it is negation-invariant.
+static void processAbsIntrinsic(IntrinsicInst *II, LazyValueInfo *LVI) {
+  Value *X = II->getArgOperand(0);
+  bool IsIntMinPoison = cast<ConstantInt>(II->getArgOperand(1))->isOne();
+
+  Type *Ty = X->getType();
+  Constant *IntMin =
+      ConstantInt::get(Ty, APInt::getSignedMinValue(Ty->getScalarSizeInBits()));
+  LazyValueInfo::Tristate Result;
+
+  // Is X in [0, IntMin]?  NOTE: INT_MIN is fine!
+  Result = LVI->getPredicateAt(CmpInst::Predicate::ICMP_ULE, X, IntMin, II,
+                               /*UseBlockValue=*/true);
+  if (Result == LazyValueInfo::True) {
+    ++NumAbs;
+    II->replaceAllUsesWith(X);
+    II->eraseFromParent();
+    return;
+  }
+
+  // Is X in [IntMin, 0]?  NOTE: INT_MIN is fine!
+  Constant *Zero = ConstantInt::getNullValue(Ty);
+  Result = LVI->getPredicateAt(CmpInst::Predicate::ICMP_SLE, X, Zero, II,
+                               /*UseBlockValue=*/true);
+  assert(Result != LazyValueInfo::False && "Should have been handled already.");
+
+  if (Result == LazyValueInfo::Unknown) {
+    // Argument's range crosses zero.
+    if (!IsIntMinPoison) {
+      // Can we at least tell that the argument is never INT_MIN?
+      Result = LVI->getPredicateAt(CmpInst::Predicate::ICMP_NE, X, IntMin, II,
+                                   /*UseBlockValue=*/true);
+      if (Result == LazyValueInfo::True) {
+        ++NumNSW;
+        ++NumSubNSW;
+        II->setArgOperand(1, ConstantInt::getTrue(II->getContext()));
+      }
+    }
+    return;
+  }
+
+  IRBuilder<> B(II);
+  Value *NegX = B.CreateNeg(X, II->getName(), /*HasNUW=*/false,
+                            /*HasNSW=*/IsIntMinPoison);
+  ++NumAbs;
+  II->replaceAllUsesWith(NegX);
+  II->eraseFromParent();
+
+  // See if we can infer some no-wrap flags.
+  if (auto *BO = dyn_cast<BinaryOperator>(NegX))
+    processBinOp(BO, LVI);
+}
+
 // Rewrite this with.overflow intrinsic as non-overflowing.
 static void processOverflowIntrinsic(WithOverflowInst *WO, LazyValueInfo *LVI) {
   IRBuilder<> B(WO);
@@ -488,6 +544,11 @@ static void processSaturatingInst(SaturatingInst *SI, LazyValueInfo *LVI) {
 /// Infer nonnull attributes for the arguments at the specified callsite.
 static bool processCallSite(CallBase &CB, LazyValueInfo *LVI) {
 
+  if (CB.getIntrinsicID() == Intrinsic::abs) {
+    processAbsIntrinsic(&cast<IntrinsicInst>(CB), LVI);
+    return true;
+  }
+
   if (auto *WO = dyn_cast<WithOverflowInst>(&CB)) {
     if (WO->getLHS()->getType()->isIntegerTy() && willNotOverflow(WO, LVI)) {
       processOverflowIntrinsic(WO, LVI);

diff  --git a/llvm/test/Transforms/CorrelatedValuePropagation/abs.ll b/llvm/test/Transforms/CorrelatedValuePropagation/abs.ll
index d534aecf7a560..c8b21a8e3ef1a 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/abs.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/abs.ll
@@ -29,7 +29,7 @@ define i8 @test2(i8 %x) {
 ; CHECK-LABEL: @test2(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
+; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
 
@@ -56,8 +56,7 @@ define i8 @test4(i8 %x) {
 ; CHECK-LABEL: @test4(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
 
   %lim = icmp sge i8 %x, 0
@@ -69,8 +68,7 @@ define i8 @test5(i8 %x) {
 ; CHECK-LABEL: @test5(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
 
   %lim = icmp sge i8 %x, 0
@@ -83,8 +81,7 @@ define i8 @test6(i8 %x) {
 ; CHECK-LABEL: @test6(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 1
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
 
   %lim = icmp sge i8 %x, 1
@@ -96,8 +93,7 @@ define i8 @test7(i8 %x) {
 ; CHECK-LABEL: @test7(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 1
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
 
   %lim = icmp sge i8 %x, 1
@@ -112,8 +108,7 @@ define i8 @test8(i8 %x) {
 ; CHECK-LABEL: @test8(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp ule i8 [[X:%.*]], 127
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
 
   %lim = icmp ule i8 %x, 127
@@ -125,8 +120,7 @@ define i8 @test9(i8 %x) {
 ; CHECK-LABEL: @test9(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp ule i8 [[X:%.*]], 127
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
 
   %lim = icmp ule i8 %x, 127
@@ -139,8 +133,7 @@ define i8 @test10(i8 %x) {
 ; CHECK-LABEL: @test10(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp ule i8 [[X:%.*]], -128
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
 
   %lim = icmp ule i8 %x, 128
@@ -152,8 +145,7 @@ define i8 @test11(i8 %x) {
 ; CHECK-LABEL: @test11(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp ule i8 [[X:%.*]], -128
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
 
   %lim = icmp ule i8 %x, 128
@@ -197,8 +189,8 @@ define i8 @test14(i8 %x) {
 ; CHECK-LABEL: @test14(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    [[R1:%.*]] = sub i8 0, [[X]]
+; CHECK-NEXT:    ret i8 [[R1]]
 ;
 
   %lim = icmp sle i8 %x, -1
@@ -210,8 +202,8 @@ define i8 @test15(i8 %x) {
 ; CHECK-LABEL: @test15(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    [[R1:%.*]] = sub nsw i8 0, [[X]]
+; CHECK-NEXT:    ret i8 [[R1]]
 ;
 
   %lim = icmp sle i8 %x, -1
@@ -224,8 +216,8 @@ define i8 @test16(i8 %x) {
 ; CHECK-LABEL: @test16(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i8 [[X:%.*]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    [[R1:%.*]] = sub i8 0, [[X]]
+; CHECK-NEXT:    ret i8 [[R1]]
 ;
 
   %lim = icmp sle i8 %x, 0
@@ -237,8 +229,8 @@ define i8 @test17(i8 %x) {
 ; CHECK-LABEL: @test17(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i8 [[X:%.*]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    [[R1:%.*]] = sub nsw i8 0, [[X]]
+; CHECK-NEXT:    ret i8 [[R1]]
 ;
 
   %lim = icmp sle i8 %x, 0
@@ -307,8 +299,8 @@ define i8 @test22(i8 %x) {
 ; CHECK-LABEL: @test22(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp uge i8 [[X:%.*]], -128
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    [[R1:%.*]] = sub i8 0, [[X]]
+; CHECK-NEXT:    ret i8 [[R1]]
 ;
 
   %lim = icmp uge i8 %x, 128
@@ -320,8 +312,8 @@ define i8 @test23(i8 %x) {
 ; CHECK-LABEL: @test23(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp uge i8 [[X:%.*]], -128
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    [[R1:%.*]] = sub nsw i8 0, [[X]]
+; CHECK-NEXT:    ret i8 [[R1]]
 ;
 
   %lim = icmp uge i8 %x, 128
@@ -334,8 +326,8 @@ define i8 @test24(i8 %x) {
 ; CHECK-LABEL: @test24(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp uge i8 [[X:%.*]], -127
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    [[R1:%.*]] = sub nsw i8 0, [[X]]
+; CHECK-NEXT:    ret i8 [[R1]]
 ;
 
   %lim = icmp uge i8 %x, 129
@@ -347,8 +339,8 @@ define i8 @test25(i8 %x) {
 ; CHECK-LABEL: @test25(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp uge i8 [[X:%.*]], -127
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    [[R1:%.*]] = sub nsw i8 0, [[X]]
+; CHECK-NEXT:    ret i8 [[R1]]
 ;
 
   %lim = icmp uge i8 %x, 129
@@ -363,7 +355,7 @@ define i8 @test26(i8 %x) {
 ; CHECK-LABEL: @test26(
 ; CHECK-NEXT:    [[LIM:%.*]] = icmp ne i8 [[X:%.*]], -128
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
+; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %lim = icmp ne i8 %x, 128

diff  --git a/llvm/test/Transforms/CorrelatedValuePropagation/minmaxabs.ll b/llvm/test/Transforms/CorrelatedValuePropagation/minmaxabs.ll
index 409503439165e..bc0a0150de76c 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/minmaxabs.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/minmaxabs.ll
@@ -74,8 +74,8 @@ define void @test_smax(i32 %x) {
 
 define void @test_abs1(i32* %p) {
 ; CHECK-LABEL: @test_abs1(
-; CHECK-NEXT:    [[X:%.*]] = load i32, i32* [[P:%.*]], align 4, [[RNG0:!range !.*]]
-; CHECK-NEXT:    [[A:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 false)
+; CHECK-NEXT:    [[X:%.*]] = load i32, i32* [[P:%.*]], align 4, !range [[RNG0:![0-9]+]]
+; CHECK-NEXT:    [[A:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 true)
 ; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C2:%.*]] = icmp ult i32 [[A]], 15
 ; CHECK-NEXT:    call void @use(i1 [[C2]])


        


More information about the llvm-commits mailing list