[llvm] 585c594 - Move delinearization logic out of SCEV [NFC]
Michael Kruse via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 8 13:05:45 PDT 2021
You left getIndexExpressionsFromGEP inside ScalarEvolution. Don't you
consider it part of Delinearization? getElementSize is also only used
in delinearization use cases/was introduced for it.
Michael
Am Mi., 8. Sept. 2021 um 14:28 Uhr schrieb Philip Reames via
llvm-commits <llvm-commits at lists.llvm.org>:
>
>
> Author: Philip Reames
> Date: 2021-09-08T12:28:35-07:00
> New Revision: 585c594d749a2a88150b63804587af85abdabeaa
>
> URL: https://github.com/llvm/llvm-project/commit/585c594d749a2a88150b63804587af85abdabeaa
> DIFF: https://github.com/llvm/llvm-project/commit/585c594d749a2a88150b63804587af85abdabeaa.diff
>
> LOG: Move delinearization logic out of SCEV [NFC]
>
> None of this logic has anything to do with SCEV's internals, it just uses the existing public APIs. As a result, we can move the code from ScalarEvolution.cpp/hpp to Delinearization.cpp/hpp with only minor changes.
>
> This was discussed in advance on today's loop opt call. It turned out to be easy as hoped.
>
> Added:
>
>
> Modified:
> llvm/include/llvm/Analysis/Delinearization.h
> llvm/include/llvm/Analysis/ScalarEvolution.h
> llvm/lib/Analysis/Delinearization.cpp
> llvm/lib/Analysis/DependenceAnalysis.cpp
> llvm/lib/Analysis/LoopCacheAnalysis.cpp
> llvm/lib/Analysis/ScalarEvolution.cpp
>
> Removed:
>
>
>
> ################################################################################
> diff --git a/llvm/include/llvm/Analysis/Delinearization.h b/llvm/include/llvm/Analysis/Delinearization.h
> index 2658b6bbc80c0..dec3fd9b08a9f 100644
> --- a/llvm/include/llvm/Analysis/Delinearization.h
> +++ b/llvm/include/llvm/Analysis/Delinearization.h
> @@ -16,10 +16,100 @@
> #ifndef LLVM_ANALYSIS_DELINEARIZATION_H
> #define LLVM_ANALYSIS_DELINEARIZATION_H
>
> +#include "llvm/ADT/SmallVector.h"
> #include "llvm/IR/PassManager.h"
> #include "llvm/Support/raw_ostream.h"
>
> namespace llvm {
> +class ScalarEvolution;
> +class SCEV;
> +
> +/// Compute the array dimensions Sizes from the set of Terms extracted from
> +/// the memory access function of this SCEVAddRecExpr (second step of
> +/// delinearization).
> +void findArrayDimensions(ScalarEvolution &SE,
> + SmallVectorImpl<const SCEV *> &Terms,
> + SmallVectorImpl<const SCEV *> &Sizes,
> + const SCEV *ElementSize);
> +
> +/// Collect parametric terms occurring in step expressions (first step of
> +/// delinearization).
> +void collectParametricTerms(ScalarEvolution &SE, const SCEV *Expr,
> + SmallVectorImpl<const SCEV *> &Terms);
> +
> +/// Return in Subscripts the access functions for each dimension in Sizes
> +/// (third step of delinearization).
> +void computeAccessFunctions(ScalarEvolution &SE, const SCEV *Expr,
> + SmallVectorImpl<const SCEV *> &Subscripts,
> + SmallVectorImpl<const SCEV *> &Sizes);
> +/// Split this SCEVAddRecExpr into two vectors of SCEVs representing the
> +/// subscripts and sizes of an array access.
> +///
> +/// The delinearization is a 3 step process: the first two steps compute the
> +/// sizes of each subscript and the third step computes the access functions
> +/// for the delinearized array:
> +///
> +/// 1. Find the terms in the step functions
> +/// 2. Compute the array size
> +/// 3. Compute the access function: divide the SCEV by the array size
> +/// starting with the innermost dimensions found in step 2. The Quotient
> +/// is the SCEV to be divided in the next step of the recursion. The
> +/// Remainder is the subscript of the innermost dimension. Loop over all
> +/// array dimensions computed in step 2.
> +///
> +/// To compute a uniform array size for several memory accesses to the same
> +/// object, one can collect in step 1 all the step terms for all the memory
> +/// accesses, and compute in step 2 a unique array shape. This guarantees
> +/// that the array shape will be the same across all memory accesses.
> +///
> +/// FIXME: We could derive the result of steps 1 and 2 from a description of
> +/// the array shape given in metadata.
> +///
> +/// Example:
> +///
> +/// A[][n][m]
> +///
> +/// for i
> +/// for j
> +/// for k
> +/// A[j+k][2i][5i] =
> +///
> +/// The initial SCEV:
> +///
> +/// A[{{{0,+,2*m+5}_i, +, n*m}_j, +, n*m}_k]
> +///
> +/// 1. Find the
> diff erent terms in the step functions:
> +/// -> [2*m, 5, n*m, n*m]
> +///
> +/// 2. Compute the array size: sort and unique them
> +/// -> [n*m, 2*m, 5]
> +/// find the GCD of all the terms = 1
> +/// divide by the GCD and erase constant terms
> +/// -> [n*m, 2*m]
> +/// GCD = m
> +/// divide by GCD -> [n, 2]
> +/// remove constant terms
> +/// -> [n]
> +/// size of the array is A[unknown][n][m]
> +///
> +/// 3. Compute the access function
> +/// a. Divide {{{0,+,2*m+5}_i, +, n*m}_j, +, n*m}_k by the innermost size m
> +/// Quotient: {{{0,+,2}_i, +, n}_j, +, n}_k
> +/// Remainder: {{{0,+,5}_i, +, 0}_j, +, 0}_k
> +/// The remainder is the subscript of the innermost array dimension: [5i].
> +///
> +/// b. Divide Quotient: {{{0,+,2}_i, +, n}_j, +, n}_k by next outer size n
> +/// Quotient: {{{0,+,0}_i, +, 1}_j, +, 1}_k
> +/// Remainder: {{{0,+,2}_i, +, 0}_j, +, 0}_k
> +/// The Remainder is the subscript of the next array dimension: [2i].
> +///
> +/// The subscript of the outermost dimension is the Quotient: [j+k].
> +///
> +/// Overall, we have: A[][n][m], and the access function: A[j+k][2i][5i].
> +void delinearize(ScalarEvolution &SE, const SCEV *Expr,
> + SmallVectorImpl<const SCEV *> &Subscripts,
> + SmallVectorImpl<const SCEV *> &Sizes, const SCEV *ElementSize);
> +
> struct DelinearizationPrinterPass
> : public PassInfoMixin<DelinearizationPrinterPass> {
> explicit DelinearizationPrinterPass(raw_ostream &OS);
>
> diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
> index 6ae865e011cf0..445a925c70e83 100644
> --- a/llvm/include/llvm/Analysis/ScalarEvolution.h
> +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
> @@ -1099,29 +1099,11 @@ class ScalarEvolution {
> /// Return the size of an element read or written by Inst.
> const SCEV *getElementSize(Instruction *Inst);
>
> - /// Compute the array dimensions Sizes from the set of Terms extracted from
> - /// the memory access function of this SCEVAddRecExpr (second step of
> - /// delinearization).
> - void findArrayDimensions(SmallVectorImpl<const SCEV *> &Terms,
> - SmallVectorImpl<const SCEV *> &Sizes,
> - const SCEV *ElementSize);
> -
> void print(raw_ostream &OS) const;
> void verify() const;
> bool invalidate(Function &F, const PreservedAnalyses &PA,
> FunctionAnalysisManager::Invalidator &Inv);
>
> - /// Collect parametric terms occurring in step expressions (first step of
> - /// delinearization).
> - void collectParametricTerms(const SCEV *Expr,
> - SmallVectorImpl<const SCEV *> &Terms);
> -
> - /// Return in Subscripts the access functions for each dimension in Sizes
> - /// (third step of delinearization).
> - void computeAccessFunctions(const SCEV *Expr,
> - SmallVectorImpl<const SCEV *> &Subscripts,
> - SmallVectorImpl<const SCEV *> &Sizes);
> -
> /// Gathers the individual index expressions from a GEP instruction.
> ///
> /// This function optimistically assumes the GEP references into a fixed size
> @@ -1135,74 +1117,6 @@ class ScalarEvolution {
> SmallVectorImpl<const SCEV *> &Subscripts,
> SmallVectorImpl<int> &Sizes);
>
> - /// Split this SCEVAddRecExpr into two vectors of SCEVs representing the
> - /// subscripts and sizes of an array access.
> - ///
> - /// The delinearization is a 3 step process: the first two steps compute the
> - /// sizes of each subscript and the third step computes the access functions
> - /// for the delinearized array:
> - ///
> - /// 1. Find the terms in the step functions
> - /// 2. Compute the array size
> - /// 3. Compute the access function: divide the SCEV by the array size
> - /// starting with the innermost dimensions found in step 2. The Quotient
> - /// is the SCEV to be divided in the next step of the recursion. The
> - /// Remainder is the subscript of the innermost dimension. Loop over all
> - /// array dimensions computed in step 2.
> - ///
> - /// To compute a uniform array size for several memory accesses to the same
> - /// object, one can collect in step 1 all the step terms for all the memory
> - /// accesses, and compute in step 2 a unique array shape. This guarantees
> - /// that the array shape will be the same across all memory accesses.
> - ///
> - /// FIXME: We could derive the result of steps 1 and 2 from a description of
> - /// the array shape given in metadata.
> - ///
> - /// Example:
> - ///
> - /// A[][n][m]
> - ///
> - /// for i
> - /// for j
> - /// for k
> - /// A[j+k][2i][5i] =
> - ///
> - /// The initial SCEV:
> - ///
> - /// A[{{{0,+,2*m+5}_i, +, n*m}_j, +, n*m}_k]
> - ///
> - /// 1. Find the
> diff erent terms in the step functions:
> - /// -> [2*m, 5, n*m, n*m]
> - ///
> - /// 2. Compute the array size: sort and unique them
> - /// -> [n*m, 2*m, 5]
> - /// find the GCD of all the terms = 1
> - /// divide by the GCD and erase constant terms
> - /// -> [n*m, 2*m]
> - /// GCD = m
> - /// divide by GCD -> [n, 2]
> - /// remove constant terms
> - /// -> [n]
> - /// size of the array is A[unknown][n][m]
> - ///
> - /// 3. Compute the access function
> - /// a. Divide {{{0,+,2*m+5}_i, +, n*m}_j, +, n*m}_k by the innermost size m
> - /// Quotient: {{{0,+,2}_i, +, n}_j, +, n}_k
> - /// Remainder: {{{0,+,5}_i, +, 0}_j, +, 0}_k
> - /// The remainder is the subscript of the innermost array dimension: [5i].
> - ///
> - /// b. Divide Quotient: {{{0,+,2}_i, +, n}_j, +, n}_k by next outer size n
> - /// Quotient: {{{0,+,0}_i, +, 1}_j, +, 1}_k
> - /// Remainder: {{{0,+,2}_i, +, 0}_j, +, 0}_k
> - /// The Remainder is the subscript of the next array dimension: [2i].
> - ///
> - /// The subscript of the outermost dimension is the Quotient: [j+k].
> - ///
> - /// Overall, we have: A[][n][m], and the access function: A[j+k][2i][5i].
> - void delinearize(const SCEV *Expr, SmallVectorImpl<const SCEV *> &Subscripts,
> - SmallVectorImpl<const SCEV *> &Sizes,
> - const SCEV *ElementSize);
> -
> /// Return the DataLayout associated with the module this SCEV instance is
> /// operating on.
> const DataLayout &getDataLayout() const {
>
> diff --git a/llvm/lib/Analysis/Delinearization.cpp b/llvm/lib/Analysis/Delinearization.cpp
> index 448e970e9bcc9..8219d59b8f40e 100644
> --- a/llvm/lib/Analysis/Delinearization.cpp
> +++ b/llvm/lib/Analysis/Delinearization.cpp
> @@ -17,6 +17,7 @@
> #include "llvm/Analysis/LoopInfo.h"
> #include "llvm/Analysis/Passes.h"
> #include "llvm/Analysis/ScalarEvolution.h"
> +#include "llvm/Analysis/ScalarEvolutionDivision.h"
> #include "llvm/Analysis/ScalarEvolutionExpressions.h"
> #include "llvm/IR/Constants.h"
> #include "llvm/IR/DerivedTypes.h"
> @@ -36,6 +37,454 @@ using namespace llvm;
> #define DL_NAME "delinearize"
> #define DEBUG_TYPE DL_NAME
>
> +// Return true when S contains at least an undef value.
> +static inline bool containsUndefs(const SCEV *S) {
> + return SCEVExprContains(S, [](const SCEV *S) {
> + if (const auto *SU = dyn_cast<SCEVUnknown>(S))
> + return isa<UndefValue>(SU->getValue());
> + return false;
> + });
> +}
> +
> +namespace {
> +
> +// Collect all steps of SCEV expressions.
> +struct SCEVCollectStrides {
> + ScalarEvolution &SE;
> + SmallVectorImpl<const SCEV *> &Strides;
> +
> + SCEVCollectStrides(ScalarEvolution &SE, SmallVectorImpl<const SCEV *> &S)
> + : SE(SE), Strides(S) {}
> +
> + bool follow(const SCEV *S) {
> + if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(S))
> + Strides.push_back(AR->getStepRecurrence(SE));
> + return true;
> + }
> +
> + bool isDone() const { return false; }
> +};
> +
> +// Collect all SCEVUnknown and SCEVMulExpr expressions.
> +struct SCEVCollectTerms {
> + SmallVectorImpl<const SCEV *> &Terms;
> +
> + SCEVCollectTerms(SmallVectorImpl<const SCEV *> &T) : Terms(T) {}
> +
> + bool follow(const SCEV *S) {
> + if (isa<SCEVUnknown>(S) || isa<SCEVMulExpr>(S) ||
> + isa<SCEVSignExtendExpr>(S)) {
> + if (!containsUndefs(S))
> + Terms.push_back(S);
> +
> + // Stop recursion: once we collected a term, do not walk its operands.
> + return false;
> + }
> +
> + // Keep looking.
> + return true;
> + }
> +
> + bool isDone() const { return false; }
> +};
> +
> +// Check if a SCEV contains an AddRecExpr.
> +struct SCEVHasAddRec {
> + bool &ContainsAddRec;
> +
> + SCEVHasAddRec(bool &ContainsAddRec) : ContainsAddRec(ContainsAddRec) {
> + ContainsAddRec = false;
> + }
> +
> + bool follow(const SCEV *S) {
> + if (isa<SCEVAddRecExpr>(S)) {
> + ContainsAddRec = true;
> +
> + // Stop recursion: once we collected a term, do not walk its operands.
> + return false;
> + }
> +
> + // Keep looking.
> + return true;
> + }
> +
> + bool isDone() const { return false; }
> +};
> +
> +// Find factors that are multiplied with an expression that (possibly as a
> +// subexpression) contains an AddRecExpr. In the expression:
> +//
> +// 8 * (100 + %p * %q * (%a + {0, +, 1}_loop))
> +//
> +// "%p * %q" are factors multiplied by the expression "(%a + {0, +, 1}_loop)"
> +// that contains the AddRec {0, +, 1}_loop. %p * %q are likely to be array size
> +// parameters as they form a product with an induction variable.
> +//
> +// This collector expects all array size parameters to be in the same MulExpr.
> +// It might be necessary to later add support for collecting parameters that are
> +// spread over
> diff erent nested MulExpr.
> +struct SCEVCollectAddRecMultiplies {
> + SmallVectorImpl<const SCEV *> &Terms;
> + ScalarEvolution &SE;
> +
> + SCEVCollectAddRecMultiplies(SmallVectorImpl<const SCEV *> &T,
> + ScalarEvolution &SE)
> + : Terms(T), SE(SE) {}
> +
> + bool follow(const SCEV *S) {
> + if (auto *Mul = dyn_cast<SCEVMulExpr>(S)) {
> + bool HasAddRec = false;
> + SmallVector<const SCEV *, 0> Operands;
> + for (auto Op : Mul->operands()) {
> + const SCEVUnknown *Unknown = dyn_cast<SCEVUnknown>(Op);
> + if (Unknown && !isa<CallInst>(Unknown->getValue())) {
> + Operands.push_back(Op);
> + } else if (Unknown) {
> + HasAddRec = true;
> + } else {
> + bool ContainsAddRec = false;
> + SCEVHasAddRec ContiansAddRec(ContainsAddRec);
> + visitAll(Op, ContiansAddRec);
> + HasAddRec |= ContainsAddRec;
> + }
> + }
> + if (Operands.size() == 0)
> + return true;
> +
> + if (!HasAddRec)
> + return false;
> +
> + Terms.push_back(SE.getMulExpr(Operands));
> + // Stop recursion: once we collected a term, do not walk its operands.
> + return false;
> + }
> +
> + // Keep looking.
> + return true;
> + }
> +
> + bool isDone() const { return false; }
> +};
> +
> +} // end anonymous namespace
> +
> +/// Find parametric terms in this SCEVAddRecExpr. We first for parameters in
> +/// two places:
> +/// 1) The strides of AddRec expressions.
> +/// 2) Unknowns that are multiplied with AddRec expressions.
> +void llvm::collectParametricTerms(ScalarEvolution &SE, const SCEV *Expr,
> + SmallVectorImpl<const SCEV *> &Terms) {
> + SmallVector<const SCEV *, 4> Strides;
> + SCEVCollectStrides StrideCollector(SE, Strides);
> + visitAll(Expr, StrideCollector);
> +
> + LLVM_DEBUG({
> + dbgs() << "Strides:\n";
> + for (const SCEV *S : Strides)
> + dbgs() << *S << "\n";
> + });
> +
> + for (const SCEV *S : Strides) {
> + SCEVCollectTerms TermCollector(Terms);
> + visitAll(S, TermCollector);
> + }
> +
> + LLVM_DEBUG({
> + dbgs() << "Terms:\n";
> + for (const SCEV *T : Terms)
> + dbgs() << *T << "\n";
> + });
> +
> + SCEVCollectAddRecMultiplies MulCollector(Terms, SE);
> + visitAll(Expr, MulCollector);
> +}
> +
> +static bool findArrayDimensionsRec(ScalarEvolution &SE,
> + SmallVectorImpl<const SCEV *> &Terms,
> + SmallVectorImpl<const SCEV *> &Sizes) {
> + int Last = Terms.size() - 1;
> + const SCEV *Step = Terms[Last];
> +
> + // End of recursion.
> + if (Last == 0) {
> + if (const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(Step)) {
> + SmallVector<const SCEV *, 2> Qs;
> + for (const SCEV *Op : M->operands())
> + if (!isa<SCEVConstant>(Op))
> + Qs.push_back(Op);
> +
> + Step = SE.getMulExpr(Qs);
> + }
> +
> + Sizes.push_back(Step);
> + return true;
> + }
> +
> + for (const SCEV *&Term : Terms) {
> + // Normalize the terms before the next call to findArrayDimensionsRec.
> + const SCEV *Q, *R;
> + SCEVDivision::divide(SE, Term, Step, &Q, &R);
> +
> + // Bail out when GCD does not evenly divide one of the terms.
> + if (!R->isZero())
> + return false;
> +
> + Term = Q;
> + }
> +
> + // Remove all SCEVConstants.
> + erase_if(Terms, [](const SCEV *E) { return isa<SCEVConstant>(E); });
> +
> + if (Terms.size() > 0)
> + if (!findArrayDimensionsRec(SE, Terms, Sizes))
> + return false;
> +
> + Sizes.push_back(Step);
> + return true;
> +}
> +
> +// Returns true when one of the SCEVs of Terms contains a SCEVUnknown parameter.
> +static inline bool containsParameters(SmallVectorImpl<const SCEV *> &Terms) {
> + for (const SCEV *T : Terms)
> + if (SCEVExprContains(T, [](const SCEV *S) { return isa<SCEVUnknown>(S); }))
> + return true;
> +
> + return false;
> +}
> +
> +// Return the number of product terms in S.
> +static inline int numberOfTerms(const SCEV *S) {
> + if (const SCEVMulExpr *Expr = dyn_cast<SCEVMulExpr>(S))
> + return Expr->getNumOperands();
> + return 1;
> +}
> +
> +static const SCEV *removeConstantFactors(ScalarEvolution &SE, const SCEV *T) {
> + if (isa<SCEVConstant>(T))
> + return nullptr;
> +
> + if (isa<SCEVUnknown>(T))
> + return T;
> +
> + if (const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(T)) {
> + SmallVector<const SCEV *, 2> Factors;
> + for (const SCEV *Op : M->operands())
> + if (!isa<SCEVConstant>(Op))
> + Factors.push_back(Op);
> +
> + return SE.getMulExpr(Factors);
> + }
> +
> + return T;
> +}
> +
> +void llvm::findArrayDimensions(ScalarEvolution &SE,
> + SmallVectorImpl<const SCEV *> &Terms,
> + SmallVectorImpl<const SCEV *> &Sizes,
> + const SCEV *ElementSize) {
> + if (Terms.size() < 1 || !ElementSize)
> + return;
> +
> + // Early return when Terms do not contain parameters: we do not delinearize
> + // non parametric SCEVs.
> + if (!containsParameters(Terms))
> + return;
> +
> + LLVM_DEBUG({
> + dbgs() << "Terms:\n";
> + for (const SCEV *T : Terms)
> + dbgs() << *T << "\n";
> + });
> +
> + // Remove duplicates.
> + array_pod_sort(Terms.begin(), Terms.end());
> + Terms.erase(std::unique(Terms.begin(), Terms.end()), Terms.end());
> +
> + // Put larger terms first.
> + llvm::sort(Terms, [](const SCEV *LHS, const SCEV *RHS) {
> + return numberOfTerms(LHS) > numberOfTerms(RHS);
> + });
> +
> + // Try to divide all terms by the element size. If term is not divisible by
> + // element size, proceed with the original term.
> + for (const SCEV *&Term : Terms) {
> + const SCEV *Q, *R;
> + SCEVDivision::divide(SE, Term, ElementSize, &Q, &R);
> + if (!Q->isZero())
> + Term = Q;
> + }
> +
> + SmallVector<const SCEV *, 4> NewTerms;
> +
> + // Remove constant factors.
> + for (const SCEV *T : Terms)
> + if (const SCEV *NewT = removeConstantFactors(SE, T))
> + NewTerms.push_back(NewT);
> +
> + LLVM_DEBUG({
> + dbgs() << "Terms after sorting:\n";
> + for (const SCEV *T : NewTerms)
> + dbgs() << *T << "\n";
> + });
> +
> + if (NewTerms.empty() || !findArrayDimensionsRec(SE, NewTerms, Sizes)) {
> + Sizes.clear();
> + return;
> + }
> +
> + // The last element to be pushed into Sizes is the size of an element.
> + Sizes.push_back(ElementSize);
> +
> + LLVM_DEBUG({
> + dbgs() << "Sizes:\n";
> + for (const SCEV *S : Sizes)
> + dbgs() << *S << "\n";
> + });
> +}
> +
> +void llvm::computeAccessFunctions(ScalarEvolution &SE, const SCEV *Expr,
> + SmallVectorImpl<const SCEV *> &Subscripts,
> + SmallVectorImpl<const SCEV *> &Sizes) {
> + // Early exit in case this SCEV is not an affine multivariate function.
> + if (Sizes.empty())
> + return;
> +
> + if (auto *AR = dyn_cast<SCEVAddRecExpr>(Expr))
> + if (!AR->isAffine())
> + return;
> +
> + const SCEV *Res = Expr;
> + int Last = Sizes.size() - 1;
> + for (int i = Last; i >= 0; i--) {
> + const SCEV *Q, *R;
> + SCEVDivision::divide(SE, Res, Sizes[i], &Q, &R);
> +
> + LLVM_DEBUG({
> + dbgs() << "Res: " << *Res << "\n";
> + dbgs() << "Sizes[i]: " << *Sizes[i] << "\n";
> + dbgs() << "Res divided by Sizes[i]:\n";
> + dbgs() << "Quotient: " << *Q << "\n";
> + dbgs() << "Remainder: " << *R << "\n";
> + });
> +
> + Res = Q;
> +
> + // Do not record the last subscript corresponding to the size of elements in
> + // the array.
> + if (i == Last) {
> +
> + // Bail out if the remainder is too complex.
> + if (isa<SCEVAddRecExpr>(R)) {
> + Subscripts.clear();
> + Sizes.clear();
> + return;
> + }
> +
> + continue;
> + }
> +
> + // Record the access function for the current subscript.
> + Subscripts.push_back(R);
> + }
> +
> + // Also push in last position the remainder of the last division: it will be
> + // the access function of the innermost dimension.
> + Subscripts.push_back(Res);
> +
> + std::reverse(Subscripts.begin(), Subscripts.end());
> +
> + LLVM_DEBUG({
> + dbgs() << "Subscripts:\n";
> + for (const SCEV *S : Subscripts)
> + dbgs() << *S << "\n";
> + });
> +}
> +
> +/// Splits the SCEV into two vectors of SCEVs representing the subscripts and
> +/// sizes of an array access. Returns the remainder of the delinearization that
> +/// is the offset start of the array. The SCEV->delinearize algorithm computes
> +/// the multiples of SCEV coefficients: that is a pattern matching of sub
> +/// expressions in the stride and base of a SCEV corresponding to the
> +/// computation of a GCD (greatest common divisor) of base and stride. When
> +/// SCEV->delinearize fails, it returns the SCEV unchanged.
> +///
> +/// For example: when analyzing the memory access A[i][j][k] in this loop nest
> +///
> +/// void foo(long n, long m, long o, double A[n][m][o]) {
> +///
> +/// for (long i = 0; i < n; i++)
> +/// for (long j = 0; j < m; j++)
> +/// for (long k = 0; k < o; k++)
> +/// A[i][j][k] = 1.0;
> +/// }
> +///
> +/// the delinearization input is the following AddRec SCEV:
> +///
> +/// AddRec: {{{%A,+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
> +///
> +/// From this SCEV, we are able to say that the base offset of the access is %A
> +/// because it appears as an offset that does not divide any of the strides in
> +/// the loops:
> +///
> +/// CHECK: Base offset: %A
> +///
> +/// and then SCEV->delinearize determines the size of some of the dimensions of
> +/// the array as these are the multiples by which the strides are happening:
> +///
> +/// CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(double)
> +/// bytes.
> +///
> +/// Note that the outermost dimension remains of UnknownSize because there are
> +/// no strides that would help identifying the size of the last dimension: when
> +/// the array has been statically allocated, one could compute the size of that
> +/// dimension by dividing the overall size of the array by the size of the known
> +/// dimensions: %m * %o * 8.
> +///
> +/// Finally delinearize provides the access functions for the array reference
> +/// that does correspond to A[i][j][k] of the above C testcase:
> +///
> +/// CHECK: ArrayRef[{0,+,1}<%for.i>][{0,+,1}<%for.j>][{0,+,1}<%for.k>]
> +///
> +/// The testcases are checking the output of a function pass:
> +/// DelinearizationPass that walks through all loads and stores of a function
> +/// asking for the SCEV of the memory access with respect to all enclosing
> +/// loops, calling SCEV->delinearize on that and printing the results.
> +void llvm::delinearize(ScalarEvolution &SE, const SCEV *Expr,
> + SmallVectorImpl<const SCEV *> &Subscripts,
> + SmallVectorImpl<const SCEV *> &Sizes,
> + const SCEV *ElementSize) {
> + // First step: collect parametric terms.
> + SmallVector<const SCEV *, 4> Terms;
> + collectParametricTerms(SE, Expr, Terms);
> +
> + if (Terms.empty())
> + return;
> +
> + // Second step: find subscript sizes.
> + findArrayDimensions(SE, Terms, Sizes, ElementSize);
> +
> + if (Sizes.empty())
> + return;
> +
> + // Third step: compute the access functions for each subscript.
> + computeAccessFunctions(SE, Expr, Subscripts, Sizes);
> +
> + if (Subscripts.empty())
> + return;
> +
> + LLVM_DEBUG({
> + dbgs() << "succeeded to delinearize " << *Expr << "\n";
> + dbgs() << "ArrayDecl[UnknownSize]";
> + for (const SCEV *S : Sizes)
> + dbgs() << "[" << *S << "]";
> +
> + dbgs() << "\nArrayRef";
> + for (const SCEV *S : Subscripts)
> + dbgs() << "[" << *S << "]";
> + dbgs() << "\n";
> + });
> +}
> +
> namespace {
>
> class Delinearization : public FunctionPass {
> @@ -84,7 +533,7 @@ void printDelinearization(raw_ostream &O, Function *F, LoopInfo *LI,
> O << "AccessFunction: " << *AccessFn << "\n";
>
> SmallVector<const SCEV *, 3> Subscripts, Sizes;
> - SE->delinearize(AccessFn, Subscripts, Sizes, SE->getElementSize(&Inst));
> + delinearize(*SE, AccessFn, Subscripts, Sizes, SE->getElementSize(&Inst));
> if (Subscripts.size() == 0 || Sizes.size() == 0 ||
> Subscripts.size() != Sizes.size()) {
> O << "failed to delinearize\n";
>
> diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
> index 9c09894f3a451..fa9c672119455 100644
> --- a/llvm/lib/Analysis/DependenceAnalysis.cpp
> +++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
> @@ -53,6 +53,7 @@
> #include "llvm/ADT/STLExtras.h"
> #include "llvm/ADT/Statistic.h"
> #include "llvm/Analysis/AliasAnalysis.h"
> +#include "llvm/Analysis/Delinearization.h"
> #include "llvm/Analysis/LoopInfo.h"
> #include "llvm/Analysis/ScalarEvolution.h"
> #include "llvm/Analysis/ScalarEvolutionExpressions.h"
> @@ -3439,16 +3440,16 @@ bool DependenceInfo::tryDelinearizeParametricSize(
>
> // First step: collect parametric terms in both array references.
> SmallVector<const SCEV *, 4> Terms;
> - SE->collectParametricTerms(SrcAR, Terms);
> - SE->collectParametricTerms(DstAR, Terms);
> + collectParametricTerms(*SE, SrcAR, Terms);
> + collectParametricTerms(*SE, DstAR, Terms);
>
> // Second step: find subscript sizes.
> SmallVector<const SCEV *, 4> Sizes;
> - SE->findArrayDimensions(Terms, Sizes, ElementSize);
> + findArrayDimensions(*SE, Terms, Sizes, ElementSize);
>
> // Third step: compute the access functions for each subscript.
> - SE->computeAccessFunctions(SrcAR, SrcSubscripts, Sizes);
> - SE->computeAccessFunctions(DstAR, DstSubscripts, Sizes);
> + computeAccessFunctions(*SE, SrcAR, SrcSubscripts, Sizes);
> + computeAccessFunctions(*SE, DstAR, DstSubscripts, Sizes);
>
> // Fail when there is only a subscript: that's a linearized access function.
> if (SrcSubscripts.size() < 2 || DstSubscripts.size() < 2 ||
>
> diff --git a/llvm/lib/Analysis/LoopCacheAnalysis.cpp b/llvm/lib/Analysis/LoopCacheAnalysis.cpp
> index 772e4eb239a9c..75bb8b02286c1 100644
> --- a/llvm/lib/Analysis/LoopCacheAnalysis.cpp
> +++ b/llvm/lib/Analysis/LoopCacheAnalysis.cpp
> @@ -30,6 +30,7 @@
> #include "llvm/ADT/Sequence.h"
> #include "llvm/ADT/SmallVector.h"
> #include "llvm/Analysis/AliasAnalysis.h"
> +#include "llvm/Analysis/Delinearization.h"
> #include "llvm/Analysis/DependenceAnalysis.h"
> #include "llvm/Analysis/LoopInfo.h"
> #include "llvm/Analysis/ScalarEvolutionExpressions.h"
> @@ -344,8 +345,8 @@ bool IndexedReference::delinearize(const LoopInfo &LI) {
> LLVM_DEBUG(dbgs().indent(2) << "In Loop '" << L->getName()
> << "', AccessFn: " << *AccessFn << "\n");
>
> - SE.delinearize(AccessFn, Subscripts, Sizes,
> - SE.getElementSize(&StoreOrLoadInst));
> + llvm::delinearize(SE, AccessFn, Subscripts, Sizes,
> + SE.getElementSize(&StoreOrLoadInst));
>
> if (Subscripts.empty() || Sizes.empty() ||
> Subscripts.size() != Sizes.size()) {
>
> diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
> index 50901f3524d1b..151883ab67367 100644
> --- a/llvm/lib/Analysis/ScalarEvolution.cpp
> +++ b/llvm/lib/Analysis/ScalarEvolution.cpp
> @@ -12187,237 +12187,6 @@ static inline bool containsUndefs(const SCEV *S) {
> });
> }
>
> -namespace {
> -
> -// Collect all steps of SCEV expressions.
> -struct SCEVCollectStrides {
> - ScalarEvolution &SE;
> - SmallVectorImpl<const SCEV *> &Strides;
> -
> - SCEVCollectStrides(ScalarEvolution &SE, SmallVectorImpl<const SCEV *> &S)
> - : SE(SE), Strides(S) {}
> -
> - bool follow(const SCEV *S) {
> - if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(S))
> - Strides.push_back(AR->getStepRecurrence(SE));
> - return true;
> - }
> -
> - bool isDone() const { return false; }
> -};
> -
> -// Collect all SCEVUnknown and SCEVMulExpr expressions.
> -struct SCEVCollectTerms {
> - SmallVectorImpl<const SCEV *> &Terms;
> -
> - SCEVCollectTerms(SmallVectorImpl<const SCEV *> &T) : Terms(T) {}
> -
> - bool follow(const SCEV *S) {
> - if (isa<SCEVUnknown>(S) || isa<SCEVMulExpr>(S) ||
> - isa<SCEVSignExtendExpr>(S)) {
> - if (!containsUndefs(S))
> - Terms.push_back(S);
> -
> - // Stop recursion: once we collected a term, do not walk its operands.
> - return false;
> - }
> -
> - // Keep looking.
> - return true;
> - }
> -
> - bool isDone() const { return false; }
> -};
> -
> -// Check if a SCEV contains an AddRecExpr.
> -struct SCEVHasAddRec {
> - bool &ContainsAddRec;
> -
> - SCEVHasAddRec(bool &ContainsAddRec) : ContainsAddRec(ContainsAddRec) {
> - ContainsAddRec = false;
> - }
> -
> - bool follow(const SCEV *S) {
> - if (isa<SCEVAddRecExpr>(S)) {
> - ContainsAddRec = true;
> -
> - // Stop recursion: once we collected a term, do not walk its operands.
> - return false;
> - }
> -
> - // Keep looking.
> - return true;
> - }
> -
> - bool isDone() const { return false; }
> -};
> -
> -// Find factors that are multiplied with an expression that (possibly as a
> -// subexpression) contains an AddRecExpr. In the expression:
> -//
> -// 8 * (100 + %p * %q * (%a + {0, +, 1}_loop))
> -//
> -// "%p * %q" are factors multiplied by the expression "(%a + {0, +, 1}_loop)"
> -// that contains the AddRec {0, +, 1}_loop. %p * %q are likely to be array size
> -// parameters as they form a product with an induction variable.
> -//
> -// This collector expects all array size parameters to be in the same MulExpr.
> -// It might be necessary to later add support for collecting parameters that are
> -// spread over
> diff erent nested MulExpr.
> -struct SCEVCollectAddRecMultiplies {
> - SmallVectorImpl<const SCEV *> &Terms;
> - ScalarEvolution &SE;
> -
> - SCEVCollectAddRecMultiplies(SmallVectorImpl<const SCEV *> &T, ScalarEvolution &SE)
> - : Terms(T), SE(SE) {}
> -
> - bool follow(const SCEV *S) {
> - if (auto *Mul = dyn_cast<SCEVMulExpr>(S)) {
> - bool HasAddRec = false;
> - SmallVector<const SCEV *, 0> Operands;
> - for (auto Op : Mul->operands()) {
> - const SCEVUnknown *Unknown = dyn_cast<SCEVUnknown>(Op);
> - if (Unknown && !isa<CallInst>(Unknown->getValue())) {
> - Operands.push_back(Op);
> - } else if (Unknown) {
> - HasAddRec = true;
> - } else {
> - bool ContainsAddRec = false;
> - SCEVHasAddRec ContiansAddRec(ContainsAddRec);
> - visitAll(Op, ContiansAddRec);
> - HasAddRec |= ContainsAddRec;
> - }
> - }
> - if (Operands.size() == 0)
> - return true;
> -
> - if (!HasAddRec)
> - return false;
> -
> - Terms.push_back(SE.getMulExpr(Operands));
> - // Stop recursion: once we collected a term, do not walk its operands.
> - return false;
> - }
> -
> - // Keep looking.
> - return true;
> - }
> -
> - bool isDone() const { return false; }
> -};
> -
> -} // end anonymous namespace
> -
> -/// Find parametric terms in this SCEVAddRecExpr. We first for parameters in
> -/// two places:
> -/// 1) The strides of AddRec expressions.
> -/// 2) Unknowns that are multiplied with AddRec expressions.
> -void ScalarEvolution::collectParametricTerms(const SCEV *Expr,
> - SmallVectorImpl<const SCEV *> &Terms) {
> - SmallVector<const SCEV *, 4> Strides;
> - SCEVCollectStrides StrideCollector(*this, Strides);
> - visitAll(Expr, StrideCollector);
> -
> - LLVM_DEBUG({
> - dbgs() << "Strides:\n";
> - for (const SCEV *S : Strides)
> - dbgs() << *S << "\n";
> - });
> -
> - for (const SCEV *S : Strides) {
> - SCEVCollectTerms TermCollector(Terms);
> - visitAll(S, TermCollector);
> - }
> -
> - LLVM_DEBUG({
> - dbgs() << "Terms:\n";
> - for (const SCEV *T : Terms)
> - dbgs() << *T << "\n";
> - });
> -
> - SCEVCollectAddRecMultiplies MulCollector(Terms, *this);
> - visitAll(Expr, MulCollector);
> -}
> -
> -static bool findArrayDimensionsRec(ScalarEvolution &SE,
> - SmallVectorImpl<const SCEV *> &Terms,
> - SmallVectorImpl<const SCEV *> &Sizes) {
> - int Last = Terms.size() - 1;
> - const SCEV *Step = Terms[Last];
> -
> - // End of recursion.
> - if (Last == 0) {
> - if (const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(Step)) {
> - SmallVector<const SCEV *, 2> Qs;
> - for (const SCEV *Op : M->operands())
> - if (!isa<SCEVConstant>(Op))
> - Qs.push_back(Op);
> -
> - Step = SE.getMulExpr(Qs);
> - }
> -
> - Sizes.push_back(Step);
> - return true;
> - }
> -
> - for (const SCEV *&Term : Terms) {
> - // Normalize the terms before the next call to findArrayDimensionsRec.
> - const SCEV *Q, *R;
> - SCEVDivision::divide(SE, Term, Step, &Q, &R);
> -
> - // Bail out when GCD does not evenly divide one of the terms.
> - if (!R->isZero())
> - return false;
> -
> - Term = Q;
> - }
> -
> - // Remove all SCEVConstants.
> - erase_if(Terms, [](const SCEV *E) { return isa<SCEVConstant>(E); });
> -
> - if (Terms.size() > 0)
> - if (!findArrayDimensionsRec(SE, Terms, Sizes))
> - return false;
> -
> - Sizes.push_back(Step);
> - return true;
> -}
> -
> -// Returns true when one of the SCEVs of Terms contains a SCEVUnknown parameter.
> -static inline bool containsParameters(SmallVectorImpl<const SCEV *> &Terms) {
> - for (const SCEV *T : Terms)
> - if (SCEVExprContains(T, [](const SCEV *S) { return isa<SCEVUnknown>(S); }))
> - return true;
> -
> - return false;
> -}
> -
> -// Return the number of product terms in S.
> -static inline int numberOfTerms(const SCEV *S) {
> - if (const SCEVMulExpr *Expr = dyn_cast<SCEVMulExpr>(S))
> - return Expr->getNumOperands();
> - return 1;
> -}
> -
> -static const SCEV *removeConstantFactors(ScalarEvolution &SE, const SCEV *T) {
> - if (isa<SCEVConstant>(T))
> - return nullptr;
> -
> - if (isa<SCEVUnknown>(T))
> - return T;
> -
> - if (const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(T)) {
> - SmallVector<const SCEV *, 2> Factors;
> - for (const SCEV *Op : M->operands())
> - if (!isa<SCEVConstant>(Op))
> - Factors.push_back(Op);
> -
> - return SE.getMulExpr(Factors);
> - }
> -
> - return T;
> -}
> -
> /// Return the size of an element read or written by Inst.
> const SCEV *ScalarEvolution::getElementSize(Instruction *Inst) {
> Type *Ty;
> @@ -12432,211 +12201,6 @@ const SCEV *ScalarEvolution::getElementSize(Instruction *Inst) {
> return getSizeOfExpr(ETy, Ty);
> }
>
> -void ScalarEvolution::findArrayDimensions(SmallVectorImpl<const SCEV *> &Terms,
> - SmallVectorImpl<const SCEV *> &Sizes,
> - const SCEV *ElementSize) {
> - if (Terms.size() < 1 || !ElementSize)
> - return;
> -
> - // Early return when Terms do not contain parameters: we do not delinearize
> - // non parametric SCEVs.
> - if (!containsParameters(Terms))
> - return;
> -
> - LLVM_DEBUG({
> - dbgs() << "Terms:\n";
> - for (const SCEV *T : Terms)
> - dbgs() << *T << "\n";
> - });
> -
> - // Remove duplicates.
> - array_pod_sort(Terms.begin(), Terms.end());
> - Terms.erase(std::unique(Terms.begin(), Terms.end()), Terms.end());
> -
> - // Put larger terms first.
> - llvm::sort(Terms, [](const SCEV *LHS, const SCEV *RHS) {
> - return numberOfTerms(LHS) > numberOfTerms(RHS);
> - });
> -
> - // Try to divide all terms by the element size. If term is not divisible by
> - // element size, proceed with the original term.
> - for (const SCEV *&Term : Terms) {
> - const SCEV *Q, *R;
> - SCEVDivision::divide(*this, Term, ElementSize, &Q, &R);
> - if (!Q->isZero())
> - Term = Q;
> - }
> -
> - SmallVector<const SCEV *, 4> NewTerms;
> -
> - // Remove constant factors.
> - for (const SCEV *T : Terms)
> - if (const SCEV *NewT = removeConstantFactors(*this, T))
> - NewTerms.push_back(NewT);
> -
> - LLVM_DEBUG({
> - dbgs() << "Terms after sorting:\n";
> - for (const SCEV *T : NewTerms)
> - dbgs() << *T << "\n";
> - });
> -
> - if (NewTerms.empty() || !findArrayDimensionsRec(*this, NewTerms, Sizes)) {
> - Sizes.clear();
> - return;
> - }
> -
> - // The last element to be pushed into Sizes is the size of an element.
> - Sizes.push_back(ElementSize);
> -
> - LLVM_DEBUG({
> - dbgs() << "Sizes:\n";
> - for (const SCEV *S : Sizes)
> - dbgs() << *S << "\n";
> - });
> -}
> -
> -void ScalarEvolution::computeAccessFunctions(
> - const SCEV *Expr, SmallVectorImpl<const SCEV *> &Subscripts,
> - SmallVectorImpl<const SCEV *> &Sizes) {
> - // Early exit in case this SCEV is not an affine multivariate function.
> - if (Sizes.empty())
> - return;
> -
> - if (auto *AR = dyn_cast<SCEVAddRecExpr>(Expr))
> - if (!AR->isAffine())
> - return;
> -
> - const SCEV *Res = Expr;
> - int Last = Sizes.size() - 1;
> - for (int i = Last; i >= 0; i--) {
> - const SCEV *Q, *R;
> - SCEVDivision::divide(*this, Res, Sizes[i], &Q, &R);
> -
> - LLVM_DEBUG({
> - dbgs() << "Res: " << *Res << "\n";
> - dbgs() << "Sizes[i]: " << *Sizes[i] << "\n";
> - dbgs() << "Res divided by Sizes[i]:\n";
> - dbgs() << "Quotient: " << *Q << "\n";
> - dbgs() << "Remainder: " << *R << "\n";
> - });
> -
> - Res = Q;
> -
> - // Do not record the last subscript corresponding to the size of elements in
> - // the array.
> - if (i == Last) {
> -
> - // Bail out if the remainder is too complex.
> - if (isa<SCEVAddRecExpr>(R)) {
> - Subscripts.clear();
> - Sizes.clear();
> - return;
> - }
> -
> - continue;
> - }
> -
> - // Record the access function for the current subscript.
> - Subscripts.push_back(R);
> - }
> -
> - // Also push in last position the remainder of the last division: it will be
> - // the access function of the innermost dimension.
> - Subscripts.push_back(Res);
> -
> - std::reverse(Subscripts.begin(), Subscripts.end());
> -
> - LLVM_DEBUG({
> - dbgs() << "Subscripts:\n";
> - for (const SCEV *S : Subscripts)
> - dbgs() << *S << "\n";
> - });
> -}
> -
> -/// Splits the SCEV into two vectors of SCEVs representing the subscripts and
> -/// sizes of an array access. Returns the remainder of the delinearization that
> -/// is the offset start of the array. The SCEV->delinearize algorithm computes
> -/// the multiples of SCEV coefficients: that is a pattern matching of sub
> -/// expressions in the stride and base of a SCEV corresponding to the
> -/// computation of a GCD (greatest common divisor) of base and stride. When
> -/// SCEV->delinearize fails, it returns the SCEV unchanged.
> -///
> -/// For example: when analyzing the memory access A[i][j][k] in this loop nest
> -///
> -/// void foo(long n, long m, long o, double A[n][m][o]) {
> -///
> -/// for (long i = 0; i < n; i++)
> -/// for (long j = 0; j < m; j++)
> -/// for (long k = 0; k < o; k++)
> -/// A[i][j][k] = 1.0;
> -/// }
> -///
> -/// the delinearization input is the following AddRec SCEV:
> -///
> -/// AddRec: {{{%A,+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
> -///
> -/// From this SCEV, we are able to say that the base offset of the access is %A
> -/// because it appears as an offset that does not divide any of the strides in
> -/// the loops:
> -///
> -/// CHECK: Base offset: %A
> -///
> -/// and then SCEV->delinearize determines the size of some of the dimensions of
> -/// the array as these are the multiples by which the strides are happening:
> -///
> -/// CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(double) bytes.
> -///
> -/// Note that the outermost dimension remains of UnknownSize because there are
> -/// no strides that would help identifying the size of the last dimension: when
> -/// the array has been statically allocated, one could compute the size of that
> -/// dimension by dividing the overall size of the array by the size of the known
> -/// dimensions: %m * %o * 8.
> -///
> -/// Finally delinearize provides the access functions for the array reference
> -/// that does correspond to A[i][j][k] of the above C testcase:
> -///
> -/// CHECK: ArrayRef[{0,+,1}<%for.i>][{0,+,1}<%for.j>][{0,+,1}<%for.k>]
> -///
> -/// The testcases are checking the output of a function pass:
> -/// DelinearizationPass that walks through all loads and stores of a function
> -/// asking for the SCEV of the memory access with respect to all enclosing
> -/// loops, calling SCEV->delinearize on that and printing the results.
> -void ScalarEvolution::delinearize(const SCEV *Expr,
> - SmallVectorImpl<const SCEV *> &Subscripts,
> - SmallVectorImpl<const SCEV *> &Sizes,
> - const SCEV *ElementSize) {
> - // First step: collect parametric terms.
> - SmallVector<const SCEV *, 4> Terms;
> - collectParametricTerms(Expr, Terms);
> -
> - if (Terms.empty())
> - return;
> -
> - // Second step: find subscript sizes.
> - findArrayDimensions(Terms, Sizes, ElementSize);
> -
> - if (Sizes.empty())
> - return;
> -
> - // Third step: compute the access functions for each subscript.
> - computeAccessFunctions(Expr, Subscripts, Sizes);
> -
> - if (Subscripts.empty())
> - return;
> -
> - LLVM_DEBUG({
> - dbgs() << "succeeded to delinearize " << *Expr << "\n";
> - dbgs() << "ArrayDecl[UnknownSize]";
> - for (const SCEV *S : Sizes)
> - dbgs() << "[" << *S << "]";
> -
> - dbgs() << "\nArrayRef";
> - for (const SCEV *S : Subscripts)
> - dbgs() << "[" << *S << "]";
> - dbgs() << "\n";
> - });
> -}
> -
> bool ScalarEvolution::getIndexExpressionsFromGEP(
> const GetElementPtrInst *GEP, SmallVectorImpl<const SCEV *> &Subscripts,
> SmallVectorImpl<int> &Sizes) {
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list