17 #define DEBUG_TYPE "linalg-padding"
22 #define DBGS() (llvm::dbgs() << "[" DEBUG_TYPE << "]: ")
23 #define DBGSNL() (llvm::dbgs() << "\n")
31 bool &alreadyHasRequestedShape) {
32 AffineMap indexingMap = opToPad.getMatchingIndexingMap(opOperand);
37 alreadyHasRequestedShape =
true;
41 if (en.value().isFunctionOfDim(dimEn.value())) {
42 int64_t dimSize = shape[en.index()];
43 if (
options.padToMultipleOf.has_value()) {
44 shapeDimToMultiple[en.index()] =
45 (*
options.padToMultipleOf)[dimEn.index()];
47 shapeDimToMultiple[en.index()] = 1;
49 if (ShapedType::isDynamic(dimSize)) {
50 alreadyHasRequestedShape =
false;
51 }
else if (dimSize % shapeDimToMultiple[en.index()] != 0) {
52 alreadyHasRequestedShape =
false;
59 auto ceil = [](int64_t val, int64_t multiple) {
60 return ((val + multiple - 1) / multiple) * multiple;
64 paddedShape.assign(shape.begin(), shape.end());
65 for (int64_t i = 0, e = shape.size(); i < e; ++i) {
66 LLVM_DEBUG(
DBGS() <<
"--compute padded size for dim " << i <<
"\n");
68 if (!shapeDimToMultiple.contains(i)) {
69 LLVM_DEBUG(
DBGS() <<
"----dim does not require padding, SKIP\n");
73 FailureOr<int64_t> upperBound =
79 if (failed(upperBound)) {
80 LLVM_DEBUG(
DBGS() <<
"----could not compute a bounding box for padding");
83 paddedShape[i] =
ceil(*upperBound, shapeDimToMultiple[i]);
84 LLVM_DEBUG(
DBGS() <<
"----new dim size: " << paddedShape[i] <<
"\n");
106 (!
options.padToMultipleOf.has_value() ||
107 options.padToMultipleOf->size() ==
options.paddingDimensions.size()) &&
108 "invalid number of elements in padToMultipleOf");
112 bool alreadyHasRequestedShape =
false;
114 alreadyHasRequestedShape)))
116 "--failed to compute padded shape");
123 if (!nofold && alreadyHasRequestedShape)
124 return opOperand->
get();
133 if (
auto complexTy = dyn_cast<ComplexType>(
135 auto complexAttr = cast<ArrayAttr>(paddingAttr);
136 paddingValue = rewriter.
create<complex::ConstantOp>(opToPad.getLoc(),
137 complexTy, complexAttr);
139 paddingValue = rewriter.
create<arith::ConstantOp>(
140 opToPad.getLoc(), cast<TypedAttr>(paddingAttr));
146 LLVM_DEBUG(
DBGS() <<
"--SUCCESS, makeComposedPadHighOp with type: "
147 << paddedTensorType);
149 opOperand->
get(), paddingValue, nofold);
157 LLVM_DEBUG(
DBGS() <<
"Start rewriteAsPaddedOp : " << opToPad <<
"\n");
163 if (
options.paddingValues.empty()) {
165 llvm::append_range(types, opToPad->getResultTypes());
166 for (
Type t : types) {
167 options.paddingValues.push_back(
173 if (!opToPad.hasPureTensorSemantics())
175 "expected operation on tensors");
183 newOperands.reserve(opToPad->getNumOperands());
184 for (
OpOperand &opOperand : opToPad->getOpOperands()) {
186 rewriter, opToPad, &opOperand,
options);
188 if (failed(paddedOperand)) {
189 LLVM_DEBUG(
DBGS() <<
"--operand cannot be bound statically : "
190 << opOperand.get() <<
" -> FAIL\n");
192 "operand cannot be bound statically");
194 newOperands.push_back(*paddedOperand);
195 if (
auto padOp = paddedOperand->getDefiningOp<tensor::PadOp>())
196 padOps.push_back(padOp);
201 LLVM_DEBUG(
DBGS() <<
"--failed to reify result shapes -> FAIL\n");
203 "failed to reify result shapes");
205 assert(reifiedResultShapes.size() == opToPad->getNumResults() &&
206 "expected same number of results");
209 auto resultTensorTypes =
212 paddedOp =
clone(rewriter, opToPad, resultTensorTypes, newOperands);
213 LLVM_DEBUG(
DBGS() <<
"--cloned padded op: " << paddedOp <<
"\n");
218 paddedSubtensorResults.reserve(opToPad->getNumResults());
220 Value paddedResult = en.value();
221 int64_t resultNumber = en.index();
222 int64_t rank = cast<RankedTensorType>(paddedResult.
getType()).getRank();
225 paddedSubtensorResults.push_back(rewriter.
create<tensor::ExtractSliceOp>(
226 loc, paddedResult, offsets, reifiedResultShapes[resultNumber],
231 replacements = std::move(paddedSubtensorResults);
239 assert(
static_cast<int64_t
>(paddedSubtensorResults.size()) ==
240 opToPad.getNumDpsInits() &&
241 "expected matching number of results");
243 llvm::zip(paddedSubtensorResults, opToPad.getDpsInitsMutable())) {
245 replacements.push_back(rewriter
246 .create<linalg::CopyOp>(loc, std::get<0>(it),
247 std::get<1>(it).
get())
249 }
else if (
options.copyBackOp ==
251 BufferizationMaterializeInDestination) {
252 replacements.push_back(
254 .create<bufferization::MaterializeInDestinationOp>(
255 loc, std::get<0>(it), std::get<1>(it).
get())
258 llvm_unreachable(
"unsupported copy back op");
270 if (!linalgOp.hasPureTensorSemantics())
272 linalgOp,
"only applies to Linalg ops with tensor semantics");
279 newResults, padOps)))
281 "failed to rewrite as a padded op");
285 if (
static_cast<int64_t
>(en.index()) >= paddedOp->getNumOperands())
287 OpOperand &opOperand = paddedOp->getOpOperand(en.index());
289 if (!padOp || en.value() == 0) {
295 if (llvm::any_of(paddedOp.getShape(&opOperand), ShapedType::isDynamic)) {
297 "non static padding shape -- skip");
301 tensor::PadOp hoistedOp;
304 en.index() <
options.transposePaddings.size()
305 ?
options.transposePaddings[en.index()]
309 padOp, en.value(), transposeVector, hoistedOp, transposeOps);
310 if (failed(newResult)) {
312 "failed to apply hoistPadding");
319 rewriter.
replaceOp(linalgOp, newResults);
static FailureOr< Value > padOperandToSmallestStaticBoundingBox(RewriterBase &rewriter, linalg::LinalgOp opToPad, OpOperand *opOperand, const LinalgPaddingOptions &options)
Pad the opOperand in the "paddingDimensions" using the padding value and the nofold flag found in "pa...
static LogicalResult computePaddedShape(linalg::LinalgOp opToPad, OpOperand *opOperand, const LinalgPaddingOptions &options, SmallVector< int64_t > &paddedShape, bool &alreadyHasRequestedShape)
Compute the padded shape of the given operand.
static llvm::ManagedStatic< PassManagerOptions > options
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
ArrayRef< AffineExpr > getResults() const
Attributes are known-constant values of operations.
IntegerAttr getIndexAttr(int64_t value)
TypedAttr getZeroAttr(Type type)
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.
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
This class represents an operand of an operation.
unsigned getOperandNumber()
Return which operand this is in the OpOperand list of the 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...
static FailureOr< int64_t > computeConstantBound(presburger::BoundType type, const Variable &var, StopConditionFn stopCondition=nullptr, bool closedUB=false)
Compute a constant bound for the given variable.
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.
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 paddingDimensions of all opToPad operands to a static bounding box.
FailureOr< Value > hoistPaddingOnTensors(RewriterBase &rewriter, tensor::PadOp opToHoist, int64_t numLoops, ArrayRef< int64_t > transposeVector, tensor::PadOp &hoistedOp, SmallVectorImpl< TransposeOp > &transposeOps)
Mechanically hoist padding operations on tensors by numLoops into a new, generally larger tensor.
Value makeComposedPadHighOp(OpBuilder &b, Location loc, RankedTensorType type, Value source, Value pad, bool nofold)
Create a tensor::PadOp that pads source to the size of the statically sized type whose static sizes a...
FailureOr< LinalgOp > padAndHoistLinalgOp(RewriterBase &rewriter, LinalgOp linalgOp, const LinalgPaddingOptions &options)
Apply padding and hoisting to linalgOp according to the configuration specified in options.
DynamicAPInt ceil(const Fraction &f)
Include the generated interface declarations.
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).
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
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...