[Mlir-commits] [mlir] [mlir][linalg] Scaled contraction op (PR #203958)
Adam Siemieniuk
llvmlistbot at llvm.org
Wed Aug 19 02:54:36 PDT 2026
================
@@ -6842,6 +6868,296 @@ Speculation::Speculatability BatchReduceMatmulOp::getSpeculatability() {
return getGenericSpeculatabilityImpl(cast<LinalgOp>(getOperation()));
}
+//===----------------------------------------------------------------------===//
+// ScaledContractOp
+//===----------------------------------------------------------------------===//
+
+SmallVector<utils::IteratorType> ScaledContractOp::getIteratorTypesArray() {
+ AffineMap outAffineMap = getIndexingMapsArray().pop_back_val();
+ // Infer iterator types based on the output.
+ SmallVector<bool> dimsInOutput(outAffineMap.getNumDims(), false);
+ for (auto result : outAffineMap.getResults()) {
+ auto dimExpr = dyn_cast<AffineDimExpr>(result);
+ assert(dimExpr && "affine_map is a projected permutation");
+ dimsInOutput[dimExpr.getPosition()] = true;
+ }
+
+ SmallVector<utils::IteratorType> iteratorTypes;
+ for (auto dimOccursInOutput : dimsInOutput)
+ iteratorTypes.push_back(dimOccursInOutput ? utils::IteratorType::parallel
+ : utils::IteratorType::reduction);
+
+ return iteratorTypes;
+}
+
+unsigned ScaledContractOp::getNumRegionArgs() { return 5; }
+
+/// Implement block region builder, which is called by 'fillStructuredOpRegion'.
+void ScaledContractOp::regionBuilder(
+ ImplicitLocOpBuilder &b, Block &block, ArrayRef<NamedAttribute> attrs,
+ function_ref<InFlightDiagnostic()> emitError) {
+ if (emitError && block.getNumArguments() != 5) {
+ emitError() << "ScaledContractOp regionBuilder expects 5 args, got "
+ << block.getNumArguments();
+ return;
+ }
+ assert(block.getNumArguments() == 5 &&
+ "ScaledContractOp regionBuilder expects 5 args");
+ RegionBuilderHelper helper(b, block);
+
+ TypeFn castSignedness = TypeFn::cast_signed;
+ auto castIter = llvm::find_if(attrs, [&](const NamedAttribute &attr) {
+ return attr.getName() == "cast";
+ });
+ if (castIter != attrs.end()) {
+ if (auto attr = llvm::dyn_cast<TypeFnAttr>(castIter->getValue()))
+ castSignedness = attr.getValue();
+ }
+
+ // TODO: Support fields with operators besides mult & add.
+ Type outType = block.getArgument(4).getType();
+
+ // Build input data value scaling.
+ // Uses specialized arith ops when possible.
+ // Otherwise, constructs computation manually.
+ auto buildScaledValue = [&](Value data, Value scale) -> Value {
+ auto dataFloatTy = dyn_cast<FloatType>(data.getType());
+ auto outFloatTy = dyn_cast<FloatType>(outType);
+ if (dataFloatTy && dyn_cast<FloatType>(scale.getType()) && outFloatTy) {
+ unsigned dataWidth = dataFloatTy.getWidth();
+ unsigned outWidth = outFloatTy.getWidth();
+ if (dataWidth < outWidth)
+ return arith::ScalingExtFOp::create(b, outType, data, scale,
+ /*fastmath=*/nullptr);
+ if (dataWidth > outWidth)
----------------
adam-smnk wrote:
> A more fundamental question is why you allow this at all (input data precision higher than accumulation precision)?
I started with the most open design in line with rest of contraction ops that allows to generally freely mix precisions.
That being said, I see no real use case where that'd be needed.
I'll restrict accumulator type to be equal or higher precision than inputs.
https://github.com/llvm/llvm-project/pull/203958
More information about the Mlir-commits
mailing list