Skip to content

Commit

Permalink
[unittest] Exercise SCEV's udiv and udiv ceiling routines
Browse files Browse the repository at this point in the history
The ceiling variant was recently added (due to the work towards D105216), and we're spending a lot of time trying to find optimizations for the expression. This patch brute forces the space of i8 unsigned divides and checks that we get a correct (well consistent with APInt) result for both udiv and udiv ceiling.

(This is basically what I've been doing locally in a hand rolled C++ program, and I realized there no good reason not to check it in as a unit test which directly exercises the logic on constants.)

Differential Revision: https://reviews.llvm.org/D106083
  • Loading branch information
preames committed Jul 15, 2021
1 parent 8fb4745 commit b980d2f
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 10 deletions.
20 changes: 10 additions & 10 deletions llvm/include/llvm/Analysis/ScalarEvolution.h
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,16 @@ class ScalarEvolution {
SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap,
unsigned Depth = 0);

/// Compute ceil(N / D). N and D are treated as unsigned values.
///
/// Since SCEV doesn't have native ceiling division, this generates a
/// SCEV expression of the following form:
///
/// umin(N, 1) + floor((N - umin(N, 1)) / D)
///
/// A denominator of zero or poison is handled the same way as getUDivExpr().
const SCEV *getUDivCeilSCEV(const SCEV *N, const SCEV *D);

/// Return a SCEV corresponding to a conversion of the input value to the
/// specified type. If the type must be extended, it is zero extended.
const SCEV *getTruncateOrZeroExtend(const SCEV *V, Type *Ty,
Expand Down Expand Up @@ -2029,16 +2039,6 @@ class ScalarEvolution {
/// that the result is undefined if it does.
const SCEV *computeBECount(const SCEV *Delta, const SCEV *Stride);

/// Compute ceil(N / D). N and D are treated as unsigned values.
///
/// Since SCEV doesn't have native ceiling division, this generates a
/// SCEV expression of the following form:
///
/// umin(N, 1) + floor((N - umin(N, 1)) / D)
///
/// A denominator of zero or poison is handled the same way as getUDivExpr().
const SCEV *getUDivCeilSCEV(const SCEV *N, const SCEV *D);

/// Compute the maximum backedge count based on the range of values
/// permitted by Start, End, and Stride. This is for loops of the form
/// {Start, +, Stride} LT End.
Expand Down
31 changes: 31 additions & 0 deletions llvm/unittests/Analysis/ScalarEvolutionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1507,4 +1507,35 @@ TEST_F(ScalarEvolutionsTest, MatchURem) {
});
}

TEST_F(ScalarEvolutionsTest, SCEVUDivFloorCeiling) {
LLVMContext C;
SMDiagnostic Err;
std::unique_ptr<Module> M = parseAssemblyString("define void @foo() { "
" ret void "
"} ",
Err, C);

ASSERT_TRUE(M && "Could not parse module?");
ASSERT_TRUE(!verifyModule(*M) && "Must have been well formed!");

runWithSE(*M, "foo", [](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
// Check that SCEV's udiv and uceil handling produce the correct results
// for all 8 bit options. Div-by-zero is deliberately excluded.
for (unsigned N = 0; N < 256; N++)
for (unsigned D = 1; D < 256; D++) {
APInt NInt(8, N);
APInt DInt(8, D);
using namespace llvm::APIntOps;
APInt FloorInt = RoundingUDiv(NInt, DInt, APInt::Rounding::DOWN);
APInt CeilingInt = RoundingUDiv(NInt, DInt, APInt::Rounding::UP);
auto *NS = SE.getConstant(NInt);
auto *DS = SE.getConstant(DInt);
auto *FloorS = cast<SCEVConstant>(SE.getUDivExpr(NS, DS));
auto *CeilingS = cast<SCEVConstant>(SE.getUDivCeilSCEV(NS, DS));
ASSERT_TRUE(FloorS->getAPInt() == FloorInt);
ASSERT_TRUE(CeilingS->getAPInt() == CeilingInt);
}
});
}

} // end namespace llvm

0 comments on commit b980d2f

Please sign in to comment.