[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 13:52:28 PDT 2026


https://github.com/javedabsar1 updated https://github.com/llvm/llvm-project/pull/205582

>From 9b51aab9844fb36f4c676f1a22c621e29283b6d5 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 +
 .../Linalg/Transforms/CategoryToNamedOp.cpp   | 104 ++++++++
 .../Dialect/Linalg/Transforms/MorphOps.cpp    |   2 +
 .../linalg-morph-elementwise-to-named.mlir    | 239 ++++++++++++++++++
 6 files changed, 354 insertions(+), 2 deletions(-)
 create mode 100644 mlir/lib/Dialect/Linalg/Transforms/CategoryToNamedOp.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 b873f260e7d92..3a43af9ca1855 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 486ef75b76859..836682de4c404 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 a2149478e4c2d..6dcc6e6d18429 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
+  CategoryToNamedOp.cpp
   EliminateEmptyTensors.cpp
   EraseUnusedOperandsAndResults.cpp
   FoldAddIntoDest.cpp
diff --git a/mlir/lib/Dialect/Linalg/Transforms/CategoryToNamedOp.cpp b/mlir/lib/Dialect/Linalg/Transforms/CategoryToNamedOp.cpp
new file mode 100644
index 0000000000000..b7ad1ef32c0ed
--- /dev/null
+++ b/mlir/lib/Dialect/Linalg/Transforms/CategoryToNamedOp.cpp
@@ -0,0 +1,104 @@
+//===- CategoryToNamedOp.cpp - convert category ops to linalg named ops ---===//
+//
+// 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 category ops (e.g.
+// `linalg.elementwise`) to their equivalent 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-category-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 fee293647deda..7d360ee734249 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 0000000000000..82365f5de8f92
--- /dev/null
+++ b/mlir/test/Dialect/Linalg/linalg-morph-elementwise-to-named.mlir
@@ -0,0 +1,239 @@
+// Category to named conversion and roundtrip (output is identical).
+// RUN: mlir-opt %s -linalg-morph-ops=category-to-named -split-input-file | \
+// RUN:   FileCheck %s
+// 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
+
+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>
+}
+
+// CHECK-LABEL: unary_ops
+// CHECK-SAME: %[[A:.+]]: tensor<16x8xf32>, %[[B:.+]]: tensor<16x8xf32>)
+// CHECK-NOT: linalg.elementwise
+// CHECK: %[[EXP:.+]] = linalg.exp
+// CHECK-SAME: ins(%[[A]] : tensor<16x8xf32>)
+// CHECK-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CHECK: %[[LOG:.+]] = linalg.log
+// CHECK-SAME: ins(%[[EXP]] : tensor<16x8xf32>)
+// CHECK-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CHECK: %[[ABS:.+]] = linalg.abs
+// CHECK-SAME: ins(%[[LOG]] : tensor<16x8xf32>)
+// CHECK-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CHECK: %[[CEIL:.+]] = linalg.ceil
+// CHECK-SAME: ins(%[[ABS]] : tensor<16x8xf32>)
+// CHECK-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CHECK: %[[FLOOR:.+]] = linalg.floor
+// CHECK-SAME: ins(%[[CEIL]] : tensor<16x8xf32>)
+// CHECK-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CHECK: %[[NEGF:.+]] = linalg.negf
+// CHECK-SAME: ins(%[[FLOOR]] : tensor<16x8xf32>)
+// CHECK-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CHECK: %[[RECIP:.+]] = linalg.reciprocal
+// CHECK-SAME: ins(%[[NEGF]] : tensor<16x8xf32>)
+// CHECK-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CHECK: %[[ROUND:.+]] = linalg.round
+// CHECK-SAME: ins(%[[RECIP]] : tensor<16x8xf32>)
+// CHECK-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CHECK: %[[SQRT:.+]] = linalg.sqrt
+// CHECK-SAME: ins(%[[ROUND]] : tensor<16x8xf32>)
+// CHECK-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CHECK: %[[RSQRT:.+]] = linalg.rsqrt
+// CHECK-SAME: ins(%[[SQRT]] : tensor<16x8xf32>)
+// CHECK-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CHECK: %[[SQUARE:.+]] = linalg.square
+// CHECK-SAME: ins(%[[RSQRT]] : tensor<16x8xf32>)
+// CHECK-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CHECK: %[[TANH:.+]] = linalg.tanh
+// CHECK-SAME: ins(%[[SQUARE]] : tensor<16x8xf32>)
+// CHECK-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+// CHECK: linalg.erf
+// CHECK-SAME: ins(%[[TANH]] : tensor<16x8xf32>)
+// CHECK-SAME: outs(%[[B]] : tensor<16x8xf32>) -> tensor<16x8xf32>
+
+// -----
+
+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>
+}
+
+// CHECK-LABEL: binary_ops_int
+// CHECK-SAME: %[[A:.+]]: tensor<?x?xi32>, %[[B:.+]]: tensor<?x?xi32>,
+// CHECK-SAME: %[[OUT:.+]]: tensor<?x?xi32>)
+// CHECK-NOT: linalg.elementwise
+// CHECK: %[[ADD:.+]] = linalg.add
+// CHECK-SAME: ins(%[[A]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+// CHECK: %[[SUB:.+]] = linalg.sub
+// CHECK-SAME: ins(%[[ADD]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+// CHECK: %[[MUL:.+]] = linalg.mul
+// CHECK-SAME: ins(%[[SUB]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+// CHECK: %[[DIV:.+]] = linalg.div
+// CHECK-SAME: ins(%[[MUL]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+// CHECK: %[[DIVU:.+]] = linalg.div_unsigned
+// CHECK-SAME: ins(%[[DIV]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+// CHECK: %[[MAX:.+]] = linalg.max
+// CHECK-SAME: ins(%[[DIVU]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+// CHECK: linalg.min
+// CHECK-SAME: ins(%[[MAX]], %[[B]] : tensor<?x?xi32>, tensor<?x?xi32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xi32>) -> tensor<?x?xi32>
+
+// -----
+
+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>
+}
+
+// CHECK-LABEL: binary_ops_float
+// CHECK-SAME: %[[A:.+]]: tensor<?x?xf32>, %[[B:.+]]: tensor<?x?xf32>,
+// CHECK-SAME: %[[OUT:.+]]: tensor<?x?xf32>)
+// CHECK-NOT: linalg.elementwise
+// CHECK: %[[ADD:.+]] = linalg.add
+// CHECK-SAME: ins(%[[A]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// CHECK: %[[SUB:.+]] = linalg.sub
+// CHECK-SAME: ins(%[[ADD]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// CHECK: %[[MUL:.+]] = linalg.mul
+// CHECK-SAME: ins(%[[SUB]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// CHECK: %[[DIV:.+]] = linalg.div
+// CHECK-SAME: ins(%[[MUL]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// CHECK: %[[MAX:.+]] = linalg.max
+// CHECK-SAME: ins(%[[DIV]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// CHECK: %[[MIN:.+]] = linalg.min
+// CHECK-SAME: ins(%[[MAX]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// CHECK: linalg.powf
+// CHECK-SAME: ins(%[[MIN]], %[[B]] : tensor<?x?xf32>, tensor<?x?xf32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+
+// -----
+
+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>
+}
+
+// CHECK-LABEL: ternary_select
+// CHECK-SAME: %[[A:.+]]: tensor<?x?xi1>, %[[B:.+]]: tensor<?x?xf32>, %[[C:.+]]: tensor<?x?xf32>, %[[OUT:.+]]: tensor<?x?xf32>)
+// CHECK-NOT: linalg.elementwise
+// CHECK: linalg.select
+// CHECK-SAME: ins(%[[A]], %[[B]], %[[C]] : tensor<?x?xi1>, tensor<?x?xf32>, tensor<?x?xf32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+
+// -----
+
+// 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>
+}
+
+// CHECK-LABEL: non_identity_maps
+// CHECK-SAME: %[[A:.+]]: tensor<?xf32>, %[[OUT:.+]]: tensor<?x?xf32>)
+// CHECK: linalg.elementwise kind=#linalg.elementwise_kind<exp>
+// CHECK-SAME: ins(%[[A]] : tensor<?xf32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>
+// CHECK-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>
+}
+
+// CHECK-LABEL: no_named_op
+// CHECK-SAME: %[[A:.+]]: tensor<?x?xf32>, %[[OUT:.+]]: tensor<?x?xf32>)
+// CHECK: linalg.elementwise kind=#linalg.elementwise_kind<sin>
+// CHECK-SAME: ins(%[[A]] : tensor<?x?xf32>)
+// CHECK-SAME: outs(%[[OUT]] : tensor<?x?xf32>) -> tensor<?x?xf32>



More information about the Mlir-commits mailing list