22 #include "llvm/ADT/STLExtras.h"
23 #include "llvm/Support/Casting.h"
25 #define DEBUG_TYPE "pad-tiling-interface"
31 #define DBGS() (llvm::dbgs() << "[" DEBUG_TYPE << "]: ")
32 #define DBGSNL() (llvm::dbgs() << "\n")
40 for (
size_t idx = 0, e = indexingSizes.size(); idx != e; ++idx) {
42 paddingSizes.push_back(
options.paddingSizes.size() > idx
52 LLVM_DEBUG(
DBGS() <<
"----idx: " << idx <<
" : " << paddingSizes[idx]
63 if (
auto binOp = dyn_cast<AffineBinaryOpExpr>(expr)) {
65 auto lhsD = dyn_cast<AffineDimExpr>(binOp.getLHS());
66 auto rhsC = dyn_cast<AffineConstantExpr>(binOp.getRHS());
68 return rhsC.getValue();
70 auto lhsC = dyn_cast<AffineConstantExpr>(binOp.getLHS());
71 auto rhsD = dyn_cast<AffineDimExpr>(binOp.getRHS());
73 return lhsC.getValue();
103 auto tensorType = cast<RankedTensorType>(v.getType());
104 paddedShape.resize_for_overwrite(tensorType.getRank());
105 assert(tensorType.getRank() == indexingMap.
getNumResults() &&
106 "expect the number of results of the affine map to match the tensor "
116 int64_t resultIndex = enResults.index();
120 LLVM_DEBUG(
DBGS() <<
"----resultIndex: " << resultIndex
121 <<
" with partialIndexingMap: " << partialIndexingMap
127 for (
size_t paddingDim = 0, e = paddingSizes.size(); paddingDim != e;
130 LLVM_DEBUG(
DBGS() <<
"------try apply padding of dim: " << paddingDim
131 <<
" to: " << paddingSize <<
"\n");
132 if (!enResults.value().isFunctionOfDim(paddingDim))
135 LLVM_DEBUG(
DBGS() <<
"------apply padding of dim: " << paddingDim
136 <<
" to: " << paddingSize <<
"\n");
139 llvm::SmallBitVector projectedDims(partialIndexingMap.
getNumDims(),
true);
140 projectedDims.flip(paddingDim);
154 rewriter, loc, composedMap,
155 {indexingSizes[paddingDim], paddingSize},
160 rewriter, loc, projectedMap, paddingSize);
170 rewriter, loc, subtractMap, {paddingDimOfr});
171 terms.push_back(maxAccessIdx);
173 LLVM_DEBUG(
DBGS() <<
"------new term: " << terms.back() <<
"\n");
178 paddedShape[resultIndex] =
187 for (
unsigned i = 1; i < dims.size(); ++i)
188 sumExpr = sumExpr + dims[i];
191 rewriter, loc, sumExpr + 1, terms);
192 paddedShape[resultIndex] = paddedDimOfr;
198 FailureOr<SmallVector<OpFoldResult>>
203 llvm::dyn_cast<IndexingMapOpInterface>(operandToPad.
getOwner());
208 assert(llvm::all_of(iterationDomain, [&rewriter](
Range r) {
211 }) &&
"expected 0-offset 1-stride loop ranges");
214 loopUpperBounds.reserve(iterationDomain.size());
215 for (
const Range &range : iterationDomain)
216 loopUpperBounds.push_back(range.size);
218 AffineMap indexingMap = transferOp.getMatchingIndexingMap(&operandToPad);
221 indexingMap, loopUpperBounds,
options);
233 auto complexAttr = cast<ArrayAttr>(paddingValueAttr);
234 paddingValue = complex::ConstantOp::create(rewriter, opToPad.getLoc(),
235 complexTy, complexAttr);
237 paddingValue = arith::ConstantOp::create(rewriter, opToPad.getLoc(),
238 cast<TypedAttr>(paddingValueAttr));
246 tensorShape.push_back(cst.has_value() ? *cst : ShapedType::kDynamic);
247 if (!cst.has_value())
248 dynDims.push_back(ofr.dyn_cast<
Value>());
252 auto paddedTensorType =
254 LLVM_DEBUG(
DBGS() <<
"--SUCCESS, makeComposedPadHighOp with type: "
255 << paddedTensorType);
257 paddingValue,
false, dynDims);
260 FailureOr<TilingInterface>
265 LLVM_DEBUG(
DBGS() <<
"Start rewriteAsPaddedOp : " << opToPad <<
"\n");
271 if (
options.paddingValues.empty()) {
273 llvm::append_range(types, opToPad->getResultTypes());
274 for (
Type t : types) {
275 options.paddingValues.push_back(
280 if (llvm::any_of(opToPad->getOperands(),
281 [](
Value v) { return isa<MemRefType>(v.getType()); })) {
283 "expected operation on tensors");
295 newOperands.reserve(opToPad->getNumOperands());
296 for (
OpOperand &opOperand : opToPad->getOpOperands()) {
297 Value operand = opOperand.get();
298 LLVM_DEBUG(
DBGS() <<
"--start padding oprd: " << operand <<
"\n");
302 if (!isa<RankedTensorType>(operandType)) {
303 assert((!isa<ShapedType>(operandType) || isa<VectorType>(operandType)) &&
304 "Unexpected non-vector ShapedType");
305 newOperands.push_back(operand);
309 FailureOr<SmallVector<OpFoldResult>> maybePaddedShape =
310 computePaddingSizeFun(rewriter, opOperand, iterationDomain,
options);
311 if (failed(maybePaddedShape)) {
318 if (opOperand.getOperandNumber() >=
options.paddingValues.size()) {
320 "--no padding value specified");
323 options.paddingValues[opOperand.getOperandNumber()];
328 *maybePaddedShape, paddingValueAttr);
329 LLVM_DEBUG(
DBGS() <<
"--done padding operand: " << paddedOperand <<
"\n");
332 newOperands.push_back(paddedOperand);
333 if (
auto padOp = paddedOperand.
getDefiningOp<tensor::PadOp>())
334 padOps.push_back(padOp);
340 LLVM_DEBUG(
DBGS() <<
"--failed to reify result shapes -> FAIL\n");
342 "failed to reify result shapes");
344 assert(reifiedResultShapes.size() == opToPad->getNumResults() &&
345 "expected same number of results");
348 auto resultTensorTypes =
351 TilingInterface paddedOp =
352 clone(rewriter, opToPad, resultTensorTypes, newOperands);
353 LLVM_DEBUG(
DBGS() <<
"--cloned padded op: " << paddedOp <<
"\n");
358 paddedSubtensorResults.reserve(opToPad->getNumResults());
360 Value paddedResult = en.value();
361 int64_t resultNumber = en.index();
362 int64_t rank = cast<RankedTensorType>(paddedResult.
getType()).getRank();
365 paddedSubtensorResults.push_back(tensor::ExtractSliceOp::create(
366 rewriter, loc, paddedResult, offsets, reifiedResultShapes[resultNumber],
370 rewriter.
replaceOp(opToPad, paddedSubtensorResults);
static Value padOperand(RewriterBase &rewriter, TilingInterface opToPad, TypedValue< RankedTensorType > v, ArrayRef< OpFoldResult > paddedShape, Attribute paddingValueAttr)
Pad a single operand to paddedShape using paddingValueAttr as padding Value.
static int64_t extractConstantMultiplier(AffineExpr expr)
Extracts the constant multiplier from an affine expression of the form d * c or c * d,...
static SmallVector< OpFoldResult > getFullRankPaddingSizes(Builder &b, ArrayRef< OpFoldResult > indexingSizes, const PadTilingInterfaceOptions &options)
Form a "full-rank" padding specification so that the application is easy.
static llvm::ManagedStatic< PassManagerOptions > options
Base type for affine expression.
AffineExpr ceilDiv(uint64_t v) const
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
unsigned getNumDims() const
ArrayRef< AffineExpr > getResults() const
unsigned getNumResults() const
AffineExpr getResult(unsigned idx) const
AffineMap getSubMap(ArrayRef< unsigned > resultPos) const
Returns the map consisting of the resultPos subset.
AffineMap compose(AffineMap map) const
Returns the AffineMap resulting from composing this with map.
Attributes are known-constant values of operations.
This class is a general helper class for creating context-global objects like types,...
IntegerAttr getIndexAttr(int64_t value)
TypedAttr getZeroAttr(Type type)
MLIRContext * getContext() const
IRValueT get() const
Return the current value being used by this operand.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
RAII guard to reset the insertion point of the builder when destroyed.
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
This class represents a single result from folding an operation.
This class represents an operand of an operation.
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
type_range getTypes() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Operation * getOwner() const
Return the owner of this operand.
OpFoldResult makeComposedFoldedAffineApply(OpBuilder &b, Location loc, AffineMap map, ArrayRef< OpFoldResult > operands, bool composeAffineMin=false)
Constructs an AffineApplyOp that applies map to operands after composing the map with the maps of any...
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
LogicalResult rewriteAsPaddedOp(RewriterBase &rewriter, LinalgOp opToPad, const LinalgPaddingOptions &options, LinalgOp &paddedOp, SmallVector< Value > &replacements, SmallVector< tensor::PadOp > &padOps)
Pad the iterator dimensions options.paddingDimensions of all opToPad operands to a static bounding bo...
SmallVector< OpFoldResult > computePaddedShape(RewriterBase &rewriter, TypedValue< RankedTensorType > v, AffineMap indexingMap, ArrayRef< OpFoldResult > indexingSizes, const PadTilingInterfaceOptions &options)
Helper function to compute the padded shape of the given value v of RankedTensorType given:
OpFoldResult createFoldedDimOp(OpBuilder &b, Location loc, Value val, int64_t dim)
Create one memref::DimOp or tensor::DimOp depending on the type of val.
FailureOr< SmallVector< OpFoldResult > > computeIndexingMapOpInterfacePaddedShape(RewriterBase &rewriter, OpOperand &operandToPad, ArrayRef< Range > iterationDomain, const PadTilingInterfaceOptions &options)
Specific helper for Linalg ops.
std::function< FailureOr< SmallVector< OpFoldResult > >(RewriterBase &, OpOperand &, ArrayRef< Range >, const PadTilingInterfaceOptions &)> PadSizeComputationFunction
Value makeComposedPadHighOp(OpBuilder &b, Location loc, RankedTensorType type, Value source, Value padding, bool nofold, ValueRange typeDynDims={})
Create a tensor::PadOp that pads source to the shape of type whose sizes are assumed to be greater th...
Include the generated interface declarations.
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
LogicalResult reifyResultShapes(OpBuilder &b, Operation *op, ReifiedRankedShapedTypeDims &reifiedReturnShapes)
Reify the shape of the result of an operation (typically in terms of the shape of its operands).
void bindDimsList(MLIRContext *ctx, MutableArrayRef< AffineExprTy > exprs)
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
void bindDims(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to DimExpr at positions: [0 .
@ Mul
RHS of mul is always a constant or a symbolic expression.
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
bool isZeroInteger(OpFoldResult v)
Return true if v is an IntegerAttr with value 0.
void bindSymbols(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to SymbolExpr at positions: [0 .
Operation * clone(OpBuilder &b, Operation *op, TypeRange newResultTypes, ValueRange newOperands)
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
AffineMap projectDims(AffineMap map, const llvm::SmallBitVector &projectedDimensions, bool compressDimsFlag=false)
Returns the map that results from projecting out the dimensions specified in projectedDimensions.
Represents a range (offset, size, and stride) where each element of the triple may be dynamic or stat...