[Mlir-commits] [mlir] [mlir][linalg] Add category-to-named conversion in linalg-morph-ops (PR #205582)
Javed Absar
llvmlistbot at llvm.org
Wed Jun 24 08:56:47 PDT 2026
https://github.com/javedabsar1 created https://github.com/llvm/llvm-project/pull/205582
Add the missing `category-to-named` morphism path that converts `linalg.elementwise` ops to their equivalent named ops (e.g. `linalg.elementwise kind=add` -> `linalg.add`). This completes the set of conversions in the linalg-morph-ops pass:
generic <---> category <---> named
The conversion only applies to elementwise ops with identity indexing maps, since named elementwise ops cannot carry custom maps. Kinds without a named op equivalent (e.g. sin, cos) are left unconverted.
>From 205cb5d84a1aef320d0e8d335b4bb859ede4dc1c Mon Sep 17 00:00:00 2001
From: mabsar <mabsar at qti.qualcommm.com>
Date: Wed, 24 Jun 2026 08:29:28 -0700
Subject: [PATCH] [mlir][linalg] Add category-to-named conversion in
linalg-morph-ops
Add the missing `category-to-named` morphism path that converts
`linalg.elementwise` ops to their equivalent named ops (e.g.
`linalg.elementwise kind=add` -> `linalg.add`). This completes
the set of conversions in the linalg-morph-ops pass:
generic <---> category <---> named
The conversion only applies to elementwise ops with identity indexing
maps, since named elementwise ops cannot carry custom maps. Kinds
without a named op equivalent (e.g. sin, cos) are left unconverted.
---
mlir/include/mlir/Dialect/Linalg/Passes.td | 5 +-
.../Dialect/Linalg/Transforms/Transforms.h | 5 +
.../Dialect/Linalg/Transforms/CMakeLists.txt | 1 +
.../Transforms/ElementwiseToNamedOp.cpp | 104 +++++++
.../Dialect/Linalg/Transforms/MorphOps.cpp | 2 +
.../linalg-morph-elementwise-to-named.mlir | 283 ++++++++++++++++++
6 files changed, 398 insertions(+), 2 deletions(-)
create mode 100644 mlir/lib/Dialect/Linalg/Transforms/ElementwiseToNamedOp.cpp
create mode 100644 mlir/test/Dialect/Linalg/linalg-morph-elementwise-to-named.mlir
diff --git a/mlir/include/mlir/Dialect/Linalg/Passes.td b/mlir/include/mlir/Dialect/Linalg/Passes.td
index b873f260e7d928..3a43af9ca18554 100644
--- a/mlir/include/mlir/Dialect/Linalg/Passes.td
+++ b/mlir/include/mlir/Dialect/Linalg/Passes.td
@@ -72,8 +72,9 @@ def LinalgMorphOpsPass : Pass<"linalg-morph-ops"> {
Option<"genericToNamed", "generic-to-named", "bool", /*default=*/"false",
"convert linalg.generic to equivalent named ops">,
Option<"genericToCategory", "generic-to-category", "bool", /*default=*/"false",
- "convert linalg.generic to equivalent category ops"> ];
- // TODOs: `category-to-named`
+ "convert linalg.generic to equivalent category ops">,
+ Option<"categoryToNamed", "category-to-named", "bool", /*default=*/"false",
+ "convert category ops e.g. `linalg.elementwise` to equivalent named ops"> ];
}
def LinalgGeneralizeNamedOpsPass : Pass<"linalg-generalize-named-ops">,
diff --git a/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h b/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h
index 486ef75b768597..836682de4c4043 100644
--- a/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h
+++ b/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h
@@ -1922,6 +1922,11 @@ void populateLinalgGenericOpsSpecializationPatterns(
/// to equivalent `linalg.elementwise`.
void populateLinalgNamedToElementwisePatterns(RewritePatternSet &patterns);
+/// Populates `patterns` that convert linalg category ops (e.g.
+/// `linalg.elementwise`, `linalg.contract`) to equivalent linalg named ops
+/// (e.g. `linalg.add`, `linalg.matmul`).
+void populateLinalgCategoryToNamedPatterns(RewritePatternSet &patterns);
+
/// Populates `patterns` with patterns that fold operations like
/// `linalg.transform` into elementwise op map.
void populateLinalgFoldIntoElementwisePatterns(RewritePatternSet &patterns);
diff --git a/mlir/lib/Dialect/Linalg/Transforms/CMakeLists.txt b/mlir/lib/Dialect/Linalg/Transforms/CMakeLists.txt
index a2149478e4c2d0..b66210f46630e8 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/CMakeLists.txt
+++ b/mlir/lib/Dialect/Linalg/Transforms/CMakeLists.txt
@@ -10,6 +10,7 @@ add_mlir_dialect_library(MLIRLinalgTransforms
DropUnitDims.cpp
ElementwiseOpFusion.cpp
ElementwiseToLinalg.cpp
+ ElementwiseToNamedOp.cpp
EliminateEmptyTensors.cpp
EraseUnusedOperandsAndResults.cpp
FoldAddIntoDest.cpp
diff --git a/mlir/lib/Dialect/Linalg/Transforms/ElementwiseToNamedOp.cpp b/mlir/lib/Dialect/Linalg/Transforms/ElementwiseToNamedOp.cpp
new file mode 100644
index 00000000000000..879454b6a76768
--- /dev/null
+++ b/mlir/lib/Dialect/Linalg/Transforms/ElementwiseToNamedOp.cpp
@@ -0,0 +1,104 @@
+//===- ElementwiseToNamedOp.cpp - convert elementwise to linalg named op --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements rewriting of `linalg.elementwise` ops to their
+// equivalent linalg named ops e.g. `linalg.add`, `linalg.exp`. This is the
+// reverse of NamedToElementwise.cpp.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/Linalg/IR/Linalg.h"
+#include "mlir/Dialect/Linalg/Transforms/Transforms.h"
+#include "mlir/IR/PatternMatch.h"
+
+using namespace mlir;
+using namespace mlir::linalg;
+
+#define DEBUG_TYPE "linalg-elementwise-to-named"
+
+namespace {
+struct ElementwiseToNamedPattern : public OpRewritePattern<ElementwiseOp> {
+ using OpRewritePattern<ElementwiseOp>::OpRewritePattern;
+
+ LogicalResult matchAndRewrite(ElementwiseOp op,
+ PatternRewriter &rewriter) const override {
+ // Named elementwise ops only support identity indexing maps.
+ if (!op.getIndexingMapsArray().empty() &&
+ !llvm::all_of(op.getIndexingMapsArray(),
+ [](AffineMap map) { return map.isIdentity(); }))
+ return failure();
+
+ auto inputs = op.getDpsInputs();
+ auto inits = op.getDpsInits();
+ auto loc = op.getLoc();
+
+ // Helper to create a named op and replace the elementwise op.
+ auto replaceWith = [&](auto namedOp) {
+ using OpTy = decltype(namedOp);
+ rewriter.replaceOp(
+ op, OpTy::create(rewriter, loc, inputs, inits,
+ ArrayRef<NamedAttribute>{}));
+ return success();
+ };
+
+ switch (op.getKind()) {
+ case ElementwiseKind::exp:
+ return replaceWith(ExpOp{});
+ case ElementwiseKind::log:
+ return replaceWith(LogOp{});
+ case ElementwiseKind::abs:
+ return replaceWith(AbsOp{});
+ case ElementwiseKind::ceil:
+ return replaceWith(CeilOp{});
+ case ElementwiseKind::floor:
+ return replaceWith(FloorOp{});
+ case ElementwiseKind::negf:
+ return replaceWith(NegFOp{});
+ case ElementwiseKind::reciprocal:
+ return replaceWith(ReciprocalOp{});
+ case ElementwiseKind::round:
+ return replaceWith(RoundOp{});
+ case ElementwiseKind::sqrt:
+ return replaceWith(SqrtOp{});
+ case ElementwiseKind::rsqrt:
+ return replaceWith(RsqrtOp{});
+ case ElementwiseKind::square:
+ return replaceWith(SquareOp{});
+ case ElementwiseKind::tanh:
+ return replaceWith(TanhOp{});
+ case ElementwiseKind::erf:
+ return replaceWith(ErfOp{});
+ case ElementwiseKind::add:
+ return replaceWith(AddOp{});
+ case ElementwiseKind::sub:
+ return replaceWith(SubOp{});
+ case ElementwiseKind::mul:
+ return replaceWith(MulOp{});
+ case ElementwiseKind::div:
+ return replaceWith(DivOp{});
+ case ElementwiseKind::div_unsigned:
+ return replaceWith(DivUnsignedOp{});
+ case ElementwiseKind::max_signed:
+ return replaceWith(MaxOp{});
+ case ElementwiseKind::min_signed:
+ return replaceWith(MinOp{});
+ case ElementwiseKind::powf:
+ return replaceWith(PowFOp{});
+ case ElementwiseKind::select:
+ return replaceWith(SelectOp{});
+ default:
+ return failure();
+ }
+ }
+};
+} // namespace
+
+void mlir::linalg::populateLinalgCategoryToNamedPatterns(
+ RewritePatternSet &patterns) {
+ patterns.add<ElementwiseToNamedPattern>(patterns.getContext());
+}
diff --git a/mlir/lib/Dialect/Linalg/Transforms/MorphOps.cpp b/mlir/lib/Dialect/Linalg/Transforms/MorphOps.cpp
index fee293647deda8..7d360ee734249a 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/MorphOps.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/MorphOps.cpp
@@ -50,6 +50,8 @@ void LinalgMorphOpsPass::runOnOperation() {
populateLinalgNamedOpsGeneralizationPatterns(patterns);
// Lifting paths (named <- category <- generic)
+ if (categoryToNamed)
+ populateLinalgCategoryToNamedPatterns(patterns);
if (genericToNamed || genericToCategory) {
GenericOpSpecializationOptions opts;
opts.emitCategoryOps = genericToCategory;
diff --git a/mlir/test/Dialect/Linalg/linalg-morph-elementwise-to-named.mlir b/mlir/test/Dialect/Linalg/linalg-morph-elementwise-to-named.mlir
new file mode 100644
index 00000000000000..5c05721aeb858c
--- /dev/null
+++ b/mlir/test/Dialect/Linalg/linalg-morph-elementwise-to-named.mlir
@@ -0,0 +1,283 @@
+// Forward path `category -> named`
+// RUN: mlir-opt %s -linalg-morph-ops=category-to-named -split-input-file | \
+// RUN: FileCheck %s --check-prefix=ALL,CATEGORY_TO_NAMED
+// RUN: mlir-opt %s -linalg-morph-ops=category-to-named -split-input-file | \
+// RUN: mlir-opt -linalg-morph-ops=named-to-category -split-input-file | \
+// RUN: mlir-opt -linalg-morph-ops=category-to-named -split-input-file | \
+// RUN: FileCheck %s --check-prefix=ALL,ROUND_TRIP
+
+func.func @unary_ops(%A : tensor<16x8xf32>, %B : tensor<16x8xf32>) -> tensor<16x8xf32> {
+ %exp = linalg.elementwise kind=#linalg.elementwise_kind<exp>
+ ins(%A : tensor<16x8xf32>) outs(%B : tensor<16x8xf32>) -> tensor<16x8xf32>
+ %log = linalg.elementwise kind=#linalg.elementwise_kind<log>
+ ins(%exp : tensor<16x8xf32>) outs(%B : tensor<16x8xf32>) -> tensor<16x8xf32>
+ %abs = linalg.elementwise kind=#linalg.elementwise_kind<abs>
+ ins(%log : tensor<16x8xf32>) outs(%B : tensor<16x8xf32>) -> tensor<16x8xf32>
+ %ceil = linalg.elementwise kind=#linalg.elementwise_kind<ceil>
+ ins(%abs : tensor<16x8xf32>) outs(%B : tensor<16x8xf32>) -> tensor<16x8xf32>
+ %floor = linalg.elementwise kind=#linalg.elementwise_kind<floor>
+ ins(%ceil : tensor<16x8xf32>) outs(%B : tensor<16x8xf32>) -> tensor<16x8xf32>
+ %negf = linalg.elementwise kind=#linalg.elementwise_kind<negf>
+ ins(%floor : tensor<16x8xf32>) outs(%B : tensor<16x8xf32>) -> tensor<16x8xf32>
+ %recip = linalg.elementwise kind=#linalg.elementwise_kind<reciprocal>
+ ins(%negf : tensor<16x8xf32>) outs(%B : tensor<16x8xf32>) -> tensor<16x8xf32>
+ %round = linalg.elementwise kind=#linalg.elementwise_kind<round>
+ ins(%recip : tensor<16x8xf32>) outs(%B : tensor<16x8xf32>) -> tensor<16x8xf32>
+ %sqrt = linalg.elementwise kind=#linalg.elementwise_kind<sqrt>
+ ins(%round : tensor<16x8xf32>) outs(%B : tensor<16x8xf32>) -> tensor<16x8xf32>
+ %rsqrt = linalg.elementwise kind=#linalg.elementwise_kind<rsqrt>
+ ins(%sqrt : tensor<16x8xf32>) outs(%B : tensor<16x8xf32>) -> tensor<16x8xf32>
+ %square = linalg.elementwise kind=#linalg.elementwise_kind<square>
+ ins(%rsqrt : tensor<16x8xf32>) outs(%B : tensor<16x8xf32>) -> tensor<16x8xf32>
+ %tanh = linalg.elementwise kind=#linalg.elementwise_kind<tanh>
+ ins(%square : tensor<16x8xf32>) outs(%B : tensor<16x8xf32>) -> tensor<16x8xf32>
+ %erf = linalg.elementwise kind=#linalg.elementwise_kind<erf>
+ ins(%tanh : tensor<16x8xf32>) outs(%B : tensor<16x8xf32>) -> tensor<16x8xf32>
+ return %erf : tensor<16x8xf32>
+}
+
+// ALL-LABEL: unary_ops
+// ALL-SAME: %[[A:.+]]: tensor<16x8xf32>, %[[B:.+]]: tensor<16x8xf32>)
+// ALL-NOT: linalg.elementwise
+// CATEGORY_TO_NAMED: %[[EXP:.+]] = linalg.exp
+// CATEGORY_TO_NAMED-SAME: ins(%[[A]] : tensor<16x8xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CATEGORY_TO_NAMED: %[[LOG:.+]] = linalg.log
+// CATEGORY_TO_NAMED-SAME: ins(%[[EXP]] : tensor<16x8xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CATEGORY_TO_NAMED: %[[ABS:.+]] = linalg.abs
+// CATEGORY_TO_NAMED-SAME: ins(%[[LOG]] : tensor<16x8xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CATEGORY_TO_NAMED: %[[CEIL:.+]] = linalg.ceil
+// CATEGORY_TO_NAMED-SAME: ins(%[[ABS]] : tensor<16x8xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CATEGORY_TO_NAMED: %[[FLOOR:.+]] = linalg.floor
+// CATEGORY_TO_NAMED-SAME: ins(%[[CEIL]] : tensor<16x8xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CATEGORY_TO_NAMED: %[[NEGF:.+]] = linalg.negf
+// CATEGORY_TO_NAMED-SAME: ins(%[[FLOOR]] : tensor<16x8xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CATEGORY_TO_NAMED: %[[RECIP:.+]] = linalg.reciprocal
+// CATEGORY_TO_NAMED-SAME: ins(%[[NEGF]] : tensor<16x8xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CATEGORY_TO_NAMED: %[[ROUND:.+]] = linalg.round
+// CATEGORY_TO_NAMED-SAME: ins(%[[RECIP]] : tensor<16x8xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CATEGORY_TO_NAMED: %[[SQRT:.+]] = linalg.sqrt
+// CATEGORY_TO_NAMED-SAME: ins(%[[ROUND]] : tensor<16x8xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CATEGORY_TO_NAMED: %[[RSQRT:.+]] = linalg.rsqrt
+// CATEGORY_TO_NAMED-SAME: ins(%[[SQRT]] : tensor<16x8xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CATEGORY_TO_NAMED: %[[SQUARE:.+]] = linalg.square
+// CATEGORY_TO_NAMED-SAME: ins(%[[RSQRT]] : tensor<16x8xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CATEGORY_TO_NAMED: %[[TANH:.+]] = linalg.tanh
+// CATEGORY_TO_NAMED-SAME: ins(%[[SQUARE]] : tensor<16x8xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CATEGORY_TO_NAMED: linalg.erf
+// CATEGORY_TO_NAMED-SAME: ins(%[[TANH]] : tensor<16x8xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+
+// ROUND_TRIP: linalg.exp
+// ROUND_TRIP-SAME: ins(%[[A]] : tensor<16x8xf32>)
+// ROUND_TRIP-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// ROUND_TRIP: linalg.log
+// ROUND_TRIP: linalg.abs
+// ROUND_TRIP: linalg.ceil
+// ROUND_TRIP: linalg.floor
+// ROUND_TRIP: linalg.negf
+// ROUND_TRIP: linalg.reciprocal
+// ROUND_TRIP: linalg.round
+// ROUND_TRIP: linalg.sqrt
+// ROUND_TRIP: linalg.rsqrt
+// ROUND_TRIP: linalg.square
+// ROUND_TRIP: linalg.tanh
+// ROUND_TRIP: linalg.erf
+// ROUND_TRIP-NOT: linalg.elementwise
+
+// -----
+
+func.func @binary_ops_int(%A: tensor<?x?xi32>, %B: tensor<?x?xi32>,
+ %Out: tensor<?x?xi32>) -> tensor<?x?xi32> {
+ %0 = linalg.elementwise kind=#linalg.elementwise_kind<add>
+ ins(%A, %B : tensor<?x?xi32>, tensor<?x?xi32>)
+ outs(%Out : tensor<?x?xi32>) -> tensor<?x?xi32>
+ %1 = linalg.elementwise kind=#linalg.elementwise_kind<sub>
+ ins(%0, %B : tensor<?x?xi32>, tensor<?x?xi32>)
+ outs(%Out : tensor<?x?xi32>) -> tensor<?x?xi32>
+ %2 = linalg.elementwise kind=#linalg.elementwise_kind<mul>
+ ins(%1, %B : tensor<?x?xi32>, tensor<?x?xi32>)
+ outs(%Out : tensor<?x?xi32>) -> tensor<?x?xi32>
+ %3 = linalg.elementwise kind=#linalg.elementwise_kind<div>
+ ins(%2, %B : tensor<?x?xi32>, tensor<?x?xi32>)
+ outs(%Out : tensor<?x?xi32>) -> tensor<?x?xi32>
+ %4 = linalg.elementwise kind=#linalg.elementwise_kind<div_unsigned>
+ ins(%3, %B : tensor<?x?xi32>, tensor<?x?xi32>)
+ outs(%Out : tensor<?x?xi32>) -> tensor<?x?xi32>
+ %5 = linalg.elementwise kind=#linalg.elementwise_kind<max_signed>
+ ins(%4, %B : tensor<?x?xi32>, tensor<?x?xi32>)
+ outs(%Out : tensor<?x?xi32>) -> tensor<?x?xi32>
+ %6 = linalg.elementwise kind=#linalg.elementwise_kind<min_signed>
+ ins(%5, %B : tensor<?x?xi32>, tensor<?x?xi32>)
+ outs(%Out : tensor<?x?xi32>) -> tensor<?x?xi32>
+ return %6 : tensor<?x?xi32>
+}
+
+// ALL-LABEL: binary_ops_int
+// ALL-SAME: %[[A:.+]]: tensor<?x?xi32>, %[[B:.+]]: tensor<?x?xi32>,
+// ALL-SAME: %[[OUT:.+]]: tensor<?x?xi32>)
+// ALL-NOT: linalg.elementwise
+// CATEGORY_TO_NAMED: %[[ADD:.+]] = linalg.add
+// CATEGORY_TO_NAMED-SAME: ins(%[[A]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+// CATEGORY_TO_NAMED: %[[SUB:.+]] = linalg.sub
+// CATEGORY_TO_NAMED-SAME: ins(%[[ADD]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+// CATEGORY_TO_NAMED: %[[MUL:.+]] = linalg.mul
+// CATEGORY_TO_NAMED-SAME: ins(%[[SUB]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+// CATEGORY_TO_NAMED: %[[DIV:.+]] = linalg.div
+// CATEGORY_TO_NAMED-SAME: ins(%[[MUL]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+// CATEGORY_TO_NAMED: %[[DIVU:.+]] = linalg.div_unsigned
+// CATEGORY_TO_NAMED-SAME: ins(%[[DIV]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+// CATEGORY_TO_NAMED: %[[MAX:.+]] = linalg.max
+// CATEGORY_TO_NAMED-SAME: ins(%[[DIVU]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+// CATEGORY_TO_NAMED: linalg.min
+// CATEGORY_TO_NAMED-SAME: ins(%[[MAX]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+
+// ROUND_TRIP: linalg.add
+// ROUND_TRIP-SAME: ins(%[[A]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// ROUND_TRIP-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+// ROUND_TRIP: linalg.sub
+// ROUND_TRIP: linalg.mul
+// ROUND_TRIP: linalg.div
+// ROUND_TRIP: linalg.div_unsigned
+// ROUND_TRIP: linalg.max
+// ROUND_TRIP: linalg.min
+// ROUND_TRIP-NOT: linalg.elementwise
+
+// -----
+
+func.func @binary_ops_float(%A: tensor<?x?xf32>, %B: tensor<?x?xf32>,
+ %Out: tensor<?x?xf32>) -> tensor<?x?xf32> {
+ %0 = linalg.elementwise kind=#linalg.elementwise_kind<add>
+ ins(%A, %B : tensor<?x?xf32>, tensor<?x?xf32>)
+ outs(%Out : tensor<?x?xf32>) -> tensor<?x?xf32>
+ %1 = linalg.elementwise kind=#linalg.elementwise_kind<sub>
+ ins(%0, %B : tensor<?x?xf32>, tensor<?x?xf32>)
+ outs(%Out : tensor<?x?xf32>) -> tensor<?x?xf32>
+ %2 = linalg.elementwise kind=#linalg.elementwise_kind<mul>
+ ins(%1, %B : tensor<?x?xf32>, tensor<?x?xf32>)
+ outs(%Out : tensor<?x?xf32>) -> tensor<?x?xf32>
+ %3 = linalg.elementwise kind=#linalg.elementwise_kind<div>
+ ins(%2, %B : tensor<?x?xf32>, tensor<?x?xf32>)
+ outs(%Out : tensor<?x?xf32>) -> tensor<?x?xf32>
+ %4 = linalg.elementwise kind=#linalg.elementwise_kind<max_signed>
+ ins(%3, %B : tensor<?x?xf32>, tensor<?x?xf32>)
+ outs(%Out : tensor<?x?xf32>) -> tensor<?x?xf32>
+ %5 = linalg.elementwise kind=#linalg.elementwise_kind<min_signed>
+ ins(%4, %B : tensor<?x?xf32>, tensor<?x?xf32>)
+ outs(%Out : tensor<?x?xf32>) -> tensor<?x?xf32>
+ %6 = linalg.elementwise kind=#linalg.elementwise_kind<powf>
+ ins(%5, %B : tensor<?x?xf32>, tensor<?x?xf32>)
+ outs(%Out : tensor<?x?xf32>) -> tensor<?x?xf32>
+ return %6 : tensor<?x?xf32>
+}
+
+// ALL-LABEL: binary_ops_float
+// ALL-SAME: %[[A:.+]]: tensor<?x?xf32>, %[[B:.+]]: tensor<?x?xf32>,
+// ALL-SAME: %[[OUT:.+]]: tensor<?x?xf32>)
+// ALL-NOT: linalg.elementwise
+// CATEGORY_TO_NAMED: %[[ADD:.+]] = linalg.add
+// CATEGORY_TO_NAMED-SAME: ins(%[[A]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// CATEGORY_TO_NAMED: %[[SUB:.+]] = linalg.sub
+// CATEGORY_TO_NAMED-SAME: ins(%[[ADD]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// CATEGORY_TO_NAMED: %[[MUL:.+]] = linalg.mul
+// CATEGORY_TO_NAMED-SAME: ins(%[[SUB]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// CATEGORY_TO_NAMED: %[[DIV:.+]] = linalg.div
+// CATEGORY_TO_NAMED-SAME: ins(%[[MUL]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// CATEGORY_TO_NAMED: %[[MAX:.+]] = linalg.max
+// CATEGORY_TO_NAMED-SAME: ins(%[[DIV]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// CATEGORY_TO_NAMED: %[[MIN:.+]] = linalg.min
+// CATEGORY_TO_NAMED-SAME: ins(%[[MAX]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// CATEGORY_TO_NAMED: linalg.powf
+// CATEGORY_TO_NAMED-SAME: ins(%[[MIN]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+
+// ROUND_TRIP: linalg.add
+// ROUND_TRIP-SAME: ins(%[[A]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// ROUND_TRIP-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// ROUND_TRIP: linalg.sub
+// ROUND_TRIP: linalg.mul
+// ROUND_TRIP: linalg.div
+// ROUND_TRIP: linalg.max
+// ROUND_TRIP: linalg.min
+// ROUND_TRIP: linalg.powf
+// ROUND_TRIP-NOT: linalg.elementwise
+
+// -----
+
+func.func @ternary_select(%A: tensor<?x?xi1>, %B: tensor<?x?xf32>,
+ %C: tensor<?x?xf32>,
+ %Out: tensor<?x?xf32>) -> tensor<?x?xf32> {
+ %0 = linalg.elementwise kind=#linalg.elementwise_kind<select>
+ ins(%A, %B, %C : tensor<?x?xi1>, tensor<?x?xf32>, tensor<?x?xf32>)
+ outs(%Out : tensor<?x?xf32>) -> tensor<?x?xf32>
+ return %0 : tensor<?x?xf32>
+}
+
+// ALL-LABEL: ternary_select
+// ALL-SAME: %[[A:.+]]: tensor<?x?xi1>, %[[B:.+]]: tensor<?x?xf32>, %[[C:.+]]: tensor<?x?xf32>, %[[OUT:.+]]: tensor<?x?xf32>)
+// ALL-NOT: linalg.elementwise
+// CATEGORY_TO_NAMED: linalg.select
+// CATEGORY_TO_NAMED-SAME: ins(%[[A]], %[[B]], %[[C]] : tensor<?x?xi1>, tensor<?x?xf32>, tensor<?x?xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+
+// ROUND_TRIP: linalg.select
+// ROUND_TRIP-SAME: ins(%[[A]], %[[B]], %[[C]] : tensor<?x?xi1>, tensor<?x?xf32>, tensor<?x?xf32>)
+// ROUND_TRIP-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// ROUND_TRIP-NOT: linalg.elementwise
+
+// -----
+
+// Non-identity indexing maps: should NOT be converted to named op.
+func.func @non_identity_maps(%A: tensor<?xf32>, %Out: tensor<?x?xf32>) -> tensor<?x?xf32> {
+ %0 = linalg.elementwise
+ kind=#linalg.elementwise_kind<exp>
+ indexing_maps = [affine_map<(d0, d1) -> (d1)>, affine_map<(d0, d1) -> (d0, d1)>]
+ ins(%A : tensor<?xf32>) outs(%Out : tensor<?x?xf32>) -> tensor<?x?xf32>
+ return %0 : tensor<?x?xf32>
+}
+
+// ALL-LABEL: non_identity_maps
+// ALL-SAME: %[[A:.+]]: tensor<?xf32>, %[[OUT:.+]]: tensor<?x?xf32>)
+// CATEGORY_TO_NAMED: linalg.elementwise kind=#linalg.elementwise_kind<exp>
+// CATEGORY_TO_NAMED-SAME: ins(%[[A]] : tensor<?xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// CATEGORY_TO_NAMED-NOT: linalg.exp
+
+// -----
+
+// Kinds without named op equivalent: should NOT be converted.
+func.func @no_named_op(%A: tensor<?x?xf32>, %Out: tensor<?x?xf32>) -> tensor<?x?xf32> {
+ %0 = linalg.elementwise kind=#linalg.elementwise_kind<sin>
+ ins(%A : tensor<?x?xf32>) outs(%Out : tensor<?x?xf32>) -> tensor<?x?xf32>
+ return %0 : tensor<?x?xf32>
+}
+
+// ALL-LABEL: no_named_op
+// ALL-SAME: %[[A:.+]]: tensor<?x?xf32>, %[[OUT:.+]]: tensor<?x?xf32>)
+// CATEGORY_TO_NAMED: linalg.elementwise kind=#linalg.elementwise_kind<sin>
+// CATEGORY_TO_NAMED-SAME: ins(%[[A]] : tensor<?x?xf32>)
+// CATEGORY_TO_NAMED-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
More information about the Mlir-commits
mailing list