1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

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
This commit is contained in:
Alexandre Isoard 2017-06-29 16:29:04 +00:00
parent 1f8fdfc89e
commit 8476e6e250
4 changed files with 64 additions and 0 deletions

View 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,

View 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)

View File

@ -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
}

View File

@ -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
}