MLIR 24.0.0git
PadTilingInterface.cpp
Go to the documentation of this file.
1//===- PaddingTilingInterface.cpp - Padding of TilingInterface ops --------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
19#include "mlir/IR/AffineExpr.h"
24#include "mlir/IR/Value.h"
26#include "llvm/ADT/STLExtras.h"
27#include "llvm/Support/Casting.h"
28
29#define DEBUG_TYPE "pad-tiling-interface"
30
31using namespace mlir;
32using namespace mlir::linalg;
33using namespace mlir::tensor;
34
35#define DBGS() (llvm::dbgs() << "[" DEBUG_TYPE << "]: ")
36#define DBGSNL() (llvm::dbgs() << "\n")
37
38/// Form a "full-rank" padding specification so that the application is easy.
42 SmallVector<OpFoldResult> paddingSizes;
43 // Complete the padding specification to specify all dimensions.
44 for (size_t idx = 0, e = indexingSizes.size(); idx != e; ++idx) {
45 // Complete to zero if needed.
46 paddingSizes.push_back(options.paddingSizes.size() > idx
47 ? options.paddingSizes[idx]
48 : b.getIndexAttr(0));
49 // If a dimension is zero (either specified or completed), replace by:
50 // - 1 if we are padding to the next multiple of.
51 // - indexingSizes[idx] otherwise
52 if (isZeroInteger(paddingSizes[idx])) {
53 paddingSizes[idx] =
54 options.padToMultipleOf ? b.getIndexAttr(1) : indexingSizes[idx];
55 }
56 LLVM_DEBUG(DBGS() << "----idx: " << idx << " : " << paddingSizes[idx]
57 << "\n");
58 }
59 return paddingSizes;
60}
61
62/// Extracts the constant multiplier from an affine expression of the form
63/// `d * c` or `c * d`, where `d` is an AffineDimExpr and `c` is an
64/// AffineConstantExpr. Returns 1 if the expression is not a simple
65/// multiplication of a dimension and a constant.
67 if (auto binOp = dyn_cast<AffineBinaryOpExpr>(expr)) {
68 if (binOp.getKind() == AffineExprKind::Mul) {
69 auto lhsD = dyn_cast<AffineDimExpr>(binOp.getLHS());
70 auto rhsC = dyn_cast<AffineConstantExpr>(binOp.getRHS());
71 if (lhsD && rhsC) {
72 return rhsC.getValue();
73 }
74 auto lhsC = dyn_cast<AffineConstantExpr>(binOp.getLHS());
75 auto rhsD = dyn_cast<AffineDimExpr>(binOp.getRHS());
76 if (lhsC && rhsD) {
77 return lhsC.getValue();
78 }
79 }
80 }
81 return 1;
82}
83
84/// Compute the padded shape of the given value `v` of `RankedTensorType` given
85/// - `indexingSizes` a list of OpFoldResult.
86/// - an `indexingMap` that encodes how the shape of varies with increases
87/// in `indexingSizes`.
88/// The `indexingMap` encodes how the shape of varies with `indexingSizes`.
89/// The `indexingMap` + `indexingSizes` encoding suits StructuredOps.
90/// The implementaiton below iteratively combines increases from contributing
91/// dimensions using affine.apply operations.
92/// The padded shape is computed by evaluating the maximum accessed index per
93/// dimension, which may involve multiplying by constant factors derived from
94/// the affine indexing expressions. Currently, only a limited set of projected
95/// permutation indexing maps are supported, such as
96/// - affine_map<(d0, d1, d2) -> (d0, d1)>
97/// - affine_map<(d0, d1, d2) -> (d0, d1 + d2)>
98/// - affine_map<(d0, d1) -> (d0 * 3 + d1)>
99/// In the future, more general interfaces can be devised to encode similar
100/// shape evolutions and map between an op and its operands.
103 AffineMap indexingMap,
104 ArrayRef<OpFoldResult> indexingSizes,
106 Location loc = v.getLoc();
107 SmallVector<OpFoldResult> paddedShape;
108 auto tensorType = cast<RankedTensorType>(v.getType());
109 paddedShape.resize_for_overwrite(tensorType.getRank());
110 assert(tensorType.getRank() == indexingMap.getNumResults() &&
111 "expect the number of results of the affine map to match the tensor "
112 "rank");
113
114 // "Full-rank" padding specification.
115 SmallVector<OpFoldResult> paddingSizes =
116 getFullRankPaddingSizes(builder, indexingSizes, options);
117
118 // For each dimension in the operand's shape, iterate over indexingSizes and
119 // add the various term contributions.
120 for (const auto &enResults : enumerate(indexingMap.getResults())) {
121 int64_t resultIndex = enResults.index();
122 AffineMap partialIndexingMap = indexingMap.getSubMap(
123 ArrayRef<unsigned>{static_cast<unsigned>(resultIndex)});
124
125 LLVM_DEBUG(DBGS() << "----resultIndex: " << resultIndex
126 << " with partialIndexingMap: " << partialIndexingMap
127 << "\n");
128
129 // Find all padding dimensions that contribute to this operand dimension
130 // and compute the padded term contribution to the final padded shape.
132 for (size_t paddingDim = 0, e = paddingSizes.size(); paddingDim != e;
133 ++paddingDim) {
134 OpFoldResult paddingSize = paddingSizes[paddingDim];
135 LLVM_DEBUG(DBGS() << "------try apply padding of dim: " << paddingDim
136 << " to: " << paddingSize << "\n");
137 if (!enResults.value().isFunctionOfDim(paddingDim))
138 continue;
139
140 LLVM_DEBUG(DBGS() << "------apply padding of dim: " << paddingDim
141 << " to: " << paddingSize << "\n");
142
143 // Project non-'paddingDim' dimensions and compress the result.
144 llvm::SmallBitVector projectedDims(partialIndexingMap.getNumDims(), true);
145 projectedDims.flip(paddingDim);
146 AffineMap projectedMap =
147 mlir::projectDims(partialIndexingMap, projectedDims,
148 /*compressDimsFlag=*/true);
149
150 // If we are padding to the next multiple of, compose with ceil(sz) * sz.
151 OpFoldResult paddingDimOfr;
152 if (options.padToMultipleOf) {
153 AffineExpr d0, s0;
154 bindDims(builder.getContext(), d0);
155 bindSymbols(builder.getContext(), s0);
156 AffineMap ceilMap = AffineMap::get(1, 1, d0.ceilDiv(s0) * s0);
157 AffineMap composedMap = projectedMap.compose(ceilMap);
159 builder, loc, composedMap, {indexingSizes[paddingDim], paddingSize},
160 /*composeAffineMin=*/true);
161 } else {
162 // Otherwise just set to paddingSize.
164 builder, loc, projectedMap, paddingSize);
165 }
166
167 // Adjust for the maximum accessed index, which is (paddingSize - 1) *
168 // multiplier.
169 AffineExpr d0;
170 bindDims(builder.getContext(), d0);
171 int64_t multiplier = extractConstantMultiplier(projectedMap.getResult(0));
172 AffineMap subtractMap = AffineMap::get(1, 0, d0 - multiplier);
174 builder, loc, subtractMap, {paddingDimOfr});
175 terms.push_back(maxAccessIdx);
176
177 LLVM_DEBUG(DBGS() << "------new term: " << terms.back() << "\n");
178 }
179
180 // If there are no terms, just return the dim.
181 if (terms.empty()) {
182 paddedShape[resultIndex] =
183 createFoldedDimOp(builder, loc, v, resultIndex);
184 continue;
185 }
186
187 // Sum individual terms' contributions.
188 SmallVector<AffineExpr> dims(terms.size());
189 bindDimsList(builder.getContext(), MutableArrayRef{dims});
190 AffineExpr sumExpr = dims.front();
191 for (unsigned i = 1; i < dims.size(); ++i)
192 sumExpr = sumExpr + dims[i];
193 // Add 1 to the maximum accessed index and get the final padded size.
194 OpFoldResult paddedDimOfr =
195 affine::makeComposedFoldedAffineApply(builder, loc, sumExpr + 1, terms);
196 paddedShape[resultIndex] = paddedDimOfr;
197 }
198
199 return paddedShape;
200}
201
202FailureOr<SmallVector<OpFoldResult>>
204 OpBuilder &builder, OpOperand &operandToPad,
205 ArrayRef<Range> iterationDomain, const PadTilingInterfaceOptions &options) {
206 auto transferOp =
207 llvm::dyn_cast<IndexingMapOpInterface>(operandToPad.getOwner());
208 if (!transferOp)
209 return failure();
210
211 // clang-format off
212 assert(llvm::all_of(iterationDomain, [&builder](Range r) {
213 return r.offset == OpFoldResult(builder.getIndexAttr(0)) &&
214 r.stride == OpFoldResult(builder.getIndexAttr(1));
215 }) && "expected 0-offset 1-stride loop ranges");
216 // clang-format on
217 SmallVector<OpFoldResult> loopUpperBounds;
218 loopUpperBounds.reserve(iterationDomain.size());
219 for (const Range &range : iterationDomain)
220 loopUpperBounds.push_back(range.size);
221
222 AffineMap indexingMap = transferOp.getMatchingIndexingMap(&operandToPad);
223 return computePaddedShape(
224 builder, cast<TypedValue<RankedTensorType>>(operandToPad.get()),
225 indexingMap, loopUpperBounds, options);
226}
227
228/// Pad a single operand to `paddedShape` using `paddingValueAttr` as padding
229/// Value.
230static Value padOperand(OpBuilder &builder, TilingInterface opToPad,
232 ArrayRef<OpFoldResult> paddedShape,
233 Attribute paddingValueAttr) {
234 Value paddingValue;
235 if (auto complexTy =
236 dyn_cast<ComplexType>(getElementTypeOrSelf(v.getType()))) {
237 if (auto complexAttr = dyn_cast<ArrayAttr>(paddingValueAttr)) {
238 paddingValue = complex::ConstantOp::create(builder, opToPad.getLoc(),
239 complexTy, complexAttr);
240 }
241 } else if (matchPattern(paddingValueAttr, ub::m_Poison())) {
242 paddingValue = ub::PoisonOp::create(builder, opToPad.getLoc(),
243 getElementTypeOrSelf(v.getType()));
244 } else if (auto typedAttr = dyn_cast<TypedAttr>(paddingValueAttr)) {
245 paddingValue =
246 arith::ConstantOp::create(builder, opToPad.getLoc(), typedAttr);
247 }
248 assert(paddingValue && "failed to create value from padding attribute");
249
250 // Pad the operand to the bounding box defined by `paddedShape`.
251 SmallVector<int64_t> tensorShape;
252 SmallVector<Value> dynDims;
253 for (OpFoldResult ofr : paddedShape) {
254 std::optional<int64_t> cst = getConstantIntValue(ofr);
255 tensorShape.push_back(cst.has_value() ? *cst : ShapedType::kDynamic);
256 if (!cst.has_value())
257 dynDims.push_back(ofr.dyn_cast<Value>());
258 }
259 // TODO: use dispatchIndexOpFoldResults(paddedShape, dynDims, paddedShape);
260
261 auto paddedTensorType =
262 RankedTensorType::get(tensorShape, getElementTypeOrSelf(v));
263 LLVM_DEBUG(DBGS() << "--SUCCESS, makeComposedPadHighOp with type: "
264 << paddedTensorType);
265 return makeComposedPadHighOp(builder, opToPad.getLoc(), paddedTensorType, v,
266 paddingValue, /*nofold=*/false, dynDims);
267}
268
269/// Returns true if `operand` is indexed along at least one reduction dimension
270/// of `linalgOp`
271static bool isReducedOperand(linalg::LinalgOp linalgOp, OpOperand *operand,
273 assert(operand->getOwner() == linalgOp.getOperation() &&
274 "expected operand to belong to the LinalgOp");
275
276 AffineMap map = linalgOp.getMatchingIndexingMap(operand);
277 return llvm::any_of(llvm::enumerate(iterTypes), [&](auto it) {
278 return it.value() == utils::IteratorType::reduction &&
279 map.isFunctionOfDim(it.index());
280 });
281}
282
283/// On success, returns a vector with pad values for every operand of linalgOp.
284/// Fails if the body of `linalgOp` is not contraction-like, or if its
285/// `elemwise`/`reduce` pair admits no padding value.
286static FailureOr<SmallVector<Attribute>>
287inferContractionPaddingValues(OpBuilder &builder, linalg::LinalgOp linalgOp,
289 ArrayRef<Attribute> defaultPadVals) {
290 // NOTE: For contraction-like Ops, we infer the padding value by looking at
291 // both elemwise and reduce Ops, where (see isContractionBody for details):
292 // %0 = <elemwise>(permutation-of(cu(block-argument-0),
293 // cu(block-argument-1)))
294 // %1 = <reduce>(permutation-of(cu(%0), cu(block-argument-2)))
295 // return-like cu(%1)
296 Operation *elemwise = nullptr, *reduce = nullptr;
297 auto captureBodyOps = [&](Operation *e, Operation *r) {
298 elemwise = e;
299 reduce = r;
300 return true;
301 };
302 if (!linalg::detail::isContractionBody(*linalgOp.getBlock(), captureBodyOps))
303 return failure();
304
305 // Identify the padding value, `p`, for which `elemwise(p, x)` is the neutral
306 // element of `reduce` for every `x`.
307 // Not every contraction can be zero-padded: a body with `elemwise` =
308 // `arith.addf` and `reduce` = `arith.maximumf` (a max-plus contraction) pads
309 // with `-inf` instead.
310 auto getPadValue = [&](Type elementType) -> Attribute {
311 // `0 * x = 0` and `0 + acc = acc`.
312 if ((isa<arith::MulFOp>(elemwise) && isa<arith::AddFOp>(reduce)) ||
313 (isa<arith::MulIOp>(elemwise) && isa<arith::AddIOp>(reduce)) ||
314 (isa<complex::MulOp>(elemwise) && isa<complex::AddOp>(reduce)))
315 return builder.getZeroAttr(elementType);
316 // `false & x = false` and `false | acc = acc`.
317 if (isa<arith::AndIOp>(elemwise) && isa<arith::OrIOp>(reduce) &&
318 elemwise->getResult(0).getType().isInteger(1))
319 return builder.getZeroAttr(elementType);
320 return {};
321 };
322
323 SmallVector<Attribute> paddingValues(defaultPadVals.begin(),
324 defaultPadVals.end());
325 for (OpOperand *input : linalgOp.getDpsInputOperands()) {
326 if (!isReducedOperand(linalgOp, input, iterTypes))
327 continue;
328 Attribute padValue =
329 getPadValue(getElementTypeOrSelf(input->get().getType()));
330 if (!padValue)
331 return failure();
332 paddingValues[input->getOperandNumber()] = padValue;
333 }
334 return paddingValues;
335}
336
337/// Infers a semantics-preserving padding value for every operand of `toPad`
338/// (indexed by operand number). Operands that are reduced are padded with the
339/// neutral element of their reduction combiner (e.g. `-inf` for `maximumf`, `1`
340/// for `mulf`); every other operand is padded with the zero value of its
341/// element type.
342///
343/// Inference is conservative: it returns failure when a semantics-preserving
344/// value cannot be determined (a non-LinalgOp reduction, or a reduction whose
345/// neutral element is unknown), letting callers set `options.paddingValues`
346/// explicitly instead.
347static FailureOr<SmallVector<Attribute>>
348inferPaddingValues(OpBuilder &builder, TilingInterface toPad) {
349 Operation *op = toPad.getOperation();
350
351 // Padding acts on operands; default each to the zero of its element type.
352 SmallVector<Attribute> paddingValues;
353 for (Type t : op->getOperandTypes())
354 paddingValues.push_back(builder.getZeroAttr(getElementTypeOrSelf(t)));
355
356 // No reduction: padded elements are never combined, so zero is always safe.
357 SmallVector<utils::IteratorType> iterTypes = toPad.getLoopIteratorTypes();
358 if (!llvm::is_contained(iterTypes, utils::IteratorType::reduction))
359 return paddingValues;
360
361 // A reduction's neutral element requires inspecting the combiner, which is
362 // only possible for a LinalgOp; fail conservatively otherwise.
363 auto linalgOp = dyn_cast<linalg::LinalgOp>(op);
364 if (!linalgOp)
365 return failure();
366
367 // A contraction-like body accumulates as `acc = reduce(elemwise(a, b), acc)`
368 // and pads with a value derived from that pair.
369 FailureOr<SmallVector<Attribute>> contractionValues =
370 inferContractionPaddingValues(builder, linalgOp, iterTypes,
371 paddingValues);
372 if (succeeded(contractionValues))
373 return *contractionValues;
374
375 // Only a single reduction has an unambiguous per-operand neutral.
376 if (linalgOp.getNumDpsInits() != 1)
377 return failure();
378
379 // For reduction-like bodies, the neutral element of the combiner is used to
380 // pad the reduced operands.
381 SmallVector<Operation *> combiners;
382 if (!matchReduction(linalgOp.getRegionOutputArgs(), /*redPos=*/0, combiners))
383 return failure();
384 if (combiners.size() != 1)
385 return failure();
386 Operation *combiner = combiners.front();
387
388 std::optional<TypedAttr> neutral = arith::getNeutralElement(combiner);
389 if (!neutral)
390 return failure();
391
392 // In case fastMath is enabled with `nnan`, the neutral element of
393 // `maxnumf`/`minnumf`, NaN, becomes an invalid padding value. Bail out and
394 // let the caller supply a value explicitly.
395 if (auto floatNeutral = dyn_cast<FloatAttr>(*neutral);
396 floatNeutral && floatNeutral.getValue().isNaN()) {
397 auto fastMath = dyn_cast<arith::ArithFastMathInterface>(combiner);
398 if (fastMath &&
399 arith::bitEnumContainsAny(fastMath.getFastMathFlagsAttr().getValue(),
400 arith::FastMathFlags::nnan))
401 return failure();
402 }
403
404 for (OpOperand *input : linalgOp.getDpsInputOperands()) {
405 if (!isReducedOperand(linalgOp, input, iterTypes))
406 continue;
407 // A reduced operand must feed the combiner directly to use its neutral; an
408 // indirect one (e.g. via a math.exp) has no valid pad value -> fail.
409 if (!llvm::is_contained(linalgOp.getMatchingBlockArgument(input).getUsers(),
410 combiner))
411 return failure();
412 paddingValues[input->getOperandNumber()] = *neutral;
413 }
414 return paddingValues;
415}
416
417FailureOr<PadTilingInterfaceResult> linalg::rewriteAsPaddedOp(
418 OpBuilder &builder, TilingInterface toPad,
420 const PadSizeComputationFunction &computePaddingSizeFun) {
421 LLVM_DEBUG(DBGS() << "Start rewriteAsPaddedOp : " << toPad << "\n");
423 Location loc = toPad.getLoc();
424
425 // Allow inference of pad values if they are not explicitly specified.
426 if (options.paddingValues.empty()) {
427 FailureOr<SmallVector<Attribute>> inferred =
428 inferPaddingValues(builder, toPad);
429 if (failed(inferred)) {
430 LLVM_DEBUG(DBGS() << "Could not infer pad values: FAIL\n");
431 return failure();
432 }
433 options.paddingValues = std::move(*inferred);
434 }
435
436 if (llvm::any_of(toPad->getOperands(),
437 [](Value v) { return isa<MemRefType>(v.getType()); })) {
438 LLVM_DEBUG(DBGS() << "Not an operation on tensors: FAIL\n");
439 return failure();
440 }
441
442 // 1. Get the loopUpperBounds from the TilingInterface.
443 SmallVector<Range> iterationDomain = toPad.getIterationDomain(builder);
444
445 // 2. For each operand.
446 SmallVector<Value> newOperands;
447 newOperands.reserve(toPad->getNumOperands());
448 for (OpOperand &opOperand : toPad->getOpOperands()) {
449 Value operand = opOperand.get();
450 LLVM_DEBUG(DBGS() << "--start padding operand: " << operand << "\n");
451
452 // 2.a. Skip scalar-like operands.
453 Type operandType = operand.getType();
454 if (!isa<RankedTensorType>(operandType)) {
455 assert((!isa<ShapedType>(operandType) || isa<VectorType>(operandType)) &&
456 "Unexpected non-vector ShapedType");
457 newOperands.push_back(operand);
458 continue;
459 }
460
461 // 2.a. Compute padded shape.
462 FailureOr<SmallVector<OpFoldResult>> maybePaddedShape =
463 computePaddingSizeFun(builder, opOperand, iterationDomain, options);
464 if (failed(maybePaddedShape)) {
465 LLVM_DEBUG(DBGS() << "Could not get padded shape of operand: FAIL\n");
466 return failure();
467 }
468
469 // 2.b. Expect proper `paddingValues`.
470 // TODO: we may want to allow garbage padding in the future, in which case
471 // we would just not assert.
472 if (opOperand.getOperandNumber() >= options.paddingValues.size()) {
473 LLVM_DEBUG(DBGS() << "Too few padding values specified: FAIL\n");
474 return failure();
475 }
476 Attribute paddingValueAttr =
477 options.paddingValues[opOperand.getOperandNumber()];
478
479 // 2.c. Perform actual padding.
480 Value paddedOperand =
481 padOperand(builder, toPad, cast<TypedValue<RankedTensorType>>(operand),
482 *maybePaddedShape, paddingValueAttr);
483 LLVM_DEBUG(DBGS() << "--done padding operand: " << paddedOperand << "\n");
484
485 newOperands.push_back(paddedOperand);
486 if (auto padOp = paddedOperand.getDefiningOp<tensor::PadOp>())
487 padOps.push_back(padOp);
488 }
489
490 // 3. Form the resulting tensor::ExtractSliceOp.
491 ReifiedRankedShapedTypeDims reifiedResultShapes;
492 if (failed(reifyResultShapes(builder, toPad, reifiedResultShapes))) {
493 LLVM_DEBUG(DBGS() << "Failed to reify result shapes: FAIL\n");
494 return failure();
495 }
496 assert(reifiedResultShapes.size() == toPad->getNumResults() &&
497 "expected same number of results");
498
499 // Clone `toPad` to operate on the statically padded shapes.
500 auto resultTensorTypes =
501 ValueRange(newOperands).take_back(toPad->getNumResults()).getTypes();
502 // clone **should** properly notify the builder.
503 TilingInterface paddedOp =
504 clone(builder, toPad, resultTensorTypes, newOperands);
505 LLVM_DEBUG(DBGS() << "--cloned padded op: " << paddedOp << "\n");
506
507 // Recover the slice out of the new static results.
508 SmallVector<Value> paddedSubtensorResults;
509 paddedSubtensorResults.reserve(toPad->getNumResults());
510 for (const auto &en : llvm::enumerate(paddedOp->getResults())) {
511 Value paddedResult = en.value();
512 int64_t resultNumber = en.index();
513 int64_t rank = cast<RankedTensorType>(paddedResult.getType()).getRank();
514 SmallVector<OpFoldResult> offsets(rank, builder.getIndexAttr(0));
515 SmallVector<OpFoldResult> strides(rank, builder.getIndexAttr(1));
516 paddedSubtensorResults.push_back(tensor::ExtractSliceOp::create(
517 builder, loc, paddedResult, offsets, reifiedResultShapes[resultNumber],
518 strides));
519 }
520
521 return PadTilingInterfaceResult{padOps, paddedOp, paddedSubtensorResults};
522}
static Value reduce(OpBuilder &builder, Location loc, Value input, Value output, int64_t dim)
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
static bool isReducedOperand(linalg::LinalgOp linalgOp, OpOperand *operand, ArrayRef< utils::IteratorType > iterTypes)
Returns true if operand is indexed along at least one reduction dimension of linalgOp
static FailureOr< SmallVector< Attribute > > inferContractionPaddingValues(OpBuilder &builder, linalg::LinalgOp linalgOp, ArrayRef< utils::IteratorType > iterTypes, ArrayRef< Attribute > defaultPadVals)
On success, returns a vector with pad values for every operand of linalgOp.
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 FailureOr< SmallVector< Attribute > > inferPaddingValues(OpBuilder &builder, TilingInterface toPad)
Infers a semantics-preserving padding value for every operand of toPad (indexed by operand number).
#define DBGS()
static int64_t extractConstantMultiplier(AffineExpr expr)
Extracts the constant multiplier from an affine expression of the form d * c or c * d,...
static Value padOperand(OpBuilder &builder, TilingInterface opToPad, TypedValue< RankedTensorType > v, ArrayRef< OpFoldResult > paddedShape, Attribute paddingValueAttr)
Pad a single operand to paddedShape using paddingValueAttr as padding Value.
static llvm::ManagedStatic< PassManagerOptions > options
Base type for affine expression.
Definition AffineExpr.h:68
AffineExpr ceilDiv(uint64_t v) const
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition AffineMap.h:46
bool isFunctionOfDim(unsigned position) const
Return true if any affine expression involves AffineDimExpr position.
Definition AffineMap.h:221
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.
Definition Attributes.h:25
This class is a general helper class for creating context-global objects like types,...
Definition Builders.h:51
IntegerAttr getIndexAttr(int64_t value)
Definition Builders.cpp:116
TypedAttr getZeroAttr(Type type)
Definition Builders.cpp:333
MLIRContext * getContext() const
Definition Builders.h:56
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...
Definition Location.h:76
This class helps build Operations.
Definition Builders.h:210
This class represents a single result from folding an operation.
This class represents an operand of an operation.
Definition Value.h:254
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition Operation.h:432
operand_type_range getOperandTypes()
Definition Operation.h:422
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
bool isInteger() const
Return true if this is an integer type (with the specified width).
Definition Types.cpp:58
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Type getType() const
Return the type of this value.
Definition Value.h:105
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition Value.cpp:18
Operation * getOwner() const
Return the owner of this operand.
Definition UseDefLists.h:38
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...
std::optional< TypedAttr > getNeutralElement(Operation *op)
Return the identity numeric value associated to the give op.
bool isContractionBody(Block &block, function_ref< bool(Operation *, Operation *)> isaPair, llvm::raw_ostream &errs=mlir::thread_safe_nulls())
Returns true if the block contains a contraction of the following form:
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...
Definition Padding.cpp:244
std::function< FailureOr< SmallVector< OpFoldResult > >( OpBuilder &, OpOperand &, ArrayRef< Range >, const PadTilingInterfaceOptions &)> PadSizeComputationFunction
Definition Transforms.h:726
SmallVector< OpFoldResult > computePaddedShape(OpBuilder &, 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(OpBuilder &, OpOperand &operandToPad, ArrayRef< Range > iterationDomain, const PadTilingInterfaceOptions &)
Specific helper for Linalg ops.
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...
Definition Utils.cpp:2233
detail::poison_attr_matcher m_Poison()
Matches a poison constant (any attribute implementing PoisonAttrInterface).
Definition UBMatchers.h:46
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
Definition Matchers.h:490
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)
Definition AffineExpr.h:316
void bindDims(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to DimExpr at positions: [0 .
Definition AffineExpr.h:311
SmallVector< SmallVector< OpFoldResult > > ReifiedRankedShapedTypeDims
Value matchReduction(ArrayRef< BlockArgument > iterCarriedArgs, unsigned redPos, SmallVectorImpl< Operation * > &combinerOps)
Utility to match a generic reduction given a list of iteration-carried arguments, iterCarriedArgs and...
@ Mul
RHS of mul is always a constant or a symbolic expression.
Definition AffineExpr.h:43
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
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.
Definition Value.h:494
bool isZeroInteger(OpFoldResult v)
Return "true" if v is an integer value/attribute with constant value 0.
void bindSymbols(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to SymbolExpr at positions: [0 .
Definition AffineExpr.h:325
Operation * clone(OpBuilder &b, Operation *op, TypeRange newResultTypes, ValueRange newOperands)
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...
OpFoldResult stride
OpFoldResult offset
Operations and values created in the process of padding a TilingInterface operation.
Definition Transforms.h:739