mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-03-07 11:59:09 +00:00
[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
This commit is contained in:
parent
27cff6cc6b
commit
a49643a387
@ -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,
|
||||
|
@ -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)
|
||||
|
22
test/Analysis/ScalarEvolution/flattened-0.ll
Normal file
22
test/Analysis/ScalarEvolution/flattened-0.ll
Normal file
@ -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
|
||||
}
|
33
test/Analysis/ScalarEvolution/urem-0.ll
Normal file
33
test/Analysis/ScalarEvolution/urem-0.ll
Normal file
@ -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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user