[Mlir-commits] [mlir] [mlir][arith] Fold scaling_extf and scaling_truncf with constant operands (PR #215123)
Hung Kuan Tseng
llvmlistbot at llvm.org
Thu Aug 13 04:28:57 PDT 2026
================
@@ -1822,6 +1822,109 @@ LogicalResult arith::ExtFOp::verify() { return verifyExtOp<FloatType>(*this); }
// ScalingExtFOp
//===----------------------------------------------------------------------===//
+/// Fold `calculate` element-wise over the operands of a scaling cast op. The
+/// `constFoldBinaryOp` helpers cannot be used: they bail out unless both
+/// operands have the same type, and `in` and `scale` never do.
+static Attribute foldScalingCastOp(
+ Attribute inAttr, Attribute scaleAttr, Type resultType,
+ function_ref<std::optional<APFloat>(const APFloat &, const APFloat &)>
+ calculate) {
+ // Poison propagates, as it does in the generic constant folders.
+ if (isa_and_nonnull<ub::PoisonAttr>(inAttr))
+ return inAttr;
+ if (isa_and_nonnull<ub::PoisonAttr>(scaleAttr))
+ return scaleAttr;
+
+ if (!inAttr || !scaleAttr || !resultType)
+ return {};
+
+ if (auto inFloat = dyn_cast<FloatAttr>(inAttr)) {
+ auto scaleFloat = dyn_cast<FloatAttr>(scaleAttr);
+ if (!scaleFloat)
+ return {};
+ std::optional<APFloat> result =
+ calculate(inFloat.getValue(), scaleFloat.getValue());
+ if (!result)
+ return {};
+ return FloatAttr::get(resultType, *result);
+ }
+
+ auto inElements = dyn_cast<DenseFPElementsAttr>(inAttr);
+ auto scaleElements = dyn_cast<DenseFPElementsAttr>(scaleAttr);
+ auto shapedResultType = dyn_cast<ShapedType>(resultType);
+ if (!inElements || !scaleElements || !shapedResultType ||
+ !shapedResultType.hasStaticShape() ||
+ inElements.getNumElements() != scaleElements.getNumElements())
+ return {};
+
+ // Both operands are splats, so avoid expanding the elements out.
+ if (inElements.isSplat() && scaleElements.isSplat()) {
+ std::optional<APFloat> result =
+ calculate(inElements.getSplatValue<APFloat>(),
+ scaleElements.getSplatValue<APFloat>());
+ if (!result)
+ return {};
+ return DenseElementsAttr::get(shapedResultType, *result);
+ }
+
+ SmallVector<APFloat> results;
+ results.reserve(inElements.getNumElements());
+ auto scaleIt = scaleElements.begin();
+ for (const APFloat &in : inElements) {
+ std::optional<APFloat> result = calculate(in, *scaleIt++);
+ if (!result)
+ return {};
+ results.push_back(*result);
+ }
----------------
Tim096 wrote:
Applied, head `36f2f3a`. `zip_equal` asserts the two ranges have the same
length, which is already a precondition here -- the guard above returns `{}` when
`inElements.getNumElements() != scaleElements.getNumElements()` -- so this is
the same iteration with the length coupling made explicit.
`check-mlir` is 3848 passed / 0 failed and `git clang-format` is clean.
https://github.com/llvm/llvm-project/pull/215123
More information about the Mlir-commits
mailing list