Skip to content

Commit

Permalink
[SCEV] Improve zext(A /u B) and zext(A % B)
Browse files Browse the repository at this point in the history
Summary:
Try to match udiv and urem patterns, and sink zext down to the leaves.

I'm not entirely sure why some unrelated tests change, but the added <nsw>s seem right.

Reviewers: sanjoy

Subscribers: jlebar, hiraditya, bixia, llvm-commits

Differential Revision: https://reviews.llvm.org/D48338

llvm-svn: 335197
  • Loading branch information
timshen91 committed Jun 21, 2018
1 parent 1f3cc8c commit 5af61e0
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 0 deletions.
4 changes: 4 additions & 0 deletions llvm/include/llvm/Analysis/ScalarEvolution.h
Expand Up @@ -1845,6 +1845,10 @@ class ScalarEvolution {
/// accordingly.
void addToLoopUseLists(const SCEV *S);

/// Try to match the pattern generated by getURemExpr(A, B). If successful,
/// Assign A and B to LHS and RHS, respectively.
bool matchURem(const SCEV *Expr, const SCEV *&LHS, const SCEV *&RHS);

FoldingSet<SCEV> UniqueSCEVs;
FoldingSet<SCEVPredicate> UniquePreds;
BumpPtrAllocator SCEVAllocator;
Expand Down
54 changes: 54 additions & 0 deletions llvm/lib/Analysis/ScalarEvolution.cpp
Expand Up @@ -1756,6 +1756,20 @@ ScalarEvolution::getZeroExtendExpr(const SCEV *Op, Type *Ty, unsigned Depth) {
}
}

// zext(A % B) --> zext(A) % zext(B)
{
const SCEV *LHS;
const SCEV *RHS;
if (matchURem(Op, LHS, RHS))
return getURemExpr(getZeroExtendExpr(LHS, Ty, Depth + 1),
getZeroExtendExpr(RHS, Ty, Depth + 1));
}

// zext(A / B) --> zext(A) / zext(B).
if (auto *Div = dyn_cast<SCEVUDivExpr>(Op))
return getUDivExpr(getZeroExtendExpr(Div->getLHS(), Ty, Depth + 1),
getZeroExtendExpr(Div->getRHS(), Ty, Depth + 1));

if (auto *SA = dyn_cast<SCEVAddExpr>(Op)) {
// zext((A + B + ...)<nuw>) --> (zext(A) + zext(B) + ...)<nuw>
if (SA->hasNoUnsignedWrap()) {
Expand Down Expand Up @@ -12153,3 +12167,43 @@ void PredicatedScalarEvolution::print(raw_ostream &OS, unsigned Depth) const {
OS.indent(Depth + 2) << "--> " << *II->second.second << "\n";
}
}

// Match the mathematical pattern A - (A / B) * B, where A and B can be
// arbitrary expressions.
// It's not always easy, as A and B can be folded (imagine A is X / 2, and B is
// 4, A / B becomes X / 8).
bool ScalarEvolution::matchURem(const SCEV *Expr, const SCEV *&LHS,
const SCEV *&RHS) {
const auto *Add = dyn_cast<SCEVAddExpr>(Expr);
if (Add == nullptr || Add->getNumOperands() != 2)
return false;

const SCEV *A = Add->getOperand(1);
const auto *Mul = dyn_cast<SCEVMulExpr>(Add->getOperand(0));

if (Mul == nullptr)
return false;

const auto MatchURemWithDivisor = [&](const SCEV *B) {
// (SomeExpr + (-(SomeExpr / B) * B)).
if (Expr == getURemExpr(A, B)) {
LHS = A;
RHS = B;
return true;
}
return false;
};

// (SomeExpr + (-1 * (SomeExpr / B) * B)).
if (Mul->getNumOperands() == 3 && isa<SCEVConstant>(Mul->getOperand(0)))
return MatchURemWithDivisor(Mul->getOperand(1)) ||
MatchURemWithDivisor(Mul->getOperand(2));

// (SomeExpr + ((-SomeExpr / B) * B)) or (SomeExpr + ((SomeExpr / B) * -B)).
if (Mul->getNumOperands() == 2)
return MatchURemWithDivisor(Mul->getOperand(1)) ||
MatchURemWithDivisor(Mul->getOperand(0)) ||
MatchURemWithDivisor(getNegativeSCEV(Mul->getOperand(1))) ||
MatchURemWithDivisor(getNegativeSCEV(Mul->getOperand(0)));
return false;
};
42 changes: 42 additions & 0 deletions llvm/test/Analysis/ScalarEvolution/zext-divrem.ll
@@ -0,0 +1,42 @@
; RUN: opt -analyze -scalar-evolution -S < %s | FileCheck %s

define i64 @test1(i32 %a, i32 %b) {
; CHECK-LABEL: @test1
%div = udiv i32 %a, %b
%zext = zext i32 %div to i64
; CHECK: %zext
; CHECK-NEXT: --> ((zext i32 %a to i64) /u (zext i32 %b to i64))
ret i64 %zext
}

define i64 @test2(i32 %a, i32 %b) {
; CHECK-LABEL: @test2
%rem = urem i32 %a, %b
%zext = zext i32 %rem to i64
; CHECK: %zext
; CHECK-NEXT: --> ((zext i32 %a to i64) + (-1 * (zext i32 %b to i64) * ((zext i32 %a to i64) /u (zext i32 %b to i64))))
ret i64 %zext
}

define i64 @test3(i32 %a, i32 %b) {
; CHECK-LABEL: @test3
%div = udiv i32 %a, %b
%mul = mul i32 %div, %b
%sub = sub i32 %a, %mul
%zext = zext i32 %sub to i64
; CHECK: %zext
; CHECK-NEXT: --> ((zext i32 %a to i64) + (-1 * (zext i32 %b to i64) * ((zext i32 %a to i64) /u (zext i32 %b to i64))))
ret i64 %zext
}

define i64 @test4(i32 %t) {
; CHECK-LABEL: @test4
%a = udiv i32 %t, 2
%div = udiv i32 %t, 112
%mul = mul i32 %div, 56
%sub = sub i32 %a, %mul
%zext = zext i32 %sub to i64
; CHECK: %zext
; CHECK-NEXT: --> ((-56 * ((zext i32 %t to i64) /u 112)) + ((zext i32 %t to i64) /u 2))
ret i64 %zext
}

0 comments on commit 5af61e0

Please sign in to comment.