]> granicus.if.org Git - llvm/commitdiff
ScalarEvolution: Add URem support
authorAlexandre Isoard <alexandre.isoard@gmail.com>
Thu, 29 Jun 2017 16:29:04 +0000 (16:29 +0000)
committerAlexandre Isoard <alexandre.isoard@gmail.com>
Thu, 29 Jun 2017 16:29:04 +0000 (16:29 +0000)
In LLVM IR the following code:

    %r = urem <ty> %t, %b

is equivalent to:

    %q = udiv <ty> %t, %b
    %s = mul <ty> nuw %q, %b
    %r = sub <ty> nuw %t, %q ; (t / b) * b + (t % b) = t

As UDiv, Mul and Sub are already supported by SCEV, URem can be
implemented with minimal effort this way.

Note: While SRem and SDiv are also related this way, SCEV does not
provides SDiv yet.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306695 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Analysis/ScalarEvolution.h
lib/Analysis/ScalarEvolution.cpp
test/Analysis/ScalarEvolution/flattened.ll [new file with mode: 0644]
test/Analysis/ScalarEvolution/urem-0.ll [new file with mode: 0644]

index 002a3174fd19d01f4224c2ea4610a9f7c756b087..c57c600075e05c10f2cd22e2476857884137a344 100644 (file)
@@ -1244,6 +1244,7 @@ public:
   }
   const SCEV *getUDivExpr(const SCEV *LHS, const SCEV *RHS);
   const SCEV *getUDivExactExpr(const SCEV *LHS, const SCEV *RHS);
+  const SCEV *getURemExpr(const SCEV *LHS, const SCEV *RHS);
   const SCEV *getAddRecExpr(const SCEV *Start, const SCEV *Step, const Loop *L,
                             SCEV::NoWrapFlags Flags);
   const SCEV *getAddRecExpr(SmallVectorImpl<const SCEV *> &Operands,
index 73a95ec405c7b6bd39f12f26102b9a5c7be74e23..80bbc8b05e21cd257d2fa73c5eb8700f55f7a2b9 100644 (file)
@@ -2935,6 +2935,29 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl<const SCEV *> &Ops,
   return getOrCreateMulExpr(Ops, Flags);
 }
 
+/// Represents an unsigned remainder expression based on unsigned division.
+const SCEV *ScalarEvolution::getURemExpr(const SCEV *LHS,
+                                         const SCEV *RHS) {
+  assert(getEffectiveSCEVType(LHS->getType()) ==
+         getEffectiveSCEVType(RHS->getType()) &&
+         "SCEVURemExpr operand types don't match!");
+
+  // TODO:
+  //  - short circuit '%a = %x urem %x --> 0' (why is it not done for udiv?)
+  //  - short circuit '%a = %x urem 0 --> %a' (same as for udiv)
+  //  - update upper-bound and lower-bound cache for the final result
+  //    (or improve how subtraction is estimated)
+
+  // Short-circuit easy cases
+  if (const SCEVConstant *RHSC = dyn_cast<SCEVConstant>(RHS))
+    if (RHSC->getValue()->equalsInt(1))
+      return getZero(LHS->getType()); // X urem 1 --> 0
+
+  const SCEV *UDiv = getUDivExpr(LHS, RHS);
+  const SCEV *Mult = getMulExpr(UDiv, RHS, SCEV::FlagNUW);
+  return getMinusSCEV(LHS, Mult, SCEV::FlagNUW);
+}
+
 /// Get a canonical unsigned division expression, or something simpler if
 /// possible.
 const SCEV *ScalarEvolution::getUDivExpr(const SCEV *LHS,
@@ -4095,6 +4118,7 @@ static Optional<BinaryOp> MatchBinaryOp(Value *V, DominatorTree &DT) {
   case Instruction::Sub:
   case Instruction::Mul:
   case Instruction::UDiv:
+  case Instruction::URem:
   case Instruction::And:
   case Instruction::Or:
   case Instruction::AShr:
@@ -5416,6 +5440,8 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) {
     }
     case Instruction::UDiv:
       return getUDivExpr(getSCEV(BO->LHS), getSCEV(BO->RHS));
+    case Instruction::URem:
+      return getURemExpr(getSCEV(BO->LHS), getSCEV(BO->RHS));
     case Instruction::Sub: {
       SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap;
       if (BO->Op)
diff --git a/test/Analysis/ScalarEvolution/flattened.ll b/test/Analysis/ScalarEvolution/flattened.ll
new file mode 100644 (file)
index 0000000..3ca5cf1
--- /dev/null
@@ -0,0 +1,22 @@
+; RUN: opt < %s -scalar-evolution -analyze | FileCheck %s
+
+
+define void @foo([7 x i8]* %a) {
+entry:
+       br label %bb
+
+bb:
+       %idx = phi i64 [ 0, %entry ], [ %idx.incr, %bb ]
+       %i = udiv i64 %idx, 7
+       %j = urem i64 %idx, 7
+       %a.ptr = getelementptr [7 x i8], [7 x i8]* %a, i64 %i, i64 %j
+; CHECK: %a.ptr
+; CHECK-NEXT: -->  {%a,+,1}<nw><%bb>
+       %val = load i8, i8* %a.ptr
+       %idx.incr = add i64 %idx, 1
+       %test = icmp ne i64 %idx.incr, 35
+       br i1 %test, label %bb, label %exit
+
+exit:
+       ret void
+}
diff --git a/test/Analysis/ScalarEvolution/urem-0.ll b/test/Analysis/ScalarEvolution/urem-0.ll
new file mode 100644 (file)
index 0000000..4239117
--- /dev/null
@@ -0,0 +1,15 @@
+; RUN: opt < %s -scalar-evolution -analyze | FileCheck %s
+
+define i8 @foo(i8 %a) {
+        %t0 = urem i8 %a, 27
+; CHECK: %t0
+; CHECK-NEXT: -->  ((-27 * (%a /u 27)) + %a)
+        ret i8 %t0
+}
+
+define i8 @bar(i8 %a) {
+        %t1 = urem i8 %a, 1
+; CHECK: %t1
+; CHECK-NEXT: -->  0
+        ret i8 %t1
+}