From a70a8a0aa7aba9190a6fdc60c1a7ddbbfd54a81f Mon Sep 17 00:00:00 2001 From: Alexandre Isoard Date: Thu, 29 Jun 2017 16:29:04 +0000 Subject: [PATCH] ScalarEvolution: Add URem support In LLVM IR the following code: %r = urem %t, %b is equivalent to: %q = udiv %t, %b %s = mul nuw %q, %b %r = sub 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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306695 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Analysis/ScalarEvolution.h | 1 + lib/Analysis/ScalarEvolution.cpp | 26 ++++++++++++++++++++++ test/Analysis/ScalarEvolution/flattened.ll | 22 ++++++++++++++++++ test/Analysis/ScalarEvolution/urem-0.ll | 15 +++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 test/Analysis/ScalarEvolution/flattened.ll create mode 100644 test/Analysis/ScalarEvolution/urem-0.ll diff --git a/include/llvm/Analysis/ScalarEvolution.h b/include/llvm/Analysis/ScalarEvolution.h index 002a3174fd1..c57c600075e 100644 --- a/include/llvm/Analysis/ScalarEvolution.h +++ b/include/llvm/Analysis/ScalarEvolution.h @@ -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 &Operands, diff --git a/lib/Analysis/ScalarEvolution.cpp b/lib/Analysis/ScalarEvolution.cpp index 73a95ec405c..80bbc8b05e2 100644 --- a/lib/Analysis/ScalarEvolution.cpp +++ b/lib/Analysis/ScalarEvolution.cpp @@ -2935,6 +2935,29 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &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(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 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) diff --git a/test/Analysis/ScalarEvolution/flattened.ll b/test/Analysis/ScalarEvolution/flattened.ll new file mode 100644 index 00000000000..3ca5cf166c8 --- /dev/null +++ b/test/Analysis/ScalarEvolution/flattened.ll @@ -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}<%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/test/Analysis/ScalarEvolution/urem-0.ll b/test/Analysis/ScalarEvolution/urem-0.ll new file mode 100644 index 00000000000..423911706ad --- /dev/null +++ b/test/Analysis/ScalarEvolution/urem-0.ll @@ -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 +} -- 2.40.0