forked from OSchip/llvm-project
Remove OpPointer, cleaning up a ton of code. This also moves Ops to using
inherited constructors, which is cleaner and means you can now use DimOp() to get a null op, instead of having to use Instruction::getNull<DimOp>(). This removes another 200 lines of code. PiperOrigin-RevId: 240068113
This commit is contained in:
parent
7ab37aaf02
commit
d9b5bc8f55
|
@ -59,6 +59,8 @@ public:
|
|||
class AffineApplyOp : public Op<AffineApplyOp, OpTrait::VariadicOperands,
|
||||
OpTrait::OneResult, OpTrait::HasNoSideEffect> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
/// Builds an affine apply op with the specified map and operands.
|
||||
static void build(Builder *builder, OperationState *result, AffineMap map,
|
||||
ArrayRef<Value *> operands);
|
||||
|
@ -84,10 +86,6 @@ public:
|
|||
|
||||
static void getCanonicalizationPatterns(OwningRewritePatternList &results,
|
||||
MLIRContext *context);
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit AffineApplyOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// The "for" instruction represents an affine loop nest, defining an SSA value
|
||||
|
@ -117,6 +115,8 @@ private:
|
|||
class AffineForOp
|
||||
: public Op<AffineForOp, OpTrait::VariadicOperands, OpTrait::ZeroResult> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
// Hooks to customize behavior of this op.
|
||||
static void build(Builder *builder, OperationState *result,
|
||||
ArrayRef<Value *> lbOperands, AffineMap lbMap,
|
||||
|
@ -225,10 +225,6 @@ public:
|
|||
/// Returns true if both the lower and upper bound have the same operand lists
|
||||
/// (same operands in the same order).
|
||||
bool matchingBoundOperandList();
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit AffineForOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// Returns if the provided value is the induction variable of a AffineForOp.
|
||||
|
@ -236,21 +232,20 @@ bool isForInductionVar(Value *val);
|
|||
|
||||
/// Returns the loop parent of an induction variable. If the provided value is
|
||||
/// not an induction variable, then return nullptr.
|
||||
OpPointer<AffineForOp> getForInductionVarOwner(Value *val);
|
||||
AffineForOp getForInductionVarOwner(Value *val);
|
||||
|
||||
/// Extracts the induction variables from a list of AffineForOps and places them
|
||||
/// in the output argument `ivs`.
|
||||
void extractForInductionVars(ArrayRef<OpPointer<AffineForOp>> forInsts,
|
||||
void extractForInductionVars(ArrayRef<AffineForOp> forInsts,
|
||||
SmallVectorImpl<Value *> *ivs);
|
||||
|
||||
|
||||
/// AffineBound represents a lower or upper bound in the for instruction.
|
||||
/// This class does not own the underlying operands. Instead, it refers
|
||||
/// to the operands stored in the AffineForOp. Its life span should not exceed
|
||||
/// that of the for instruction it refers to.
|
||||
class AffineBound {
|
||||
public:
|
||||
OpPointer<AffineForOp> getAffineForOp() { return inst; }
|
||||
AffineForOp getAffineForOp() { return inst; }
|
||||
AffineMap getMap() { return map; }
|
||||
|
||||
/// Returns an AffineValueMap representing this bound.
|
||||
|
@ -274,15 +269,14 @@ public:
|
|||
|
||||
private:
|
||||
// 'for' instruction that contains this bound.
|
||||
OpPointer<AffineForOp> inst;
|
||||
AffineForOp inst;
|
||||
// Start and end positions of this affine bound operands in the list of
|
||||
// the containing 'for' instruction operands.
|
||||
unsigned opStart, opEnd;
|
||||
// Affine map for this bound.
|
||||
AffineMap map;
|
||||
|
||||
AffineBound(OpPointer<AffineForOp> inst, unsigned opStart, unsigned opEnd,
|
||||
AffineMap map)
|
||||
AffineBound(AffineForOp inst, unsigned opStart, unsigned opEnd, AffineMap map)
|
||||
: inst(inst), opStart(opStart), opEnd(opEnd), map(map) {}
|
||||
|
||||
friend class AffineForOp;
|
||||
|
@ -309,6 +303,8 @@ private:
|
|||
class AffineIfOp
|
||||
: public Op<AffineIfOp, OpTrait::VariadicOperands, OpTrait::ZeroResult> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
// Hooks to customize behavior of this op.
|
||||
static void build(Builder *builder, OperationState *result,
|
||||
IntegerSet condition, ArrayRef<Value *> conditionOperands);
|
||||
|
@ -328,10 +324,6 @@ public:
|
|||
bool verify();
|
||||
static bool parse(OpAsmParser *parser, OperationState *result);
|
||||
void print(OpAsmPrinter *p);
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit AffineIfOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// Returns true if the given Value can be used as a dimension id.
|
||||
|
@ -349,9 +341,9 @@ void canonicalizeMapAndOperands(AffineMap *map,
|
|||
/// Returns a composed AffineApplyOp by composing `map` and `operands` with
|
||||
/// other AffineApplyOps supplying those operands. The operands of the resulting
|
||||
/// AffineApplyOp do not change the length of AffineApplyOp chains.
|
||||
OpPointer<AffineApplyOp>
|
||||
makeComposedAffineApply(FuncBuilder *b, Location loc, AffineMap map,
|
||||
llvm::ArrayRef<Value *> operands);
|
||||
AffineApplyOp makeComposedAffineApply(FuncBuilder *b, Location loc,
|
||||
AffineMap map,
|
||||
llvm::ArrayRef<Value *> operands);
|
||||
|
||||
/// Given an affine map `map` and its input `operands`, this method composes
|
||||
/// into `map`, maps of AffineApplyOps whose results are the values in
|
||||
|
|
|
@ -36,7 +36,6 @@ class AffineForOp;
|
|||
class AffineValueMap;
|
||||
class FlatAffineConstraints;
|
||||
class Instruction;
|
||||
template <typename OpType> class OpPointer;
|
||||
class Value;
|
||||
|
||||
/// Returns in `affineApplyOps`, the sequence of those AffineApplyOp
|
||||
|
@ -52,7 +51,7 @@ void getReachableAffineApplyOps(
|
|||
/// operands are added as symbols in the system. Returns failure for the yet
|
||||
/// unimplemented cases.
|
||||
// TODO(bondhugula): handle non-unit strides.
|
||||
LogicalResult getIndexSet(llvm::MutableArrayRef<OpPointer<AffineForOp>> forOps,
|
||||
LogicalResult getIndexSet(llvm::MutableArrayRef<AffineForOp> forOps,
|
||||
FlatAffineConstraints *domain);
|
||||
|
||||
/// Encapsulates a memref load or store access information.
|
||||
|
|
|
@ -131,7 +131,7 @@ public:
|
|||
AffineValueMap(AffineMap map, ArrayRef<Value *> operands,
|
||||
ArrayRef<Value *> results = llvm::None);
|
||||
|
||||
explicit AffineValueMap(OpPointer<AffineApplyOp> applyOp);
|
||||
explicit AffineValueMap(AffineApplyOp applyOp);
|
||||
explicit AffineValueMap(AffineBound bound);
|
||||
|
||||
~AffineValueMap();
|
||||
|
@ -385,7 +385,7 @@ public:
|
|||
/// instruction are added as trailing identifiers (either dimensional or
|
||||
/// symbolic depending on whether the operand is a valid ML Function symbol).
|
||||
// TODO(bondhugula): add support for non-unit strides.
|
||||
LogicalResult addAffineForOpDomain(OpPointer<AffineForOp> forOp);
|
||||
LogicalResult addAffineForOpDomain(AffineForOp forOp);
|
||||
|
||||
/// Adds a lower or an upper bound for the identifier at the specified
|
||||
/// position with constraints being drawn from the specified bound map and
|
||||
|
|
|
@ -31,7 +31,6 @@ namespace mlir {
|
|||
class AffineExpr;
|
||||
class AffineForOp;
|
||||
class AffineMap;
|
||||
template <typename T> class OpPointer;
|
||||
class Instruction;
|
||||
class MemRefType;
|
||||
class Value;
|
||||
|
@ -44,18 +43,18 @@ class Value;
|
|||
/// bounds before computing the trip count expressions
|
||||
// TODO(mlir-team): this should be moved into 'Transforms/' and be replaced by a
|
||||
// pure analysis method relying on FlatAffineConstraints
|
||||
void buildTripCountMapAndOperands(OpPointer<AffineForOp> forOp, AffineMap *map,
|
||||
void buildTripCountMapAndOperands(AffineForOp forOp, AffineMap *map,
|
||||
SmallVectorImpl<Value *> *operands);
|
||||
|
||||
/// Returns the trip count of the loop if it's a constant, None otherwise. This
|
||||
/// uses affine expression analysis and is able to determine constant trip count
|
||||
/// in non-trivial cases.
|
||||
llvm::Optional<uint64_t> getConstantTripCount(OpPointer<AffineForOp> forOp);
|
||||
llvm::Optional<uint64_t> getConstantTripCount(AffineForOp forOp);
|
||||
|
||||
/// Returns the greatest known integral divisor of the trip count. Affine
|
||||
/// expression analysis is used (indirectly through getTripCount), and
|
||||
/// this method is thus able to determine non-trivial divisors.
|
||||
uint64_t getLargestDivisorOfTripCount(OpPointer<AffineForOp> forOp);
|
||||
uint64_t getLargestDivisorOfTripCount(AffineForOp forOp);
|
||||
|
||||
/// Given an induction variable `iv` of type AffineForOp and an `index` of type
|
||||
/// IndexType, returns `true` if `index` is independent of `iv` and false
|
||||
|
@ -92,13 +91,13 @@ getInvariantAccesses(Value &iv, llvm::ArrayRef<Value *> indices);
|
|||
/// 3. all nested load/stores are to scalar MemRefs.
|
||||
/// TODO(ntv): implement dependence semantics
|
||||
/// TODO(ntv): relax the no-conditionals restriction
|
||||
bool isVectorizableLoop(OpPointer<AffineForOp> loop);
|
||||
bool isVectorizableLoop(AffineForOp loop);
|
||||
|
||||
/// Checks whether the loop is structurally vectorizable and that all the LoadOp
|
||||
/// and StoreOp matched have access indexing functions that are are either:
|
||||
/// 1. invariant along the loop induction variable created by 'loop';
|
||||
/// 2. varying along the 'fastestVaryingDim' memory dimension.
|
||||
bool isVectorizableLoopAlongFastestVaryingMemRefDim(OpPointer<AffineForOp> loop,
|
||||
bool isVectorizableLoopAlongFastestVaryingMemRefDim(AffineForOp loop,
|
||||
unsigned fastestVaryingDim);
|
||||
|
||||
/// Checks where SSA dominance would be violated if a for inst's body
|
||||
|
@ -106,8 +105,7 @@ bool isVectorizableLoopAlongFastestVaryingMemRefDim(OpPointer<AffineForOp> loop,
|
|||
/// 'def' and all its uses have the same shift factor.
|
||||
// TODO(mlir-team): extend this to check for memory-based dependence
|
||||
// violation when we have the support.
|
||||
bool isInstwiseShiftValid(OpPointer<AffineForOp> forOp,
|
||||
llvm::ArrayRef<uint64_t> shifts);
|
||||
bool isInstwiseShiftValid(AffineForOp forOp, llvm::ArrayRef<uint64_t> shifts);
|
||||
} // end namespace mlir
|
||||
|
||||
#endif // MLIR_ANALYSIS_LOOP_ANALYSIS_H
|
||||
|
|
|
@ -41,15 +41,13 @@ class FlatAffineConstraints;
|
|||
class Instruction;
|
||||
class Location;
|
||||
class MemRefAccess;
|
||||
template <typename T> class OpPointer;
|
||||
class Instruction;
|
||||
class Value;
|
||||
|
||||
/// Populates 'loops' with IVs of the loops surrounding 'inst' ordered from
|
||||
/// the outermost 'for' instruction to the innermost one.
|
||||
// TODO(bondhugula): handle 'if' inst's.
|
||||
void getLoopIVs(Instruction &inst,
|
||||
SmallVectorImpl<OpPointer<AffineForOp>> *loops);
|
||||
void getLoopIVs(Instruction &inst, SmallVectorImpl<AffineForOp> *loops);
|
||||
|
||||
/// Returns the nesting depth of this instruction, i.e., the number of loops
|
||||
/// surrounding this instruction.
|
||||
|
@ -57,7 +55,7 @@ unsigned getNestingDepth(Instruction &inst);
|
|||
|
||||
/// Returns in 'sequentialLoops' all sequential loops in loop nest rooted
|
||||
/// at 'forOp'.
|
||||
void getSequentialLoops(OpPointer<AffineForOp> forOp,
|
||||
void getSequentialLoops(AffineForOp forOp,
|
||||
llvm::SmallDenseSet<Value *, 8> *sequentialLoops);
|
||||
|
||||
/// ComputationSliceState aggregates loop IVs, loop bound AffineMaps and their
|
||||
|
@ -105,10 +103,10 @@ LogicalResult getBackwardComputationSliceState(
|
|||
// materialize the results of the backward slice - presenting a trade-off b/w
|
||||
// storage and redundant computation in several cases.
|
||||
// TODO(andydavis) Support computation slices with common surrounding loops.
|
||||
OpPointer<AffineForOp>
|
||||
insertBackwardComputationSlice(Instruction *srcOpInst, Instruction *dstOpInst,
|
||||
unsigned dstLoopDepth,
|
||||
ComputationSliceState *sliceState);
|
||||
AffineForOp insertBackwardComputationSlice(Instruction *srcOpInst,
|
||||
Instruction *dstOpInst,
|
||||
unsigned dstLoopDepth,
|
||||
ComputationSliceState *sliceState);
|
||||
|
||||
/// A region of a memref's data space; this is typically constructed by
|
||||
/// analyzing load/store op's on this memref and the index space of loops
|
||||
|
@ -235,11 +233,11 @@ unsigned getNumCommonSurroundingLoops(Instruction &A, Instruction &B);
|
|||
|
||||
/// Gets the memory footprint of all data touched in the specified memory space
|
||||
/// in bytes; if the memory space is unspecified, considers all memory spaces.
|
||||
Optional<int64_t> getMemoryFootprintBytes(OpPointer<AffineForOp> forOp,
|
||||
Optional<int64_t> getMemoryFootprintBytes(AffineForOp forOp,
|
||||
int memorySpace = -1);
|
||||
|
||||
/// Returns true if `forOp' is a parallel loop.
|
||||
bool isLoopParallel(OpPointer<AffineForOp> forOp);
|
||||
bool isLoopParallel(AffineForOp forOp);
|
||||
|
||||
} // end namespace mlir
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ struct MLIREmitter {
|
|||
}
|
||||
return res;
|
||||
}
|
||||
OpPointer<AffineForOp> getAffineForOp(Expr e);
|
||||
AffineForOp getAffineForOp(Expr e);
|
||||
|
||||
private:
|
||||
/// Emits the MLIR for `expr` and inserts at the `builder`'s insertion point.
|
||||
|
|
|
@ -254,7 +254,7 @@ public:
|
|||
|
||||
/// Create operation of specific op type at the current insertion point.
|
||||
template <typename OpTy, typename... Args>
|
||||
OpPointer<OpTy> create(Location location, Args... args) {
|
||||
OpTy create(Location location, Args... args) {
|
||||
OperationState state(getContext(), location, OpTy::getOperationName());
|
||||
OpTy::build(this, &state, args...);
|
||||
auto *inst = createOperation(state);
|
||||
|
|
|
@ -37,7 +37,6 @@ class FunctionType;
|
|||
class MLIRContext;
|
||||
class Module;
|
||||
class ArgumentIterator;
|
||||
template <typename T> class OpPointer;
|
||||
|
||||
/// This is the base class for all of the MLIR function types.
|
||||
class Function : public llvm::ilist_node_with_parent<Function, Module> {
|
||||
|
@ -110,8 +109,7 @@ public:
|
|||
void walk(const std::function<void(Instruction *)> &callback);
|
||||
|
||||
/// Specialization of walk to only visit operations of 'OpTy'.
|
||||
template <typename OpTy>
|
||||
void walk(std::function<void(OpPointer<OpTy>)> callback) {
|
||||
template <typename OpTy> void walk(std::function<void(OpTy)> callback) {
|
||||
walk([&](Instruction *inst) {
|
||||
if (auto op = inst->dyn_cast<OpTy>())
|
||||
callback(op);
|
||||
|
@ -124,7 +122,7 @@ public:
|
|||
|
||||
/// Specialization of walkPostOrder to only visit operations of 'OpTy'.
|
||||
template <typename OpTy>
|
||||
void walkPostOrder(std::function<void(OpPointer<OpTy>)> callback) {
|
||||
void walkPostOrder(std::function<void(OpTy)> callback) {
|
||||
walkPostOrder([&](Instruction *inst) {
|
||||
if (auto op = inst->dyn_cast<OpTy>())
|
||||
callback(op);
|
||||
|
|
|
@ -33,7 +33,6 @@ namespace mlir {
|
|||
class BlockAndValueMapping;
|
||||
class Location;
|
||||
class MLIRContext;
|
||||
template <typename OpType> class OpPointer;
|
||||
class OperandIterator;
|
||||
class ResultIterator;
|
||||
class ResultTypeIterator;
|
||||
|
@ -363,27 +362,20 @@ public:
|
|||
// Conversions to declared operations like DimOp
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
// Return a null OpPointer for the specified type.
|
||||
template <typename OpClass> static OpPointer<OpClass> getNull() {
|
||||
return OpPointer<OpClass>(OpClass(nullptr));
|
||||
}
|
||||
|
||||
/// The dyn_cast methods perform a dynamic cast from an Instruction to a typed
|
||||
/// Op like DimOp. This returns a null OpPointer on failure.
|
||||
template <typename OpClass> OpPointer<OpClass> dyn_cast() {
|
||||
if (isa<OpClass>()) {
|
||||
/// Op like DimOp. This returns a null Op on failure.
|
||||
template <typename OpClass> OpClass dyn_cast() {
|
||||
if (isa<OpClass>())
|
||||
return cast<OpClass>();
|
||||
} else {
|
||||
return OpPointer<OpClass>(OpClass(nullptr));
|
||||
}
|
||||
return OpClass();
|
||||
}
|
||||
|
||||
/// The cast methods perform a cast from an Instruction to a typed Op like
|
||||
/// DimOp. This aborts if the parameter to the template isn't an instance of
|
||||
/// the template type argument.
|
||||
template <typename OpClass> OpPointer<OpClass> cast() {
|
||||
template <typename OpClass> OpClass cast() {
|
||||
assert(isa<OpClass>() && "cast<Ty>() argument of incompatible type!");
|
||||
return OpPointer<OpClass>(OpClass(this));
|
||||
return OpClass(this);
|
||||
}
|
||||
|
||||
/// The is methods return true if the operation is a typed op (like DimOp) of
|
||||
|
@ -399,8 +391,7 @@ public:
|
|||
void walk(const std::function<void(Instruction *)> &callback);
|
||||
|
||||
/// Specialization of walk to only visit operations of 'OpTy'.
|
||||
template <typename OpTy>
|
||||
void walk(std::function<void(OpPointer<OpTy>)> callback) {
|
||||
template <typename OpTy> void walk(std::function<void(OpTy)> callback) {
|
||||
walk([&](Instruction *inst) {
|
||||
if (auto op = inst->dyn_cast<OpTy>())
|
||||
callback(op);
|
||||
|
@ -413,7 +404,7 @@ public:
|
|||
|
||||
/// Specialization of walkPostOrder to only visit operations of 'OpTy'.
|
||||
template <typename OpTy>
|
||||
void walkPostOrder(std::function<void(OpPointer<OpTy>)> callback) {
|
||||
void walkPostOrder(std::function<void(OpTy)> callback) {
|
||||
walkPostOrder([&](Instruction *inst) {
|
||||
if (auto op = inst->dyn_cast<OpTy>())
|
||||
callback(op);
|
||||
|
|
|
@ -54,48 +54,6 @@ template <typename OpType> struct IsSingleResult {
|
|||
OpType *, OpTrait::OneResult<typename OpType::ConcreteOpType> *>::value;
|
||||
};
|
||||
|
||||
/// This pointer represents a notional "Instruction*" but where the actual
|
||||
/// storage of the pointer is maintained in the templated "OpType" class.
|
||||
template <typename OpType>
|
||||
class OpPointer {
|
||||
public:
|
||||
explicit OpPointer() : value(Instruction::getNull<OpType>().value) {}
|
||||
explicit OpPointer(OpType value) : value(value) {}
|
||||
|
||||
OpType &operator*() { return value; }
|
||||
|
||||
OpType *operator->() { return &value; }
|
||||
|
||||
explicit operator bool() { return value.getInstruction(); }
|
||||
|
||||
bool operator==(OpPointer rhs) {
|
||||
return value.getInstruction() == rhs.value.getInstruction();
|
||||
}
|
||||
bool operator!=(OpPointer rhs) { return !(*this == rhs); }
|
||||
|
||||
/// OpPointer can be implicitly converted to OpType*.
|
||||
/// Return `nullptr` if there is no associated Instruction*.
|
||||
operator OpType *() {
|
||||
if (!value.getInstruction())
|
||||
return nullptr;
|
||||
return &value;
|
||||
}
|
||||
|
||||
operator OpType() { return value; }
|
||||
|
||||
/// If the OpType operation includes the OneResult trait, then OpPointer can
|
||||
/// be implicitly converted to an Value*. This yields the value of the
|
||||
/// only result.
|
||||
template <typename SFINAE = OpType>
|
||||
operator typename std::enable_if<IsSingleResult<SFINAE>::value,
|
||||
Value *>::type() {
|
||||
return value.getResult();
|
||||
}
|
||||
|
||||
private:
|
||||
OpType value;
|
||||
};
|
||||
|
||||
/// This is the concrete base class that holds the operation pointer and has
|
||||
/// non-generic methods that only depend on State (to avoid having them
|
||||
/// instantiated on template types that don't affect them.
|
||||
|
@ -104,6 +62,12 @@ private:
|
|||
/// they aren't customized.
|
||||
class OpState {
|
||||
public:
|
||||
/// Ops are pointer-like, so we allow implicit conversion to bool.
|
||||
operator bool() { return getInstruction() != nullptr; }
|
||||
|
||||
/// This implicitly converts to Instruction*.
|
||||
operator Instruction *() const { return state; }
|
||||
|
||||
/// Return the operation that this refers to.
|
||||
Instruction *getInstruction() { return state; }
|
||||
|
||||
|
@ -186,6 +150,14 @@ private:
|
|||
Instruction *state;
|
||||
};
|
||||
|
||||
// Allow comparing operators.
|
||||
inline bool operator==(OpState lhs, OpState rhs) {
|
||||
return lhs.getInstruction() == rhs.getInstruction();
|
||||
}
|
||||
inline bool operator!=(OpState lhs, OpState rhs) {
|
||||
return lhs.getInstruction() != rhs.getInstruction();
|
||||
}
|
||||
|
||||
/// This template defines the constantFoldHook and foldHook as used by
|
||||
/// AbstractOperation.
|
||||
///
|
||||
|
@ -257,6 +229,12 @@ template <typename ConcreteType, bool isSingleResult>
|
|||
class FoldingHook<ConcreteType, isSingleResult,
|
||||
typename std::enable_if<isSingleResult>::type> {
|
||||
public:
|
||||
/// If the operation returns a single value, then the Op can be implicitly
|
||||
/// converted to an Value*. This yields the value of the only result.
|
||||
operator Value *() {
|
||||
return static_cast<ConcreteType *>(this)->getInstruction()->getResult(0);
|
||||
}
|
||||
|
||||
/// This is an implementation detail of the constant folder hook for
|
||||
/// AbstractOperation.
|
||||
static LogicalResult constantFoldHook(Instruction *op,
|
||||
|
@ -801,8 +779,14 @@ public:
|
|||
/// to introspect traits on this operation.
|
||||
using ConcreteOpType = ConcreteType;
|
||||
|
||||
/// This is a public constructor. Any op can be initialized to null.
|
||||
explicit Op() : OpState(nullptr) {}
|
||||
|
||||
protected:
|
||||
/// This is a private constructor only accessible through the
|
||||
/// Instruction::cast family of methods.
|
||||
explicit Op(Instruction *state) : OpState(state) {}
|
||||
friend class Instruction;
|
||||
|
||||
private:
|
||||
template <typename... Types> struct BaseVerifier;
|
||||
|
@ -866,6 +850,9 @@ template <typename ConcreteType, template <typename T> class... Traits>
|
|||
class CastOp : public Op<ConcreteType, OpTrait::OneOperand, OpTrait::OneResult,
|
||||
OpTrait::HasNoSideEffect, Traits...> {
|
||||
public:
|
||||
using Op<ConcreteType, OpTrait::OneOperand, OpTrait::OneResult,
|
||||
OpTrait::HasNoSideEffect, Traits...>::Op;
|
||||
|
||||
static void build(Builder *builder, OperationState *result, Value *source,
|
||||
Type destType) {
|
||||
impl::buildCastOp(builder, result, source, destType);
|
||||
|
@ -876,11 +863,6 @@ public:
|
|||
void print(OpAsmPrinter *p) {
|
||||
return impl::printCastOp(this->getInstruction(), p);
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit CastOp(Instruction *state)
|
||||
: Op<ConcreteType, OpTrait::OneOperand, OpTrait::OneResult,
|
||||
OpTrait::HasNoSideEffect, Traits...>(state) {}
|
||||
};
|
||||
|
||||
} // end namespace mlir
|
||||
|
|
|
@ -185,7 +185,7 @@ public:
|
|||
/// Create operation of specific op type at the current insertion point
|
||||
/// without verifying to see if it is valid.
|
||||
template <typename OpTy, typename... Args>
|
||||
OpPointer<OpTy> create(Location location, Args... args) {
|
||||
OpTy create(Location location, Args... args) {
|
||||
OperationState state(getContext(), location, OpTy::getOperationName());
|
||||
OpTy::build(this, &state, args...);
|
||||
auto *op = createOperation(state);
|
||||
|
@ -198,7 +198,7 @@ public:
|
|||
/// If the result is an invalid op (the verifier hook fails), emit an error
|
||||
/// and return null.
|
||||
template <typename OpTy, typename... Args>
|
||||
OpPointer<OpTy> createChecked(Location location, Args... args) {
|
||||
OpTy createChecked(Location location, Args... args) {
|
||||
OperationState state(getContext(), location, OpTy::getOperationName());
|
||||
OpTy::build(this, &state, args...);
|
||||
auto *op = createOperation(state);
|
||||
|
@ -213,7 +213,7 @@ public:
|
|||
// Otherwise, the error message got emitted. Just remove the instruction
|
||||
// we made.
|
||||
op->erase();
|
||||
return OpPointer<OpTy>();
|
||||
return OpTy();
|
||||
}
|
||||
|
||||
/// This method performs the final replacement for a pattern, where the
|
||||
|
|
|
@ -68,6 +68,8 @@ public:
|
|||
class AllocOp
|
||||
: public Op<AllocOp, OpTrait::VariadicOperands, OpTrait::OneResult> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
/// The result of an alloc is always a MemRefType.
|
||||
MemRefType getType() { return getResult()->getType().cast<MemRefType>(); }
|
||||
|
||||
|
@ -81,10 +83,6 @@ public:
|
|||
void print(OpAsmPrinter *p);
|
||||
static void getCanonicalizationPatterns(OwningRewritePatternList &results,
|
||||
MLIRContext *context);
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit AllocOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// The "br" operation represents a branch instruction in a function.
|
||||
|
@ -100,6 +98,8 @@ private:
|
|||
class BranchOp : public Op<BranchOp, OpTrait::VariadicOperands,
|
||||
OpTrait::ZeroResult, OpTrait::IsTerminator> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
static StringRef getOperationName() { return "std.br"; }
|
||||
|
||||
static void build(Builder *builder, OperationState *result, Block *dest,
|
||||
|
@ -115,10 +115,6 @@ public:
|
|||
|
||||
/// Erase the operand at 'index' from the operand list.
|
||||
void eraseOperand(unsigned index);
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit BranchOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// The "call" operation represents a direct call to a function. The operands
|
||||
|
@ -130,6 +126,8 @@ private:
|
|||
class CallOp
|
||||
: public Op<CallOp, OpTrait::VariadicOperands, OpTrait::VariadicResults> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
static StringRef getOperationName() { return "std.call"; }
|
||||
|
||||
static void build(Builder *builder, OperationState *result, Function *callee,
|
||||
|
@ -151,10 +149,6 @@ public:
|
|||
static bool parse(OpAsmParser *parser, OperationState *result);
|
||||
void print(OpAsmPrinter *p);
|
||||
bool verify();
|
||||
|
||||
protected:
|
||||
friend class Instruction;
|
||||
explicit CallOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// The "call_indirect" operation represents an indirect call to a value of
|
||||
|
@ -168,6 +162,7 @@ protected:
|
|||
class CallIndirectOp : public Op<CallIndirectOp, OpTrait::VariadicOperands,
|
||||
OpTrait::VariadicResults> {
|
||||
public:
|
||||
using Op::Op;
|
||||
static StringRef getOperationName() { return "std.call_indirect"; }
|
||||
|
||||
static void build(Builder *builder, OperationState *result, Value *callee,
|
||||
|
@ -189,10 +184,6 @@ public:
|
|||
bool verify();
|
||||
static void getCanonicalizationPatterns(OwningRewritePatternList &results,
|
||||
MLIRContext *context);
|
||||
|
||||
protected:
|
||||
friend class Instruction;
|
||||
explicit CallIndirectOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// The predicate indicates the type of the comparison to perform:
|
||||
|
@ -240,6 +231,8 @@ class CmpIOp
|
|||
OpTrait::OneResult, OpTrait::ResultsAreBoolLike,
|
||||
OpTrait::SameOperandsAndResultShape, OpTrait::HasNoSideEffect> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
CmpIPredicate getPredicate() {
|
||||
return (CmpIPredicate)getAttrOfType<IntegerAttr>(getPredicateAttrName())
|
||||
.getInt();
|
||||
|
@ -255,10 +248,6 @@ public:
|
|||
void print(OpAsmPrinter *p);
|
||||
bool verify();
|
||||
Attribute constantFold(ArrayRef<Attribute> operands, MLIRContext *context);
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit CmpIOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// The "cond_br" operation represents a conditional branch instruction in a
|
||||
|
@ -283,6 +272,8 @@ class CondBranchOp : public Op<CondBranchOp, OpTrait::AtLeastNOperands<1>::Impl,
|
|||
/// follows:
|
||||
/// { condition, [true_operands], [false_operands] }
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
static StringRef getOperationName() { return "std.cond_br"; }
|
||||
|
||||
static void build(Builder *builder, OperationState *result, Value *condition,
|
||||
|
@ -363,9 +354,6 @@ private:
|
|||
unsigned getFalseDestOperandIndex() {
|
||||
return getTrueDestOperandIndex() + getNumTrueOperands();
|
||||
}
|
||||
|
||||
friend class Instruction;
|
||||
explicit CondBranchOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// The "constant" operation requires a single attribute named "value".
|
||||
|
@ -377,6 +365,8 @@ private:
|
|||
class ConstantOp : public Op<ConstantOp, OpTrait::ZeroOperands,
|
||||
OpTrait::OneResult, OpTrait::HasNoSideEffect> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
/// Builds a constant op with the specified attribute value and result type.
|
||||
static void build(Builder *builder, OperationState *result, Type type,
|
||||
Attribute value);
|
||||
|
@ -394,10 +384,6 @@ public:
|
|||
void print(OpAsmPrinter *p);
|
||||
bool verify();
|
||||
Attribute constantFold(ArrayRef<Attribute> operands, MLIRContext *context);
|
||||
|
||||
protected:
|
||||
friend class Instruction;
|
||||
explicit ConstantOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// This is a refinement of the "constant" op for the case where it is
|
||||
|
@ -407,6 +393,8 @@ protected:
|
|||
///
|
||||
class ConstantFloatOp : public ConstantOp {
|
||||
public:
|
||||
using ConstantOp::ConstantOp;
|
||||
|
||||
/// Builds a constant float op producing a float of the specified type.
|
||||
static void build(Builder *builder, OperationState *result,
|
||||
const APFloat &value, FloatType type);
|
||||
|
@ -414,10 +402,6 @@ public:
|
|||
APFloat getValue() { return getAttrOfType<FloatAttr>("value").getValue(); }
|
||||
|
||||
static bool isClassFor(Instruction *op);
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit ConstantFloatOp(Instruction *state) : ConstantOp(state) {}
|
||||
};
|
||||
|
||||
/// This is a refinement of the "constant" op for the case where it is
|
||||
|
@ -427,6 +411,7 @@ private:
|
|||
///
|
||||
class ConstantIntOp : public ConstantOp {
|
||||
public:
|
||||
using ConstantOp::ConstantOp;
|
||||
/// Build a constant int op producing an integer of the specified width.
|
||||
static void build(Builder *builder, OperationState *result, int64_t value,
|
||||
unsigned width);
|
||||
|
@ -439,10 +424,6 @@ public:
|
|||
int64_t getValue() { return getAttrOfType<IntegerAttr>("value").getInt(); }
|
||||
|
||||
static bool isClassFor(Instruction *op);
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit ConstantIntOp(Instruction *state) : ConstantOp(state) {}
|
||||
};
|
||||
|
||||
/// This is a refinement of the "constant" op for the case where it is
|
||||
|
@ -452,16 +433,14 @@ private:
|
|||
///
|
||||
class ConstantIndexOp : public ConstantOp {
|
||||
public:
|
||||
using ConstantOp::ConstantOp;
|
||||
|
||||
/// Build a constant int op producing an index.
|
||||
static void build(Builder *builder, OperationState *result, int64_t value);
|
||||
|
||||
int64_t getValue() { return getAttrOfType<IntegerAttr>("value").getInt(); }
|
||||
|
||||
static bool isClassFor(Instruction *op);
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit ConstantIndexOp(Instruction *state) : ConstantOp(state) {}
|
||||
};
|
||||
|
||||
/// The "dealloc" operation frees the region of memory referenced by a memref
|
||||
|
@ -477,6 +456,8 @@ private:
|
|||
class DeallocOp
|
||||
: public Op<DeallocOp, OpTrait::OneOperand, OpTrait::ZeroResult> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
Value *getMemRef() { return getOperand(); }
|
||||
void setMemRef(Value *value) { setOperand(value); }
|
||||
|
||||
|
@ -489,10 +470,6 @@ public:
|
|||
void print(OpAsmPrinter *p);
|
||||
static void getCanonicalizationPatterns(OwningRewritePatternList &results,
|
||||
MLIRContext *context);
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit DeallocOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// The "dim" operation takes a memref or tensor operand and returns an
|
||||
|
@ -504,6 +481,8 @@ private:
|
|||
class DimOp : public Op<DimOp, OpTrait::OneOperand, OpTrait::OneResult,
|
||||
OpTrait::HasNoSideEffect> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
static void build(Builder *builder, OperationState *result,
|
||||
Value *memrefOrTensor, unsigned index);
|
||||
|
||||
|
@ -520,10 +499,6 @@ public:
|
|||
bool verify();
|
||||
static bool parse(OpAsmParser *parser, OperationState *result);
|
||||
void print(OpAsmPrinter *p);
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit DimOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
// DmaStartOp starts a non-blocking DMA operation that transfers data from a
|
||||
|
@ -566,6 +541,8 @@ private:
|
|||
class DmaStartOp
|
||||
: public Op<DmaStartOp, OpTrait::VariadicOperands, OpTrait::ZeroResult> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
static void build(Builder *builder, OperationState *result, Value *srcMemRef,
|
||||
ArrayRef<Value *> srcIndices, Value *destMemRef,
|
||||
ArrayRef<Value *> destIndices, Value *numElements,
|
||||
|
@ -671,10 +648,6 @@ public:
|
|||
return nullptr;
|
||||
return getOperand(getNumOperands() - 1);
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class Instruction;
|
||||
explicit DmaStartOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
// DmaWaitOp blocks until the completion of a DMA operation associated with the
|
||||
|
@ -693,6 +666,8 @@ protected:
|
|||
class DmaWaitOp
|
||||
: public Op<DmaWaitOp, OpTrait::VariadicOperands, OpTrait::ZeroResult> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
static void build(Builder *builder, OperationState *result, Value *tagMemRef,
|
||||
ArrayRef<Value *> tagIndices, Value *numElements);
|
||||
|
||||
|
@ -719,10 +694,6 @@ public:
|
|||
void print(OpAsmPrinter *p);
|
||||
static void getCanonicalizationPatterns(OwningRewritePatternList &results,
|
||||
MLIRContext *context);
|
||||
|
||||
protected:
|
||||
friend class Instruction;
|
||||
explicit DmaWaitOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// The "extract_element" op reads a tensor or vector and returns one element
|
||||
|
@ -740,6 +711,8 @@ class ExtractElementOp
|
|||
: public Op<ExtractElementOp, OpTrait::VariadicOperands, OpTrait::OneResult,
|
||||
OpTrait::HasNoSideEffect> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
static void build(Builder *builder, OperationState *result, Value *aggregate,
|
||||
ArrayRef<Value *> indices = {});
|
||||
|
||||
|
@ -757,10 +730,6 @@ public:
|
|||
static bool parse(OpAsmParser *parser, OperationState *result);
|
||||
void print(OpAsmPrinter *p);
|
||||
Attribute constantFold(ArrayRef<Attribute> operands, MLIRContext *context);
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit ExtractElementOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// The "load" op reads an element from a memref specified by an index list. The
|
||||
|
@ -774,6 +743,8 @@ private:
|
|||
class LoadOp
|
||||
: public Op<LoadOp, OpTrait::VariadicOperands, OpTrait::OneResult> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
// Hooks to customize behavior of this op.
|
||||
static void build(Builder *builder, OperationState *result, Value *memref,
|
||||
ArrayRef<Value *> indices = {});
|
||||
|
@ -796,10 +767,6 @@ public:
|
|||
void print(OpAsmPrinter *p);
|
||||
static void getCanonicalizationPatterns(OwningRewritePatternList &results,
|
||||
MLIRContext *context);
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit LoadOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// The "memref_cast" operation converts a memref from one type to an equivalent
|
||||
|
@ -819,6 +786,7 @@ private:
|
|||
///
|
||||
class MemRefCastOp : public CastOp<MemRefCastOp> {
|
||||
public:
|
||||
using CastOp::CastOp;
|
||||
static StringRef getOperationName() { return "std.memref_cast"; }
|
||||
|
||||
/// The result of a memref_cast is always a memref.
|
||||
|
@ -827,10 +795,6 @@ public:
|
|||
void print(OpAsmPrinter *p);
|
||||
|
||||
bool verify();
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit MemRefCastOp(Instruction *state) : CastOp(state) {}
|
||||
};
|
||||
|
||||
/// The "return" operation represents a return instruction within a function.
|
||||
|
@ -845,6 +809,8 @@ private:
|
|||
class ReturnOp : public Op<ReturnOp, OpTrait::VariadicOperands,
|
||||
OpTrait::ZeroResult, OpTrait::IsTerminator> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
static StringRef getOperationName() { return "std.return"; }
|
||||
|
||||
static void build(Builder *builder, OperationState *result,
|
||||
|
@ -854,10 +820,6 @@ public:
|
|||
static bool parse(OpAsmParser *parser, OperationState *result);
|
||||
void print(OpAsmPrinter *p);
|
||||
bool verify();
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit ReturnOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// The "select" operation chooses one value based on a binary condition
|
||||
|
@ -874,6 +836,8 @@ private:
|
|||
class SelectOp : public Op<SelectOp, OpTrait::NOperands<3>::Impl,
|
||||
OpTrait::OneResult, OpTrait::HasNoSideEffect> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
static StringRef getOperationName() { return "std.select"; }
|
||||
static void build(Builder *builder, OperationState *result, Value *condition,
|
||||
Value *trueValue, Value *falseValue);
|
||||
|
@ -886,10 +850,6 @@ public:
|
|||
Value *getFalseValue() { return getOperand(2); }
|
||||
|
||||
Value *fold();
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit SelectOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// The "store" op writes an element to a memref specified by an index list.
|
||||
|
@ -905,6 +865,8 @@ private:
|
|||
class StoreOp
|
||||
: public Op<StoreOp, OpTrait::VariadicOperands, OpTrait::ZeroResult> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
// Hooks to customize behavior of this op.
|
||||
static void build(Builder *builder, OperationState *result,
|
||||
Value *valueToStore, Value *memref,
|
||||
|
@ -931,10 +893,6 @@ public:
|
|||
|
||||
static void getCanonicalizationPatterns(OwningRewritePatternList &results,
|
||||
MLIRContext *context);
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit StoreOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// The "tensor_cast" operation converts a tensor from one type to an equivalent
|
||||
|
@ -949,6 +907,8 @@ private:
|
|||
///
|
||||
class TensorCastOp : public CastOp<TensorCastOp> {
|
||||
public:
|
||||
using CastOp::CastOp;
|
||||
|
||||
static StringRef getOperationName() { return "std.tensor_cast"; }
|
||||
|
||||
/// The result of a tensor_cast is always a tensor.
|
||||
|
@ -957,10 +917,6 @@ public:
|
|||
void print(OpAsmPrinter *p);
|
||||
|
||||
bool verify();
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit TensorCastOp(Instruction *state) : CastOp(state) {}
|
||||
};
|
||||
|
||||
/// Prints dimension and symbol list.
|
||||
|
|
|
@ -96,6 +96,8 @@ class VectorTransferReadOp
|
|||
enum Offsets : unsigned { MemRefOffset = 0, FirstIndexOffset = 1 };
|
||||
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
static StringRef getOperationName() { return "vector_transfer_read"; }
|
||||
static StringRef getPermutationMapAttrName() { return "permutation_map"; }
|
||||
static void build(Builder *builder, OperationState *result,
|
||||
|
@ -118,10 +120,6 @@ public:
|
|||
static bool parse(OpAsmParser *parser, OperationState *result);
|
||||
void print(OpAsmPrinter *p);
|
||||
bool verify();
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit VectorTransferReadOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// VectorTransferWriteOp performs a blocking write from a super-vector to
|
||||
|
@ -162,6 +160,8 @@ class VectorTransferWriteOp
|
|||
};
|
||||
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
static StringRef getOperationName() { return "vector_transfer_write"; }
|
||||
static StringRef getPermutationMapAttrName() { return "permutation_map"; }
|
||||
static void build(Builder *builder, OperationState *result, Value *srcVector,
|
||||
|
@ -181,10 +181,6 @@ public:
|
|||
static bool parse(OpAsmParser *parser, OperationState *result);
|
||||
void print(OpAsmPrinter *p);
|
||||
bool verify();
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit VectorTransferWriteOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
/// VectorTypeCastOp performs a conversion from a memref with scalar element to
|
||||
|
@ -199,16 +195,14 @@ private:
|
|||
class VectorTypeCastOp
|
||||
: public Op<VectorTypeCastOp, OpTrait::OneOperand, OpTrait::OneResult> {
|
||||
public:
|
||||
using Op::Op;
|
||||
|
||||
static StringRef getOperationName() { return "vector_type_cast"; }
|
||||
static void build(Builder *builder, OperationState *result, Value *srcVector,
|
||||
Type dstType);
|
||||
static bool parse(OpAsmParser *parser, OperationState *result);
|
||||
void print(OpAsmPrinter *p);
|
||||
bool verify();
|
||||
|
||||
private:
|
||||
friend class Instruction;
|
||||
explicit VectorTypeCastOp(Instruction *state) : Op(state) {}
|
||||
};
|
||||
|
||||
} // end namespace mlir
|
||||
|
|
|
@ -32,35 +32,32 @@ class AffineMap;
|
|||
class AffineForOp;
|
||||
class Function;
|
||||
class FuncBuilder;
|
||||
template <typename T> class OpPointer;
|
||||
class Value;
|
||||
|
||||
/// Unrolls this for instruction completely if the trip count is known to be
|
||||
/// constant. Returns failure otherwise.
|
||||
LogicalResult loopUnrollFull(OpPointer<AffineForOp> forOp);
|
||||
LogicalResult loopUnrollFull(AffineForOp forOp);
|
||||
/// Unrolls this for instruction by the specified unroll factor. Returns failure
|
||||
/// if the loop cannot be unrolled either due to restrictions or due to invalid
|
||||
/// unroll factors.
|
||||
LogicalResult loopUnrollByFactor(OpPointer<AffineForOp> forOp,
|
||||
uint64_t unrollFactor);
|
||||
LogicalResult loopUnrollByFactor(AffineForOp forOp, uint64_t unrollFactor);
|
||||
/// Unrolls this loop by the specified unroll factor or its trip count,
|
||||
/// whichever is lower.
|
||||
LogicalResult loopUnrollUpToFactor(OpPointer<AffineForOp> forOp,
|
||||
uint64_t unrollFactor);
|
||||
LogicalResult loopUnrollUpToFactor(AffineForOp forOp, uint64_t unrollFactor);
|
||||
|
||||
/// Unrolls and jams this loop by the specified factor. Returns success if the
|
||||
/// loop is successfully unroll-jammed.
|
||||
LogicalResult loopUnrollJamByFactor(OpPointer<AffineForOp> forOp,
|
||||
LogicalResult loopUnrollJamByFactor(AffineForOp forOp,
|
||||
uint64_t unrollJamFactor);
|
||||
|
||||
/// Unrolls and jams this loop by the specified factor or by the trip count (if
|
||||
/// constant), whichever is lower.
|
||||
LogicalResult loopUnrollJamUpToFactor(OpPointer<AffineForOp> forOp,
|
||||
LogicalResult loopUnrollJamUpToFactor(AffineForOp forOp,
|
||||
uint64_t unrollJamFactor);
|
||||
|
||||
/// Promotes the loop body of a AffineForOp to its containing block if the
|
||||
/// AffineForOp was known to have a single iteration.
|
||||
LogicalResult promoteIfSingleIteration(OpPointer<AffineForOp> forOp);
|
||||
LogicalResult promoteIfSingleIteration(AffineForOp forOp);
|
||||
|
||||
/// Promotes all single iteration AffineForOp's in the Function, i.e., moves
|
||||
/// their body into the containing Block.
|
||||
|
@ -71,8 +68,8 @@ void promoteSingleIterationLoops(Function *f);
|
|||
/// part of the unrolled loop. Computes the bound as an AffineMap with its
|
||||
/// operands or a null map when the trip count can't be expressed as an affine
|
||||
/// expression.
|
||||
void getCleanupLoopLowerBound(OpPointer<AffineForOp> forOp,
|
||||
unsigned unrollFactor, AffineMap *map,
|
||||
void getCleanupLoopLowerBound(AffineForOp forOp, unsigned unrollFactor,
|
||||
AffineMap *map,
|
||||
SmallVectorImpl<Value *> *operands,
|
||||
FuncBuilder *builder);
|
||||
|
||||
|
@ -80,42 +77,39 @@ void getCleanupLoopLowerBound(OpPointer<AffineForOp> forOp,
|
|||
/// instruction-wise shifts. The shifts are with respect to the original
|
||||
/// execution order, and are multiplied by the loop 'step' before being applied.
|
||||
LLVM_NODISCARD
|
||||
LogicalResult instBodySkew(OpPointer<AffineForOp> forOp,
|
||||
ArrayRef<uint64_t> shifts,
|
||||
LogicalResult instBodySkew(AffineForOp forOp, ArrayRef<uint64_t> shifts,
|
||||
bool unrollPrologueEpilogue = false);
|
||||
|
||||
/// Tiles the specified band of perfectly nested loops creating tile-space loops
|
||||
/// and intra-tile loops. A band is a contiguous set of loops.
|
||||
LLVM_NODISCARD
|
||||
LogicalResult tileCodeGen(MutableArrayRef<OpPointer<AffineForOp>> band,
|
||||
LogicalResult tileCodeGen(MutableArrayRef<AffineForOp> band,
|
||||
ArrayRef<unsigned> tileSizes);
|
||||
|
||||
/// Performs loop interchange on 'forOpA' and 'forOpB'. Requires that 'forOpA'
|
||||
/// and 'forOpB' are part of a perfectly nested sequence of loops.
|
||||
void interchangeLoops(OpPointer<AffineForOp> forOpA,
|
||||
OpPointer<AffineForOp> forOpB);
|
||||
void interchangeLoops(AffineForOp forOpA, AffineForOp forOpB);
|
||||
|
||||
/// Sinks 'forOp' by 'loopDepth' levels by performing a series of loop
|
||||
/// interchanges. Requires that 'forOp' is part of a perfect nest with
|
||||
/// 'loopDepth' AffineForOps consecutively nested under it.
|
||||
void sinkLoop(OpPointer<AffineForOp> forOp, unsigned loopDepth);
|
||||
void sinkLoop(AffineForOp forOp, unsigned loopDepth);
|
||||
|
||||
/// Performs tiling fo imperfectly nested loops (with interchange) by
|
||||
/// strip-mining the `forOps` by `sizes` and sinking them, in their order of
|
||||
/// occurrence in `forOps`, under each of the `targets`.
|
||||
/// Returns the new AffineForOps, one per each of (`forOps`, `targets`) pair,
|
||||
/// nested immediately under each of `targets`.
|
||||
SmallVector<SmallVector<OpPointer<AffineForOp>, 8>, 8>
|
||||
tile(ArrayRef<OpPointer<AffineForOp>> forOps, ArrayRef<uint64_t> sizes,
|
||||
ArrayRef<OpPointer<AffineForOp>> targets);
|
||||
SmallVector<SmallVector<AffineForOp, 8>, 8> tile(ArrayRef<AffineForOp> forOps,
|
||||
ArrayRef<uint64_t> sizes,
|
||||
ArrayRef<AffineForOp> targets);
|
||||
|
||||
/// Performs tiling (with interchange) by strip-mining the `forOps` by `sizes`
|
||||
/// and sinking them, in their order of occurrence in `forOps`, under `target`.
|
||||
/// Returns the new AffineForOps, one per `forOps`, nested immediately under
|
||||
/// `target`.
|
||||
SmallVector<OpPointer<AffineForOp>, 8>
|
||||
tile(ArrayRef<OpPointer<AffineForOp>> forOps, ArrayRef<uint64_t> sizes,
|
||||
OpPointer<AffineForOp> target);
|
||||
SmallVector<AffineForOp, 8> tile(ArrayRef<AffineForOp> forOps,
|
||||
ArrayRef<uint64_t> sizes, AffineForOp target);
|
||||
|
||||
} // end namespace mlir
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
namespace mlir {
|
||||
|
||||
class AffineForOp;
|
||||
template <typename T> class OpPointer;
|
||||
class FunctionPassBase;
|
||||
class ModulePassBase;
|
||||
|
||||
|
@ -62,8 +61,7 @@ FunctionPassBase *createMaterializeVectorsPass();
|
|||
/// all) or the default unroll factor is used (LoopUnroll:kDefaultUnrollFactor).
|
||||
FunctionPassBase *createLoopUnrollPass(
|
||||
int unrollFactor = -1, int unrollFull = -1,
|
||||
const std::function<unsigned(OpPointer<AffineForOp>)> &getUnrollFactor =
|
||||
nullptr);
|
||||
const std::function<unsigned(AffineForOp)> &getUnrollFactor = nullptr);
|
||||
|
||||
/// Creates a loop unroll jam pass to unroll jam by the specified factor. A
|
||||
/// factor of -1 lets the pass use the default factor or the one on the command
|
||||
|
|
|
@ -116,8 +116,8 @@ Instruction *createComposedAffineApplyOp(FuncBuilder *builder, Location loc,
|
|||
/// all the affine.apply op's supplying operands to this opInst did not have any
|
||||
/// uses other than those in this opInst. The method otherwise returns the list
|
||||
/// of affine.apply operations created in output argument `sliceOps`.
|
||||
void createAffineComputationSlice(
|
||||
Instruction *opInst, SmallVectorImpl<OpPointer<AffineApplyOp>> *sliceOps);
|
||||
void createAffineComputationSlice(Instruction *opInst,
|
||||
SmallVectorImpl<AffineApplyOp> *sliceOps);
|
||||
|
||||
/// Replaces (potentially nested) function attributes in the operation "op"
|
||||
/// with those specified in "remappingTable".
|
||||
|
|
|
@ -485,7 +485,7 @@ AffineApplyNormalizer::AffineApplyNormalizer(AffineMap map,
|
|||
auto *t = operands[i];
|
||||
auto affineApply = t->getDefiningInst()
|
||||
? t->getDefiningInst()->dyn_cast<AffineApplyOp>()
|
||||
: OpPointer<AffineApplyOp>();
|
||||
: AffineApplyOp();
|
||||
if (affineApply) {
|
||||
// a. Compose affine.apply instructions.
|
||||
LLVM_DEBUG(affineApply->getInstruction()->print(
|
||||
|
@ -567,9 +567,9 @@ void mlir::fullyComposeAffineMapAndOperands(
|
|||
}
|
||||
}
|
||||
|
||||
OpPointer<AffineApplyOp>
|
||||
mlir::makeComposedAffineApply(FuncBuilder *b, Location loc, AffineMap map,
|
||||
ArrayRef<Value *> operands) {
|
||||
AffineApplyOp mlir::makeComposedAffineApply(FuncBuilder *b, Location loc,
|
||||
AffineMap map,
|
||||
ArrayRef<Value *> operands) {
|
||||
AffineMap normalizedMap = map;
|
||||
SmallVector<Value *, 8> normalizedOperands(operands.begin(), operands.end());
|
||||
composeAffineMapAndOperands(&normalizedMap, &normalizedOperands);
|
||||
|
@ -1070,15 +1070,14 @@ Block *AffineForOp::createBody() {
|
|||
|
||||
AffineBound AffineForOp::getLowerBound() {
|
||||
auto lbMap = getLowerBoundMap();
|
||||
return AffineBound(OpPointer<AffineForOp>(*this), 0, lbMap.getNumInputs(),
|
||||
lbMap);
|
||||
return AffineBound(AffineForOp(*this), 0, lbMap.getNumInputs(), lbMap);
|
||||
}
|
||||
|
||||
AffineBound AffineForOp::getUpperBound() {
|
||||
auto lbMap = getLowerBoundMap();
|
||||
auto ubMap = getUpperBoundMap();
|
||||
return AffineBound(OpPointer<AffineForOp>(*this), lbMap.getNumInputs(),
|
||||
getNumOperands(), ubMap);
|
||||
return AffineBound(AffineForOp(*this), lbMap.getNumInputs(), getNumOperands(),
|
||||
ubMap);
|
||||
}
|
||||
|
||||
void AffineForOp::setLowerBound(ArrayRef<Value *> lbOperands, AffineMap map) {
|
||||
|
@ -1178,24 +1177,24 @@ Value *AffineForOp::getInductionVar() { return getBody()->getArgument(0); }
|
|||
|
||||
/// Returns if the provided value is the induction variable of a AffineForOp.
|
||||
bool mlir::isForInductionVar(Value *val) {
|
||||
return getForInductionVarOwner(val) != nullptr;
|
||||
return getForInductionVarOwner(val) != AffineForOp();
|
||||
}
|
||||
|
||||
/// Returns the loop parent of an induction variable. If the provided value is
|
||||
/// not an induction variable, then return nullptr.
|
||||
OpPointer<AffineForOp> mlir::getForInductionVarOwner(Value *val) {
|
||||
AffineForOp mlir::getForInductionVarOwner(Value *val) {
|
||||
auto *ivArg = dyn_cast<BlockArgument>(val);
|
||||
if (!ivArg || !ivArg->getOwner())
|
||||
return OpPointer<AffineForOp>();
|
||||
return AffineForOp();
|
||||
auto *containingInst = ivArg->getOwner()->getParent()->getContainingInst();
|
||||
if (!containingInst)
|
||||
return OpPointer<AffineForOp>();
|
||||
return AffineForOp();
|
||||
return containingInst->dyn_cast<AffineForOp>();
|
||||
}
|
||||
|
||||
/// Extracts the induction variables from a list of AffineForOps and returns
|
||||
/// them.
|
||||
void mlir::extractForInductionVars(ArrayRef<OpPointer<AffineForOp>> forInsts,
|
||||
void mlir::extractForInductionVars(ArrayRef<AffineForOp> forInsts,
|
||||
SmallVectorImpl<Value *> *ivs) {
|
||||
ivs->reserve(forInsts.size());
|
||||
for (auto forInst : forInsts)
|
||||
|
|
|
@ -98,7 +98,7 @@ void mlir::getReachableAffineApplyOps(
|
|||
// stride information in FlatAffineConstraints. (For eg., by using iv - lb %
|
||||
// step = 0 and/or by introducing a method in FlatAffineConstraints
|
||||
// setExprStride(ArrayRef<int64_t> expr, int64_t stride)
|
||||
LogicalResult mlir::getIndexSet(MutableArrayRef<OpPointer<AffineForOp>> forOps,
|
||||
LogicalResult mlir::getIndexSet(MutableArrayRef<AffineForOp> forOps,
|
||||
FlatAffineConstraints *domain) {
|
||||
SmallVector<Value *, 4> indices;
|
||||
extractForInductionVars(forOps, &indices);
|
||||
|
@ -122,7 +122,7 @@ static LogicalResult getInstIndexSet(Instruction *inst,
|
|||
FlatAffineConstraints *indexSet) {
|
||||
// TODO(andydavis) Extend this to gather enclosing IfInsts and consider
|
||||
// factoring it out into a utility function.
|
||||
SmallVector<OpPointer<AffineForOp>, 4> loops;
|
||||
SmallVector<AffineForOp, 4> loops;
|
||||
getLoopIVs(*inst, &loops);
|
||||
return getIndexSet(loops, indexSet);
|
||||
}
|
||||
|
@ -461,7 +461,7 @@ addMemRefAccessConstraints(const AffineValueMap &srcAccessMap,
|
|||
if (auto *opInst = symbol->getDefiningInst()) {
|
||||
if (auto constOp = opInst->dyn_cast<ConstantIndexOp>()) {
|
||||
dependenceDomain->setIdToConstant(valuePosMap.getSymPos(symbol),
|
||||
constOp->getValue());
|
||||
constOp.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -217,7 +217,7 @@ AffineValueMap::AffineValueMap(AffineMap map, ArrayRef<Value *> operands,
|
|||
: map(map), operands(operands.begin(), operands.end()),
|
||||
results(results.begin(), results.end()) {}
|
||||
|
||||
AffineValueMap::AffineValueMap(OpPointer<AffineApplyOp> applyOp)
|
||||
AffineValueMap::AffineValueMap(AffineApplyOp applyOp)
|
||||
: map(applyOp->getAffineMap()),
|
||||
operands(applyOp->operand_begin(), applyOp->operand_end()) {
|
||||
results.push_back(applyOp->getResult());
|
||||
|
@ -729,13 +729,12 @@ void FlatAffineConstraints::addInductionVarOrTerminalSymbol(Value *id) {
|
|||
// Check if the symbol is a constant.
|
||||
if (auto *opInst = id->getDefiningInst()) {
|
||||
if (auto constOp = opInst->dyn_cast<ConstantIndexOp>()) {
|
||||
setIdToConstant(*id, constOp->getValue());
|
||||
setIdToConstant(*id, constOp.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogicalResult
|
||||
FlatAffineConstraints::addAffineForOpDomain(OpPointer<AffineForOp> forOp) {
|
||||
LogicalResult FlatAffineConstraints::addAffineForOpDomain(AffineForOp forOp) {
|
||||
unsigned pos;
|
||||
// Pre-condition for this method.
|
||||
if (!findId(*forOp->getInductionVar(), &pos)) {
|
||||
|
@ -772,10 +771,8 @@ FlatAffineConstraints::addAffineForOpDomain(OpPointer<AffineForOp> forOp) {
|
|||
addConstantLowerBound(pos, forOp->getConstantLowerBound());
|
||||
} else {
|
||||
// Non-constant lower bound case.
|
||||
OpPointer<AffineForOp> ncForOp =
|
||||
*reinterpret_cast<OpPointer<AffineForOp> *>(&forOp);
|
||||
SmallVector<Value *, 4> lbOperands(ncForOp->getLowerBoundOperands().begin(),
|
||||
ncForOp->getLowerBoundOperands().end());
|
||||
SmallVector<Value *, 4> lbOperands(forOp->getLowerBoundOperands().begin(),
|
||||
forOp->getLowerBoundOperands().end());
|
||||
if (failed(addLowerOrUpperBound(pos, forOp->getLowerBoundMap(), lbOperands,
|
||||
/*eq=*/false, /*lower=*/true)))
|
||||
return failure();
|
||||
|
@ -786,10 +783,8 @@ FlatAffineConstraints::addAffineForOpDomain(OpPointer<AffineForOp> forOp) {
|
|||
return success();
|
||||
}
|
||||
// Non-constant upper bound case.
|
||||
OpPointer<AffineForOp> ncForOp =
|
||||
*reinterpret_cast<OpPointer<AffineForOp> *>(&forOp);
|
||||
SmallVector<Value *, 4> ubOperands(ncForOp->getUpperBoundOperands().begin(),
|
||||
ncForOp->getUpperBoundOperands().end());
|
||||
SmallVector<Value *, 4> ubOperands(forOp->getUpperBoundOperands().begin(),
|
||||
forOp->getUpperBoundOperands().end());
|
||||
return addLowerOrUpperBound(pos, forOp->getUpperBoundMap(), ubOperands,
|
||||
/*eq=*/false, /*lower=*/false);
|
||||
}
|
||||
|
|
|
@ -49,16 +49,12 @@ using namespace mlir;
|
|||
// pure analysis method relying on FlatAffineConstraints; the latter will also
|
||||
// be more powerful (since both inequalities and equalities will be considered).
|
||||
void mlir::buildTripCountMapAndOperands(
|
||||
OpPointer<AffineForOp> forOp, AffineMap *map,
|
||||
AffineForOp forOp, AffineMap *map,
|
||||
SmallVectorImpl<Value *> *tripCountOperands) {
|
||||
int64_t loopSpan;
|
||||
|
||||
int64_t step = forOp->getStep();
|
||||
|
||||
// We need to get operands; we aren't changing them here.
|
||||
auto ncForOp = *reinterpret_cast<OpPointer<AffineForOp> *>(&forOp);
|
||||
|
||||
FuncBuilder b(ncForOp->getInstruction());
|
||||
FuncBuilder b(forOp->getInstruction());
|
||||
|
||||
if (forOp->hasConstantBounds()) {
|
||||
int64_t lb = forOp->getConstantLowerBound();
|
||||
|
@ -76,8 +72,8 @@ void mlir::buildTripCountMapAndOperands(
|
|||
*map = AffineMap();
|
||||
return;
|
||||
}
|
||||
SmallVector<Value *, 4> lbOperands(ncForOp->getLowerBoundOperands());
|
||||
SmallVector<Value *, 4> ubOperands(ncForOp->getUpperBoundOperands());
|
||||
SmallVector<Value *, 4> lbOperands(forOp->getLowerBoundOperands());
|
||||
SmallVector<Value *, 4> ubOperands(forOp->getUpperBoundOperands());
|
||||
auto lb = b.create<AffineApplyOp>(forOp->getLoc(), lbMap, lbOperands);
|
||||
SmallVector<Value *, 4> ubs;
|
||||
ubs.reserve(ubMap.getNumResults());
|
||||
|
@ -117,8 +113,7 @@ void mlir::buildTripCountMapAndOperands(
|
|||
// being an analysis utility, it shouldn't. Replace with a version that just
|
||||
// works with analysis structures (FlatAffineConstraints) and thus doesn't
|
||||
// update the IR.
|
||||
llvm::Optional<uint64_t>
|
||||
mlir::getConstantTripCount(OpPointer<AffineForOp> forOp) {
|
||||
llvm::Optional<uint64_t> mlir::getConstantTripCount(AffineForOp forOp) {
|
||||
SmallVector<Value *, 4> operands;
|
||||
AffineMap map;
|
||||
buildTripCountMapAndOperands(forOp, &map, &operands);
|
||||
|
@ -144,7 +139,7 @@ mlir::getConstantTripCount(OpPointer<AffineForOp> forOp) {
|
|||
/// Returns the greatest known integral divisor of the trip count. Affine
|
||||
/// expression analysis is used (indirectly through getTripCount), and
|
||||
/// this method is thus able to determine non-trivial divisors.
|
||||
uint64_t mlir::getLargestDivisorOfTripCount(OpPointer<AffineForOp> forOp) {
|
||||
uint64_t mlir::getLargestDivisorOfTripCount(AffineForOp forOp) {
|
||||
SmallVector<Value *, 4> operands;
|
||||
AffineMap map;
|
||||
buildTripCountMapAndOperands(forOp, &map, &operands);
|
||||
|
@ -235,7 +230,7 @@ mlir::getInvariantAccesses(Value &iv, llvm::ArrayRef<Value *> indices) {
|
|||
///
|
||||
// TODO(ntv): check strides.
|
||||
template <typename LoadOrStoreOp>
|
||||
static bool isContiguousAccess(Value &iv, OpPointer<LoadOrStoreOp> memoryOp,
|
||||
static bool isContiguousAccess(Value &iv, LoadOrStoreOp memoryOp,
|
||||
unsigned fastestVaryingDim) {
|
||||
static_assert(std::is_same<LoadOrStoreOp, LoadOp>::value ||
|
||||
std::is_same<LoadOrStoreOp, StoreOp>::value,
|
||||
|
@ -281,10 +276,9 @@ static bool isVectorTransferReadOrWrite(Instruction &inst) {
|
|||
return inst.isa<VectorTransferReadOp>() || inst.isa<VectorTransferWriteOp>();
|
||||
}
|
||||
|
||||
using VectorizableInstFun =
|
||||
std::function<bool(OpPointer<AffineForOp>, Instruction &)>;
|
||||
using VectorizableInstFun = std::function<bool(AffineForOp, Instruction &)>;
|
||||
|
||||
static bool isVectorizableLoopWithCond(OpPointer<AffineForOp> loop,
|
||||
static bool isVectorizableLoopWithCond(AffineForOp loop,
|
||||
VectorizableInstFun isVectorizableInst) {
|
||||
auto *forInst = const_cast<Instruction *>(loop->getInstruction());
|
||||
if (!matcher::isParallelLoop(*forInst) &&
|
||||
|
@ -340,9 +334,9 @@ static bool isVectorizableLoopWithCond(OpPointer<AffineForOp> loop,
|
|||
}
|
||||
|
||||
bool mlir::isVectorizableLoopAlongFastestVaryingMemRefDim(
|
||||
OpPointer<AffineForOp> loop, unsigned fastestVaryingDim) {
|
||||
AffineForOp loop, unsigned fastestVaryingDim) {
|
||||
VectorizableInstFun fun(
|
||||
[fastestVaryingDim](OpPointer<AffineForOp> loop, Instruction &op) {
|
||||
[fastestVaryingDim](AffineForOp loop, Instruction &op) {
|
||||
auto load = op.dyn_cast<LoadOp>();
|
||||
auto store = op.dyn_cast<StoreOp>();
|
||||
return load ? isContiguousAccess(*loop->getInductionVar(), load,
|
||||
|
@ -353,10 +347,10 @@ bool mlir::isVectorizableLoopAlongFastestVaryingMemRefDim(
|
|||
return isVectorizableLoopWithCond(loop, fun);
|
||||
}
|
||||
|
||||
bool mlir::isVectorizableLoop(OpPointer<AffineForOp> loop) {
|
||||
bool mlir::isVectorizableLoop(AffineForOp loop) {
|
||||
VectorizableInstFun fun(
|
||||
// TODO: implement me
|
||||
[](OpPointer<AffineForOp> loop, Instruction &op) { return true; });
|
||||
[](AffineForOp loop, Instruction &op) { return true; });
|
||||
return isVectorizableLoopWithCond(loop, fun);
|
||||
}
|
||||
|
||||
|
@ -365,8 +359,7 @@ bool mlir::isVectorizableLoop(OpPointer<AffineForOp> loop) {
|
|||
/// 'def' and all its uses have the same shift factor.
|
||||
// TODO(mlir-team): extend this to check for memory-based dependence
|
||||
// violation when we have the support.
|
||||
bool mlir::isInstwiseShiftValid(OpPointer<AffineForOp> forOp,
|
||||
ArrayRef<uint64_t> shifts) {
|
||||
bool mlir::isInstwiseShiftValid(AffineForOp forOp, ArrayRef<uint64_t> shifts) {
|
||||
auto *forBody = forOp->getBody();
|
||||
assert(shifts.size() == forBody->getInstructions().size());
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ FunctionPassBase *mlir::createParallelismDetectionTestPass() {
|
|||
void TestParallelismDetection::runOnFunction() {
|
||||
Function *f = getFunction();
|
||||
FuncBuilder b(f);
|
||||
f->walk<AffineForOp>([&](OpPointer<AffineForOp> forOp) {
|
||||
f->walk<AffineForOp>([&](AffineForOp forOp) {
|
||||
if (isLoopParallel(forOp))
|
||||
forOp->emitNote("parallel loop");
|
||||
});
|
||||
|
|
|
@ -39,10 +39,9 @@ using llvm::SmallDenseMap;
|
|||
|
||||
/// Populates 'loops' with IVs of the loops surrounding 'inst' ordered from
|
||||
/// the outermost 'for' instruction to the innermost one.
|
||||
void mlir::getLoopIVs(Instruction &inst,
|
||||
SmallVectorImpl<OpPointer<AffineForOp>> *loops) {
|
||||
void mlir::getLoopIVs(Instruction &inst, SmallVectorImpl<AffineForOp> *loops) {
|
||||
auto *currInst = inst.getParentInst();
|
||||
OpPointer<AffineForOp> currAffineForOp;
|
||||
AffineForOp currAffineForOp;
|
||||
// Traverse up the hierarchy collecing all 'for' instruction while
|
||||
// skipping over 'if' instructions.
|
||||
while (currInst && ((currAffineForOp = currInst->dyn_cast<AffineForOp>()) ||
|
||||
|
@ -76,7 +75,7 @@ ComputationSliceState::getAsConstraints(FlatAffineConstraints *cst) {
|
|||
// Check if the symbol is a constant.
|
||||
if (auto *inst = value->getDefiningInst()) {
|
||||
if (auto constOp = inst->dyn_cast<ConstantIndexOp>()) {
|
||||
cst->setIdToConstant(*value, constOp->getValue());
|
||||
cst->setIdToConstant(*value, constOp.getValue());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -189,7 +188,7 @@ LogicalResult MemRefRegion::compute(Instruction *inst, unsigned loopDepth,
|
|||
<< "depth: " << loopDepth << "\n";);
|
||||
|
||||
if (rank == 0) {
|
||||
SmallVector<OpPointer<AffineForOp>, 4> ivs;
|
||||
SmallVector<AffineForOp, 4> ivs;
|
||||
getLoopIVs(*inst, &ivs);
|
||||
SmallVector<Value *, 8> regionSymbols;
|
||||
extractForInductionVars(ivs, ®ionSymbols);
|
||||
|
@ -245,7 +244,7 @@ LogicalResult MemRefRegion::compute(Instruction *inst, unsigned loopDepth,
|
|||
// Check if the symbol is a constant.
|
||||
if (auto *inst = symbol->getDefiningInst()) {
|
||||
if (auto constOp = inst->dyn_cast<ConstantIndexOp>()) {
|
||||
cst.setIdToConstant(*symbol, constOp->getValue());
|
||||
cst.setIdToConstant(*symbol, constOp.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,14 +279,14 @@ LogicalResult MemRefRegion::compute(Instruction *inst, unsigned loopDepth,
|
|||
|
||||
// Eliminate any loop IVs other than the outermost 'loopDepth' IVs, on which
|
||||
// this memref region is symbolic.
|
||||
SmallVector<OpPointer<AffineForOp>, 4> enclosingIVs;
|
||||
SmallVector<AffineForOp, 4> enclosingIVs;
|
||||
getLoopIVs(*inst, &enclosingIVs);
|
||||
assert(loopDepth <= enclosingIVs.size() && "invalid loop depth");
|
||||
enclosingIVs.resize(loopDepth);
|
||||
SmallVector<Value *, 4> ids;
|
||||
cst.getIdValues(cst.getNumDimIds(), cst.getNumDimAndSymbolIds(), &ids);
|
||||
for (auto *id : ids) {
|
||||
OpPointer<AffineForOp> iv;
|
||||
AffineForOp iv;
|
||||
if ((iv = getForInductionVarOwner(id)) &&
|
||||
llvm::is_contained(enclosingIVs, iv) == false) {
|
||||
cst.projectOut(id);
|
||||
|
@ -371,10 +370,9 @@ Optional<uint64_t> mlir::getMemRefSizeInBytes(MemRefType memRefType) {
|
|||
template <typename LoadOrStoreOpPointer>
|
||||
LogicalResult mlir::boundCheckLoadOrStoreOp(LoadOrStoreOpPointer loadOrStoreOp,
|
||||
bool emitError) {
|
||||
static_assert(
|
||||
std::is_same<LoadOrStoreOpPointer, OpPointer<LoadOp>>::value ||
|
||||
std::is_same<LoadOrStoreOpPointer, OpPointer<StoreOp>>::value,
|
||||
"argument should be either a LoadOp or a StoreOp");
|
||||
static_assert(std::is_same<LoadOrStoreOpPointer, LoadOp>::value ||
|
||||
std::is_same<LoadOrStoreOpPointer, StoreOp>::value,
|
||||
"argument should be either a LoadOp or a StoreOp");
|
||||
|
||||
Instruction *opInst = loadOrStoreOp->getInstruction();
|
||||
|
||||
|
@ -424,9 +422,9 @@ LogicalResult mlir::boundCheckLoadOrStoreOp(LoadOrStoreOpPointer loadOrStoreOp,
|
|||
}
|
||||
|
||||
// Explicitly instantiate the template so that the compiler knows we need them!
|
||||
template LogicalResult mlir::boundCheckLoadOrStoreOp(OpPointer<LoadOp> loadOp,
|
||||
template LogicalResult mlir::boundCheckLoadOrStoreOp(LoadOp loadOp,
|
||||
bool emitError);
|
||||
template LogicalResult mlir::boundCheckLoadOrStoreOp(OpPointer<StoreOp> storeOp,
|
||||
template LogicalResult mlir::boundCheckLoadOrStoreOp(StoreOp storeOp,
|
||||
bool emitError);
|
||||
|
||||
// Returns in 'positions' the Block positions of 'inst' in each ancestor
|
||||
|
@ -490,12 +488,12 @@ LogicalResult mlir::getBackwardComputationSliceState(
|
|||
return failure();
|
||||
}
|
||||
// Get loop nest surrounding src operation.
|
||||
SmallVector<OpPointer<AffineForOp>, 4> srcLoopIVs;
|
||||
SmallVector<AffineForOp, 4> srcLoopIVs;
|
||||
getLoopIVs(*srcAccess.opInst, &srcLoopIVs);
|
||||
unsigned numSrcLoopIVs = srcLoopIVs.size();
|
||||
|
||||
// Get loop nest surrounding dst operation.
|
||||
SmallVector<OpPointer<AffineForOp>, 4> dstLoopIVs;
|
||||
SmallVector<AffineForOp, 4> dstLoopIVs;
|
||||
getLoopIVs(*dstAccess.opInst, &dstLoopIVs);
|
||||
unsigned numDstLoopIVs = dstLoopIVs.size();
|
||||
if (dstLoopDepth > numDstLoopIVs) {
|
||||
|
@ -566,21 +564,21 @@ LogicalResult mlir::getBackwardComputationSliceState(
|
|||
// entire destination index set. Subtract out the dependent destination
|
||||
// iterations from destination index set and check for emptiness --- this is one
|
||||
// solution.
|
||||
OpPointer<AffineForOp> mlir::insertBackwardComputationSlice(
|
||||
AffineForOp mlir::insertBackwardComputationSlice(
|
||||
Instruction *srcOpInst, Instruction *dstOpInst, unsigned dstLoopDepth,
|
||||
ComputationSliceState *sliceState) {
|
||||
// Get loop nest surrounding src operation.
|
||||
SmallVector<OpPointer<AffineForOp>, 4> srcLoopIVs;
|
||||
SmallVector<AffineForOp, 4> srcLoopIVs;
|
||||
getLoopIVs(*srcOpInst, &srcLoopIVs);
|
||||
unsigned numSrcLoopIVs = srcLoopIVs.size();
|
||||
|
||||
// Get loop nest surrounding dst operation.
|
||||
SmallVector<OpPointer<AffineForOp>, 4> dstLoopIVs;
|
||||
SmallVector<AffineForOp, 4> dstLoopIVs;
|
||||
getLoopIVs(*dstOpInst, &dstLoopIVs);
|
||||
unsigned dstLoopIVsSize = dstLoopIVs.size();
|
||||
if (dstLoopDepth > dstLoopIVsSize) {
|
||||
dstOpInst->emitError("invalid destination loop depth");
|
||||
return OpPointer<AffineForOp>();
|
||||
return AffineForOp();
|
||||
}
|
||||
|
||||
// Find the inst block positions of 'srcOpInst' within 'srcLoopIVs'.
|
||||
|
@ -599,7 +597,7 @@ OpPointer<AffineForOp> mlir::insertBackwardComputationSlice(
|
|||
Instruction *sliceInst =
|
||||
getInstAtPosition(positions, /*level=*/0, sliceLoopNest->getBody());
|
||||
// Get loop nest surrounding 'sliceInst'.
|
||||
SmallVector<OpPointer<AffineForOp>, 4> sliceSurroundingLoops;
|
||||
SmallVector<AffineForOp, 4> sliceSurroundingLoops;
|
||||
getLoopIVs(*sliceInst, &sliceSurroundingLoops);
|
||||
|
||||
// Sanity check.
|
||||
|
@ -666,7 +664,7 @@ unsigned mlir::getNestingDepth(Instruction &inst) {
|
|||
/// Returns the number of surrounding loops common to 'loopsA' and 'loopsB',
|
||||
/// where each lists loops from outer-most to inner-most in loop nest.
|
||||
unsigned mlir::getNumCommonSurroundingLoops(Instruction &A, Instruction &B) {
|
||||
SmallVector<OpPointer<AffineForOp>, 4> loopsA, loopsB;
|
||||
SmallVector<AffineForOp, 4> loopsA, loopsB;
|
||||
getLoopIVs(A, &loopsA);
|
||||
getLoopIVs(B, &loopsB);
|
||||
|
||||
|
@ -728,7 +726,7 @@ static Optional<int64_t> getMemoryFootprintBytes(Block &block,
|
|||
return totalSizeInBytes;
|
||||
}
|
||||
|
||||
Optional<int64_t> mlir::getMemoryFootprintBytes(OpPointer<AffineForOp> forOp,
|
||||
Optional<int64_t> mlir::getMemoryFootprintBytes(AffineForOp forOp,
|
||||
int memorySpace) {
|
||||
auto *forInst = forOp->getInstruction();
|
||||
return ::getMemoryFootprintBytes(
|
||||
|
@ -739,8 +737,7 @@ Optional<int64_t> mlir::getMemoryFootprintBytes(OpPointer<AffineForOp> forOp,
|
|||
/// Returns in 'sequentialLoops' all sequential loops in loop nest rooted
|
||||
/// at 'forOp'.
|
||||
void mlir::getSequentialLoops(
|
||||
OpPointer<AffineForOp> forOp,
|
||||
llvm::SmallDenseSet<Value *, 8> *sequentialLoops) {
|
||||
AffineForOp forOp, llvm::SmallDenseSet<Value *, 8> *sequentialLoops) {
|
||||
forOp->getInstruction()->walk([&](Instruction *inst) {
|
||||
if (auto innerFor = inst->dyn_cast<AffineForOp>())
|
||||
if (!isLoopParallel(innerFor))
|
||||
|
@ -749,7 +746,7 @@ void mlir::getSequentialLoops(
|
|||
}
|
||||
|
||||
/// Returns true if 'forOp' is parallel.
|
||||
bool mlir::isLoopParallel(OpPointer<AffineForOp> forOp) {
|
||||
bool mlir::isLoopParallel(AffineForOp forOp) {
|
||||
// Collect all load and store ops in loop nest rooted at 'forOp'.
|
||||
SmallVector<Instruction *, 8> loadAndStoreOpInsts;
|
||||
forOp->getInstruction()->walk([&](Instruction *opInst) {
|
||||
|
|
|
@ -155,8 +155,8 @@ static llvm::Optional<ValueHandle> emitStaticFor(ArrayRef<ValueHandle> lbs,
|
|||
if (!lbConst || !ubConst)
|
||||
return llvm::Optional<ValueHandle>();
|
||||
|
||||
return ValueHandle::create<AffineForOp>(lbConst->getValue(),
|
||||
ubConst->getValue(), step);
|
||||
return ValueHandle::create<AffineForOp>(lbConst.getValue(),
|
||||
ubConst.getValue(), step);
|
||||
}
|
||||
|
||||
mlir::edsc::LoopBuilder::LoopBuilder(ValueHandle *iv,
|
||||
|
@ -268,10 +268,9 @@ categorizeValueByAffineType(MLIRContext *context, Value *val, unsigned &numDims,
|
|||
AffineExpr d;
|
||||
Value *resultVal = nullptr;
|
||||
auto *inst = val->getDefiningInst();
|
||||
auto constant =
|
||||
inst ? inst->dyn_cast<ConstantIndexOp>() : OpPointer<ConstantIndexOp>();
|
||||
auto constant = inst ? inst->dyn_cast<ConstantIndexOp>() : ConstantIndexOp();
|
||||
if (constant) {
|
||||
d = getAffineConstantExpr(constant->getValue(), context);
|
||||
d = getAffineConstantExpr(constant.getValue(), context);
|
||||
} else if (isValidSymbol(val) && !isValidDim(val)) {
|
||||
d = getAffineSymbolExpr(numSymbols++, context);
|
||||
resultVal = val;
|
||||
|
|
|
@ -94,25 +94,24 @@ static void checkAffineProvenance(ArrayRef<Value *> values) {
|
|||
}
|
||||
}
|
||||
|
||||
static OpPointer<AffineForOp> emitStaticFor(FuncBuilder &builder, Location loc,
|
||||
ArrayRef<Value *> lbs,
|
||||
ArrayRef<Value *> ubs,
|
||||
uint64_t step) {
|
||||
static AffineForOp emitStaticFor(FuncBuilder &builder, Location loc,
|
||||
ArrayRef<Value *> lbs, ArrayRef<Value *> ubs,
|
||||
uint64_t step) {
|
||||
if (lbs.size() != 1 || ubs.size() != 1)
|
||||
return OpPointer<AffineForOp>();
|
||||
return AffineForOp();
|
||||
|
||||
auto *lbDef = lbs.front()->getDefiningInst();
|
||||
auto *ubDef = ubs.front()->getDefiningInst();
|
||||
if (!lbDef || !ubDef)
|
||||
return OpPointer<AffineForOp>();
|
||||
return AffineForOp();
|
||||
|
||||
auto lbConst = lbDef->dyn_cast<ConstantIndexOp>();
|
||||
auto ubConst = ubDef->dyn_cast<ConstantIndexOp>();
|
||||
if (!lbConst || !ubConst)
|
||||
return OpPointer<AffineForOp>();
|
||||
return AffineForOp();
|
||||
|
||||
return builder.create<AffineForOp>(loc, lbConst->getValue(),
|
||||
ubConst->getValue(), step);
|
||||
return builder.create<AffineForOp>(loc, lbConst.getValue(),
|
||||
ubConst.getValue(), step);
|
||||
}
|
||||
|
||||
Value *mlir::edsc::MLIREmitter::emitExpr(Expr e) {
|
||||
|
@ -166,11 +165,10 @@ Value *mlir::edsc::MLIREmitter::emitExpr(Expr e) {
|
|||
|
||||
// Step must be a static constant.
|
||||
auto step =
|
||||
stepExpr->getDefiningInst()->cast<ConstantIndexOp>()->getValue();
|
||||
stepExpr->getDefiningInst()->cast<ConstantIndexOp>().getValue();
|
||||
|
||||
// Special case with more concise emitted code for static bounds.
|
||||
OpPointer<AffineForOp> forOp =
|
||||
emitStaticFor(*builder, location, lbs, ubs, step);
|
||||
AffineForOp forOp = emitStaticFor(*builder, location, lbs, ubs, step);
|
||||
|
||||
// General case.
|
||||
if (!forOp)
|
||||
|
@ -387,7 +385,7 @@ mlir::edsc::MLIREmitter::makeBoundMemRefView(Expr boundMemRef) {
|
|||
return makeBoundMemRefView(v);
|
||||
}
|
||||
|
||||
OpPointer<AffineForOp> mlir::edsc::MLIREmitter::getAffineForOp(Expr e) {
|
||||
AffineForOp mlir::edsc::MLIREmitter::getAffineForOp(Expr e) {
|
||||
auto *value = ssaBindings.lookup(e);
|
||||
assert(value && "Expr not bound");
|
||||
return getForInductionVarOwner(value);
|
||||
|
|
|
@ -319,10 +319,10 @@ struct SimplifyAllocConst : public RewritePattern {
|
|||
continue;
|
||||
}
|
||||
auto *defOp = allocOp->getOperand(dynamicDimPos)->getDefiningInst();
|
||||
OpPointer<ConstantIndexOp> constantIndexOp;
|
||||
ConstantIndexOp constantIndexOp;
|
||||
if (defOp && (constantIndexOp = defOp->dyn_cast<ConstantIndexOp>())) {
|
||||
// Dynamic shape dimension will be folded.
|
||||
newShapeConstants.push_back(constantIndexOp->getValue());
|
||||
newShapeConstants.push_back(constantIndexOp.getValue());
|
||||
// Record to check for zero uses later below.
|
||||
droppedOperands.push_back(constantIndexOp);
|
||||
} else {
|
||||
|
|
|
@ -187,7 +187,7 @@ static bool getFullMemRefAsRegion(Instruction *opInst, unsigned numParamLoopIVs,
|
|||
|
||||
// Just get the first numSymbols IVs, which the memref region is parametric
|
||||
// on.
|
||||
SmallVector<OpPointer<AffineForOp>, 4> ivs;
|
||||
SmallVector<AffineForOp, 4> ivs;
|
||||
getLoopIVs(*opInst, &ivs);
|
||||
ivs.resize(numParamLoopIVs);
|
||||
SmallVector<Value *, 4> symbols;
|
||||
|
@ -485,7 +485,7 @@ bool DmaGeneration::runOnBlock(Block *block) {
|
|||
for (auto it = curBegin; it != block->end(); ++it) {
|
||||
if (auto forOp = it->dyn_cast<AffineForOp>()) {
|
||||
// Returns true if the footprint is known to exceed capacity.
|
||||
auto exceedsCapacity = [&](OpPointer<AffineForOp> forOp) {
|
||||
auto exceedsCapacity = [&](AffineForOp forOp) {
|
||||
Optional<int64_t> footprint =
|
||||
getMemoryFootprintBytes(forOp,
|
||||
/*memorySpace=*/0);
|
||||
|
@ -553,7 +553,7 @@ findHighestBlockForPlacement(const MemRefRegion ®ion, Block &block,
|
|||
SmallVector<Value *, 4> symbols;
|
||||
cst->getIdValues(cst->getNumDimIds(), cst->getNumDimAndSymbolIds(), &symbols);
|
||||
|
||||
SmallVector<OpPointer<AffineForOp>, 4> enclosingFors;
|
||||
SmallVector<AffineForOp, 4> enclosingFors;
|
||||
getLoopIVs(*block.begin(), &enclosingFors);
|
||||
// Walk up loop parents till we find an IV on which this region is
|
||||
// symbolic/variant.
|
||||
|
@ -733,7 +733,7 @@ uint64_t DmaGeneration::runOnBlock(Block::iterator begin, Block::iterator end) {
|
|||
|
||||
// For a range of operation instructions, a note will be emitted at the
|
||||
// caller.
|
||||
OpPointer<AffineForOp> forOp;
|
||||
AffineForOp forOp;
|
||||
uint64_t sizeInKib = llvm::divideCeil(totalDmaBuffersSizeInBytes, 1024);
|
||||
if (llvm::DebugFlag && (forOp = begin->dyn_cast<AffineForOp>())) {
|
||||
forOp->emitNote(
|
||||
|
|
|
@ -122,7 +122,7 @@ namespace {
|
|||
// LoopNestStateCollector walks loop nests and collects load and store
|
||||
// operations, and whether or not an IfInst was encountered in the loop nest.
|
||||
struct LoopNestStateCollector {
|
||||
SmallVector<OpPointer<AffineForOp>, 4> forOps;
|
||||
SmallVector<AffineForOp, 4> forOps;
|
||||
SmallVector<Instruction *, 4> loadOpInsts;
|
||||
SmallVector<Instruction *, 4> storeOpInsts;
|
||||
bool hasNonForRegion = false;
|
||||
|
@ -691,7 +691,7 @@ bool MemRefDependenceGraph::init(Function *f) {
|
|||
auto *opInst = node.inst;
|
||||
for (auto *value : opInst->getResults()) {
|
||||
for (auto &use : value->getUses()) {
|
||||
SmallVector<OpPointer<AffineForOp>, 4> loops;
|
||||
SmallVector<AffineForOp, 4> loops;
|
||||
getLoopIVs(*use.getOwner(), &loops);
|
||||
if (loops.empty())
|
||||
continue;
|
||||
|
@ -727,7 +727,7 @@ namespace {
|
|||
// and operation count) for a loop nest up until the innermost loop body.
|
||||
struct LoopNestStats {
|
||||
// Map from AffineForOp to immediate child AffineForOps in its loop body.
|
||||
DenseMap<Instruction *, SmallVector<OpPointer<AffineForOp>, 2>> loopMap;
|
||||
DenseMap<Instruction *, SmallVector<AffineForOp, 2>> loopMap;
|
||||
// Map from AffineForOp to count of operations in its loop body.
|
||||
DenseMap<Instruction *, uint64_t> opCountMap;
|
||||
// Map from AffineForOp to its constant trip count.
|
||||
|
@ -743,7 +743,7 @@ struct LoopNestStatsCollector {
|
|||
LoopNestStatsCollector(LoopNestStats *stats) : stats(stats) {}
|
||||
|
||||
void collect(Instruction *inst) {
|
||||
inst->walk<AffineForOp>([&](OpPointer<AffineForOp> forOp) {
|
||||
inst->walk<AffineForOp>([&](AffineForOp forOp) {
|
||||
auto *forInst = forOp->getInstruction();
|
||||
auto *parentInst = forOp->getInstruction()->getParentInst();
|
||||
if (parentInst != nullptr) {
|
||||
|
@ -844,7 +844,7 @@ static Optional<uint64_t> getConstDifference(AffineMap lbMap, AffineMap ubMap) {
|
|||
static bool buildSliceTripCountMap(
|
||||
Instruction *srcOpInst, ComputationSliceState *sliceState,
|
||||
llvm::SmallDenseMap<Instruction *, uint64_t, 8> *tripCountMap) {
|
||||
SmallVector<OpPointer<AffineForOp>, 4> srcLoopIVs;
|
||||
SmallVector<AffineForOp, 4> srcLoopIVs;
|
||||
getLoopIVs(*srcOpInst, &srcLoopIVs);
|
||||
unsigned numSrcLoopIVs = srcLoopIVs.size();
|
||||
// Populate map from AffineForOp -> trip count
|
||||
|
@ -892,7 +892,7 @@ static unsigned getInnermostCommonLoopDepth(ArrayRef<Instruction *> ops) {
|
|||
unsigned numOps = ops.size();
|
||||
assert(numOps > 0);
|
||||
|
||||
std::vector<SmallVector<OpPointer<AffineForOp>, 4>> loops(numOps);
|
||||
std::vector<SmallVector<AffineForOp, 4>> loops(numOps);
|
||||
unsigned loopDepthLimit = std::numeric_limits<unsigned>::max();
|
||||
for (unsigned i = 0; i < numOps; ++i) {
|
||||
getLoopIVs(*ops[i], &loops[i]);
|
||||
|
@ -1056,8 +1056,8 @@ static void sinkSequentialLoops(MemRefDependenceGraph::Node *node) {
|
|||
assert(node->inst->isa<AffineForOp>());
|
||||
// Get perfectly nested sequence of loops starting at root of loop nest.
|
||||
// TODO(andydavis,bondhugula) Share this with similar code in loop tiling.
|
||||
SmallVector<OpPointer<AffineForOp>, 4> loops;
|
||||
OpPointer<AffineForOp> curr = node->inst->cast<AffineForOp>();
|
||||
SmallVector<AffineForOp, 4> loops;
|
||||
AffineForOp curr = node->inst->cast<AffineForOp>();
|
||||
loops.push_back(curr);
|
||||
auto *currBody = curr->getBody();
|
||||
while (!currBody->empty() &&
|
||||
|
@ -1113,7 +1113,7 @@ unsigned getMemRefEltSizeInBytes(MemRefType memRefType) {
|
|||
// MemRefRegion written to by 'srcStoreOpInst' at depth 'dstLoopDepth'.
|
||||
// TODO(bondhugula): consider refactoring the common code from generateDma and
|
||||
// this one.
|
||||
static Value *createPrivateMemRef(OpPointer<AffineForOp> forOp,
|
||||
static Value *createPrivateMemRef(AffineForOp forOp,
|
||||
Instruction *srcStoreOpInst,
|
||||
unsigned dstLoopDepth,
|
||||
Optional<unsigned> fastMemorySpace,
|
||||
|
@ -1429,7 +1429,7 @@ static bool isFusionProfitable(Instruction *srcOpInst,
|
|||
});
|
||||
|
||||
// Compute cost of sliced and unsliced src loop nest.
|
||||
SmallVector<OpPointer<AffineForOp>, 4> srcLoopIVs;
|
||||
SmallVector<AffineForOp, 4> srcLoopIVs;
|
||||
getLoopIVs(*srcOpInst, &srcLoopIVs);
|
||||
unsigned numSrcLoopIVs = srcLoopIVs.size();
|
||||
|
||||
|
@ -1443,7 +1443,7 @@ static bool isFusionProfitable(Instruction *srcOpInst,
|
|||
return false;
|
||||
}
|
||||
// Compute cost of dst loop nest.
|
||||
SmallVector<OpPointer<AffineForOp>, 4> dstLoopIVs;
|
||||
SmallVector<AffineForOp, 4> dstLoopIVs;
|
||||
getLoopIVs(*dstLoadOpInsts[0], &dstLoopIVs);
|
||||
|
||||
LoopNestStats dstLoopNestStats;
|
||||
|
@ -1933,7 +1933,7 @@ public:
|
|||
// Fuse computation slice of 'srcLoopNest' into 'dstLoopNest'.
|
||||
auto sliceLoopNest = mlir::insertBackwardComputationSlice(
|
||||
srcStoreOpInst, dstLoadOpInsts[0], bestDstLoopDepth, &sliceState);
|
||||
if (sliceLoopNest != nullptr) {
|
||||
if (sliceLoopNest) {
|
||||
LLVM_DEBUG(llvm::dbgs()
|
||||
<< "\tslice loop nest:\n"
|
||||
<< *sliceLoopNest->getInstruction() << "\n");
|
||||
|
@ -2182,8 +2182,8 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
void updateStateAfterSiblingFusion(OpPointer<AffineForOp> sliceLoopNest,
|
||||
Node *sibNode, Node *dstNode) {
|
||||
void updateStateAfterSiblingFusion(AffineForOp sliceLoopNest, Node *sibNode,
|
||||
Node *dstNode) {
|
||||
// Update 'sibNode' and 'dstNode' input/output edges to reflect fusion.
|
||||
mdg->updateEdges(sibNode->id, dstNode->id);
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ struct LoopTiling : public FunctionPass<LoopTiling> {
|
|||
: cacheSizeBytes(cacheSizeBytes), avoidMaxMinBounds(avoidMaxMinBounds) {}
|
||||
|
||||
void runOnFunction() override;
|
||||
void getTileSizes(ArrayRef<OpPointer<AffineForOp>> band,
|
||||
void getTileSizes(ArrayRef<AffineForOp> band,
|
||||
SmallVectorImpl<unsigned> *tileSizes);
|
||||
|
||||
// Default tile size if nothing is provided.
|
||||
|
@ -90,7 +90,7 @@ FunctionPassBase *mlir::createLoopTilingPass(uint64_t cacheSizeBytes) {
|
|||
|
||||
// Move the loop body of AffineForOp 'src' from 'src' into the specified
|
||||
// location in destination's body.
|
||||
static inline void moveLoopBody(AffineForOp *src, AffineForOp *dest,
|
||||
static inline void moveLoopBody(AffineForOp src, AffineForOp dest,
|
||||
Block::iterator loc) {
|
||||
dest->getBody()->getInstructions().splice(loc,
|
||||
src->getBody()->getInstructions());
|
||||
|
@ -98,7 +98,7 @@ static inline void moveLoopBody(AffineForOp *src, AffineForOp *dest,
|
|||
|
||||
// Move the loop body of AffineForOp 'src' from 'src' to the start of dest's
|
||||
// body.
|
||||
static inline void moveLoopBody(AffineForOp *src, AffineForOp *dest) {
|
||||
static inline void moveLoopBody(AffineForOp src, AffineForOp dest) {
|
||||
moveLoopBody(src, dest, dest->getBody()->begin());
|
||||
}
|
||||
|
||||
|
@ -107,10 +107,10 @@ static inline void moveLoopBody(AffineForOp *src, AffineForOp *dest) {
|
|||
/// depend on other dimensions. Bounds of each dimension can thus be treated
|
||||
/// independently, and deriving the new bounds is much simpler and faster
|
||||
/// than for the case of tiling arbitrary polyhedral shapes.
|
||||
static void constructTiledIndexSetHyperRect(
|
||||
MutableArrayRef<OpPointer<AffineForOp>> origLoops,
|
||||
MutableArrayRef<OpPointer<AffineForOp>> newLoops,
|
||||
ArrayRef<unsigned> tileSizes) {
|
||||
static void
|
||||
constructTiledIndexSetHyperRect(MutableArrayRef<AffineForOp> origLoops,
|
||||
MutableArrayRef<AffineForOp> newLoops,
|
||||
ArrayRef<unsigned> tileSizes) {
|
||||
assert(!origLoops.empty());
|
||||
assert(origLoops.size() == tileSizes.size());
|
||||
|
||||
|
@ -174,7 +174,7 @@ static void constructTiledIndexSetHyperRect(
|
|||
/// Tiles the specified band of perfectly nested loops creating tile-space loops
|
||||
/// and intra-tile loops. A band is a contiguous set of loops.
|
||||
// TODO(bondhugula): handle non hyper-rectangular spaces.
|
||||
LogicalResult mlir::tileCodeGen(MutableArrayRef<OpPointer<AffineForOp>> band,
|
||||
LogicalResult mlir::tileCodeGen(MutableArrayRef<AffineForOp> band,
|
||||
ArrayRef<unsigned> tileSizes) {
|
||||
assert(!band.empty());
|
||||
assert(band.size() == tileSizes.size() && "Incorrect number of tile sizes");
|
||||
|
@ -187,13 +187,13 @@ LogicalResult mlir::tileCodeGen(MutableArrayRef<OpPointer<AffineForOp>> band,
|
|||
|
||||
auto origLoops = band;
|
||||
|
||||
OpPointer<AffineForOp> rootAffineForOp = origLoops[0];
|
||||
AffineForOp rootAffineForOp = origLoops[0];
|
||||
auto loc = rootAffineForOp->getLoc();
|
||||
// Note that width is at least one since band isn't empty.
|
||||
unsigned width = band.size();
|
||||
|
||||
SmallVector<OpPointer<AffineForOp>, 12> newLoops(2 * width);
|
||||
OpPointer<AffineForOp> innermostPointLoop;
|
||||
SmallVector<AffineForOp, 12> newLoops(2 * width);
|
||||
AffineForOp innermostPointLoop;
|
||||
|
||||
// The outermost among the loops as we add more..
|
||||
auto *topLoop = rootAffineForOp->getInstruction();
|
||||
|
@ -256,13 +256,12 @@ LogicalResult mlir::tileCodeGen(MutableArrayRef<OpPointer<AffineForOp>> band,
|
|||
// Identify valid and profitable bands of loops to tile. This is currently just
|
||||
// a temporary placeholder to test the mechanics of tiled code generation.
|
||||
// Returns all maximal outermost perfect loop nests to tile.
|
||||
static void
|
||||
getTileableBands(Function *f,
|
||||
std::vector<SmallVector<OpPointer<AffineForOp>, 6>> *bands) {
|
||||
static void getTileableBands(Function *f,
|
||||
std::vector<SmallVector<AffineForOp, 6>> *bands) {
|
||||
// Get maximal perfect nest of 'for' insts starting from root (inclusive).
|
||||
auto getMaximalPerfectLoopNest = [&](OpPointer<AffineForOp> root) {
|
||||
SmallVector<OpPointer<AffineForOp>, 6> band;
|
||||
OpPointer<AffineForOp> currInst = root;
|
||||
auto getMaximalPerfectLoopNest = [&](AffineForOp root) {
|
||||
SmallVector<AffineForOp, 6> band;
|
||||
AffineForOp currInst = root;
|
||||
do {
|
||||
band.push_back(currInst);
|
||||
} while (currInst->getBody()->getInstructions().size() == 1 &&
|
||||
|
@ -278,7 +277,7 @@ getTileableBands(Function *f,
|
|||
|
||||
// Reduce each tile size to the largest divisor of the corresponding trip count
|
||||
// (if the trip count is known).
|
||||
static void adjustToDivisorsOfTripCounts(ArrayRef<OpPointer<AffineForOp>> band,
|
||||
static void adjustToDivisorsOfTripCounts(ArrayRef<AffineForOp> band,
|
||||
SmallVectorImpl<unsigned> *tileSizes) {
|
||||
assert(band.size() == tileSizes->size() && "invalid tile size count");
|
||||
for (unsigned i = 0, e = band.size(); i < e; i++) {
|
||||
|
@ -302,7 +301,7 @@ static void adjustToDivisorsOfTripCounts(ArrayRef<OpPointer<AffineForOp>> band,
|
|||
// along each of the dimensions being tiled.
|
||||
// TODO(mlir-team): evolve this model. Tile size determination is a large area
|
||||
// to play with in general.
|
||||
void LoopTiling::getTileSizes(ArrayRef<OpPointer<AffineForOp>> band,
|
||||
void LoopTiling::getTileSizes(ArrayRef<AffineForOp> band,
|
||||
SmallVectorImpl<unsigned> *tileSizes) {
|
||||
if (band.empty())
|
||||
return;
|
||||
|
@ -383,7 +382,7 @@ void LoopTiling::runOnFunction() {
|
|||
cacheSizeBytes = clCacheSizeKiB * 1024;
|
||||
|
||||
// Bands of loops to tile.
|
||||
std::vector<SmallVector<OpPointer<AffineForOp>, 6>> bands;
|
||||
std::vector<SmallVector<AffineForOp, 6>> bands;
|
||||
getTileableBands(getFunction(), &bands);
|
||||
|
||||
for (auto &band : bands) {
|
||||
|
|
|
@ -69,19 +69,18 @@ struct LoopUnroll : public FunctionPass<LoopUnroll> {
|
|||
const Optional<bool> unrollFull;
|
||||
// Callback to obtain unroll factors; if this has a callable target, takes
|
||||
// precedence over command-line argument or passed argument.
|
||||
const std::function<unsigned(OpPointer<AffineForOp>)> getUnrollFactor;
|
||||
const std::function<unsigned(AffineForOp)> getUnrollFactor;
|
||||
|
||||
explicit LoopUnroll(Optional<unsigned> unrollFactor = None,
|
||||
Optional<bool> unrollFull = None,
|
||||
const std::function<unsigned(OpPointer<AffineForOp>)>
|
||||
&getUnrollFactor = nullptr)
|
||||
explicit LoopUnroll(
|
||||
Optional<unsigned> unrollFactor = None, Optional<bool> unrollFull = None,
|
||||
const std::function<unsigned(AffineForOp)> &getUnrollFactor = nullptr)
|
||||
: unrollFactor(unrollFactor), unrollFull(unrollFull),
|
||||
getUnrollFactor(getUnrollFactor) {}
|
||||
|
||||
void runOnFunction() override;
|
||||
|
||||
/// Unroll this for inst. Returns failure if nothing was done.
|
||||
LogicalResult runOnAffineForOp(OpPointer<AffineForOp> forOp);
|
||||
LogicalResult runOnAffineForOp(AffineForOp forOp);
|
||||
|
||||
static const unsigned kDefaultUnrollFactor = 4;
|
||||
};
|
||||
|
@ -91,7 +90,7 @@ void LoopUnroll::runOnFunction() {
|
|||
// Gathers all innermost loops through a post order pruned walk.
|
||||
struct InnermostLoopGatherer {
|
||||
// Store innermost loops as we walk.
|
||||
std::vector<OpPointer<AffineForOp>> loops;
|
||||
std::vector<AffineForOp> loops;
|
||||
|
||||
void walkPostOrder(Function *f) {
|
||||
for (auto &b : *f)
|
||||
|
@ -124,18 +123,16 @@ void LoopUnroll::runOnFunction() {
|
|||
if (clUnrollFull.getNumOccurrences() > 0 &&
|
||||
clUnrollFullThreshold.getNumOccurrences() > 0) {
|
||||
// Store short loops as we walk.
|
||||
std::vector<OpPointer<AffineForOp>> loops;
|
||||
std::vector<AffineForOp> loops;
|
||||
|
||||
// Gathers all loops with trip count <= minTripCount. Do a post order walk
|
||||
// so that loops are gathered from innermost to outermost (or else unrolling
|
||||
// an outer one may delete gathered inner ones).
|
||||
getFunction()->walkPostOrder<AffineForOp>(
|
||||
[&](OpPointer<AffineForOp> forOp) {
|
||||
Optional<uint64_t> tripCount = getConstantTripCount(forOp);
|
||||
if (tripCount.hasValue() &&
|
||||
tripCount.getValue() <= clUnrollFullThreshold)
|
||||
loops.push_back(forOp);
|
||||
});
|
||||
getFunction()->walkPostOrder<AffineForOp>([&](AffineForOp forOp) {
|
||||
Optional<uint64_t> tripCount = getConstantTripCount(forOp);
|
||||
if (tripCount.hasValue() && tripCount.getValue() <= clUnrollFullThreshold)
|
||||
loops.push_back(forOp);
|
||||
});
|
||||
for (auto forOp : loops)
|
||||
loopUnrollFull(forOp);
|
||||
return;
|
||||
|
@ -163,7 +160,7 @@ void LoopUnroll::runOnFunction() {
|
|||
|
||||
/// Unrolls a 'for' inst. Returns success if the loop was unrolled, failure
|
||||
/// otherwise. The default unroll factor is 4.
|
||||
LogicalResult LoopUnroll::runOnAffineForOp(OpPointer<AffineForOp> forOp) {
|
||||
LogicalResult LoopUnroll::runOnAffineForOp(AffineForOp forOp) {
|
||||
// Use the function callback if one was provided.
|
||||
if (getUnrollFactor) {
|
||||
return loopUnrollByFactor(forOp, getUnrollFactor(forOp));
|
||||
|
@ -185,7 +182,7 @@ LogicalResult LoopUnroll::runOnAffineForOp(OpPointer<AffineForOp> forOp) {
|
|||
|
||||
FunctionPassBase *mlir::createLoopUnrollPass(
|
||||
int unrollFactor, int unrollFull,
|
||||
const std::function<unsigned(OpPointer<AffineForOp>)> &getUnrollFactor) {
|
||||
const std::function<unsigned(AffineForOp)> &getUnrollFactor) {
|
||||
return new LoopUnroll(
|
||||
unrollFactor == -1 ? None : Optional<unsigned>(unrollFactor),
|
||||
unrollFull == -1 ? None : Optional<bool>(unrollFull), getUnrollFactor);
|
||||
|
|
|
@ -78,7 +78,7 @@ struct LoopUnrollAndJam : public FunctionPass<LoopUnrollAndJam> {
|
|||
: unrollJamFactor(unrollJamFactor) {}
|
||||
|
||||
void runOnFunction() override;
|
||||
LogicalResult runOnAffineForOp(OpPointer<AffineForOp> forOp);
|
||||
LogicalResult runOnAffineForOp(AffineForOp forOp);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
@ -98,7 +98,7 @@ void LoopUnrollAndJam::runOnFunction() {
|
|||
|
||||
/// Unroll and jam a 'for' inst. Default unroll jam factor is
|
||||
/// kDefaultUnrollJamFactor. Return failure if nothing was done.
|
||||
LogicalResult LoopUnrollAndJam::runOnAffineForOp(OpPointer<AffineForOp> forOp) {
|
||||
LogicalResult LoopUnrollAndJam::runOnAffineForOp(AffineForOp forOp) {
|
||||
// Unroll and jam by the factor that was passed if any.
|
||||
if (unrollJamFactor.hasValue())
|
||||
return loopUnrollJamByFactor(forOp, unrollJamFactor.getValue());
|
||||
|
@ -110,7 +110,7 @@ LogicalResult LoopUnrollAndJam::runOnAffineForOp(OpPointer<AffineForOp> forOp) {
|
|||
return loopUnrollJamByFactor(forOp, kDefaultUnrollJamFactor);
|
||||
}
|
||||
|
||||
LogicalResult mlir::loopUnrollJamUpToFactor(OpPointer<AffineForOp> forOp,
|
||||
LogicalResult mlir::loopUnrollJamUpToFactor(AffineForOp forOp,
|
||||
uint64_t unrollJamFactor) {
|
||||
Optional<uint64_t> mayBeConstantTripCount = getConstantTripCount(forOp);
|
||||
|
||||
|
@ -121,7 +121,7 @@ LogicalResult mlir::loopUnrollJamUpToFactor(OpPointer<AffineForOp> forOp,
|
|||
}
|
||||
|
||||
/// Unrolls and jams this loop by the specified factor.
|
||||
LogicalResult mlir::loopUnrollJamByFactor(OpPointer<AffineForOp> forOp,
|
||||
LogicalResult mlir::loopUnrollJamByFactor(AffineForOp forOp,
|
||||
uint64_t unrollJamFactor) {
|
||||
// Gathers all maximal sub-blocks of instructions that do not themselves
|
||||
// include a for inst (a instruction could have a descendant for inst though
|
||||
|
|
|
@ -244,9 +244,9 @@ namespace {
|
|||
struct LowerAffinePass : public FunctionPass<LowerAffinePass> {
|
||||
void runOnFunction() override;
|
||||
|
||||
bool lowerAffineFor(OpPointer<AffineForOp> forOp);
|
||||
bool lowerAffineIf(AffineIfOp *ifOp);
|
||||
bool lowerAffineApply(AffineApplyOp *op);
|
||||
bool lowerAffineFor(AffineForOp forOp);
|
||||
bool lowerAffineIf(AffineIfOp ifOp);
|
||||
bool lowerAffineApply(AffineApplyOp op);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
@ -319,7 +319,7 @@ static Value *buildMinMaxReductionSeq(Location loc, CmpIPredicate predicate,
|
|||
// | <code after the AffineForOp> |
|
||||
// +--------------------------------+
|
||||
//
|
||||
bool LowerAffinePass::lowerAffineFor(OpPointer<AffineForOp> forOp) {
|
||||
bool LowerAffinePass::lowerAffineFor(AffineForOp forOp) {
|
||||
auto loc = forOp->getLoc();
|
||||
auto *forInst = forOp->getInstruction();
|
||||
|
||||
|
@ -452,7 +452,7 @@ bool LowerAffinePass::lowerAffineFor(OpPointer<AffineForOp> forOp) {
|
|||
// | <code after the AffineIfOp> |
|
||||
// +--------------------------------+
|
||||
//
|
||||
bool LowerAffinePass::lowerAffineIf(AffineIfOp *ifOp) {
|
||||
bool LowerAffinePass::lowerAffineIf(AffineIfOp ifOp) {
|
||||
auto *ifInst = ifOp->getInstruction();
|
||||
auto loc = ifInst->getLoc();
|
||||
|
||||
|
@ -568,7 +568,7 @@ bool LowerAffinePass::lowerAffineIf(AffineIfOp *ifOp) {
|
|||
|
||||
// Convert an "affine.apply" operation into a sequence of arithmetic
|
||||
// instructions using the StandardOps dialect. Return true on error.
|
||||
bool LowerAffinePass::lowerAffineApply(AffineApplyOp *op) {
|
||||
bool LowerAffinePass::lowerAffineApply(AffineApplyOp op) {
|
||||
FuncBuilder builder(op->getInstruction());
|
||||
auto maybeExpandedMap =
|
||||
expandAffineMap(&builder, op->getLoc(), op->getAffineMap(),
|
||||
|
|
|
@ -102,7 +102,7 @@ namespace {
|
|||
/// a VectorTransferWriteOp is rewritten.
|
||||
template <typename VectorTransferOpTy> class VectorTransferRewriter {
|
||||
public:
|
||||
VectorTransferRewriter(VectorTransferOpTy *transfer,
|
||||
VectorTransferRewriter(VectorTransferOpTy transfer,
|
||||
MLFuncLoweringRewriter *rewriter,
|
||||
MLFuncGlobalLoweringState *state);
|
||||
|
||||
|
@ -121,7 +121,7 @@ public:
|
|||
void rewrite();
|
||||
|
||||
private:
|
||||
VectorTransferOpTy *transfer;
|
||||
VectorTransferOpTy transfer;
|
||||
MLFuncLoweringRewriter *rewriter;
|
||||
MLFuncGlobalLoweringState *state;
|
||||
};
|
||||
|
@ -132,7 +132,7 @@ private:
|
|||
/// `pivs` and `vectorView` are swapped so that the invocation of
|
||||
/// LoopNestBuilder captures it in the innermost loop.
|
||||
template <typename VectorTransferOpTy>
|
||||
void coalesceCopy(VectorTransferOpTy *transfer,
|
||||
void coalesceCopy(VectorTransferOpTy transfer,
|
||||
SmallVectorImpl<edsc::ValueHandle *> *pivs,
|
||||
edsc::VectorView *vectorView) {
|
||||
// rank of the remote memory access, coalescing behavior occurs on the
|
||||
|
@ -166,7 +166,7 @@ void coalesceCopy(VectorTransferOpTy *transfer,
|
|||
/// MemRef.
|
||||
template <typename VectorTransferOpTy>
|
||||
static llvm::SmallVector<edsc::ValueHandle, 8>
|
||||
clip(VectorTransferOpTy *transfer, edsc::MemRefView &view,
|
||||
clip(VectorTransferOpTy transfer, edsc::MemRefView &view,
|
||||
ArrayRef<edsc::IndexHandle> ivs) {
|
||||
using namespace mlir::edsc;
|
||||
using namespace edsc::op;
|
||||
|
@ -216,7 +216,7 @@ clip(VectorTransferOpTy *transfer, edsc::MemRefView &view,
|
|||
|
||||
template <typename VectorTransferOpTy>
|
||||
VectorTransferRewriter<VectorTransferOpTy>::VectorTransferRewriter(
|
||||
VectorTransferOpTy *transfer, MLFuncLoweringRewriter *rewriter,
|
||||
VectorTransferOpTy transfer, MLFuncLoweringRewriter *rewriter,
|
||||
MLFuncGlobalLoweringState *state)
|
||||
: transfer(transfer), rewriter(rewriter), state(state){};
|
||||
|
||||
|
@ -368,7 +368,7 @@ public:
|
|||
std::unique_ptr<PatternState> opState,
|
||||
MLFuncLoweringRewriter *rewriter) const override {
|
||||
VectorTransferRewriter<VectorTransferOpTy>(
|
||||
&*op->dyn_cast<VectorTransferOpTy>(), rewriter, funcWiseState)
|
||||
op->dyn_cast<VectorTransferOpTy>(), rewriter, funcWiseState)
|
||||
.rewrite();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -441,7 +441,7 @@ static Instruction *instantiate(FuncBuilder *b, Instruction *opInst,
|
|||
/// In particular, if a dimension is fully instantiated (i.e. unrolled) then it
|
||||
/// is projected out in the final result.
|
||||
template <typename VectorTransferOpTy>
|
||||
static AffineMap projectedPermutationMap(VectorTransferOpTy *transfer,
|
||||
static AffineMap projectedPermutationMap(VectorTransferOpTy transfer,
|
||||
VectorType hwVectorType) {
|
||||
static_assert(
|
||||
std::is_same<VectorTransferOpTy, VectorTransferReadOp>::value ||
|
||||
|
@ -481,7 +481,7 @@ static AffineMap projectedPermutationMap(VectorTransferOpTy *transfer,
|
|||
/// `hwVectorType` int the covering of the super-vector type. For a more
|
||||
/// detailed description of the problem, see the description of
|
||||
/// reindexAffineIndices.
|
||||
static Instruction *instantiate(FuncBuilder *b, VectorTransferReadOp *read,
|
||||
static Instruction *instantiate(FuncBuilder *b, VectorTransferReadOp read,
|
||||
VectorType hwVectorType,
|
||||
ArrayRef<unsigned> hwVectorInstance,
|
||||
DenseMap<Value *, Value *> *substitutionsMap) {
|
||||
|
@ -505,7 +505,7 @@ static Instruction *instantiate(FuncBuilder *b, VectorTransferReadOp *read,
|
|||
/// `hwVectorType` int the covering of th3e super-vector type. For a more
|
||||
/// detailed description of the problem, see the description of
|
||||
/// reindexAffineIndices.
|
||||
static Instruction *instantiate(FuncBuilder *b, VectorTransferWriteOp *write,
|
||||
static Instruction *instantiate(FuncBuilder *b, VectorTransferWriteOp write,
|
||||
VectorType hwVectorType,
|
||||
ArrayRef<unsigned> hwVectorInstance,
|
||||
DenseMap<Value *, Value *> *substitutionsMap) {
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace {
|
|||
struct MemRefDataFlowOpt : public FunctionPass<MemRefDataFlowOpt> {
|
||||
void runOnFunction() override;
|
||||
|
||||
void forwardStoreToLoad(OpPointer<LoadOp> loadOp);
|
||||
void forwardStoreToLoad(LoadOp loadOp);
|
||||
|
||||
// A list of memref's that are potentially dead / could be eliminated.
|
||||
SmallPtrSet<Value *, 4> memrefsToErase;
|
||||
|
@ -93,7 +93,7 @@ FunctionPassBase *mlir::createMemRefDataFlowOptPass() {
|
|||
|
||||
// This is a straightforward implementation not optimized for speed. Optimize
|
||||
// this in the future if needed.
|
||||
void MemRefDataFlowOpt::forwardStoreToLoad(OpPointer<LoadOp> loadOp) {
|
||||
void MemRefDataFlowOpt::forwardStoreToLoad(LoadOp loadOp) {
|
||||
Instruction *lastWriteStoreOp = nullptr;
|
||||
Instruction *loadOpInst = loadOp->getInstruction();
|
||||
|
||||
|
@ -224,8 +224,7 @@ void MemRefDataFlowOpt::runOnFunction() {
|
|||
memrefsToErase.clear();
|
||||
|
||||
// Walk all load's and perform load/store forwarding.
|
||||
f->walk<LoadOp>(
|
||||
[&](OpPointer<LoadOp> loadOp) { forwardStoreToLoad(loadOp); });
|
||||
f->walk<LoadOp>([&](LoadOp loadOp) { forwardStoreToLoad(loadOp); });
|
||||
|
||||
// Erase all load op's whose results were replaced with store fwd'ed ones.
|
||||
for (auto *loadOp : loadOpsToErase) {
|
||||
|
|
|
@ -40,9 +40,9 @@ namespace {
|
|||
|
||||
struct PipelineDataTransfer : public FunctionPass<PipelineDataTransfer> {
|
||||
void runOnFunction() override;
|
||||
void runOnAffineForOp(OpPointer<AffineForOp> forOp);
|
||||
void runOnAffineForOp(AffineForOp forOp);
|
||||
|
||||
std::vector<OpPointer<AffineForOp>> forOps;
|
||||
std::vector<AffineForOp> forOps;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
@ -71,7 +71,7 @@ static unsigned getTagMemRefPos(Instruction &dmaInst) {
|
|||
/// of the old memref by the new one while indexing the newly added dimension by
|
||||
/// the loop IV of the specified 'for' instruction modulo 2. Returns false if
|
||||
/// such a replacement cannot be performed.
|
||||
static bool doubleBuffer(Value *oldMemRef, OpPointer<AffineForOp> forOp) {
|
||||
static bool doubleBuffer(Value *oldMemRef, AffineForOp forOp) {
|
||||
auto *forBody = forOp->getBody();
|
||||
FuncBuilder bInner(forBody, forBody->begin());
|
||||
bInner.setInsertionPoint(forBody, forBody->begin());
|
||||
|
@ -145,14 +145,13 @@ void PipelineDataTransfer::runOnFunction() {
|
|||
// epilogue).
|
||||
forOps.clear();
|
||||
getFunction()->walkPostOrder<AffineForOp>(
|
||||
[&](OpPointer<AffineForOp> forOp) { forOps.push_back(forOp); });
|
||||
[&](AffineForOp forOp) { forOps.push_back(forOp); });
|
||||
for (auto forOp : forOps)
|
||||
runOnAffineForOp(forOp);
|
||||
}
|
||||
|
||||
// Check if tags of the dma start op and dma wait op match.
|
||||
static bool checkTagMatch(OpPointer<DmaStartOp> startOp,
|
||||
OpPointer<DmaWaitOp> waitOp) {
|
||||
static bool checkTagMatch(DmaStartOp startOp, DmaWaitOp waitOp) {
|
||||
if (startOp->getTagMemRef() != waitOp->getTagMemRef())
|
||||
return false;
|
||||
auto startIndices = startOp->getTagIndices();
|
||||
|
@ -176,15 +175,14 @@ static bool checkTagMatch(OpPointer<DmaStartOp> startOp,
|
|||
|
||||
// Identify matching DMA start/finish instructions to overlap computation with.
|
||||
static void findMatchingStartFinishInsts(
|
||||
OpPointer<AffineForOp> forOp,
|
||||
AffineForOp forOp,
|
||||
SmallVectorImpl<std::pair<Instruction *, Instruction *>> &startWaitPairs) {
|
||||
|
||||
// Collect outgoing DMA instructions - needed to check for dependences below.
|
||||
SmallVector<OpPointer<DmaStartOp>, 4> outgoingDmaOps;
|
||||
SmallVector<DmaStartOp, 4> outgoingDmaOps;
|
||||
for (auto &inst : *forOp->getBody()) {
|
||||
OpPointer<DmaStartOp> dmaStartOp;
|
||||
if ((dmaStartOp = inst.dyn_cast<DmaStartOp>()) &&
|
||||
dmaStartOp->isSrcMemorySpaceFaster())
|
||||
auto dmaStartOp = inst.dyn_cast<DmaStartOp>();
|
||||
if (dmaStartOp && dmaStartOp->isSrcMemorySpaceFaster())
|
||||
outgoingDmaOps.push_back(dmaStartOp);
|
||||
}
|
||||
|
||||
|
@ -195,9 +193,10 @@ static void findMatchingStartFinishInsts(
|
|||
dmaFinishInsts.push_back(&inst);
|
||||
continue;
|
||||
}
|
||||
OpPointer<DmaStartOp> dmaStartOp;
|
||||
if (!(dmaStartOp = inst.dyn_cast<DmaStartOp>()))
|
||||
auto dmaStartOp = inst.dyn_cast<DmaStartOp>();
|
||||
if (!dmaStartOp)
|
||||
continue;
|
||||
|
||||
// Only DMAs incoming into higher memory spaces are pipelined for now.
|
||||
// TODO(bondhugula): handle outgoing DMA pipelining.
|
||||
if (!dmaStartOp->isDestMemorySpaceFaster())
|
||||
|
@ -247,7 +246,7 @@ static void findMatchingStartFinishInsts(
|
|||
/// Overlap DMA transfers with computation in this loop. If successful,
|
||||
/// 'forOp' is deleted, and a prologue, a new pipelined loop, and epilogue are
|
||||
/// inserted right before where it was.
|
||||
void PipelineDataTransfer::runOnAffineForOp(OpPointer<AffineForOp> forOp) {
|
||||
void PipelineDataTransfer::runOnAffineForOp(AffineForOp forOp) {
|
||||
auto mayBeConstTripCount = getConstantTripCount(forOp);
|
||||
if (!mayBeConstTripCount.hasValue()) {
|
||||
LLVM_DEBUG(
|
||||
|
@ -329,7 +328,7 @@ void PipelineDataTransfer::runOnAffineForOp(OpPointer<AffineForOp> forOp) {
|
|||
assert(dmaStartInst->isa<DmaStartOp>());
|
||||
instShiftMap[dmaStartInst] = 0;
|
||||
// Set shifts for DMA start inst's affine operand computation slices to 0.
|
||||
SmallVector<OpPointer<AffineApplyOp>, 4> sliceOps;
|
||||
SmallVector<AffineApplyOp, 4> sliceOps;
|
||||
mlir::createAffineComputationSlice(dmaStartInst, &sliceOps);
|
||||
if (!sliceOps.empty()) {
|
||||
for (auto sliceOp : sliceOps) {
|
||||
|
|
|
@ -43,8 +43,8 @@ using namespace mlir;
|
|||
/// part of the unrolled loop. Computes the bound as an AffineMap with its
|
||||
/// operands or a null map when the trip count can't be expressed as an affine
|
||||
/// expression.
|
||||
void mlir::getCleanupLoopLowerBound(OpPointer<AffineForOp> forOp,
|
||||
unsigned unrollFactor, AffineMap *map,
|
||||
void mlir::getCleanupLoopLowerBound(AffineForOp forOp, unsigned unrollFactor,
|
||||
AffineMap *map,
|
||||
SmallVectorImpl<Value *> *operands,
|
||||
FuncBuilder *b) {
|
||||
auto lbMap = forOp->getLowerBoundMap();
|
||||
|
@ -67,11 +67,8 @@ void mlir::getCleanupLoopLowerBound(OpPointer<AffineForOp> forOp,
|
|||
|
||||
unsigned step = forOp->getStep();
|
||||
|
||||
// We need to get non-const operands; we aren't changing them here.
|
||||
auto ncForOp = *reinterpret_cast<OpPointer<AffineForOp> *>(&forOp);
|
||||
|
||||
SmallVector<Value *, 4> lbOperands(ncForOp->getLowerBoundOperands());
|
||||
auto lb = b->create<AffineApplyOp>(ncForOp->getLoc(), lbMap, lbOperands);
|
||||
SmallVector<Value *, 4> lbOperands(forOp->getLowerBoundOperands());
|
||||
auto lb = b->create<AffineApplyOp>(forOp->getLoc(), lbMap, lbOperands);
|
||||
|
||||
// For each upper bound expr, get the range.
|
||||
// Eg: for %i = lb to min (ub1, ub2),
|
||||
|
@ -115,7 +112,7 @@ void mlir::getCleanupLoopLowerBound(OpPointer<AffineForOp> forOp,
|
|||
/// Promotes the loop body of a forOp to its containing block if the forOp
|
||||
/// was known to have a single iteration.
|
||||
// TODO(bondhugula): extend this for arbitrary affine bounds.
|
||||
LogicalResult mlir::promoteIfSingleIteration(OpPointer<AffineForOp> forOp) {
|
||||
LogicalResult mlir::promoteIfSingleIteration(AffineForOp forOp) {
|
||||
Optional<uint64_t> tripCount = getConstantTripCount(forOp);
|
||||
if (!tripCount.hasValue() || tripCount.getValue() != 1)
|
||||
return failure();
|
||||
|
@ -161,7 +158,7 @@ LogicalResult mlir::promoteIfSingleIteration(OpPointer<AffineForOp> forOp) {
|
|||
void mlir::promoteSingleIterationLoops(Function *f) {
|
||||
// Gathers all innermost loops through a post order pruned walk.
|
||||
f->walkPostOrder<AffineForOp>(
|
||||
[](OpPointer<AffineForOp> forOp) { promoteIfSingleIteration(forOp); });
|
||||
[](AffineForOp forOp) { promoteIfSingleIteration(forOp); });
|
||||
}
|
||||
|
||||
/// Generates a 'for' inst with the specified lower and upper bounds while
|
||||
|
@ -171,12 +168,11 @@ void mlir::promoteSingleIterationLoops(Function *f) {
|
|||
/// the pair specifies the shift applied to that group of instructions; note
|
||||
/// that the shift is multiplied by the loop step before being applied. Returns
|
||||
/// nullptr if the generated loop simplifies to a single iteration one.
|
||||
static OpPointer<AffineForOp>
|
||||
static AffineForOp
|
||||
generateLoop(AffineMap lbMap, AffineMap ubMap,
|
||||
const std::vector<std::pair<uint64_t, ArrayRef<Instruction *>>>
|
||||
&instGroupQueue,
|
||||
unsigned offset, OpPointer<AffineForOp> srcForInst,
|
||||
FuncBuilder *b) {
|
||||
unsigned offset, AffineForOp srcForInst, FuncBuilder *b) {
|
||||
SmallVector<Value *, 4> lbOperands(srcForInst->getLowerBoundOperands());
|
||||
SmallVector<Value *, 4> ubOperands(srcForInst->getUpperBoundOperands());
|
||||
|
||||
|
@ -216,7 +212,7 @@ generateLoop(AffineMap lbMap, AffineMap ubMap,
|
|||
}
|
||||
}
|
||||
if (succeeded(promoteIfSingleIteration(loopChunk)))
|
||||
return OpPointer<AffineForOp>();
|
||||
return AffineForOp();
|
||||
return loopChunk;
|
||||
}
|
||||
|
||||
|
@ -235,8 +231,7 @@ generateLoop(AffineMap lbMap, AffineMap ubMap,
|
|||
// asserts preservation of SSA dominance. A check for that as well as that for
|
||||
// memory-based depedence preservation check rests with the users of this
|
||||
// method.
|
||||
LogicalResult mlir::instBodySkew(OpPointer<AffineForOp> forOp,
|
||||
ArrayRef<uint64_t> shifts,
|
||||
LogicalResult mlir::instBodySkew(AffineForOp forOp, ArrayRef<uint64_t> shifts,
|
||||
bool unrollPrologueEpilogue) {
|
||||
if (forOp->getBody()->empty())
|
||||
return success();
|
||||
|
@ -285,8 +280,8 @@ LogicalResult mlir::instBodySkew(OpPointer<AffineForOp> forOp,
|
|||
// Nevertheless, if 'unrollPrologueEpilogue' is set, we will treat the first
|
||||
// loop generated as the prologue and the last as epilogue and unroll these
|
||||
// fully.
|
||||
OpPointer<AffineForOp> prologue;
|
||||
OpPointer<AffineForOp> epilogue;
|
||||
AffineForOp prologue;
|
||||
AffineForOp epilogue;
|
||||
|
||||
// Do a sweep over the sorted shifts while storing open groups in a
|
||||
// vector, and generating loop portions as necessary during the sweep. A block
|
||||
|
@ -306,7 +301,7 @@ LogicalResult mlir::instBodySkew(OpPointer<AffineForOp> forOp,
|
|||
// The interval for which the loop needs to be generated here is:
|
||||
// [lbShift, min(lbShift + tripCount, d)) and the body of the
|
||||
// loop needs to have all instructions in instQueue in that order.
|
||||
OpPointer<AffineForOp> res;
|
||||
AffineForOp res;
|
||||
if (lbShift + tripCount * step < d * step) {
|
||||
res = generateLoop(
|
||||
b.getShiftedAffineMap(origLbMap, lbShift),
|
||||
|
@ -357,7 +352,7 @@ LogicalResult mlir::instBodySkew(OpPointer<AffineForOp> forOp,
|
|||
}
|
||||
|
||||
/// Unrolls this loop completely.
|
||||
LogicalResult mlir::loopUnrollFull(OpPointer<AffineForOp> forOp) {
|
||||
LogicalResult mlir::loopUnrollFull(AffineForOp forOp) {
|
||||
Optional<uint64_t> mayBeConstantTripCount = getConstantTripCount(forOp);
|
||||
if (mayBeConstantTripCount.hasValue()) {
|
||||
uint64_t tripCount = mayBeConstantTripCount.getValue();
|
||||
|
@ -371,7 +366,7 @@ LogicalResult mlir::loopUnrollFull(OpPointer<AffineForOp> forOp) {
|
|||
|
||||
/// Unrolls and jams this loop by the specified factor or by the trip count (if
|
||||
/// constant) whichever is lower.
|
||||
LogicalResult mlir::loopUnrollUpToFactor(OpPointer<AffineForOp> forOp,
|
||||
LogicalResult mlir::loopUnrollUpToFactor(AffineForOp forOp,
|
||||
uint64_t unrollFactor) {
|
||||
Optional<uint64_t> mayBeConstantTripCount = getConstantTripCount(forOp);
|
||||
|
||||
|
@ -383,7 +378,7 @@ LogicalResult mlir::loopUnrollUpToFactor(OpPointer<AffineForOp> forOp,
|
|||
|
||||
/// Unrolls this loop by the specified factor. Returns success if the loop
|
||||
/// is successfully unrolled.
|
||||
LogicalResult mlir::loopUnrollByFactor(OpPointer<AffineForOp> forOp,
|
||||
LogicalResult mlir::loopUnrollByFactor(AffineForOp forOp,
|
||||
uint64_t unrollFactor) {
|
||||
assert(unrollFactor >= 1 && "unroll factor should be >= 1");
|
||||
|
||||
|
@ -471,8 +466,7 @@ LogicalResult mlir::loopUnrollByFactor(OpPointer<AffineForOp> forOp,
|
|||
|
||||
/// Performs loop interchange on 'forOpA' and 'forOpB', where 'forOpB' is
|
||||
/// nested within 'forOpA' as the only instruction in its block.
|
||||
void mlir::interchangeLoops(OpPointer<AffineForOp> forOpA,
|
||||
OpPointer<AffineForOp> forOpB) {
|
||||
void mlir::interchangeLoops(AffineForOp forOpA, AffineForOp forOpB) {
|
||||
auto *forOpAInst = forOpA->getInstruction();
|
||||
// 1) Slice forOpA's instruction list (which is just forOpB) just before
|
||||
// forOpA (in forOpA's parent's block) this should leave 'forOpA's
|
||||
|
@ -492,11 +486,10 @@ void mlir::interchangeLoops(OpPointer<AffineForOp> forOpA,
|
|||
|
||||
/// Performs a series of loop interchanges to sink 'forOp' 'loopDepth' levels
|
||||
/// deeper in the loop nest.
|
||||
void mlir::sinkLoop(OpPointer<AffineForOp> forOp, unsigned loopDepth) {
|
||||
void mlir::sinkLoop(AffineForOp forOp, unsigned loopDepth) {
|
||||
for (unsigned i = 0; i < loopDepth; ++i) {
|
||||
assert(forOp->getBody()->front().isa<AffineForOp>());
|
||||
OpPointer<AffineForOp> nextForOp =
|
||||
forOp->getBody()->front().cast<AffineForOp>();
|
||||
AffineForOp nextForOp = forOp->getBody()->front().cast<AffineForOp>();
|
||||
interchangeLoops(forOp, nextForOp);
|
||||
}
|
||||
}
|
||||
|
@ -525,8 +518,8 @@ static void augmentMapAndBounds(FuncBuilder *b, Value *iv, AffineMap *map,
|
|||
// substituting `oldIv` in place of
|
||||
// `forOp.getInductionVariable()`.
|
||||
// Note: `newForOp` may be nested under `forOp`.
|
||||
static void cloneLoopBodyInto(OpPointer<AffineForOp> forOp, Value *oldIv,
|
||||
OpPointer<AffineForOp> newForOp) {
|
||||
static void cloneLoopBodyInto(AffineForOp forOp, Value *oldIv,
|
||||
AffineForOp newForOp) {
|
||||
BlockAndValueMapping map;
|
||||
map.map(oldIv, newForOp->getInductionVar());
|
||||
FuncBuilder b(newForOp->getBody(), newForOp->getBody()->end());
|
||||
|
@ -554,9 +547,9 @@ static void cloneLoopBodyInto(OpPointer<AffineForOp> forOp, Value *oldIv,
|
|||
// responsibility to specify `targets` that are dominated by `forOp`.
|
||||
// Returns the new AffineForOps, one per `targets`, nested immediately under
|
||||
// each of the `targets`.
|
||||
static SmallVector<OpPointer<AffineForOp>, 8>
|
||||
stripmineSink(OpPointer<AffineForOp> forOp, uint64_t factor,
|
||||
ArrayRef<OpPointer<AffineForOp>> targets) {
|
||||
static SmallVector<AffineForOp, 8>
|
||||
stripmineSink(AffineForOp forOp, uint64_t factor,
|
||||
ArrayRef<AffineForOp> targets) {
|
||||
// TODO(ntv): Use cheap structural assertions that targets are nested under
|
||||
// forOp and that targets are not nested under each other when DominanceInfo
|
||||
// exposes the capability. It seems overkill to construct a whole function
|
||||
|
@ -579,7 +572,7 @@ stripmineSink(OpPointer<AffineForOp> forOp, uint64_t factor,
|
|||
augmentMapAndBounds(&b, forOp->getInductionVar(), &ubMap, &ubOperands,
|
||||
/*offset=*/scaledStep);
|
||||
|
||||
SmallVector<OpPointer<AffineForOp>, 8> innerLoops;
|
||||
SmallVector<AffineForOp, 8> innerLoops;
|
||||
for (auto t : targets) {
|
||||
// Insert newForOp at the end of `t`.
|
||||
FuncBuilder b(t->getBody(), t->getBody()->end());
|
||||
|
@ -601,21 +594,18 @@ stripmineSink(OpPointer<AffineForOp> forOp, uint64_t factor,
|
|||
|
||||
// Stripmines a `forOp` by `factor` and sinks it under a single `target`.
|
||||
// Returns the new AffineForOps, nested immediately under `target`.
|
||||
OpPointer<AffineForOp> stripmineSink(OpPointer<AffineForOp> forOp,
|
||||
uint64_t factor,
|
||||
OpPointer<AffineForOp> target) {
|
||||
auto res =
|
||||
stripmineSink(forOp, factor, ArrayRef<OpPointer<AffineForOp>>{target});
|
||||
AffineForOp stripmineSink(AffineForOp forOp, uint64_t factor,
|
||||
AffineForOp target) {
|
||||
auto res = stripmineSink(forOp, factor, ArrayRef<AffineForOp>{target});
|
||||
assert(res.size() == 1 && "Expected 1 inner forOp");
|
||||
return res[0];
|
||||
}
|
||||
|
||||
SmallVector<SmallVector<OpPointer<AffineForOp>, 8>, 8>
|
||||
mlir::tile(ArrayRef<OpPointer<AffineForOp>> forOps, ArrayRef<uint64_t> sizes,
|
||||
ArrayRef<OpPointer<AffineForOp>> targets) {
|
||||
SmallVector<SmallVector<OpPointer<AffineForOp>, 8>, 8> res;
|
||||
SmallVector<OpPointer<AffineForOp>, 8> currentTargets(targets.begin(),
|
||||
targets.end());
|
||||
SmallVector<SmallVector<AffineForOp, 8>, 8>
|
||||
mlir::tile(ArrayRef<AffineForOp> forOps, ArrayRef<uint64_t> sizes,
|
||||
ArrayRef<AffineForOp> targets) {
|
||||
SmallVector<SmallVector<AffineForOp, 8>, 8> res;
|
||||
SmallVector<AffineForOp, 8> currentTargets(targets.begin(), targets.end());
|
||||
for (auto it : llvm::zip(forOps, sizes)) {
|
||||
auto step = stripmineSink(std::get<0>(it), std::get<1>(it), currentTargets);
|
||||
res.push_back(step);
|
||||
|
@ -624,8 +614,8 @@ mlir::tile(ArrayRef<OpPointer<AffineForOp>> forOps, ArrayRef<uint64_t> sizes,
|
|||
return res;
|
||||
}
|
||||
|
||||
SmallVector<OpPointer<AffineForOp>, 8>
|
||||
mlir::tile(ArrayRef<OpPointer<AffineForOp>> forOps, ArrayRef<uint64_t> sizes,
|
||||
OpPointer<AffineForOp> target) {
|
||||
return tile(forOps, sizes, ArrayRef<OpPointer<AffineForOp>>{target})[0];
|
||||
SmallVector<AffineForOp, 8> mlir::tile(ArrayRef<AffineForOp> forOps,
|
||||
ArrayRef<uint64_t> sizes,
|
||||
AffineForOp target) {
|
||||
return tile(forOps, sizes, ArrayRef<AffineForOp>{target})[0];
|
||||
}
|
||||
|
|
|
@ -221,7 +221,7 @@ bool mlir::replaceAllMemRefUsesWith(Value *oldMemRef, Value *newMemRef,
|
|||
/// uses besides this opInst; otherwise returns the list of affine.apply
|
||||
/// operations created in output argument `sliceOps`.
|
||||
void mlir::createAffineComputationSlice(
|
||||
Instruction *opInst, SmallVectorImpl<OpPointer<AffineApplyOp>> *sliceOps) {
|
||||
Instruction *opInst, SmallVectorImpl<AffineApplyOp> *sliceOps) {
|
||||
// Collect all operands that are results of affine apply ops.
|
||||
SmallVector<Value *, 4> subOperands;
|
||||
subOperands.reserve(opInst->getNumOperands());
|
||||
|
|
|
@ -853,7 +853,7 @@ static LogicalResult vectorizeRootOrTerminal(Value *iv,
|
|||
|
||||
/// Coarsens the loops bounds and transforms all remaining load and store
|
||||
/// operations into the appropriate vector_transfer.
|
||||
static LogicalResult vectorizeAffineForOp(AffineForOp *loop, int64_t step,
|
||||
static LogicalResult vectorizeAffineForOp(AffineForOp loop, int64_t step,
|
||||
VectorizationState *state) {
|
||||
using namespace functional;
|
||||
loop->setStep(step);
|
||||
|
@ -936,7 +936,7 @@ vectorizeLoopsAndLoadsRecursively(NestedMatch oneMatch,
|
|||
LLVM_DEBUG(dbgs() << "\n[early-vect] vectorizeForOp by " << vectorSize
|
||||
<< " : ");
|
||||
LLVM_DEBUG(loopInst->print(dbgs()));
|
||||
return vectorizeAffineForOp(loop, loop->getStep() * vectorSize, state);
|
||||
return vectorizeAffineForOp(loop, loop.getStep() * vectorSize, state);
|
||||
}
|
||||
|
||||
/// Tries to transform a scalar constant into a vector splat of that constant.
|
||||
|
@ -1012,7 +1012,7 @@ static Value *vectorizeOperand(Value *operand, Instruction *inst,
|
|||
// 3. vectorize constant.
|
||||
if (auto constant = operand->getDefiningInst()->dyn_cast<ConstantOp>()) {
|
||||
return vectorizeConstant(
|
||||
inst, *constant,
|
||||
inst, constant,
|
||||
VectorType::get(state->strategy->vectorSizes, operand->getType()));
|
||||
}
|
||||
// 4. currently non-vectorizable.
|
||||
|
@ -1178,8 +1178,8 @@ static LogicalResult vectorizeRootMatch(NestedMatch m,
|
|||
clonedLoop->erase();
|
||||
return mlir::success();
|
||||
}
|
||||
OpPointer<AffineForOp> loop;
|
||||
OpPointer<AffineForOp> clonedLoop;
|
||||
AffineForOp loop;
|
||||
AffineForOp clonedLoop;
|
||||
} guard{loop, clonedLoop};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -30,6 +30,7 @@ def NS_AOp : Op<"a_op", [NoSideEffect]> {
|
|||
|
||||
// CHECK: class AOp : public Op<AOp, OpTrait::AtLeastNResults<1>::Impl, OpTrait::HasNoSideEffect, OpTrait::AtLeastNOperands<1>::Impl> {
|
||||
// CHECK: public:
|
||||
// CHECK: using Op::Op;
|
||||
// CHECK: static StringRef getOperationName();
|
||||
// CHECK: Value *a();
|
||||
// CHECK: Instruction::operand_range b();
|
||||
|
@ -45,7 +46,4 @@ def NS_AOp : Op<"a_op", [NoSideEffect]> {
|
|||
// CHECK: static void getCanonicalizationPatterns(OwningRewritePatternList &results, MLIRContext *context);
|
||||
// CHECK: LogicalResult constantFold(ArrayRef<Attribute> operands, SmallVectorImpl<Attribute> &results, MLIRContext *context);
|
||||
// CHECK: bool fold(SmallVectorImpl<Value *> &results);
|
||||
// CHECK: private:
|
||||
// CHECK: friend class ::mlir::Instruction;
|
||||
// CHECK: explicit AOp(Instruction *state) : Op(state) {}
|
||||
// CHECK: };
|
||||
|
|
|
@ -315,14 +315,12 @@ void OpClass::writeDeclTo(raw_ostream &os) const {
|
|||
for (const auto &trait : traits)
|
||||
os << ", " << trait;
|
||||
os << "> {\npublic:\n";
|
||||
os << " using Op::Op;\n";
|
||||
for (const auto &method : methods) {
|
||||
method.writeDeclTo(os);
|
||||
os << "\n";
|
||||
}
|
||||
os << "\nprivate:\n"
|
||||
<< " friend class ::mlir::Instruction;\n";
|
||||
os << " explicit " << className << "(Instruction *state) : Op(state) {}\n"
|
||||
<< "};";
|
||||
os << "};";
|
||||
}
|
||||
|
||||
void OpClass::writeDefTo(raw_ostream &os) const {
|
||||
|
|
Loading…
Reference in New Issue