[llvm] 4eeeb35 - [CVP] Enhance SRem -> URem fold to work not just on non-negative operands

Roman Lebedev via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 22 11:37:54 PDT 2020


Author: Roman Lebedev
Date: 2020-09-22T21:37:28+03:00
New Revision: 4eeeb356fc41babf46797b062f74f978b818622b

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

LOG: [CVP] Enhance SRem -> URem fold to work not just on non-negative operands

This is a continuation of 8d487668d09fb0e4e54f36207f07c1480ffabbfd,
the logic is pretty much identical for SRem:

Name: pos pos
Pre: C0 >= 0 && C1 >= 0
%r = srem i8 C0, C1
  =>
%r = urem i8 C0, C1

Name: pos neg
Pre: C0 >= 0 && C1 <= 0
%r = srem i8 C0, C1
  =>
%r = urem i8 C0, -C1

Name: neg pos
Pre: C0 <= 0 && C1 >= 0
%r = srem i8 C0, C1
  =>
%t0 = urem i8 -C0, C1
%r = sub i8 0, %t0

Name: neg neg
Pre: C0 <= 0 && C1 <= 0
%r = srem i8 C0, C1
  =>
%t0 = urem i8 -C0, -C1
%r = sub i8 0, %t0

https://rise4fun.com/Alive/Vd6

Now, this new logic does not result in any new catches
as of vanilla llvm test-suite + RawSpeed.
but it should be virtually compile-time free,
and it may be important to be consistent in their handling,
because if we had a pair of sdiv-srem, and only converted one of them,
-divrempairs will no longer see them as a pair,
and thus not "merge" them.

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
index 397d62a5d21d..3d51a9f2c6aa 100644
--- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
+++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
@@ -613,10 +613,15 @@ static bool isNonPositive(Value *V, LazyValueInfo *LVI, Instruction *CxtI) {
   return Result == LazyValueInfo::True;
 }
 
-static bool allOperandsAreNonNegative(BinaryOperator *SDI, LazyValueInfo *LVI) {
-  return all_of(SDI->operands(),
-                [&](Value *Op) { return isNonNegative(Op, LVI, SDI); });
-}
+enum class Domain { NonNegative, NonPositive, Unknown };
+
+Domain getDomain(Value *V, LazyValueInfo *LVI, Instruction *CxtI) {
+  if (isNonNegative(V, LVI, CxtI))
+    return Domain::NonNegative;
+  if (isNonPositive(V, LVI, CxtI))
+    return Domain::NonPositive;
+  return Domain::Unknown;
+};
 
 /// Try to shrink a udiv/urem's width down to the smallest power of two that's
 /// sufficient to contain its operands.
@@ -661,18 +666,51 @@ static bool processUDivOrURem(BinaryOperator *Instr, LazyValueInfo *LVI) {
 }
 
 static bool processSRem(BinaryOperator *SDI, LazyValueInfo *LVI) {
-  if (SDI->getType()->isVectorTy() || !allOperandsAreNonNegative(SDI, LVI))
+  if (SDI->getType()->isVectorTy())
     return false;
 
+  struct Operand {
+    Value *V;
+    Domain D;
+  };
+  std::array<Operand, 2> Ops;
+
+  for (const auto I : zip(Ops, SDI->operands())) {
+    Operand &Op = std::get<0>(I);
+    Op.V = std::get<1>(I);
+    Op.D = getDomain(Op.V, LVI, SDI);
+    if (Op.D == Domain::Unknown)
+      return false;
+  }
+
+  // We know domains of both of the operands!
   ++NumSRems;
-  auto *BO = BinaryOperator::CreateURem(SDI->getOperand(0), SDI->getOperand(1),
-                                        SDI->getName(), SDI);
-  BO->setDebugLoc(SDI->getDebugLoc());
-  SDI->replaceAllUsesWith(BO);
+
+  // We need operands to be non-negative, so negate each one that isn't.
+  for (Operand &Op : Ops) {
+    if (Op.D == Domain::NonNegative)
+      continue;
+    auto *BO =
+        BinaryOperator::CreateNeg(Op.V, Op.V->getName() + ".nonneg", SDI);
+    BO->setDebugLoc(SDI->getDebugLoc());
+    Op.V = BO;
+  }
+
+  auto *URem =
+      BinaryOperator::CreateURem(Ops[0].V, Ops[1].V, SDI->getName(), SDI);
+  URem->setDebugLoc(SDI->getDebugLoc());
+
+  Value *Res = URem;
+
+  // If the divident was non-positive, we need to negate the result.
+  if (Ops[0].D == Domain::NonPositive)
+    Res = BinaryOperator::CreateNeg(Res, Res->getName() + ".neg", SDI);
+
+  SDI->replaceAllUsesWith(Res);
   SDI->eraseFromParent();
 
-  // Try to process our new urem.
-  processUDivOrURem(BO, LVI);
+  // Try to simplify our new urem.
+  processUDivOrURem(URem, LVI);
 
   return true;
 }
@@ -686,24 +724,16 @@ static bool processSDiv(BinaryOperator *SDI, LazyValueInfo *LVI) {
   if (SDI->getType()->isVectorTy())
     return false;
 
-  enum class Domain { NonNegative, NonPositive, Unknown };
-  auto getDomain = [&](Value *V) {
-    if (isNonNegative(V, LVI, SDI))
-      return Domain::NonNegative;
-    if (isNonPositive(V, LVI, SDI))
-      return Domain::NonPositive;
-    return Domain::Unknown;
-  };
-
   struct Operand {
     Value *V;
     Domain D;
   };
   std::array<Operand, 2> Ops;
+
   for (const auto I : zip(Ops, SDI->operands())) {
     Operand &Op = std::get<0>(I);
     Op.V = std::get<1>(I);
-    Op.D = getDomain(Op.V);
+    Op.D = getDomain(Op.V, LVI, SDI);
     if (Op.D == Domain::Unknown)
       return false;
   }

diff  --git a/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll b/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll
index 2f64d740cdc4..af202e8483d2 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll
@@ -90,8 +90,9 @@ define i8 @test6_pos_neg(i8 %x, i8 %y) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
 ; CHECK-NEXT:    [[C1:%.*]] = icmp sle i8 [[Y:%.*]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
-; CHECK-NEXT:    [[REM:%.*]] = srem i8 [[X]], [[Y]]
-; CHECK-NEXT:    ret i8 [[REM]]
+; CHECK-NEXT:    [[Y_NONNEG:%.*]] = sub i8 0, [[Y]]
+; CHECK-NEXT:    [[REM1:%.*]] = urem i8 [[X]], [[Y_NONNEG]]
+; CHECK-NEXT:    ret i8 [[REM1]]
 ;
   %c0 = icmp sge i8 %x, 0
   call void @llvm.assume(i1 %c0)
@@ -107,8 +108,10 @@ define i8 @test7_neg_pos(i8 %x, i8 %y) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
 ; CHECK-NEXT:    [[C1:%.*]] = icmp sge i8 [[Y:%.*]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
-; CHECK-NEXT:    [[REM:%.*]] = srem i8 [[X]], [[Y]]
-; CHECK-NEXT:    ret i8 [[REM]]
+; CHECK-NEXT:    [[X_NONNEG:%.*]] = sub i8 0, [[X]]
+; CHECK-NEXT:    [[REM1:%.*]] = urem i8 [[X_NONNEG]], [[Y]]
+; CHECK-NEXT:    [[REM1_NEG:%.*]] = sub i8 0, [[REM1]]
+; CHECK-NEXT:    ret i8 [[REM1_NEG]]
 ;
   %c0 = icmp sle i8 %x, 0
   call void @llvm.assume(i1 %c0)
@@ -124,8 +127,11 @@ define i8 @test8_neg_neg(i8 %x, i8 %y) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
 ; CHECK-NEXT:    [[C1:%.*]] = icmp sle i8 [[Y:%.*]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
-; CHECK-NEXT:    [[REM:%.*]] = srem i8 [[X]], [[Y]]
-; CHECK-NEXT:    ret i8 [[REM]]
+; CHECK-NEXT:    [[X_NONNEG:%.*]] = sub i8 0, [[X]]
+; CHECK-NEXT:    [[Y_NONNEG:%.*]] = sub i8 0, [[Y]]
+; CHECK-NEXT:    [[REM1:%.*]] = urem i8 [[X_NONNEG]], [[Y_NONNEG]]
+; CHECK-NEXT:    [[REM1_NEG:%.*]] = sub i8 0, [[REM1]]
+; CHECK-NEXT:    ret i8 [[REM1_NEG]]
 ;
   %c0 = icmp sle i8 %x, 0
   call void @llvm.assume(i1 %c0)


        


More information about the llvm-commits mailing list