diff options
| author | Alexandre Isoard <alexandre.isoard@gmail.com> | 2017-09-01 14:59:59 +0000 |
|---|---|---|
| committer | Alexandre Isoard <alexandre.isoard@gmail.com> | 2017-09-01 14:59:59 +0000 |
| commit | 405728fd47a555e51196a6883d33318f22fab9a4 (patch) | |
| tree | 0aa242b490a05acf28737503cd6324006e5b3951 /llvm | |
| parent | 65528f29913a541f3d250dbee2d93a3b1db68e4d (diff) | |
| download | bcm5719-llvm-405728fd47a555e51196a6883d33318f22fab9a4.tar.gz bcm5719-llvm-405728fd47a555e51196a6883d33318f22fab9a4.zip | |
[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.
llvm-svn: 312329
Diffstat (limited to 'llvm')
| -rw-r--r-- | llvm/include/llvm/Analysis/ScalarEvolution.h | 1 | ||||
| -rw-r--r-- | llvm/lib/Analysis/ScalarEvolution.cpp | 31 | ||||
| -rw-r--r-- | llvm/test/Analysis/ScalarEvolution/flattened-0.ll | 22 | ||||
| -rw-r--r-- | llvm/test/Analysis/ScalarEvolution/urem-0.ll | 33 |
4 files changed, 87 insertions, 0 deletions
diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h index 306c79e7f3b..d63aaf6d055 100644 --- a/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -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, diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index 25decab88ed..e3bd30a9e3c 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -2981,6 +2981,34 @@ 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!"); + + // 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(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: @@ -5782,6 +5811,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/llvm/test/Analysis/ScalarEvolution/flattened-0.ll b/llvm/test/Analysis/ScalarEvolution/flattened-0.ll new file mode 100644 index 00000000000..e6614ffd646 --- /dev/null +++ b/llvm/test/Analysis/ScalarEvolution/flattened-0.ll @@ -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 +} diff --git a/llvm/test/Analysis/ScalarEvolution/urem-0.ll b/llvm/test/Analysis/ScalarEvolution/urem-0.ll new file mode 100644 index 00000000000..a53f75b86fa --- /dev/null +++ b/llvm/test/Analysis/ScalarEvolution/urem-0.ll @@ -0,0 +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 = 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 = 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 +} |

