diff options
author | Alexandre Isoard <alexandre.isoard@gmail.com> | 2017-06-29 16:29:04 +0000 |
---|---|---|
committer | Alexandre Isoard <alexandre.isoard@gmail.com> | 2017-06-29 16:29:04 +0000 |
commit | aa29afc75600c659e9eef0f124b7fa74fd8006cb (patch) | |
tree | 9c9c43296812661cad7b1a50efd682e085465895 /llvm/lib | |
parent | 39b88f01a53cc561c0002361eb77b1a4d0d35bfd (diff) | |
download | bcm5719-llvm-aa29afc75600c659e9eef0f124b7fa74fd8006cb.tar.gz bcm5719-llvm-aa29afc75600c659e9eef0f124b7fa74fd8006cb.zip |
ScalarEvolution: Add URem support
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.
llvm-svn: 306695
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Analysis/ScalarEvolution.cpp | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index 73a95ec405c..80bbc8b05e2 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -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) |