Skip to content

Commit 0f3c9b5

Browse files
committed
[SCEV] SCEVExpander::isHighCostExpansionHelper(): cost-model polynomial recurrence
Summary: So, i wouldn't call this *obviously* correct, but i think i got it right this time :) Roughly, we have ``` Op0*x^0 + Op1*x^1 + Op2*x^2 ... ``` where `Op_{n} * x^{n}` is called term, and `n` the degree of term. Due to the way they are stored internally in `SCEVAddRecExpr`, i believe we can have `Op_{n}` to be `0`, so we should not charge for those. I think it is most straight-forward to count the cost in 4 steps: 1. First, count it the same way we counted `scAddExpr`, but be sure to skip terms with zero constants. Much like with `add` expr we will have one less addition than number of terms. 2. Each non-constant term (term degree >= 1) requires a multiplication between the `Op_{n}` and `x^{n}`. But again, only charge for it if it is required - `Op_{n}` must not be 0 (no term) or 1 (no multiplication needed), and obviously don't charge constant terms (`x^0 == 1`). 3. We must charge for all the `x^0`..`x^{poly_degree}` themselves. Since `x^{poly_degree}` is `x * x * ... * x`, i.e. `poly_degree` `x`'es multiplied, for final `poly_degree` term we again require `poly_degree-1` multiplications. Note that all the `x^{0}`..`x^{poly_degree-1}` will be computed for the free along the way there. 4. And finally, the operands themselves. Here, much like with add/mul exprs, we really don't look for preexisting instructions.. Reviewers: reames, mkazantsev, wmi, sanjoy Reviewed By: mkazantsev Subscribers: hiraditya, javed.absar, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D73741
1 parent 756af2f commit 0f3c9b5

File tree

1 file changed

+58
-9
lines changed

1 file changed

+58
-9
lines changed

llvm/lib/Analysis/ScalarEvolutionExpander.cpp

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2219,6 +2219,64 @@ bool SCEVExpander::isHighCostExpansionHelper(
22192219
TTI, Processed);
22202220
}
22212221

2222+
if (const auto *NAry = dyn_cast<SCEVAddRecExpr>(S)) {
2223+
Type *OpType = NAry->getType();
2224+
2225+
assert(NAry->getNumOperands() >= 2 &&
2226+
"Polynomial should be at least linear");
2227+
2228+
int AddCost = TTI.getOperationCost(Instruction::Add, OpType);
2229+
int MulCost = TTI.getOperationCost(Instruction::Mul, OpType);
2230+
2231+
// In this polynominal, we may have some zero operands, and we shouldn't
2232+
// really charge for those. So how many non-zero coeffients are there?
2233+
int NumTerms = llvm::count_if(NAry->operands(),
2234+
[](const SCEV *S) { return !S->isZero(); });
2235+
assert(NumTerms >= 1 && "Polynominal should have at least one term.");
2236+
assert(!(*std::prev(NAry->operands().end()))->isZero() &&
2237+
"Last operand should not be zero");
2238+
2239+
// Much like with normal add expr, the polynominal will require
2240+
// one less addition than the number of it's terms.
2241+
BudgetRemaining -= AddCost * (NumTerms - 1);
2242+
if (BudgetRemaining < 0)
2243+
return true;
2244+
2245+
// Ignoring constant term (operand 0), how many of the coeffients are u> 1?
2246+
int NumNonZeroDegreeNonOneTerms =
2247+
llvm::count_if(make_range(std::next(NAry->op_begin()), NAry->op_end()),
2248+
[](const SCEV *S) {
2249+
auto *SConst = dyn_cast<SCEVConstant>(S);
2250+
return !SConst || SConst->getAPInt().ugt(1);
2251+
});
2252+
// Here, *each* one of those will require a multiplication.
2253+
BudgetRemaining -= MulCost * NumNonZeroDegreeNonOneTerms;
2254+
if (BudgetRemaining < 0)
2255+
return true;
2256+
2257+
// What is the degree of this polynominal?
2258+
int PolyDegree = NAry->getNumOperands() - 1;
2259+
assert(PolyDegree >= 1 && "Should be at least affine.");
2260+
2261+
// The final term will be:
2262+
// Op_{PolyDegree} * x ^ {PolyDegree}
2263+
// Where x ^ {PolyDegree} will again require PolyDegree-1 mul operations.
2264+
// Note that x ^ {PolyDegree} = x * x ^ {PolyDegree-1} so charging for
2265+
// x ^ {PolyDegree} will give us x ^ {2} .. x ^ {PolyDegree-1} for free.
2266+
// FIXME: this is conservatively correct, but might be overly pessimistic.
2267+
BudgetRemaining -= MulCost * (PolyDegree - 1);
2268+
if (BudgetRemaining < 0)
2269+
return true;
2270+
2271+
// And finally, the operands themselves should fit within the budget.
2272+
for (const SCEV *Op : NAry->operands()) {
2273+
if (isHighCostExpansionHelper(Op, L, At, BudgetRemaining, TTI, Processed))
2274+
return true;
2275+
}
2276+
2277+
return BudgetRemaining < 0;
2278+
}
2279+
22222280
if (S->getSCEVType() == scAddExpr || S->getSCEVType() == scMulExpr) {
22232281
const SCEVNAryExpr *NAry = dyn_cast<SCEVNAryExpr>(S);
22242282

@@ -2258,15 +2316,6 @@ bool SCEVExpander::isHighCostExpansionHelper(
22582316
if (isa<SCEVMinMaxExpr>(S))
22592317
return true;
22602318

2261-
// Recurse past nary expressions, which commonly occur in the
2262-
// BackedgeTakenCount. They may already exist in program code, and if not,
2263-
// they are not too expensive rematerialize.
2264-
if (const SCEVNAryExpr *NAry = dyn_cast<SCEVNAryExpr>(S)) {
2265-
for (auto *Op : NAry->operands())
2266-
if (isHighCostExpansionHelper(Op, L, At, BudgetRemaining, TTI, Processed))
2267-
return true;
2268-
}
2269-
22702319
// If we haven't recognized an expensive SCEV pattern, assume it's an
22712320
// expression produced by program code.
22722321
return false;

0 commit comments

Comments
 (0)