[Mlir-commits] [mlir] [MLIR][Linalg] Improve morphism semantics (PR #222959)

Federico Bruzzone llvmlistbot at llvm.org
Sun Sep 13 14:00:21 PDT 2026


================
@@ -90,8 +91,57 @@ static bool findIndexOfScalarOperand(GenericOp genericOp, int &index) {
   return false;
 }
 
-// Attempt to specialize unary or binary linalg.generic ops to named elementwise
-// ops or linalg.elementwise.
+// Maps a linalg.generic body operation to its corresponding elementwise kind,
+// if one exists. Handles the ops with a straightforward one-to-one mapping;
+// ops needing extra context (e.g. boolean add/mul, reciprocal, square) are
+// handled by the caller.
+static std::optional<ElementwiseKind> getElementwiseKind(Operation *op) {
+  return llvm::TypeSwitch<Operation *, std::optional<ElementwiseKind>>(op)
+      .Case<arith::AddFOp, arith::AddIOp, complex::AddOp>(
+          [](Operation *) { return ElementwiseKind::add; })
+      .Case<arith::MulIOp, arith::MulFOp, complex::MulOp>(
+          [](Operation *) { return ElementwiseKind::mul; })
+      .Case([](math::ExpOp) { return ElementwiseKind::exp; })
+      .Case([](math::AbsFOp) { return ElementwiseKind::abs; })
+      .Case([](math::CeilOp) { return ElementwiseKind::ceil; })
+      .Case([](math::FloorOp) { return ElementwiseKind::floor; })
+      .Case([](arith::NegFOp) { return ElementwiseKind::negf; })
+      .Case([](math::RoundOp) { return ElementwiseKind::round; })
+      .Case([](math::SqrtOp) { return ElementwiseKind::sqrt; })
+      .Case([](math::RsqrtOp) { return ElementwiseKind::rsqrt; })
+      .Case([](math::TanhOp) { return ElementwiseKind::tanh; })
+      .Case([](math::ErfOp) { return ElementwiseKind::erf; })
+      .Case([](math::SinOp) { return ElementwiseKind::sin; })
+      .Case([](math::CosOp) { return ElementwiseKind::cos; })
+      .Case([](math::TanOp) { return ElementwiseKind::tan; })
+      .Case([](math::AcosOp) { return ElementwiseKind::acos; })
+      .Case([](math::AcoshOp) { return ElementwiseKind::acosh; })
+      .Case([](math::AsinOp) { return ElementwiseKind::asin; })
+      .Case([](math::AsinhOp) { return ElementwiseKind::asinh; })
+      .Case([](math::AtanOp) { return ElementwiseKind::atan; })
+      .Case([](math::AtanhOp) { return ElementwiseKind::atanh; })
+      .Case([](math::LogOp) { return ElementwiseKind::log; })
+      .Case([](math::Log10Op) { return ElementwiseKind::log10; })
+      .Case([](math::Log1pOp) { return ElementwiseKind::log1p; })
+      .Case([](math::Log2Op) { return ElementwiseKind::log2; })
+      .Case<arith::SubIOp, arith::SubFOp, complex::SubOp>(
+          [](Operation *) { return ElementwiseKind::sub; })
+      .Case<arith::DivSIOp, arith::DivFOp, complex::DivOp>(
+          [](Operation *) { return ElementwiseKind::div; })
+      .Case([](arith::DivUIOp) { return ElementwiseKind::div_unsigned; })
+      .Case<arith::MaxSIOp, arith::MaximumFOp>(
+          [](Operation *) { return ElementwiseKind::max_signed; })
+      .Case<arith::MinSIOp, arith::MinimumFOp>(
+          [](Operation *) { return ElementwiseKind::min_signed; })
+      .Case([](math::PowFOp) { return ElementwiseKind::powf; })
+      .Case([](arith::MaxUIOp) { return ElementwiseKind::max_unsigned; })
+      .Case([](arith::MinUIOp) { return ElementwiseKind::min_unsigned; })
+      .Case([](arith::SelectOp) { return ElementwiseKind::select; })
----------------
FedericoBruzzone wrote:

Please correct me if I'm missing something here :D

The `SelectOp` was not present in the previous implementation. 
The documentation of `specializeLinalgElementwise` specifies:
https://github.com/llvm/llvm-project/blob/e1a4305b37f20140819a1c768cd873f93add61b5/mlir/lib/Dialect/Linalg/Transforms/Specialize.cpp#L143-L144
But with this PR, we will end up using it also with the `SelectOp`, which is neither unary nor binary: 
https://github.com/llvm/llvm-project/blob/e1a4305b37f20140819a1c768cd873f93add61b5/mlir/lib/Dialect/Linalg/Transforms/Specialize.cpp#L239-L246
My concern is about the swap within the `replaceOp` closure:
https://github.com/llvm/llvm-project/blob/e1a4305b37f20140819a1c768cd873f93add61b5/mlir/lib/Dialect/Linalg/Transforms/Specialize.cpp#L192-L195
Because `hasSwappedOperands` does not considers ternary ops:
https://github.com/llvm/llvm-project/blob/e1a4305b37f20140819a1c768cd873f93add61b5/mlir/lib/Dialect/Linalg/Transforms/Specialize.cpp#L180

Should ternary ops be reordered here too?
For instance, consider `select %c, %f, %t` over `ins(%C, %T, %F)` becomes `elementwise <select>(C, T, F)`, which is fine. But what if the condition is the second input?




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


More information about the Mlir-commits mailing list