mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-15 20:29:48 +00:00
79facc9e29
No functional change is intended: instead of relying on the delinearization to come up with the base pointer as a remainder of the divisions in the delinearization, we just compute it from the array access and use that value. We substract the base pointer from the SCEV to be delinearized and that simplifies the work of the delinearizer. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@209692 91177308-0d34-0410-b5e6-96231b3b80d8
835 lines
30 KiB
C++
835 lines
30 KiB
C++
//===- llvm/Analysis/ScalarEvolutionExpressions.h - SCEV Exprs --*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the classes used to represent and build scalar expressions.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_ANALYSIS_SCALAREVOLUTIONEXPRESSIONS_H
|
|
#define LLVM_ANALYSIS_SCALAREVOLUTIONEXPRESSIONS_H
|
|
|
|
#include "llvm/ADT/iterator_range.h"
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
#include "llvm/Analysis/ScalarEvolution.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
namespace llvm {
|
|
class ConstantInt;
|
|
class ConstantRange;
|
|
class DominatorTree;
|
|
|
|
enum SCEVTypes {
|
|
// These should be ordered in terms of increasing complexity to make the
|
|
// folders simpler.
|
|
scConstant, scTruncate, scZeroExtend, scSignExtend, scAddExpr, scMulExpr,
|
|
scUDivExpr, scAddRecExpr, scUMaxExpr, scSMaxExpr,
|
|
scUnknown, scCouldNotCompute
|
|
};
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SCEVConstant - This class represents a constant integer value.
|
|
///
|
|
class SCEVConstant : public SCEV {
|
|
friend class ScalarEvolution;
|
|
|
|
ConstantInt *V;
|
|
SCEVConstant(const FoldingSetNodeIDRef ID, ConstantInt *v) :
|
|
SCEV(ID, scConstant), V(v) {}
|
|
public:
|
|
ConstantInt *getValue() const { return V; }
|
|
|
|
Type *getType() const { return V->getType(); }
|
|
|
|
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const SCEV *S) {
|
|
return S->getSCEVType() == scConstant;
|
|
}
|
|
};
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SCEVCastExpr - This is the base class for unary cast operator classes.
|
|
///
|
|
class SCEVCastExpr : public SCEV {
|
|
protected:
|
|
const SCEV *Op;
|
|
Type *Ty;
|
|
|
|
SCEVCastExpr(const FoldingSetNodeIDRef ID,
|
|
unsigned SCEVTy, const SCEV *op, Type *ty);
|
|
|
|
public:
|
|
const SCEV *getOperand() const { return Op; }
|
|
Type *getType() const { return Ty; }
|
|
|
|
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const SCEV *S) {
|
|
return S->getSCEVType() == scTruncate ||
|
|
S->getSCEVType() == scZeroExtend ||
|
|
S->getSCEVType() == scSignExtend;
|
|
}
|
|
};
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SCEVTruncateExpr - This class represents a truncation of an integer value
|
|
/// to a smaller integer value.
|
|
///
|
|
class SCEVTruncateExpr : public SCEVCastExpr {
|
|
friend class ScalarEvolution;
|
|
|
|
SCEVTruncateExpr(const FoldingSetNodeIDRef ID,
|
|
const SCEV *op, Type *ty);
|
|
|
|
public:
|
|
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const SCEV *S) {
|
|
return S->getSCEVType() == scTruncate;
|
|
}
|
|
};
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SCEVZeroExtendExpr - This class represents a zero extension of a small
|
|
/// integer value to a larger integer value.
|
|
///
|
|
class SCEVZeroExtendExpr : public SCEVCastExpr {
|
|
friend class ScalarEvolution;
|
|
|
|
SCEVZeroExtendExpr(const FoldingSetNodeIDRef ID,
|
|
const SCEV *op, Type *ty);
|
|
|
|
public:
|
|
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const SCEV *S) {
|
|
return S->getSCEVType() == scZeroExtend;
|
|
}
|
|
};
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SCEVSignExtendExpr - This class represents a sign extension of a small
|
|
/// integer value to a larger integer value.
|
|
///
|
|
class SCEVSignExtendExpr : public SCEVCastExpr {
|
|
friend class ScalarEvolution;
|
|
|
|
SCEVSignExtendExpr(const FoldingSetNodeIDRef ID,
|
|
const SCEV *op, Type *ty);
|
|
|
|
public:
|
|
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const SCEV *S) {
|
|
return S->getSCEVType() == scSignExtend;
|
|
}
|
|
};
|
|
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SCEVNAryExpr - This node is a base class providing common
|
|
/// functionality for n'ary operators.
|
|
///
|
|
class SCEVNAryExpr : public SCEV {
|
|
protected:
|
|
// Since SCEVs are immutable, ScalarEvolution allocates operand
|
|
// arrays with its SCEVAllocator, so this class just needs a simple
|
|
// pointer rather than a more elaborate vector-like data structure.
|
|
// This also avoids the need for a non-trivial destructor.
|
|
const SCEV *const *Operands;
|
|
size_t NumOperands;
|
|
|
|
SCEVNAryExpr(const FoldingSetNodeIDRef ID,
|
|
enum SCEVTypes T, const SCEV *const *O, size_t N)
|
|
: SCEV(ID, T), Operands(O), NumOperands(N) {}
|
|
|
|
public:
|
|
size_t getNumOperands() const { return NumOperands; }
|
|
const SCEV *getOperand(unsigned i) const {
|
|
assert(i < NumOperands && "Operand index out of range!");
|
|
return Operands[i];
|
|
}
|
|
|
|
typedef const SCEV *const *op_iterator;
|
|
typedef iterator_range<op_iterator> op_range;
|
|
op_iterator op_begin() const { return Operands; }
|
|
op_iterator op_end() const { return Operands + NumOperands; }
|
|
op_range operands() const {
|
|
return make_range(op_begin(), op_end());
|
|
}
|
|
|
|
Type *getType() const { return getOperand(0)->getType(); }
|
|
|
|
NoWrapFlags getNoWrapFlags(NoWrapFlags Mask = NoWrapMask) const {
|
|
return (NoWrapFlags)(SubclassData & Mask);
|
|
}
|
|
|
|
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const SCEV *S) {
|
|
return S->getSCEVType() == scAddExpr ||
|
|
S->getSCEVType() == scMulExpr ||
|
|
S->getSCEVType() == scSMaxExpr ||
|
|
S->getSCEVType() == scUMaxExpr ||
|
|
S->getSCEVType() == scAddRecExpr;
|
|
}
|
|
};
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SCEVCommutativeExpr - This node is the base class for n'ary commutative
|
|
/// operators.
|
|
///
|
|
class SCEVCommutativeExpr : public SCEVNAryExpr {
|
|
protected:
|
|
SCEVCommutativeExpr(const FoldingSetNodeIDRef ID,
|
|
enum SCEVTypes T, const SCEV *const *O, size_t N)
|
|
: SCEVNAryExpr(ID, T, O, N) {}
|
|
|
|
public:
|
|
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const SCEV *S) {
|
|
return S->getSCEVType() == scAddExpr ||
|
|
S->getSCEVType() == scMulExpr ||
|
|
S->getSCEVType() == scSMaxExpr ||
|
|
S->getSCEVType() == scUMaxExpr;
|
|
}
|
|
|
|
/// Set flags for a non-recurrence without clearing previously set flags.
|
|
void setNoWrapFlags(NoWrapFlags Flags) {
|
|
SubclassData |= Flags;
|
|
}
|
|
};
|
|
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SCEVAddExpr - This node represents an addition of some number of SCEVs.
|
|
///
|
|
class SCEVAddExpr : public SCEVCommutativeExpr {
|
|
friend class ScalarEvolution;
|
|
|
|
SCEVAddExpr(const FoldingSetNodeIDRef ID,
|
|
const SCEV *const *O, size_t N)
|
|
: SCEVCommutativeExpr(ID, scAddExpr, O, N) {
|
|
}
|
|
|
|
public:
|
|
Type *getType() const {
|
|
// Use the type of the last operand, which is likely to be a pointer
|
|
// type, if there is one. This doesn't usually matter, but it can help
|
|
// reduce casts when the expressions are expanded.
|
|
return getOperand(getNumOperands() - 1)->getType();
|
|
}
|
|
|
|
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const SCEV *S) {
|
|
return S->getSCEVType() == scAddExpr;
|
|
}
|
|
};
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SCEVMulExpr - This node represents multiplication of some number of SCEVs.
|
|
///
|
|
class SCEVMulExpr : public SCEVCommutativeExpr {
|
|
friend class ScalarEvolution;
|
|
|
|
SCEVMulExpr(const FoldingSetNodeIDRef ID,
|
|
const SCEV *const *O, size_t N)
|
|
: SCEVCommutativeExpr(ID, scMulExpr, O, N) {
|
|
}
|
|
|
|
public:
|
|
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const SCEV *S) {
|
|
return S->getSCEVType() == scMulExpr;
|
|
}
|
|
};
|
|
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SCEVUDivExpr - This class represents a binary unsigned division operation.
|
|
///
|
|
class SCEVUDivExpr : public SCEV {
|
|
friend class ScalarEvolution;
|
|
|
|
const SCEV *LHS;
|
|
const SCEV *RHS;
|
|
SCEVUDivExpr(const FoldingSetNodeIDRef ID, const SCEV *lhs, const SCEV *rhs)
|
|
: SCEV(ID, scUDivExpr), LHS(lhs), RHS(rhs) {}
|
|
|
|
public:
|
|
const SCEV *getLHS() const { return LHS; }
|
|
const SCEV *getRHS() const { return RHS; }
|
|
|
|
Type *getType() const {
|
|
// In most cases the types of LHS and RHS will be the same, but in some
|
|
// crazy cases one or the other may be a pointer. ScalarEvolution doesn't
|
|
// depend on the type for correctness, but handling types carefully can
|
|
// avoid extra casts in the SCEVExpander. The LHS is more likely to be
|
|
// a pointer type than the RHS, so use the RHS' type here.
|
|
return getRHS()->getType();
|
|
}
|
|
|
|
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const SCEV *S) {
|
|
return S->getSCEVType() == scUDivExpr;
|
|
}
|
|
};
|
|
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SCEVAddRecExpr - This node represents a polynomial recurrence on the trip
|
|
/// count of the specified loop. This is the primary focus of the
|
|
/// ScalarEvolution framework; all the other SCEV subclasses are mostly just
|
|
/// supporting infrastructure to allow SCEVAddRecExpr expressions to be
|
|
/// created and analyzed.
|
|
///
|
|
/// All operands of an AddRec are required to be loop invariant.
|
|
///
|
|
class SCEVAddRecExpr : public SCEVNAryExpr {
|
|
friend class ScalarEvolution;
|
|
|
|
const Loop *L;
|
|
|
|
SCEVAddRecExpr(const FoldingSetNodeIDRef ID,
|
|
const SCEV *const *O, size_t N, const Loop *l)
|
|
: SCEVNAryExpr(ID, scAddRecExpr, O, N), L(l) {}
|
|
|
|
public:
|
|
const SCEV *getStart() const { return Operands[0]; }
|
|
const Loop *getLoop() const { return L; }
|
|
|
|
/// getStepRecurrence - This method constructs and returns the recurrence
|
|
/// indicating how much this expression steps by. If this is a polynomial
|
|
/// of degree N, it returns a chrec of degree N-1.
|
|
/// We cannot determine whether the step recurrence has self-wraparound.
|
|
const SCEV *getStepRecurrence(ScalarEvolution &SE) const {
|
|
if (isAffine()) return getOperand(1);
|
|
return SE.getAddRecExpr(SmallVector<const SCEV *, 3>(op_begin()+1,
|
|
op_end()),
|
|
getLoop(), FlagAnyWrap);
|
|
}
|
|
|
|
/// isAffine - Return true if this is an affine AddRec (i.e., it represents
|
|
/// an expressions A+B*x where A and B are loop invariant values.
|
|
bool isAffine() const {
|
|
// We know that the start value is invariant. This expression is thus
|
|
// affine iff the step is also invariant.
|
|
return getNumOperands() == 2;
|
|
}
|
|
|
|
/// isQuadratic - Return true if this is an quadratic AddRec (i.e., it
|
|
/// represents an expressions A+B*x+C*x^2 where A, B and C are loop
|
|
/// invariant values. This corresponds to an addrec of the form {L,+,M,+,N}
|
|
bool isQuadratic() const {
|
|
return getNumOperands() == 3;
|
|
}
|
|
|
|
/// Set flags for a recurrence without clearing any previously set flags.
|
|
/// For AddRec, either NUW or NSW implies NW. Keep track of this fact here
|
|
/// to make it easier to propagate flags.
|
|
void setNoWrapFlags(NoWrapFlags Flags) {
|
|
if (Flags & (FlagNUW | FlagNSW))
|
|
Flags = ScalarEvolution::setFlags(Flags, FlagNW);
|
|
SubclassData |= Flags;
|
|
}
|
|
|
|
/// evaluateAtIteration - Return the value of this chain of recurrences at
|
|
/// the specified iteration number.
|
|
const SCEV *evaluateAtIteration(const SCEV *It, ScalarEvolution &SE) const;
|
|
|
|
/// getNumIterationsInRange - Return the number of iterations of this loop
|
|
/// that produce values in the specified constant range. Another way of
|
|
/// looking at this is that it returns the first iteration number where the
|
|
/// value is not in the condition, thus computing the exit count. If the
|
|
/// iteration count can't be computed, an instance of SCEVCouldNotCompute is
|
|
/// returned.
|
|
const SCEV *getNumIterationsInRange(ConstantRange Range,
|
|
ScalarEvolution &SE) const;
|
|
|
|
/// getPostIncExpr - Return an expression representing the value of
|
|
/// this expression one iteration of the loop ahead.
|
|
const SCEVAddRecExpr *getPostIncExpr(ScalarEvolution &SE) const {
|
|
return cast<SCEVAddRecExpr>(SE.getAddExpr(this, getStepRecurrence(SE)));
|
|
}
|
|
|
|
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const SCEV *S) {
|
|
return S->getSCEVType() == scAddRecExpr;
|
|
}
|
|
|
|
/// Collect parametric terms occurring in step expressions.
|
|
void collectParametricTerms(ScalarEvolution &SE,
|
|
SmallVectorImpl<const SCEV *> &Terms) const;
|
|
|
|
/// Return in Subscripts the access functions for each dimension in Sizes.
|
|
void computeAccessFunctions(ScalarEvolution &SE,
|
|
SmallVectorImpl<const SCEV *> &Subscripts,
|
|
SmallVectorImpl<const SCEV *> &Sizes) const;
|
|
|
|
/// 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 different 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,
|
|
SmallVectorImpl<const SCEV *> &Subscripts,
|
|
SmallVectorImpl<const SCEV *> &Sizes,
|
|
const SCEV *ElementSize) const;
|
|
};
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SCEVSMaxExpr - This class represents a signed maximum selection.
|
|
///
|
|
class SCEVSMaxExpr : public SCEVCommutativeExpr {
|
|
friend class ScalarEvolution;
|
|
|
|
SCEVSMaxExpr(const FoldingSetNodeIDRef ID,
|
|
const SCEV *const *O, size_t N)
|
|
: SCEVCommutativeExpr(ID, scSMaxExpr, O, N) {
|
|
// Max never overflows.
|
|
setNoWrapFlags((NoWrapFlags)(FlagNUW | FlagNSW));
|
|
}
|
|
|
|
public:
|
|
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const SCEV *S) {
|
|
return S->getSCEVType() == scSMaxExpr;
|
|
}
|
|
};
|
|
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SCEVUMaxExpr - This class represents an unsigned maximum selection.
|
|
///
|
|
class SCEVUMaxExpr : public SCEVCommutativeExpr {
|
|
friend class ScalarEvolution;
|
|
|
|
SCEVUMaxExpr(const FoldingSetNodeIDRef ID,
|
|
const SCEV *const *O, size_t N)
|
|
: SCEVCommutativeExpr(ID, scUMaxExpr, O, N) {
|
|
// Max never overflows.
|
|
setNoWrapFlags((NoWrapFlags)(FlagNUW | FlagNSW));
|
|
}
|
|
|
|
public:
|
|
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const SCEV *S) {
|
|
return S->getSCEVType() == scUMaxExpr;
|
|
}
|
|
};
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SCEVUnknown - This means that we are dealing with an entirely unknown SCEV
|
|
/// value, and only represent it as its LLVM Value. This is the "bottom"
|
|
/// value for the analysis.
|
|
///
|
|
class SCEVUnknown : public SCEV, private CallbackVH {
|
|
friend class ScalarEvolution;
|
|
|
|
// Implement CallbackVH.
|
|
void deleted() override;
|
|
void allUsesReplacedWith(Value *New) override;
|
|
|
|
/// SE - The parent ScalarEvolution value. This is used to update
|
|
/// the parent's maps when the value associated with a SCEVUnknown
|
|
/// is deleted or RAUW'd.
|
|
ScalarEvolution *SE;
|
|
|
|
/// Next - The next pointer in the linked list of all
|
|
/// SCEVUnknown instances owned by a ScalarEvolution.
|
|
SCEVUnknown *Next;
|
|
|
|
SCEVUnknown(const FoldingSetNodeIDRef ID, Value *V,
|
|
ScalarEvolution *se, SCEVUnknown *next) :
|
|
SCEV(ID, scUnknown), CallbackVH(V), SE(se), Next(next) {}
|
|
|
|
public:
|
|
Value *getValue() const { return getValPtr(); }
|
|
|
|
/// isSizeOf, isAlignOf, isOffsetOf - Test whether this is a special
|
|
/// constant representing a type size, alignment, or field offset in
|
|
/// a target-independent manner, and hasn't happened to have been
|
|
/// folded with other operations into something unrecognizable. This
|
|
/// is mainly only useful for pretty-printing and other situations
|
|
/// where it isn't absolutely required for these to succeed.
|
|
bool isSizeOf(Type *&AllocTy) const;
|
|
bool isAlignOf(Type *&AllocTy) const;
|
|
bool isOffsetOf(Type *&STy, Constant *&FieldNo) const;
|
|
|
|
Type *getType() const { return getValPtr()->getType(); }
|
|
|
|
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const SCEV *S) {
|
|
return S->getSCEVType() == scUnknown;
|
|
}
|
|
};
|
|
|
|
/// SCEVVisitor - This class defines a simple visitor class that may be used
|
|
/// for various SCEV analysis purposes.
|
|
template<typename SC, typename RetVal=void>
|
|
struct SCEVVisitor {
|
|
RetVal visit(const SCEV *S) {
|
|
switch (S->getSCEVType()) {
|
|
case scConstant:
|
|
return ((SC*)this)->visitConstant((const SCEVConstant*)S);
|
|
case scTruncate:
|
|
return ((SC*)this)->visitTruncateExpr((const SCEVTruncateExpr*)S);
|
|
case scZeroExtend:
|
|
return ((SC*)this)->visitZeroExtendExpr((const SCEVZeroExtendExpr*)S);
|
|
case scSignExtend:
|
|
return ((SC*)this)->visitSignExtendExpr((const SCEVSignExtendExpr*)S);
|
|
case scAddExpr:
|
|
return ((SC*)this)->visitAddExpr((const SCEVAddExpr*)S);
|
|
case scMulExpr:
|
|
return ((SC*)this)->visitMulExpr((const SCEVMulExpr*)S);
|
|
case scUDivExpr:
|
|
return ((SC*)this)->visitUDivExpr((const SCEVUDivExpr*)S);
|
|
case scAddRecExpr:
|
|
return ((SC*)this)->visitAddRecExpr((const SCEVAddRecExpr*)S);
|
|
case scSMaxExpr:
|
|
return ((SC*)this)->visitSMaxExpr((const SCEVSMaxExpr*)S);
|
|
case scUMaxExpr:
|
|
return ((SC*)this)->visitUMaxExpr((const SCEVUMaxExpr*)S);
|
|
case scUnknown:
|
|
return ((SC*)this)->visitUnknown((const SCEVUnknown*)S);
|
|
case scCouldNotCompute:
|
|
return ((SC*)this)->visitCouldNotCompute((const SCEVCouldNotCompute*)S);
|
|
default:
|
|
llvm_unreachable("Unknown SCEV type!");
|
|
}
|
|
}
|
|
|
|
RetVal visitCouldNotCompute(const SCEVCouldNotCompute *S) {
|
|
llvm_unreachable("Invalid use of SCEVCouldNotCompute!");
|
|
}
|
|
};
|
|
|
|
/// Visit all nodes in the expression tree using worklist traversal.
|
|
///
|
|
/// Visitor implements:
|
|
/// // return true to follow this node.
|
|
/// bool follow(const SCEV *S);
|
|
/// // return true to terminate the search.
|
|
/// bool isDone();
|
|
template<typename SV>
|
|
class SCEVTraversal {
|
|
SV &Visitor;
|
|
SmallVector<const SCEV *, 8> Worklist;
|
|
SmallPtrSet<const SCEV *, 8> Visited;
|
|
|
|
void push(const SCEV *S) {
|
|
if (Visited.insert(S) && Visitor.follow(S))
|
|
Worklist.push_back(S);
|
|
}
|
|
public:
|
|
SCEVTraversal(SV& V): Visitor(V) {}
|
|
|
|
void visitAll(const SCEV *Root) {
|
|
push(Root);
|
|
while (!Worklist.empty() && !Visitor.isDone()) {
|
|
const SCEV *S = Worklist.pop_back_val();
|
|
|
|
switch (S->getSCEVType()) {
|
|
case scConstant:
|
|
case scUnknown:
|
|
break;
|
|
case scTruncate:
|
|
case scZeroExtend:
|
|
case scSignExtend:
|
|
push(cast<SCEVCastExpr>(S)->getOperand());
|
|
break;
|
|
case scAddExpr:
|
|
case scMulExpr:
|
|
case scSMaxExpr:
|
|
case scUMaxExpr:
|
|
case scAddRecExpr: {
|
|
const SCEVNAryExpr *NAry = cast<SCEVNAryExpr>(S);
|
|
for (SCEVNAryExpr::op_iterator I = NAry->op_begin(),
|
|
E = NAry->op_end(); I != E; ++I) {
|
|
push(*I);
|
|
}
|
|
break;
|
|
}
|
|
case scUDivExpr: {
|
|
const SCEVUDivExpr *UDiv = cast<SCEVUDivExpr>(S);
|
|
push(UDiv->getLHS());
|
|
push(UDiv->getRHS());
|
|
break;
|
|
}
|
|
case scCouldNotCompute:
|
|
llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!");
|
|
default:
|
|
llvm_unreachable("Unknown SCEV kind!");
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/// Use SCEVTraversal to visit all nodes in the givien expression tree.
|
|
template<typename SV>
|
|
void visitAll(const SCEV *Root, SV& Visitor) {
|
|
SCEVTraversal<SV> T(Visitor);
|
|
T.visitAll(Root);
|
|
}
|
|
|
|
typedef DenseMap<const Value*, Value*> ValueToValueMap;
|
|
|
|
/// The SCEVParameterRewriter takes a scalar evolution expression and updates
|
|
/// the SCEVUnknown components following the Map (Value -> Value).
|
|
struct SCEVParameterRewriter
|
|
: public SCEVVisitor<SCEVParameterRewriter, const SCEV*> {
|
|
public:
|
|
static const SCEV *rewrite(const SCEV *Scev, ScalarEvolution &SE,
|
|
ValueToValueMap &Map,
|
|
bool InterpretConsts = false) {
|
|
SCEVParameterRewriter Rewriter(SE, Map, InterpretConsts);
|
|
return Rewriter.visit(Scev);
|
|
}
|
|
|
|
SCEVParameterRewriter(ScalarEvolution &S, ValueToValueMap &M, bool C)
|
|
: SE(S), Map(M), InterpretConsts(C) {}
|
|
|
|
const SCEV *visitConstant(const SCEVConstant *Constant) {
|
|
return Constant;
|
|
}
|
|
|
|
const SCEV *visitTruncateExpr(const SCEVTruncateExpr *Expr) {
|
|
const SCEV *Operand = visit(Expr->getOperand());
|
|
return SE.getTruncateExpr(Operand, Expr->getType());
|
|
}
|
|
|
|
const SCEV *visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) {
|
|
const SCEV *Operand = visit(Expr->getOperand());
|
|
return SE.getZeroExtendExpr(Operand, Expr->getType());
|
|
}
|
|
|
|
const SCEV *visitSignExtendExpr(const SCEVSignExtendExpr *Expr) {
|
|
const SCEV *Operand = visit(Expr->getOperand());
|
|
return SE.getSignExtendExpr(Operand, Expr->getType());
|
|
}
|
|
|
|
const SCEV *visitAddExpr(const SCEVAddExpr *Expr) {
|
|
SmallVector<const SCEV *, 2> Operands;
|
|
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
|
Operands.push_back(visit(Expr->getOperand(i)));
|
|
return SE.getAddExpr(Operands);
|
|
}
|
|
|
|
const SCEV *visitMulExpr(const SCEVMulExpr *Expr) {
|
|
SmallVector<const SCEV *, 2> Operands;
|
|
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
|
Operands.push_back(visit(Expr->getOperand(i)));
|
|
return SE.getMulExpr(Operands);
|
|
}
|
|
|
|
const SCEV *visitUDivExpr(const SCEVUDivExpr *Expr) {
|
|
return SE.getUDivExpr(visit(Expr->getLHS()), visit(Expr->getRHS()));
|
|
}
|
|
|
|
const SCEV *visitAddRecExpr(const SCEVAddRecExpr *Expr) {
|
|
SmallVector<const SCEV *, 2> Operands;
|
|
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
|
Operands.push_back(visit(Expr->getOperand(i)));
|
|
return SE.getAddRecExpr(Operands, Expr->getLoop(),
|
|
Expr->getNoWrapFlags());
|
|
}
|
|
|
|
const SCEV *visitSMaxExpr(const SCEVSMaxExpr *Expr) {
|
|
SmallVector<const SCEV *, 2> Operands;
|
|
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
|
Operands.push_back(visit(Expr->getOperand(i)));
|
|
return SE.getSMaxExpr(Operands);
|
|
}
|
|
|
|
const SCEV *visitUMaxExpr(const SCEVUMaxExpr *Expr) {
|
|
SmallVector<const SCEV *, 2> Operands;
|
|
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
|
Operands.push_back(visit(Expr->getOperand(i)));
|
|
return SE.getUMaxExpr(Operands);
|
|
}
|
|
|
|
const SCEV *visitUnknown(const SCEVUnknown *Expr) {
|
|
Value *V = Expr->getValue();
|
|
if (Map.count(V)) {
|
|
Value *NV = Map[V];
|
|
if (InterpretConsts && isa<ConstantInt>(NV))
|
|
return SE.getConstant(cast<ConstantInt>(NV));
|
|
return SE.getUnknown(NV);
|
|
}
|
|
return Expr;
|
|
}
|
|
|
|
const SCEV *visitCouldNotCompute(const SCEVCouldNotCompute *Expr) {
|
|
return Expr;
|
|
}
|
|
|
|
private:
|
|
ScalarEvolution &SE;
|
|
ValueToValueMap ⤅
|
|
bool InterpretConsts;
|
|
};
|
|
|
|
typedef DenseMap<const Loop*, const SCEV*> LoopToScevMapT;
|
|
|
|
/// The SCEVApplyRewriter takes a scalar evolution expression and applies
|
|
/// the Map (Loop -> SCEV) to all AddRecExprs.
|
|
struct SCEVApplyRewriter
|
|
: public SCEVVisitor<SCEVApplyRewriter, const SCEV*> {
|
|
public:
|
|
static const SCEV *rewrite(const SCEV *Scev, LoopToScevMapT &Map,
|
|
ScalarEvolution &SE) {
|
|
SCEVApplyRewriter Rewriter(SE, Map);
|
|
return Rewriter.visit(Scev);
|
|
}
|
|
|
|
SCEVApplyRewriter(ScalarEvolution &S, LoopToScevMapT &M)
|
|
: SE(S), Map(M) {}
|
|
|
|
const SCEV *visitConstant(const SCEVConstant *Constant) {
|
|
return Constant;
|
|
}
|
|
|
|
const SCEV *visitTruncateExpr(const SCEVTruncateExpr *Expr) {
|
|
const SCEV *Operand = visit(Expr->getOperand());
|
|
return SE.getTruncateExpr(Operand, Expr->getType());
|
|
}
|
|
|
|
const SCEV *visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) {
|
|
const SCEV *Operand = visit(Expr->getOperand());
|
|
return SE.getZeroExtendExpr(Operand, Expr->getType());
|
|
}
|
|
|
|
const SCEV *visitSignExtendExpr(const SCEVSignExtendExpr *Expr) {
|
|
const SCEV *Operand = visit(Expr->getOperand());
|
|
return SE.getSignExtendExpr(Operand, Expr->getType());
|
|
}
|
|
|
|
const SCEV *visitAddExpr(const SCEVAddExpr *Expr) {
|
|
SmallVector<const SCEV *, 2> Operands;
|
|
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
|
Operands.push_back(visit(Expr->getOperand(i)));
|
|
return SE.getAddExpr(Operands);
|
|
}
|
|
|
|
const SCEV *visitMulExpr(const SCEVMulExpr *Expr) {
|
|
SmallVector<const SCEV *, 2> Operands;
|
|
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
|
Operands.push_back(visit(Expr->getOperand(i)));
|
|
return SE.getMulExpr(Operands);
|
|
}
|
|
|
|
const SCEV *visitUDivExpr(const SCEVUDivExpr *Expr) {
|
|
return SE.getUDivExpr(visit(Expr->getLHS()), visit(Expr->getRHS()));
|
|
}
|
|
|
|
const SCEV *visitAddRecExpr(const SCEVAddRecExpr *Expr) {
|
|
SmallVector<const SCEV *, 2> Operands;
|
|
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
|
Operands.push_back(visit(Expr->getOperand(i)));
|
|
|
|
const Loop *L = Expr->getLoop();
|
|
const SCEV *Res = SE.getAddRecExpr(Operands, L, Expr->getNoWrapFlags());
|
|
|
|
if (0 == Map.count(L))
|
|
return Res;
|
|
|
|
const SCEVAddRecExpr *Rec = (const SCEVAddRecExpr *) Res;
|
|
return Rec->evaluateAtIteration(Map[L], SE);
|
|
}
|
|
|
|
const SCEV *visitSMaxExpr(const SCEVSMaxExpr *Expr) {
|
|
SmallVector<const SCEV *, 2> Operands;
|
|
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
|
Operands.push_back(visit(Expr->getOperand(i)));
|
|
return SE.getSMaxExpr(Operands);
|
|
}
|
|
|
|
const SCEV *visitUMaxExpr(const SCEVUMaxExpr *Expr) {
|
|
SmallVector<const SCEV *, 2> Operands;
|
|
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
|
Operands.push_back(visit(Expr->getOperand(i)));
|
|
return SE.getUMaxExpr(Operands);
|
|
}
|
|
|
|
const SCEV *visitUnknown(const SCEVUnknown *Expr) {
|
|
return Expr;
|
|
}
|
|
|
|
const SCEV *visitCouldNotCompute(const SCEVCouldNotCompute *Expr) {
|
|
return Expr;
|
|
}
|
|
|
|
private:
|
|
ScalarEvolution &SE;
|
|
LoopToScevMapT ⤅
|
|
};
|
|
|
|
/// Applies the Map (Loop -> SCEV) to the given Scev.
|
|
static inline const SCEV *apply(const SCEV *Scev, LoopToScevMapT &Map,
|
|
ScalarEvolution &SE) {
|
|
return SCEVApplyRewriter::rewrite(Scev, Map, SE);
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|