| //===-- SPIRVArithmeticOps.td - MLIR SPIR-V Arithmetic Ops -*- tablegen -*-===// |
| // |
| // 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 contains arithmetic ops for the SPIR-V dialect. It corresponds |
| // to "3.32.13. Arithmetic Instructions" of the SPIR-V specification. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef MLIR_DIALECT_SPIRV_IR_ARITHMETIC_OPS |
| #define MLIR_DIALECT_SPIRV_IR_ARITHMETIC_OPS |
| |
| include "mlir/Dialect/SPIRV/IR/SPIRVBase.td" |
| include "mlir/Interfaces/InferTypeOpInterface.td" |
| include "mlir/Interfaces/SideEffectInterfaces.td" |
| |
| class SPIRV_ArithmeticBinaryOp<string mnemonic, Type type, |
| list<Trait> traits = []> : |
| // Operands type same as result type. |
| SPIRV_BinaryOp<mnemonic, type, type, |
| !listconcat(traits, |
| [Pure, SameOperandsAndResultType])> { |
| // In addition to normal types arithmetic instructions can support cooperative |
| // matrix. |
| let arguments = (ins |
| SPIRV_ScalarOrVectorOrCoopMatrixOf<type>:$operand1, |
| SPIRV_ScalarOrVectorOrCoopMatrixOf<type>:$operand2 |
| ); |
| |
| let results = (outs |
| SPIRV_ScalarOrVectorOrCoopMatrixOf<type>:$result |
| ); |
| let assemblyFormat = "operands attr-dict `:` type($result)"; |
| } |
| |
| class SPIRV_ArithmeticUnaryOp<string mnemonic, Type type, |
| list<Trait> traits = []> : |
| // Operand type same as result type. |
| SPIRV_UnaryOp<mnemonic, type, type, |
| !listconcat(traits, |
| [Pure, SameOperandsAndResultType])> { |
| // In addition to normal types arithmetic instructions can support cooperative |
| // matrix. |
| let arguments = (ins |
| SPIRV_ScalarOrVectorOrCoopMatrixOf<type>:$operand |
| ); |
| |
| let results = (outs |
| SPIRV_ScalarOrVectorOrCoopMatrixOf<type>:$result |
| ); |
| let assemblyFormat = "operands attr-dict `:` type($result)"; |
| } |
| |
| class SPIRV_ArithmeticExtendedBinaryOp<string mnemonic, |
| list<Trait> traits = []> : |
| // Result type is a struct with two operand-typed elements. |
| SPIRV_BinaryOp<mnemonic, SPIRV_AnyStruct, SPIRV_Integer, traits> { |
| let arguments = (ins |
| SPIRV_ScalarOrVectorOf<SPIRV_Integer>:$operand1, |
| SPIRV_ScalarOrVectorOf<SPIRV_Integer>:$operand2 |
| ); |
| |
| let results = (outs |
| SPIRV_AnyStruct:$result |
| ); |
| |
| let builders = [ |
| OpBuilder<(ins "Value":$operand1, "Value":$operand2), [{ |
| build($_builder, $_state, |
| ::mlir::spirv::StructType::get({operand1.getType(), operand1.getType()}), |
| operand1, operand2); |
| }]> |
| ]; |
| |
| // These ops require a custom verifier. |
| let hasVerifier = 1; |
| } |
| |
| // ----- |
| |
| def SPIRV_FAddOp : SPIRV_ArithmeticBinaryOp<"FAdd", SPIRV_Float, [Commutative]> { |
| let summary = "Floating-point addition of Operand 1 and Operand 2."; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of floating-point type. |
| |
| The types of Operand 1 and Operand 2 both must be the same as Result |
| Type. |
| |
| Results are computed per component. |
| |
| #### Example: |
| |
| ```mlir |
| %4 = spirv.FAdd %0, %1 : f32 |
| %5 = spirv.FAdd %2, %3 : vector<4xf32> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPIRV_FDivOp : SPIRV_ArithmeticBinaryOp<"FDiv", SPIRV_Float, []> { |
| let summary = "Floating-point division of Operand 1 divided by Operand 2."; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of floating-point type. |
| |
| The types of Operand 1 and Operand 2 both must be the same as Result |
| Type. |
| |
| Results are computed per component. The resulting value is undefined |
| if Operand 2 is 0. |
| |
| #### Example: |
| |
| ```mlir |
| %4 = spirv.FDiv %0, %1 : f32 |
| %5 = spirv.FDiv %2, %3 : vector<4xf32> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPIRV_FModOp : SPIRV_ArithmeticBinaryOp<"FMod", SPIRV_Float, []> { |
| let summary = [{ |
| The floating-point remainder whose sign matches the sign of Operand 2. |
| }]; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of floating-point type. |
| |
| The types of Operand 1 and Operand 2 both must be the same as Result |
| Type. |
| |
| Results are computed per component. The resulting value is undefined |
| if Operand 2 is 0. Otherwise, the result is the remainder r of Operand |
| 1 divided by Operand 2 where if r ≠ 0, the sign of r is the same as the |
| sign of Operand 2. |
| |
| #### Example: |
| |
| ```mlir |
| %4 = spirv.FMod %0, %1 : f32 |
| %5 = spirv.FMod %2, %3 : vector<4xf32> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPIRV_FMulOp : SPIRV_ArithmeticBinaryOp<"FMul", SPIRV_Float, [Commutative]> { |
| let summary = "Floating-point multiplication of Operand 1 and Operand 2."; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of floating-point type. |
| |
| The types of Operand 1 and Operand 2 both must be the same as Result |
| Type. |
| |
| Results are computed per component. |
| |
| #### Example: |
| |
| ```mlir |
| %4 = spirv.FMul %0, %1 : f32 |
| %5 = spirv.FMul %2, %3 : vector<4xf32> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPIRV_FNegateOp : SPIRV_ArithmeticUnaryOp<"FNegate", SPIRV_Float, []> { |
| let summary = [{ |
| Inverts the sign bit of Operand. (Note, however, that OpFNegate is still |
| considered a floating-point instruction, and so is subject to the |
| general floating-point rules regarding, for example, subnormals and NaN |
| propagation). |
| }]; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of floating-point type. |
| |
| The type of Operand must be the same as Result Type. |
| |
| Results are computed per component. |
| |
| #### Example: |
| |
| ```mlir |
| %1 = spirv.FNegate %0 : f32 |
| %3 = spirv.FNegate %2 : vector<4xf32> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPIRV_FRemOp : SPIRV_ArithmeticBinaryOp<"FRem", SPIRV_Float, []> { |
| let summary = [{ |
| The floating-point remainder whose sign matches the sign of Operand 1. |
| }]; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of floating-point type. |
| |
| The types of Operand 1 and Operand 2 both must be the same as Result |
| Type. |
| |
| Results are computed per component. The resulting value is undefined |
| if Operand 2 is 0. Otherwise, the result is the remainder r of Operand |
| 1 divided by Operand 2 where if r ≠ 0, the sign of r is the same as the |
| sign of Operand 1. |
| |
| #### Example: |
| |
| ```mlir |
| %4 = spirv.FRemOp %0, %1 : f32 |
| %5 = spirv.FRemOp %2, %3 : vector<4xf32> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPIRV_FSubOp : SPIRV_ArithmeticBinaryOp<"FSub", SPIRV_Float, []> { |
| let summary = "Floating-point subtraction of Operand 2 from Operand 1."; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of floating-point type. |
| |
| The types of Operand 1 and Operand 2 both must be the same as Result |
| Type. |
| |
| Results are computed per component. |
| |
| #### Example: |
| |
| ```mlir |
| %4 = spirv.FRemOp %0, %1 : f32 |
| %5 = spirv.FRemOp %2, %3 : vector<4xf32> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPIRV_IAddOp : SPIRV_ArithmeticBinaryOp<"IAdd", |
| SPIRV_Integer, |
| [Commutative, UsableInSpecConstantOp]> { |
| let summary = "Integer addition of Operand 1 and Operand 2."; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of integer type. |
| |
| The type of Operand 1 and Operand 2 must be a scalar or vector of |
| integer type. They must have the same number of components as Result |
| Type. They must have the same component width as Result Type. |
| |
| The resulting value will equal the low-order N bits of the correct |
| result R, where N is the component width and R is computed with enough |
| precision to avoid overflow and underflow. |
| |
| Results are computed per component. |
| |
| #### Example: |
| |
| ```mlir |
| %4 = spirv.IAdd %0, %1 : i32 |
| %5 = spirv.IAdd %2, %3 : vector<4xi32> |
| |
| ``` |
| }]; |
| |
| let hasFolder = 1; |
| } |
| |
| // ----- |
| |
| def SPIRV_IAddCarryOp : SPIRV_ArithmeticExtendedBinaryOp<"IAddCarry", |
| [Commutative, Pure]> { |
| let summary = [{ |
| Integer addition of Operand 1 and Operand 2, including the carry. |
| }]; |
| |
| let description = [{ |
| Result Type must be from OpTypeStruct. The struct must have two |
| members, and the two members must be the same type. The member type |
| must be a scalar or vector of integer type, whose Signedness operand is |
| 0. |
| |
| Operand 1 and Operand 2 must have the same type as the members of Result |
| Type. These are consumed as unsigned integers. |
| |
| Results are computed per component. |
| |
| Member 0 of the result gets the low-order bits (full component width) of |
| the addition. |
| |
| Member 1 of the result gets the high-order (carry) bit of the result of |
| the addition. That is, it gets the value 1 if the addition overflowed |
| the component width, and 0 otherwise. |
| |
| <!-- End of AutoGen section --> |
| |
| #### Example: |
| |
| ```mlir |
| %2 = spirv.IAddCarry %0, %1 : !spirv.struct<(i32, i32)> |
| %2 = spirv.IAddCarry %0, %1 : !spirv.struct<(vector<2xi32>, vector<2xi32>)> |
| ``` |
| }]; |
| |
| let hasCanonicalizer = 1; |
| } |
| |
| // ----- |
| |
| def SPIRV_IMulOp : SPIRV_ArithmeticBinaryOp<"IMul", |
| SPIRV_Integer, |
| [Commutative, UsableInSpecConstantOp]> { |
| let summary = "Integer multiplication of Operand 1 and Operand 2."; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of integer type. |
| |
| The type of Operand 1 and Operand 2 must be a scalar or vector of |
| integer type. They must have the same number of components as Result |
| Type. They must have the same component width as Result Type. |
| |
| The resulting value will equal the low-order N bits of the correct |
| result R, where N is the component width and R is computed with enough |
| precision to avoid overflow and underflow. |
| |
| Results are computed per component. |
| |
| #### Example: |
| |
| ```mlir |
| %4 = spirv.IMul %0, %1 : i32 |
| %5 = spirv.IMul %2, %3 : vector<4xi32> |
| |
| ``` |
| }]; |
| |
| let hasFolder = 1; |
| } |
| |
| // ----- |
| |
| def SPIRV_ISubOp : SPIRV_ArithmeticBinaryOp<"ISub", |
| SPIRV_Integer, |
| [UsableInSpecConstantOp]> { |
| let summary = "Integer subtraction of Operand 2 from Operand 1."; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of integer type. |
| |
| The type of Operand 1 and Operand 2 must be a scalar or vector of |
| integer type. They must have the same number of components as Result |
| Type. They must have the same component width as Result Type. |
| |
| The resulting value will equal the low-order N bits of the correct |
| result R, where N is the component width and R is computed with enough |
| precision to avoid overflow and underflow. |
| |
| Results are computed per component. |
| |
| #### Example: |
| |
| ```mlir |
| %4 = spirv.ISub %0, %1 : i32 |
| %5 = spirv.ISub %2, %3 : vector<4xi32> |
| |
| ``` |
| }]; |
| |
| let hasFolder = 1; |
| } |
| |
| // ----- |
| |
| def SPIRV_ISubBorrowOp : SPIRV_ArithmeticExtendedBinaryOp<"ISubBorrow", |
| [Pure]> { |
| let summary = [{ |
| Result is the unsigned integer subtraction of Operand 2 from Operand 1, |
| and what it needed to borrow. |
| }]; |
| |
| let description = [{ |
| Result Type must be from OpTypeStruct. The struct must have two |
| members, and the two members must be the same type. The member type |
| must be a scalar or vector of integer type, whose Signedness operand is |
| 0. |
| |
| Operand 1 and Operand 2 must have the same type as the members of Result |
| Type. These are consumed as unsigned integers. |
| |
| Results are computed per component. |
| |
| Member 0 of the result gets the low-order bits (full component width) of |
| the subtraction. That is, if Operand 1 is larger than Operand 2, member |
| 0 gets the full value of the subtraction; if Operand 2 is larger than |
| Operand 1, member 0 gets 2w + Operand 1 - Operand 2, where w is the |
| component width. |
| |
| Member 1 of the result gets 0 if Operand 1 ≥ Operand 2, and gets 1 |
| otherwise. |
| |
| <!-- End of AutoGen section --> |
| |
| #### Example: |
| |
| ```mlir |
| %2 = spirv.ISubBorrow %0, %1 : !spirv.struct<(i32, i32)> |
| %2 = spirv.ISubBorrow %0, %1 : !spirv.struct<(vector<2xi32>, vector<2xi32>)> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPIRV_DotOp : SPIRV_Op<"Dot", |
| [Pure, AllTypesMatch<["vector1", "vector2"]>, |
| AllElementTypesMatch<["vector1", "result"]>]> { |
| let summary = "Dot product of Vector 1 and Vector 2"; |
| |
| let description = [{ |
| Result Type must be a floating point scalar. |
| |
| Vector 1 and Vector 2 must be vectors of the same type, and their component |
| type must be Result Type. |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spirv.Dot %v1, %v2 : vector<4xf32> -> f32 |
| ``` |
| }]; |
| |
| let arguments = (ins |
| SPIRV_VectorOf<SPIRV_Float>:$vector1, |
| SPIRV_VectorOf<SPIRV_Float>:$vector2 |
| ); |
| |
| let results = (outs |
| SPIRV_Float:$result |
| ); |
| |
| let assemblyFormat = "operands attr-dict `:` type($vector1) `->` type($result)"; |
| |
| let hasVerifier = 0; |
| } |
| |
| // ----- |
| |
| def SPIRV_SDivOp : SPIRV_ArithmeticBinaryOp<"SDiv", |
| SPIRV_Integer, |
| [UsableInSpecConstantOp]> { |
| let summary = "Signed-integer division of Operand 1 divided by Operand 2."; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of integer type. |
| |
| The type of Operand 1 and Operand 2 must be a scalar or vector of |
| integer type. They must have the same number of components as Result |
| Type. They must have the same component width as Result Type. |
| |
| Results are computed per component. The resulting value is undefined |
| if Operand 2 is 0. |
| |
| #### Example: |
| |
| ```mlir |
| %4 = spirv.SDiv %0, %1 : i32 |
| %5 = spirv.SDiv %2, %3 : vector<4xi32> |
| |
| ``` |
| }]; |
| |
| let hasFolder = 1; |
| } |
| |
| // ----- |
| |
| def SPIRV_SModOp : SPIRV_ArithmeticBinaryOp<"SMod", |
| SPIRV_Integer, |
| [UsableInSpecConstantOp]> { |
| let summary = [{ |
| Signed remainder operation for the remainder whose sign matches the sign |
| of Operand 2. |
| }]; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of integer type. |
| |
| The type of Operand 1 and Operand 2 must be a scalar or vector of |
| integer type. They must have the same number of components as Result |
| Type. They must have the same component width as Result Type. |
| |
| Results are computed per component. The resulting value is undefined |
| if Operand 2 is 0. Otherwise, the result is the remainder r of Operand |
| 1 divided by Operand 2 where if r ≠ 0, the sign of r is the same as the |
| sign of Operand 2. |
| |
| #### Example: |
| |
| ```mlir |
| %4 = spirv.SMod %0, %1 : i32 |
| %5 = spirv.SMod %2, %3 : vector<4xi32> |
| |
| ``` |
| }]; |
| |
| let hasFolder = 1; |
| } |
| |
| // ----- |
| |
| def SPIRV_SMulExtendedOp : SPIRV_ArithmeticExtendedBinaryOp<"SMulExtended", |
| [Pure, Commutative]> { |
| let summary = [{ |
| Result is the full value of the signed integer multiplication of Operand |
| 1 and Operand 2. |
| }]; |
| |
| let description = [{ |
| Result Type must be from OpTypeStruct. The struct must have two |
| members, and the two members must be the same type. The member type |
| must be a scalar or vector of integer type. |
| |
| Operand 1 and Operand 2 must have the same type as the members of Result |
| Type. These are consumed as signed integers. |
| |
| Results are computed per component. |
| |
| Member 0 of the result gets the low-order bits of the multiplication. |
| |
| Member 1 of the result gets the high-order bits of the multiplication. |
| |
| <!-- End of AutoGen section --> |
| |
| #### Example: |
| |
| ```mlir |
| %2 = spirv.SMulExtended %0, %1 : !spirv.struct<(i32, i32)> |
| %2 = spirv.SMulExtended %0, %1 : !spirv.struct<(vector<2xi32>, vector<2xi32>)> |
| ``` |
| }]; |
| |
| let hasCanonicalizer = 1; |
| } |
| |
| // ----- |
| |
| def SPIRV_SNegateOp : SPIRV_ArithmeticUnaryOp<"SNegate", |
| SPIRV_Integer, |
| [UsableInSpecConstantOp]> { |
| let summary = "Signed-integer subtract of Operand from zero."; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of integer type. |
| |
| Operand's type must be a scalar or vector of integer type. It must |
| have the same number of components as Result Type. The component width |
| must equal the component width in Result Type. |
| |
| Results are computed per component. |
| |
| <!-- End of AutoGen section --> |
| |
| #### Example: |
| |
| ```mlir |
| %1 = spirv.SNegate %0 : i32 |
| %3 = spirv.SNegate %2 : vector<4xi32> |
| ``` |
| }]; |
| |
| let hasFolder = 1; |
| } |
| |
| // ----- |
| |
| def SPIRV_SRemOp : SPIRV_ArithmeticBinaryOp<"SRem", |
| SPIRV_Integer, |
| [UsableInSpecConstantOp]> { |
| let summary = [{ |
| Signed remainder operation for the remainder whose sign matches the sign |
| of Operand 1. |
| }]; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of integer type. |
| |
| The type of Operand 1 and Operand 2 must be a scalar or vector of |
| integer type. They must have the same number of components as Result |
| Type. They must have the same component width as Result Type. |
| |
| Results are computed per component. The resulting value is undefined |
| if Operand 2 is 0. Otherwise, the result is the remainder r of Operand |
| 1 divided by Operand 2 where if r ≠ 0, the sign of r is the same as the |
| sign of Operand 1. |
| |
| #### Example: |
| |
| ```mlir |
| %4 = spirv.SRem %0, %1 : i32 |
| %5 = spirv.SRem %2, %3 : vector<4xi32> |
| |
| ``` |
| }]; |
| |
| let hasFolder = 1; |
| } |
| |
| // ----- |
| |
| def SPIRV_UDivOp : SPIRV_ArithmeticBinaryOp<"UDiv", |
| SPIRV_Integer, |
| [UnsignedOp, UsableInSpecConstantOp]> { |
| let summary = "Unsigned-integer division of Operand 1 divided by Operand 2."; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of integer type, whose Signedness |
| operand is 0. |
| |
| The types of Operand 1 and Operand 2 both must be the same as Result |
| Type. |
| |
| Results are computed per component. The resulting value is undefined |
| if Operand 2 is 0. |
| |
| #### Example: |
| |
| ```mlir |
| %4 = spirv.UDiv %0, %1 : i32 |
| %5 = spirv.UDiv %2, %3 : vector<4xi32> |
| ``` |
| }]; |
| |
| let hasFolder = 1; |
| } |
| |
| // ----- |
| |
| def SPIRV_UMulExtendedOp : SPIRV_ArithmeticExtendedBinaryOp<"UMulExtended", |
| [Pure, Commutative]> { |
| let summary = [{ |
| Result is the full value of the unsigned integer multiplication of |
| Operand 1 and Operand 2. |
| }]; |
| |
| let description = [{ |
| Result Type must be from OpTypeStruct. The struct must have two |
| members, and the two members must be the same type. The member type |
| must be a scalar or vector of integer type, whose Signedness operand is |
| 0. |
| |
| Operand 1 and Operand 2 must have the same type as the members of Result |
| Type. These are consumed as unsigned integers. |
| |
| Results are computed per component. |
| |
| Member 0 of the result gets the low-order bits of the multiplication. |
| |
| Member 1 of the result gets the high-order bits of the multiplication. |
| |
| <!-- End of AutoGen section --> |
| |
| #### Example: |
| |
| ```mlir |
| %2 = spirv.UMulExtended %0, %1 : !spirv.struct<(i32, i32)> |
| %2 = spirv.UMulExtended %0, %1 : !spirv.struct<(vector<2xi32>, vector<2xi32>)> |
| ``` |
| }]; |
| |
| let hasCanonicalizer = 1; |
| } |
| |
| // ----- |
| |
| def SPIRV_VectorTimesScalarOp : SPIRV_Op<"VectorTimesScalar", [Pure]> { |
| let summary = "Scale a floating-point vector."; |
| |
| let description = [{ |
| Result Type must be a vector of floating-point type. |
| |
| The type of Vector must be the same as Result Type. Each component of |
| Vector is multiplied by Scalar. |
| |
| Scalar must have the same type as the Component Type in Result Type. |
| |
| <!-- End of AutoGen section --> |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spirv.VectorTimesScalar %vector, %scalar : vector<4xf32> |
| ``` |
| }]; |
| |
| let arguments = (ins |
| VectorOfLengthAndType<[2, 3, 4], [SPIRV_Float]>:$vector, |
| SPIRV_Float:$scalar |
| ); |
| |
| let results = (outs |
| VectorOfLengthAndType<[2, 3, 4], [SPIRV_Float]>:$result |
| ); |
| |
| let assemblyFormat = "operands attr-dict `:` `(` type(operands) `)` `->` type($result)"; |
| } |
| |
| // ----- |
| |
| def SPIRV_UModOp : SPIRV_ArithmeticBinaryOp<"UMod", |
| SPIRV_Integer, |
| [UnsignedOp, UsableInSpecConstantOp]> { |
| let summary = "Unsigned modulo operation of Operand 1 modulo Operand 2."; |
| |
| let description = [{ |
| Result Type must be a scalar or vector of integer type, whose Signedness |
| operand is 0. |
| |
| The types of Operand 1 and Operand 2 both must be the same as Result |
| Type. |
| |
| Results are computed per component. The resulting value is undefined |
| if Operand 2 is 0. |
| |
| #### Example: |
| |
| ```mlir |
| %4 = spirv.UMod %0, %1 : i32 |
| %5 = spirv.UMod %2, %3 : vector<4xi32> |
| ``` |
| }]; |
| |
| let hasFolder = 1; |
| let hasCanonicalizer = 1; |
| } |
| |
| #endif // MLIR_DIALECT_SPIRV_IR_ARITHMETIC_OPS |