[Mlir-commits] [mlir] [mlir][spirv] Add Element Bynary operators to TOSA Ext Inst Set (PR #179627)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Wed Feb 4 01:01:02 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir-spirv

Author: Davide Grohmann (davidegrohmann)

<details>
<summary>Changes</summary>

This patch introduces the following element binary operators:
* spirv.Tosa.Add
* spirv.Tosa.ArithmeticRightShift
* spirv.Tosa.BitwiseAnd
* spirv.Tosa.BitwiseOr
* spirv.Tosa.BitwiseXor
* spirv.Tosa.IntDiv
* spirv.Tosa.LogicalAnd
* spirv.Tosa.LogicalLeftShift
* spirv.Tosa.LogicalRightShift
* spirv.Tosa.LogicalOr
* spirv.Tosa.LogicalXor
* spirv.Tosa.Maximum
* spirv.Tosa.Minimum
* spirv.Tosa.Mul
* spirv.Tosa.Pow
* spirv.Tosa.Sub
* spirv.Tosa.Table

Also dialect and serialization round-trip tests have been added.


Change-Id: I477dec54212d4201230ba63753c4138fdcb83915

---

Patch is 92.84 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/179627.diff


5 Files Affected:

- (modified) mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaOps.td (+804) 
- (modified) mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaTypes.td (+11) 
- (modified) mlir/test/Dialect/SPIRV/IR/tosa-ops-verification.mlir (+93) 
- (modified) mlir/test/Dialect/SPIRV/IR/tosa-ops.mlir (+245) 
- (modified) mlir/test/Target/SPIRV/tosa-ops.mlir (+442) 


``````````diff
diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaOps.td
index 61e8ea2c9ebc8..d81985fb9a40f 100644
--- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaOps.td
+++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaOps.td
@@ -863,4 +863,808 @@ def SPIRV_TosaTanhOp : SPIRV_TosaOpWithResult<"Tanh", 13, [Pure,
 }
 
 
+def SPIRV_TosaAddOp : SPIRV_TosaOpWithResult<"Add", 14, [Pure,
+  AllElementTypesMatch<["input1", "input2", "output"]>,
+  AllRanksMatch<["input1", "input2"]>]> {
+  let summary = "Addition operator.";
+
+  let description = [{
+    Elementwise Addition of input1 and input2. Axis of size 1 will be broadcast,
+    as necessary. Rank of input tensors must match.
+
+    References:
+      * https://github.khronos.org/SPIRV-Registry/extended/TOSA.001000.1.html#_add
+      * https://www.mlplatform.org/tosa/tosa_spec_1_0_1.html#_add
+
+    #### Example:
+    ```mlir
+    %0 = spirv.Tosa.Add %arg0, %arg1 : !spirv.arm.tensor<4x7x3x10xi32>, !spirv.arm.tensor<4x7x3x1xi32> -> !spirv.arm.tensor<4x7x3x10xi32>
+    %0 = spirv.Tosa.Add %arg0, %arg1 : !spirv.arm.tensor<26x37x18xf16>, !spirv.arm.tensor<1x37x18xf16> -> !spirv.arm.tensor<26x37x18xf16>
+    ```
+  }];
+
+  let arguments = (ins
+    SPIRV_TosaNumerical_TensorArm: $input1,
+    SPIRV_TosaNumerical_TensorArm: $input2
+  );
+
+  let results = (outs
+    SPIRV_TosaNumerical_TensorArm: $output
+  );
+
+  let assemblyFormat = [{
+    $input1 `,`
+    $input2
+    attr-dict `:` type(operands) `->` type(results)
+  }];
+
+  let extraClassDeclaration = extraBaseClassDeclaration#[{
+    ::mlir::spirv::TensorArmType getInput1Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput1().getType());
+    }
+    ::mlir::spirv::TensorArmType getInput2Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput2().getType());
+    }
+  }];
+}
+
+
+def SPIRV_TosaArithmeticRightShiftOp : SPIRV_TosaOpWithResult<"ArithmeticRightShift", 15, [Pure,
+  AllElementTypesMatch<["input1", "input2", "output"]>,
+  AllRanksMatch<["input1", "input2"]>]> {
+  let summary = "Arithmetic Right Shift.";
+
+  let description = [{
+    Elementwise Arithmetic Right Shift of input1 by the amount specified in
+    input2. Axis of size 1 will be broadcast, as necessary. Rank of input tensors
+    must match.
+
+    References:
+      * https://github.khronos.org/SPIRV-Registry/extended/TOSA.001000.1.html#_arithmetic_right_shift
+      * https://www.mlplatform.org/tosa/tosa_spec_1_0_1.html#_arithmetic_right_shift
+
+    #### Example:
+    ```mlir
+    %1 = spirv.Tosa.ArithmeticRightShift round = true, %arg0, %arg1 : !spirv.arm.tensor<1x47x22xi16>, !spirv.arm.tensor<49x47x22xi16> -> !spirv.arm.tensor<49x47x22xi16>
+    ```
+  }];
+
+  let arguments = (ins
+    SPIRV_BoolConstAttr: $round,
+    SPIRV_TosaInteger_TensorArm: $input1,
+    SPIRV_TosaInteger_TensorArm: $input2
+  );
+
+  let results = (outs
+    SPIRV_TosaInteger_TensorArm: $output
+  );
+
+  let assemblyFormat = [{
+    `round` `=` $round `,`
+    $input1 `,`
+    $input2
+    attr-dict `:` type(operands) `->` type(results)
+  }];
+
+  let extraClassDeclaration = extraBaseClassDeclaration#[{
+    ::mlir::spirv::TensorArmType getInput1Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput1().getType());
+    }
+    ::mlir::spirv::TensorArmType getInput2Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput2().getType());
+    }
+  }];
+}
+
+
+def SPIRV_TosaBitwiseAndOp : SPIRV_TosaOpWithResult<"BitwiseAnd", 16, [Pure,
+  AllElementTypesMatch<["input1", "input2", "output"]>,
+  AllRanksMatch<["input1", "input2"]>]> {
+  let summary = "Bitwise AND operator.";
+
+  let description = [{
+    Elementwise Bitwise AND of input1 and input2. Axis of size 1
+    will be broadcast as necessary. Rank of input tensors must match.
+
+    References:
+      * https://github.khronos.org/SPIRV-Registry/extended/TOSA.001000.1.html#_bitwise_and
+      * https://www.mlplatform.org/tosa/tosa_spec_1_0_1.html#_bitwise_and
+
+    #### Example:
+    ```mlir
+    %0 = spirv.Tosa.BitwiseAnd %arg0, %arg1 : !spirv.arm.tensor<4x1x7x12xi16>, !spirv.arm.tensor<4x13x7x12xi16> -> !spirv.arm.tensor<4x13x7x12xi16>
+    ```
+  }];
+
+  let arguments = (ins
+    SPIRV_TosaInteger_TensorArm: $input1,
+    SPIRV_TosaInteger_TensorArm: $input2
+  );
+
+  let results = (outs
+    SPIRV_TosaInteger_TensorArm: $output
+  );
+
+  let assemblyFormat = [{
+    $input1 `,`
+    $input2
+    attr-dict `:` type(operands) `->` type(results)
+  }];
+
+  let extraClassDeclaration = extraBaseClassDeclaration#[{
+    ::mlir::spirv::TensorArmType getInput1Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput1().getType());
+    }
+    ::mlir::spirv::TensorArmType getInput2Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput2().getType());
+    }
+  }];
+}
+
+
+def SPIRV_TosaBitwiseOrOp : SPIRV_TosaOpWithResult<"BitwiseOr", 17, [Pure,
+  AllElementTypesMatch<["input1", "input2", "output"]>,
+  AllRanksMatch<["input1", "input2"]>]> {
+  let summary = "Bitwise OR operator.";
+
+  let description = [{
+    Elementwise Bitwise OR of input1 and input2. Axis of size 1 will be
+    broadcast as necessary. Rank of input tensors must match.
+
+    References:
+      * https://github.khronos.org/SPIRV-Registry/extended/TOSA.001000.1.html#_bitwise_or
+      * https://www.mlplatform.org/tosa/tosa_spec_1_0_1.html#_bitwise_or
+
+    #### Example:
+    ```mlir
+    %0 = spirv.Tosa.BitwiseOr %arg0, %arg1 : !spirv.arm.tensor<11x30x23xi32>, !spirv.arm.tensor<1x30x23xi32> -> !spirv.arm.tensor<11x30x23xi32>
+    ```
+  }];
+
+  let arguments = (ins
+    SPIRV_TosaInteger_TensorArm: $input1,
+    SPIRV_TosaInteger_TensorArm: $input2
+  );
+
+  let results = (outs
+    SPIRV_TosaInteger_TensorArm: $output
+  );
+
+  let assemblyFormat = [{
+    $input1 `,`
+    $input2
+    attr-dict `:` type(operands) `->` type(results)
+  }];
+
+  let extraClassDeclaration = extraBaseClassDeclaration#[{
+    ::mlir::spirv::TensorArmType getInput1Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput1().getType());
+    }
+    ::mlir::spirv::TensorArmType getInput2Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput2().getType());
+    }
+  }];
+}
+
+
+def SPIRV_TosaBitwiseXorOp : SPIRV_TosaOpWithResult<"BitwiseXor", 18, [Pure,
+  AllElementTypesMatch<["input1", "input2", "output"]>,
+  AllRanksMatch<["input1", "input2"]>]> {
+  let summary = "Bitwise XOR operator.";
+
+  let description = [{
+    Elementwise Bitwise XOR of input1 and input2. Axis of size 1 will be
+    broadcast as necessary. Rank of input tensors must match.
+
+    References:
+      * https://github.khronos.org/SPIRV-Registry/extended/TOSA.001000.1.html#_bitwise_xor
+      * https://www.mlplatform.org/tosa/tosa_spec_1_0_1.html#_bitwise_xor
+
+    #### Example:
+    ```mlir
+    %0 = spirv.Tosa.BitwiseXor %arg0, %arg1 : !spirv.arm.tensor<4x8x13x9xi16>, !spirv.arm.tensor<4x8x1x9xi16> -> !spirv.arm.tensor<4x8x13x9xi16>
+    ```
+  }];
+
+  let arguments = (ins
+    SPIRV_TosaInteger_TensorArm: $input1,
+    SPIRV_TosaInteger_TensorArm: $input2
+  );
+
+  let results = (outs
+    SPIRV_TosaInteger_TensorArm: $output
+  );
+
+  let assemblyFormat = [{
+    $input1 `,`
+    $input2
+    attr-dict `:` type(operands) `->` type(results)
+  }];
+
+  let extraClassDeclaration = extraBaseClassDeclaration#[{
+    ::mlir::spirv::TensorArmType getInput1Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput1().getType());
+    }
+    ::mlir::spirv::TensorArmType getInput2Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput2().getType());
+    }
+  }];
+}
+
+
+def SPIRV_TosaIntDivOp : SPIRV_TosaOpWithResult<"IntDiv", 19, [Pure]> {
+  let summary = "Integer Divide operator.";
+
+  let description = [{
+    Elementwise Integer Divide of input1 by input2. Axis of size 1 will be
+    broadcast as necessary. Rank of input tensors must match.
+
+    The result of the divide is truncated towards zero. Expected use is for
+    operations on non-scaled integers. Floating point divide should use
+    `spirv.Tosa.Reciprocal` and `spirv.Tosa.Mul`. Quantized integer divide
+    should use `spirv.Tosa.Table`(for $ 1/x $) and `spirv.Tosa.Mul`.
+
+    References:
+      * https://github.khronos.org/SPIRV-Registry/extended/TOSA.001000.1.html#_intdiv
+      * https://www.mlplatform.org/tosa/tosa_spec_1_0_1.html#_intdiv
+
+    #### Example:
+    ```mlir
+    %0 = spirv.Tosa.IntDiv %arg0, %arg1 : !spirv.arm.tensor<1x65533x1xi32>, !spirv.arm.tensor<2x65533x1xi32> -> !spirv.arm.tensor<2x65533x1xi32>
+    ```
+  }];
+
+  let arguments = (ins
+    SPIRV_Int32_TensorArm: $input1,
+    SPIRV_Int32_TensorArm: $input2
+  );
+
+  let results = (outs
+    SPIRV_Int32_TensorArm: $output
+  );
+
+  let assemblyFormat = [{
+    $input1 `,`
+    $input2
+    attr-dict `:` type(operands) `->` type(results)
+  }];
+
+  let extraClassDeclaration = extraBaseClassDeclaration#[{
+    ::mlir::spirv::TensorArmType getInput1Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput1().getType());
+    }
+    ::mlir::spirv::TensorArmType getInput2Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput2().getType());
+    }
+  }];
+}
+
+
+def SPIRV_TosaLogicalAndOp : SPIRV_TosaOpWithResult<"LogicalAnd", 20, [Pure]> {
+  let summary = "Logical AND operator.";
+
+  let description = [{
+    Elementwise Logical AND of input1 and input2. Axis of size 1 will be
+    broadcast, as necessary. Rank of input tensors must match.
+
+    References:
+      * https://github.khronos.org/SPIRV-Registry/extended/TOSA.001000.1.html#_logical_and
+      * https://www.mlplatform.org/tosa/tosa_spec_1_0_1.html#_logical_and
+
+    #### Example:
+    ```mlir
+    %0 = spirv.Tosa.LogicalAnd %arg0, %arg1 : !spirv.arm.tensor<2x1x7x11xi1>, !spirv.arm.tensor<2x4x7x11xi1> -> !spirv.arm.tensor<2x4x7x11xi1>
+    ```
+  }];
+
+  let arguments = (ins
+    SPIRV_Bool_TensorArm: $input1,
+    SPIRV_Bool_TensorArm: $input2
+  );
+
+  let results = (outs
+    SPIRV_Bool_TensorArm: $output
+  );
+
+  let assemblyFormat = [{
+    $input1 `,`
+    $input2
+    attr-dict `:` type(operands) `->` type(results)
+  }];
+
+  let extraClassDeclaration = extraBaseClassDeclaration#[{
+    ::mlir::spirv::TensorArmType getInput1Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput1().getType());
+    }
+    ::mlir::spirv::TensorArmType getInput2Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput2().getType());
+    }
+  }];
+}
+
+
+def SPIRV_TosaLogicalLeftShiftOp : SPIRV_TosaOpWithResult<"LogicalLeftShift", 21, [Pure,
+  AllElementTypesMatch<["input1", "input2", "output"]>,
+  AllRanksMatch<["input1", "input2"]>]> {
+  let summary = "Logical Left Shift operator.";
+
+  let description = [{
+    Elementwise Logical Left Shift of input1 by the amount specified in input2.
+    Axis of size 1 will be broadcast, as necessary.
+    Rank of input tensors must match.
+
+    References:
+      * https://github.khronos.org/SPIRV-Registry/extended/TOSA.001000.1.html#_logical_left_shift
+      * https://www.mlplatform.org/tosa/tosa_spec_1_0_1.html#_logical_left_shift
+
+    #### Example:
+    ```mlir
+    %0 = spirv.Tosa.LogicalLeftShift %arg0, %arg1 : !spirv.arm.tensor<7x1x11x4xi8>, !spirv.arm.tensor<7x8x11x4xi8> -> !spirv.arm.tensor<7x8x11x4xi8>
+    ```
+  }];
+
+  let arguments = (ins
+    SPIRV_TosaInteger_TensorArm: $input1,
+    SPIRV_TosaInteger_TensorArm: $input2
+  );
+
+  let results = (outs
+    SPIRV_TosaInteger_TensorArm: $output
+  );
+
+  let assemblyFormat = [{
+    $input1 `,`
+    $input2
+    attr-dict `:` type(operands) `->` type(results)
+  }];
+
+  let extraClassDeclaration = extraBaseClassDeclaration#[{
+    ::mlir::spirv::TensorArmType getInput1Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput1().getType());
+    }
+    ::mlir::spirv::TensorArmType getInput2Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput2().getType());
+    }
+  }];
+}
+
+
+def SPIRV_TosaLogicalRightShiftOp : SPIRV_TosaOpWithResult<"LogicalRightShift", 22, [Pure,
+  AllElementTypesMatch<["input1", "input2", "output"]>,
+  AllRanksMatch<["input1", "input2"]>]> {
+  let summary = "Logical Right Shift operator.";
+
+  let description = [{
+    Elementwise Logical Right Shift of input1 by the amount specified in input2.
+    Axis of size 1 will be broadcast, as necessary. Rank of input tensors must
+    match.
+
+    References:
+      * https://github.khronos.org/SPIRV-Registry/extended/TOSA.001000.1.html#_logical_right_shift
+      * https://www.mlplatform.org/tosa/tosa_spec_1_0_1.html#_logical_right_shift
+
+    #### Example:
+    ```mlir
+    %0 = spirv.Tosa.LogicalRightShift %arg0, %arg1 : !spirv.arm.tensor<6x13x1x19xi8>, !spirv.arm.tensor<6x13x6x19xi8> -> !spirv.arm.tensor<6x13x6x19xi8>
+    ```
+  }];
+
+  let arguments = (ins
+    SPIRV_TosaInteger_TensorArm: $input1,
+    SPIRV_TosaInteger_TensorArm: $input2
+  );
+
+  let results = (outs
+    SPIRV_TosaInteger_TensorArm: $output
+  );
+
+  let assemblyFormat = [{
+    $input1 `,`
+    $input2
+    attr-dict `:` type(operands) `->` type(results)
+  }];
+
+  let extraClassDeclaration = extraBaseClassDeclaration#[{
+    ::mlir::spirv::TensorArmType getInput1Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput1().getType());
+    }
+    ::mlir::spirv::TensorArmType getInput2Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput2().getType());
+    }
+  }];
+}
+
+
+def SPIRV_TosaLogicalOrOp : SPIRV_TosaOpWithResult<"LogicalOr", 23, [Pure]> {
+  let summary = "Logical OR operator.";
+
+  let description = [{
+    Elementwise logical OR of input1 and input2. Axis of size 1 will be
+    broadcast as necessary. Rank of input tensors must match.
+
+    References:
+      * https://github.khronos.org/SPIRV-Registry/extended/TOSA.001000.1.html#_logical_or
+      * https://www.mlplatform.org/tosa/tosa_spec_1_0_1.html#_logical_or
+
+    #### Example:
+    ```mlir
+    %0 = spirv.Tosa.LogicalOr %arg0, %arg1 : !spirv.arm.tensor<3x6x12x5xi1>, !spirv.arm.tensor<3x6x1x5xi1> -> !spirv.arm.tensor<3x6x12x5xi1>
+    ```
+  }];
+
+  let arguments = (ins
+    SPIRV_Bool_TensorArm: $input1,
+    SPIRV_Bool_TensorArm: $input2
+  );
+
+  let results = (outs
+    SPIRV_Bool_TensorArm: $output
+  );
+
+  let assemblyFormat = [{
+    $input1 `,`
+    $input2
+    attr-dict `:` type(operands) `->` type(results)
+  }];
+
+  let extraClassDeclaration = extraBaseClassDeclaration#[{
+    ::mlir::spirv::TensorArmType getInput1Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput1().getType());
+    }
+    ::mlir::spirv::TensorArmType getInput2Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput2().getType());
+    }
+  }];
+}
+
+
+def SPIRV_TosaLogicalXorOp : SPIRV_TosaOpWithResult<"LogicalXor", 24, [Pure]> {
+  let summary = "Logical XOR operator.";
+
+  let description = [{
+    Elementwise logical XOR of input1 and input2. Axis of size 1 will be
+    broadcast as necessary. Rank of input tensors must match.
+
+    References:
+      * https://github.khronos.org/SPIRV-Registry/extended/TOSA.001000.1.html#_logical_xor
+      * https://www.mlplatform.org/tosa/tosa_spec_1_0_1.html#_logical_xor
+
+    #### Example:
+    ```mlir
+    %0 = spirv.Tosa.LogicalXor %arg0, %arg1 : !spirv.arm.tensor<11x4x9x12xi1>, !spirv.arm.tensor<11x4x9x1xi1> -> !spirv.arm.tensor<11x4x9x12xi1>
+    ```
+  }];
+
+  let arguments = (ins
+    SPIRV_Bool_TensorArm: $input1,
+    SPIRV_Bool_TensorArm: $input2
+  );
+
+  let results = (outs
+    SPIRV_Bool_TensorArm: $output
+  );
+
+  let assemblyFormat = [{
+    $input1 `,`
+    $input2
+    attr-dict `:` type(operands) `->` type(results)
+  }];
+
+  let extraClassDeclaration = extraBaseClassDeclaration#[{
+    ::mlir::spirv::TensorArmType getInput1Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput1().getType());
+    }
+    ::mlir::spirv::TensorArmType getInput2Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput2().getType());
+    }
+  }];
+}
+
+
+def SPIRV_TosaMaximumOp : SPIRV_TosaOpWithResult<"Maximum", 25, [Pure,
+  AllElementTypesMatch<["input1", "input2", "output"]>,
+  AllRanksMatch<["input1", "input2"]>,
+  TypeConstraintImplicationOn<"input1", AnyInteger, "input1", [I32]>,
+  TypeConstraintImplicationOn<"input2", AnyInteger, "input2", [I32]>,
+  TypeConstraintImplicationOn<"output", AnyInteger, "output", [I32]>]> {
+  let summary = "Maximum.";
+
+  let description = [{
+    Elementwise maximum of input1 and input2. Axis of size 1 will be broadcast,
+    as necessary. Rank of input tensors must match.
+
+    References:
+      * https://github.khronos.org/SPIRV-Registry/extended/TOSA.001000.1.html#_maximum
+      * https://www.mlplatform.org/tosa/tosa_spec_1_0_1.html#_maximum
+
+    #### Example:
+    ```mlir
+    %1 = spirv.Tosa.Maximum nan_mode = <Propagate>, %arg0, %arg1 : !spirv.arm.tensor<1x2x65533x1xi32>, !spirv.arm.tensor<1x2x65533x2xi32> -> !spirv.arm.tensor<1x2x65533x2xi32>
+    %1 = spirv.Tosa.Maximum nan_mode = <Ignore>, %arg0, %arg1 : !spirv.arm.tensor<1x12x14x7xf16>, !spirv.arm.tensor<11x12x14x7xf16> -> !spirv.arm.tensor<11x12x14x7xf16>
+    ```
+  }];
+
+  let arguments = (ins
+    SPIRV_TosaExtNaNPropagationModeAttr: $nan_mode,
+    SPIRV_TosaNumerical_TensorArm: $input1,
+    SPIRV_TosaNumerical_TensorArm: $input2
+  );
+
+  let results = (outs
+    SPIRV_TosaNumerical_TensorArm: $output
+  );
+
+  let assemblyFormat = [{
+    `nan_mode` `=` $nan_mode `,`
+    $input1 `,`
+    $input2
+    attr-dict `:` type(operands) `->` type(results)
+  }];
+
+  let extraClassDeclaration = extraBaseClassDeclaration#[{
+    ::mlir::spirv::TensorArmType getInput1Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput1().getType());
+    }
+    ::mlir::spirv::TensorArmType getInput2Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput2().getType());
+    }
+  }];
+}
+
+
+def SPIRV_TosaMinimumOp : SPIRV_TosaOpWithResult<"Minimum", 26, [Pure,
+  AllElementTypesMatch<["input1", "input2", "output"]>,
+  AllRanksMatch<["input1", "input2"]>,
+  TypeConstraintImplicationOn<"input1", AnyInteger, "input1", [I32]>,
+  TypeConstraintImplicationOn<"input2", AnyInteger, "input2", [I32]>,
+  TypeConstraintImplicationOn<"output", AnyInteger, "output", [I32]>]> {
+  let summary = "Minimum.";
+
+  let description = [{
+    Elementwise minimum of input1 and input2. Axis of size 1 will be broadcast,
+    as necessary. Rank of input tensors must match.
+
+    References:
+      * https://github.khronos.org/SPIRV-Registry/extended/TOSA.001000.1.html#_minimum
+      * https://www.mlplatform.org/tosa/tosa_spec_1_0_1.html#_minimum
+
+    #### Example:
+    ```mlir
+    %1 = spirv.Tosa.Minimum nan_mode = <Propagate>, %arg0, %arg1 : !spirv.arm.tensor<15x2x10x11xi32>, !spirv.arm.tensor<15x1x10x11xi32> -> !spirv.arm.tensor<15x2x10x11xi32>
+    %1 = spirv.Tosa.Minimum nan_mode = <Propagate>, %arg0, %arg1 : !spirv.arm.tensor<1x65531x2x1xf32>, !spirv.arm.tensor<1x1x2x1xf32> -> !spirv.arm.tensor<1x65531x2x1xf32>
+    ```
+  }];
+
+  let arguments = (ins
+    SPIRV_TosaExtNaNPropagationModeAttr: $nan_mode,
+    SPIRV_TosaNumerical_TensorArm: $input1,
+    SPIRV_TosaNumerical_TensorArm: $input2
+  );
+
+  let results = (outs
+    SPIRV_TosaNumerical_TensorArm: $output
+  );
+
+  let assemblyFormat = [{
+    `nan_mode` `=` $nan_mode `,`
+    $input1 `,`
+    $input2
+    attr-dict `:` type(operands) `->` type(results)
+  }];
+
+  let extraClassDeclaration = extraBaseClassDeclaration#[{
+    ::mlir::spirv::TensorArmType getInput1Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput1().getType());
+    }
+    ::mlir::spirv::TensorArmType getInput2Type() {
+      return cast<::mlir::spirv::TensorArmType>(getInput2().getType());
+    }
+  }];
+}
+
+
+def SPIRV_TosaMulOp : SPIRV_TosaOpWithResult<"Mul", 27, [Pure,
+  AllElementTypesMatch<["input1", "input2"]>,
+  AllRanksMatch<["input1", "input2"]>,
+  TypeConstraintImplicationOn<"input1", F16, "output", [F16]>,
+  TypeConstraintImplicationOn<"input1", F32, "output", [F32]>,
+  TypeConstraintImplicationOn<"input1", BF16, "output", [BF16]>,
+  TypeConstraintImplicationOn<"input1", AnyInteger, "output", [I32]>]> {
+  let summary = "Multiplication operator.";
+
+  let description = [{
+    Elementwise Multiplication (Hadamard product) of inp...
[truncated]

``````````

</details>


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


More information about the Mlir-commits mailing list