[Mlir-commits] [mlir] [[mlir][linalg] Infer reduction-neutral padding values in rewriteAsPaddedOp (PR #216517)

Jianhui Li llvmlistbot at llvm.org
Fri Sep 11 08:55:17 PDT 2026


================
@@ -263,6 +266,142 @@ static Value padOperand(OpBuilder &builder, TilingInterface opToPad,
                                paddingValue, /*nofold=*/false, dynDims);
 }
 
+/// Returns true if `operand` is indexed along at least one reduction dimension
+/// of `linalgOp`
+static bool isReducedOperand(linalg::LinalgOp linalgOp, OpOperand *operand,
+                             ArrayRef<utils::IteratorType> iterTypes) {
+  AffineMap map = linalgOp.getMatchingIndexingMap(operand);
+  return llvm::any_of(llvm::enumerate(iterTypes), [&](auto it) {
+    return it.value() == utils::IteratorType::reduction &&
+           map.isFunctionOfDim(it.index());
+  });
+}
+
+/// Set `paddingValues` with the padding value of every input of `contractOp`
+/// that is indexed along a reduction dimension. Fails if the pair admits no
+/// padding value.
+static LogicalResult
+setContractionPaddingValues(OpBuilder &builder, linalg::LinalgOp contractOp,
+                            Operation *mul, Operation *add,
+                            ArrayRef<utils::IteratorType> iterTypes,
+                            MutableArrayRef<Attribute> paddingValues) {
+  // Identify the padding value, `p`, for which `mul(p, x)` is the neutral
+  // element of `add` for every `x`.
+  // Not every contraction can be zero-padded: a body with `mul` = `addf` and
+  // `add` = `maximumf` (a max-plus contraction) pads with `-inf` instead.
+  auto getPadValue = [&](Type elementType) -> Attribute {
+    // `0 * x = 0` and `0 + acc = acc`.
+    if ((isa<arith::MulFOp>(mul) && isa<arith::AddFOp>(add)) ||
+        (isa<arith::MulIOp>(mul) && isa<arith::AddIOp>(add)) ||
+        (isa<complex::MulOp>(mul) && isa<complex::AddOp>(add)))
+      return builder.getZeroAttr(elementType);
+    // `false & x = false` and `false | acc = acc`.
+    if (isa<arith::AndIOp>(mul) && isa<arith::OrIOp>(add) &&
+        mul->getResult(0).getType().isInteger(1))
+      return builder.getZeroAttr(elementType);
+    return {};
+  };
+
+  for (OpOperand *input : contractOp.getDpsInputOperands()) {
+    if (!isReducedOperand(contractOp, input, iterTypes))
+      continue;
+    Attribute padValue =
+        getPadValue(getElementTypeOrSelf(input->get().getType()));
+    if (!padValue)
+      return failure();
+    paddingValues[input->getOperandNumber()] = padValue;
+  }
+  return success();
+}
+
+/// Infers a semantics-preserving padding value for every operand of `toPad`
+/// (indexed by operand number). Operands that are reduced are padded with the
+/// neutral element of their reduction combiner (e.g. `-inf` for `maximumf`, `1`
+/// for `mulf`); every other operand is padded with the zero value of its
+/// element type.
+///
+/// Inference is conservative: it returns failure when a semantics-preserving
+/// value cannot be determined (a non-LinalgOp reduction, or a reduction whose
+/// neutral element is unknown), letting callers set `options.paddingValues`
+/// explicitly instead.
+static FailureOr<SmallVector<Attribute>>
+inferPaddingValues(OpBuilder &builder, TilingInterface toPad) {
+  Operation *op = toPad.getOperation();
+
+  // Padding acts on operands; default each to the zero of its element type.
+  SmallVector<Attribute> paddingValues;
+  for (Type t : op->getOperandTypes())
+    paddingValues.push_back(builder.getZeroAttr(getElementTypeOrSelf(t)));
+
+  // No reduction: padded elements are never combined, so zero is always safe.
+  SmallVector<utils::IteratorType> iterTypes = toPad.getLoopIteratorTypes();
+  if (!llvm::is_contained(iterTypes, utils::IteratorType::reduction))
+    return paddingValues;
+
+  // A reduction's neutral element requires inspecting the combiner, which is
+  // only possible for a LinalgOp; fail conservatively otherwise.
+  auto linalgOp = dyn_cast<linalg::LinalgOp>(op);
+  if (!linalgOp)
+    return failure();
+
+  // A contraction-like body accumulates as `acc = add(mul(a, b), acc)`. Use
+  // `isContractionBody` as an extractor: it hands back these two ops, from
+  // which the padding value is derived.
+  Operation *mulOp = nullptr, *addOp = nullptr;
+  auto captureBodyOps = [&](Operation *mul, Operation *add) {
+    mulOp = mul;
+    addOp = add;
+    return true;
+  };
+  if (linalg::detail::isContractionBody(*linalgOp.getBlock(), captureBodyOps)) {
+    if (failed(setContractionPaddingValues(builder, linalgOp, mulOp, addOp,
+                                           iterTypes, paddingValues)))
+      return failure();
+    return paddingValues;
+  }
----------------
Jianhui-Li wrote:

added

https://github.com/llvm/llvm-project/pull/216517


More information about the Mlir-commits mailing list