[llvm] r312329 - [SCEV] Add URem support to SCEV

Alexandre Isoard via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 1 07:59:59 PDT 2017


Author: aisoard
Date: Fri Sep  1 07:59:59 2017
New Revision: 312329

URL: http://llvm.org/viewvc/llvm-project?rev=312329&view=rev
Log:
[SCEV] Add URem support to SCEV

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 using that relation:

    %r --> (-%b * (%t /u %b)) + %t

We implement two special cases:

  - if %b is 1, the result is always 0
  - if %b is a power-of-two, we produce a zext/trunc based expression instead

That is, the following code:

    %r = urem i32 %t, 65536

Produces:

    %r --> (zext i16 (trunc i32 %a to i16) to i32)

Note that while this helps get a tighter bound on the range analysis and the
known-bits analysis, this exposes some normalization shortcoming of SCEVs:

    %div = udim i32 %a, 65536
    %mul = mul i32 %div, 65536
    %rem = urem i32 %a, 65536
    %add = add i32 %mul, %rem

Will usually not be reduced.


Added:
    llvm/trunk/test/Analysis/ScalarEvolution/flattened-0.ll
    llvm/trunk/test/Analysis/ScalarEvolution/urem-0.ll
      - copied, changed from r306722, llvm/trunk/test/Analysis/ScalarEvolution/urem-0.ll
Modified:
    llvm/trunk/include/llvm/Analysis/ScalarEvolution.h
    llvm/trunk/lib/Analysis/ScalarEvolution.cpp

Modified: llvm/trunk/include/llvm/Analysis/ScalarEvolution.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ScalarEvolution.h?rev=312329&r1=312328&r2=312329&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/ScalarEvolution.h (original)
+++ llvm/trunk/include/llvm/Analysis/ScalarEvolution.h Fri Sep  1 07:59:59 2017
@@ -1269,6 +1269,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,

Modified: llvm/trunk/lib/Analysis/ScalarEvolution.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolution.cpp?rev=312329&r1=312328&r2=312329&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ScalarEvolution.cpp (original)
+++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp Fri Sep  1 07:59:59 2017
@@ -2981,6 +2981,34 @@ const SCEV *ScalarEvolution::getMulExpr(
   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!");
+
+  // Short-circuit easy cases
+  if (const SCEVConstant *RHSC = dyn_cast<SCEVConstant>(RHS)) {
+    // If constant is one, the result is trivial
+    if (RHSC->getValue()->isOne())
+      return getZero(LHS->getType()); // X urem 1 --> 0
+
+    // If constant is a power of two, fold into a zext(trunc(LHS)).
+    if (RHSC->getAPInt().isPowerOf2()) {
+      Type *FullTy = LHS->getType();
+      Type *TruncTy =
+          IntegerType::get(getContext(), RHSC->getAPInt().logBase2());
+      return getZeroExtendExpr(getTruncateExpr(LHS, TruncTy), FullTy);
+    }
+  }
+
+  // Fallback to %a == %x urem %y == %x -<nuw> ((%x udiv %y) *<nuw> %y)
+  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,
@@ -4144,6 +4172,7 @@ static Optional<BinaryOp> MatchBinaryOp(
   case Instruction::Sub:
   case Instruction::Mul:
   case Instruction::UDiv:
+  case Instruction::URem:
   case Instruction::And:
   case Instruction::Or:
   case Instruction::AShr:
@@ -5782,6 +5811,8 @@ const SCEV *ScalarEvolution::createSCEV(
     }
     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)

Added: llvm/trunk/test/Analysis/ScalarEvolution/flattened-0.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/ScalarEvolution/flattened-0.ll?rev=312329&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/ScalarEvolution/flattened-0.ll (added)
+++ llvm/trunk/test/Analysis/ScalarEvolution/flattened-0.ll Fri Sep  1 07:59:59 2017
@@ -0,0 +1,22 @@
+; RUN: opt < %s -scalar-evolution -analyze | FileCheck %s
+
+define void @foo([7 x i8]* %a) {
+; CHECK-LABEL: @foo
+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 = getelementptr [7 x i8], [7 x i8]* %a, i64 %i, i64 %j
+; 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
+}

Copied: llvm/trunk/test/Analysis/ScalarEvolution/urem-0.ll (from r306722, llvm/trunk/test/Analysis/ScalarEvolution/urem-0.ll)
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/ScalarEvolution/urem-0.ll?p2=llvm/trunk/test/Analysis/ScalarEvolution/urem-0.ll&p1=llvm/trunk/test/Analysis/ScalarEvolution/urem-0.ll&r1=306722&r2=312329&rev=312329&view=diff
==============================================================================
--- llvm/trunk/test/Analysis/ScalarEvolution/urem-0.ll (original)
+++ llvm/trunk/test/Analysis/ScalarEvolution/urem-0.ll Fri Sep  1 07:59:59 2017
@@ -1,15 +1,33 @@
 ; RUN: opt < %s -scalar-evolution -analyze | FileCheck %s
 
 define i8 @foo(i8 %a) {
+; CHECK-LABEL: @foo
         %t0 = urem i8 %a, 27
-; CHECK: %t0
+; CHECK: %t0 = urem i8 %a, 27
 ; CHECK-NEXT: -->  ((-27 * (%a /u 27)) + %a)
         ret i8 %t0
 }
 
 define i8 @bar(i8 %a) {
+; CHECK-LABEL: @bar
         %t1 = urem i8 %a, 1
-; CHECK: %t1
+; CHECK: %t1 = urem i8 %a, 1
 ; CHECK-NEXT: -->  0
         ret i8 %t1
 }
+
+define i8 @baz(i8 %a) {
+; CHECK-LABEL: @baz
+        %t2 = urem i8 %a, 32
+; CHECK: %t2 = urem i8 %a, 32
+; CHECK-NEXT: -->  (zext i5 (trunc i8 %a to i5) to i8)
+        ret i8 %t2
+}
+
+define i8 @qux(i8 %a) {
+; CHECK-LABEL: @qux
+        %t3 = urem i8 %a, 2
+; CHECK: %t3 = urem i8 %a, 2
+; CHECK-NEXT: -->  (zext i1 (trunc i8 %a to i1) to i8)
+        ret i8 %t3
+}




More information about the llvm-commits mailing list