[Mlir-commits] [mlir] a460d7e - [mlir][linalg] Add category-to-named conversion in linalg-morph-ops (#205582)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Thu Jun 25 02:31:53 PDT 2026
Author: Javed Absar
Date: 2026-06-25T10:31:48+01:00
New Revision: a460d7ecf04e551234edf1a342e333abdf346431
URL: https://github.com/llvm/llvm-project/commit/a460d7ecf04e551234edf1a342e333abdf346431
DIFF: https://github.com/llvm/llvm-project/commit/a460d7ecf04e551234edf1a342e333abdf346431.diff
LOG: [mlir][linalg] Add category-to-named conversion in linalg-morph-ops (#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.
Co-authored-by: mabsar <mabsar at qti.qualcommm.com>
Added:
mlir/lib/Dialect/Linalg/Transforms/CategoryToNamedOp.cpp
mlir/test/Dialect/Linalg/linalg-morph-elementwise-to-named.mlir
Modified:
mlir/include/mlir/Dialect/Linalg/Passes.td
mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h
mlir/lib/Dialect/Linalg/Transforms/CMakeLists.txt
mlir/lib/Dialect/Linalg/Transforms/MorphOps.cpp
Removed:
################################################################################
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..6d1f61100dbf5
--- /dev/null
+++ b/mlir/lib/Dialect/Linalg/Transforms/CategoryToNamedOp.cpp
@@ -0,0 +1,103 @@
+//===- 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