| //===-- SPIRVStructureOps.td - MLIR SPIR-V Structure 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 ops for defining the SPIR-V structure: module, function, |
| // and module-level operations. The representational form of these ops deviate |
| // from the SPIR-V binary format in order to utilize MLIR mechanisms. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef MLIR_DIALECT_SPIRV_IR_STRUCTURE_OPS |
| #define MLIR_DIALECT_SPIRV_IR_STRUCTURE_OPS |
| |
| include "mlir/Dialect/SPIRV/IR/SPIRVBase.td" |
| include "mlir/IR/OpAsmInterface.td" |
| include "mlir/IR/SymbolInterfaces.td" |
| include "mlir/Interfaces/CallInterfaces.td" |
| include "mlir/Interfaces/SideEffectInterfaces.td" |
| |
| // ----- |
| |
| def SPV_AddressOfOp : SPV_Op<"mlir.addressof", |
| [DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmResultNames"]>, |
| InFunctionScope, NoSideEffect]> { |
| let summary = "Get the address of a global variable."; |
| |
| let description = [{ |
| Variables in module scope are defined using symbol names. This op generates |
| an SSA value that can be used to refer to the symbol within function scope |
| for use in ops that expect an SSA value. This operation has no corresponding |
| SPIR-V instruction; it's merely used for modelling purpose in the SPIR-V |
| dialect. Since variables in module scope in SPIR-V dialect are of pointer |
| type, this op returns a pointer type as well, and the type is the same as |
| the variable referenced. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| spv-address-of-op ::= ssa-id `=` `spv.mlir.addressof` symbol-ref-id |
| `:` spirv-pointer-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.mlir.addressof @global_var : !spv.ptr<f32, Input> |
| ``` |
| }]; |
| |
| let arguments = (ins |
| FlatSymbolRefAttr:$variable |
| ); |
| |
| let results = (outs |
| SPV_AnyPtr:$pointer |
| ); |
| |
| let hasOpcode = 0; |
| |
| let autogenSerialization = 0; |
| |
| let builders = [OpBuilder<(ins "spirv::GlobalVariableOp":$var)>]; |
| |
| let assemblyFormat = "$variable attr-dict `:` type($pointer)"; |
| } |
| |
| // ----- |
| |
| def SPV_ConstantOp : SPV_Op<"Constant", |
| [ConstantLike, |
| DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmResultNames"]>, |
| NoSideEffect]> { |
| let summary = "The op that declares a SPIR-V normal constant"; |
| |
| let description = [{ |
| This op declares a SPIR-V normal constant. SPIR-V has multiple constant |
| instructions covering different constant types: |
| |
| * `OpConstantTrue` and `OpConstantFalse` for boolean constants |
| * `OpConstant` for scalar constants |
| * `OpConstantComposite` for composite constants |
| * `OpConstantNull` for null constants |
| * ... |
| |
| Having such a plethora of constant instructions renders IR transformations |
| more tedious. Therefore, we use a single `spv.Constant` op to represent |
| them all. Note that conversion between those SPIR-V constant instructions |
| and this op is purely mechanical; so it can be scoped to the binary |
| (de)serialization process. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| spv.Constant-op ::= ssa-id `=` `spv.Constant` attribute-value |
| (`:` spirv-type)? |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.Constant true |
| %1 = spv.Constant dense<[2, 3]> : vector<2xf32> |
| %2 = spv.Constant [dense<3.0> : vector<2xf32>] : !spv.array<1xvector<2xf32>> |
| ``` |
| |
| TODO: support constant structs |
| }]; |
| |
| let arguments = (ins |
| AnyAttr:$value |
| ); |
| |
| let results = (outs |
| SPV_Type:$constant |
| ); |
| |
| let hasFolder = 1; |
| |
| let extraClassDeclaration = [{ |
| // Returns true if a constant can be built for the given `type`. |
| static bool isBuildableWith(Type type); |
| |
| // Creates a constant zero/one of the given `type` at the current insertion |
| // point of `builder` and returns it. |
| static spirv::ConstantOp getZero(Type type, Location loc, |
| OpBuilder &builder); |
| static spirv::ConstantOp getOne(Type type, Location loc, |
| OpBuilder &builder); |
| }]; |
| |
| let hasOpcode = 0; |
| |
| let autogenSerialization = 0; |
| } |
| |
| // ----- |
| |
| def SPV_EntryPointOp : SPV_Op<"EntryPoint", [InModuleScope]> { |
| let summary = [{ |
| Declare an entry point, its execution model, and its interface. |
| }]; |
| |
| let description = [{ |
| Execution Model is the execution model for the entry point and its |
| static call tree. See Execution Model. |
| |
| Entry Point must be the Result <id> of an OpFunction instruction. |
| |
| Name is a name string for the entry point. A module cannot have two |
| OpEntryPoint instructions with the same Execution Model and the same |
| Name string. |
| |
| Interface is a list of symbol references to `spv.GlobalVariable` |
| operations. These declare the set of global variables from a |
| module that form the interface of this entry point. The set of |
| Interface symbols must be equal to or a superset of the |
| `spv.GlobalVariable`s referenced by the entry point’s static call |
| tree, within the interface’s storage classes. Before version 1.4, |
| the interface’s storage classes are limited to the Input and |
| Output storage classes. Starting with version 1.4, the interface’s |
| storage classes are all storage classes used in declaring all |
| global variables referenced by the entry point’s call tree. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| execution-model ::= "Vertex" | "TesellationControl" | |
| <and other SPIR-V execution models...> |
| |
| entry-point-op ::= ssa-id `=` `spv.EntryPoint` execution-model |
| symbol-reference (`, ` symbol-reference)* |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| spv.EntryPoint "GLCompute" @foo |
| spv.EntryPoint "Kernel" @foo, @var1, @var2 |
| |
| ``` |
| }]; |
| |
| let arguments = (ins |
| SPV_ExecutionModelAttr:$execution_model, |
| FlatSymbolRefAttr:$fn, |
| SymbolRefArrayAttr:$interface |
| ); |
| |
| let results = (outs); |
| |
| let autogenSerialization = 0; |
| |
| let builders = [ |
| OpBuilder<(ins "spirv::ExecutionModel":$executionModel, |
| "spirv::FuncOp":$function, "ArrayRef<Attribute>":$interfaceVars)>]; |
| } |
| |
| // ----- |
| |
| def SPV_ExecutionModeOp : SPV_Op<"ExecutionMode", [InModuleScope]> { |
| let summary = "Declare an execution mode for an entry point."; |
| |
| let description = [{ |
| Entry Point must be the Entry Point <id> operand of an OpEntryPoint |
| instruction. |
| |
| Mode is the execution mode. See Execution Mode. |
| |
| This instruction is only valid when the Mode operand is an execution |
| mode that takes no Extra Operands, or takes Extra Operands that are not |
| <id> operands. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| execution-mode ::= "Invocations" | "SpacingEqual" | |
| <and other SPIR-V execution modes...> |
| |
| execution-mode-op ::= `spv.ExecutionMode ` ssa-use execution-mode |
| (integer-literal (`, ` integer-literal)* )? |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| spv.ExecutionMode @foo "ContractionOff" |
| spv.ExecutionMode @bar "LocalSizeHint", 3, 4, 5 |
| ``` |
| }]; |
| |
| let arguments = (ins |
| FlatSymbolRefAttr:$fn, |
| SPV_ExecutionModeAttr:$execution_mode, |
| I32ArrayAttr:$values |
| ); |
| |
| let results = (outs); |
| |
| let verifier = [{ return success(); }]; |
| |
| let autogenSerialization = 0; |
| |
| let builders = [ |
| OpBuilder<(ins "spirv::FuncOp":$function, |
| "spirv::ExecutionMode":$executionMode, "ArrayRef<int32_t>":$params)>]; |
| } |
| |
| // ----- |
| |
| def SPV_FuncOp : SPV_Op<"func", [ |
| AutomaticAllocationScope, DeclareOpInterfaceMethods<CallableOpInterface>, |
| FunctionLike, InModuleScope, IsolatedFromAbove, Symbol |
| ]> { |
| let summary = "Declare or define a function"; |
| |
| let description = [{ |
| This op declares or defines a SPIR-V function using one region, which |
| contains one or more blocks. |
| |
| Different from the SPIR-V binary format, this op is not allowed to |
| implicitly capture global values, and all external references must use |
| function arguments or symbol references. This op itself defines a symbol |
| that is unique in the enclosing module op. |
| |
| This op itself takes no operands and generates no results. Its region |
| can take zero or more arguments and return zero or one values. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| spv-function-control ::= "None" | "Inline" | "DontInline" | ... |
| spv-function-op ::= `spv.func` function-signature |
| spv-function-control region |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| spv.func @foo() -> () "None" { ... } |
| spv.func @bar() -> () "Inline|Pure" { ... } |
| ``` |
| }]; |
| |
| let arguments = (ins |
| TypeAttr:$type, |
| StrAttr:$sym_name, |
| SPV_FunctionControlAttr:$function_control |
| ); |
| |
| let results = (outs); |
| |
| let regions = (region AnyRegion:$body); |
| |
| let verifier = [{ return success(); }]; |
| |
| let builders = [ |
| OpBuilder<(ins "StringRef":$name, "FunctionType":$type, |
| CArg<"spirv::FunctionControl", "spirv::FunctionControl::None">:$control, |
| CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>]; |
| |
| let hasOpcode = 0; |
| |
| let autogenSerialization = 0; |
| |
| let extraClassDeclaration = [{ |
| private: |
| // This trait needs access to the hooks defined below. |
| friend class OpTrait::FunctionLike<FuncOp>; |
| |
| /// Returns the number of arguments. Hook for OpTrait::FunctionLike. |
| unsigned getNumFuncArguments() { return getType().getNumInputs(); } |
| |
| /// Returns the number of results. Hook for OpTrait::FunctionLike. |
| unsigned getNumFuncResults() { return getType().getNumResults(); } |
| |
| /// Hook for OpTrait::FunctionLike, called after verifying that the 'type' |
| /// attribute is present and checks if it holds a function type. Ensures |
| /// getType, getNumFuncArguments, and getNumFuncResults can be called safely |
| LogicalResult verifyType(); |
| |
| /// Hook for OpTrait::FunctionLike, called after verifying the function |
| /// type and the presence of the (potentially empty) function body. |
| /// Ensures SPIR-V specific semantics. |
| LogicalResult verifyBody(); |
| }]; |
| } |
| |
| // ----- |
| |
| def SPV_GlobalVariableOp : SPV_Op<"GlobalVariable", [InModuleScope, Symbol]> { |
| let summary = [{ |
| Allocate an object in memory at module scope. The object is |
| referenced using a symbol name. |
| }]; |
| |
| let description = [{ |
| The variable type must be an OpTypePointer. Its type operand is the type of |
| object in memory. |
| |
| Storage Class is the Storage Class of the memory holding the object. It |
| cannot be Generic. It must be the same as the Storage Class operand of |
| the variable types. Only those storage classes that are valid at module |
| scope (like Input, Output, StorageBuffer, etc.) are valid. |
| |
| Initializer is optional. If Initializer is present, it will be |
| the initial value of the variable’s memory content. Initializer |
| must be an symbol defined from a constant instruction or other |
| `spv.GlobalVariable` operation in module scope. Initializer must |
| have the same type as the type of the defined symbol. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| variable-op ::= `spv.GlobalVariable` spirv-type symbol-ref-id |
| (`initializer(` symbol-ref-id `)`)? |
| (`bind(` integer-literal, integer-literal `)`)? |
| (`built_in(` string-literal `)`)? |
| attribute-dict? |
| ``` |
| |
| where `initializer` specifies initializer and `bind` specifies the |
| descriptor set and binding number. `built_in` specifies SPIR-V |
| BuiltIn decoration associated with the op. |
| |
| #### Example: |
| |
| ```mlir |
| spv.GlobalVariable @var0 : !spv.ptr<f32, Input> @var0 |
| spv.GlobalVariable @var1 initializer(@var0) : !spv.ptr<f32, Output> |
| spv.GlobalVariable @var2 bind(1, 2) : !spv.ptr<f32, Uniform> |
| spv.GlobalVariable @var3 built_in("GlobalInvocationId") : !spv.ptr<vector<3xi32>, Input> |
| ``` |
| }]; |
| |
| let arguments = (ins |
| TypeAttr:$type, |
| StrAttr:$sym_name, |
| OptionalAttr<FlatSymbolRefAttr>:$initializer, |
| OptionalAttr<I32Attr>:$location, |
| OptionalAttr<I32Attr>:$binding, |
| OptionalAttr<I32Attr>:$descriptorSet, |
| OptionalAttr<StrAttr>:$builtin |
| ); |
| |
| let results = (outs); |
| |
| let builders = [ |
| OpBuilder<(ins "TypeAttr":$type, |
| "StringAttr":$sym_name, |
| CArg<"FlatSymbolRefAttr", "nullptr">:$initializer), |
| [{ |
| $_state.addAttribute("type", type); |
| $_state.addAttribute(sym_nameAttrName($_state.name), sym_name); |
| if (initializer) |
| $_state.addAttribute(initializerAttrName($_state.name), initializer); |
| }]>, |
| OpBuilder<(ins "TypeAttr":$type, "ArrayRef<NamedAttribute>":$namedAttrs), |
| [{ |
| $_state.addAttribute("type", type); |
| $_state.addAttributes(namedAttrs); |
| }]>, |
| OpBuilder<(ins "Type":$type, "StringRef":$name, |
| "unsigned":$descriptorSet, "unsigned":$binding)>, |
| OpBuilder<(ins "Type":$type, "StringRef":$name, |
| "spirv::BuiltIn":$builtin)>, |
| OpBuilder<(ins "Type":$type, |
| "StringRef":$sym_name, |
| CArg<"FlatSymbolRefAttr", "{}">:$initializer), |
| [{ |
| $_state.addAttribute("type", TypeAttr::get(type)); |
| $_state.addAttribute(sym_nameAttrName($_state.name), $_builder.getStringAttr(sym_name)); |
| if (initializer) |
| $_state.addAttribute(initializerAttrName($_state.name), initializer); |
| }]> |
| ]; |
| |
| let hasOpcode = 0; |
| |
| let autogenSerialization = 0; |
| |
| let extraClassDeclaration = [{ |
| ::mlir::spirv::StorageClass storageClass() { |
| return this->type().cast<::mlir::spirv::PointerType>().getStorageClass(); |
| } |
| }]; |
| } |
| |
| // ----- |
| |
| def SPV_ModuleOp : SPV_Op<"module", |
| [IsolatedFromAbove, NoRegionArguments, NoTerminator, |
| SingleBlock, SymbolTable, Symbol]> { |
| let summary = "The top-level op that defines a SPIR-V module"; |
| |
| let description = [{ |
| This op defines a SPIR-V module using a MLIR region. The region contains |
| one block. Module-level operations, including functions definitions, |
| are all placed in this block. |
| |
| Using an op with a region to define a SPIR-V module enables "embedding" |
| SPIR-V modules in other dialects in a clean manner: this op guarantees |
| the validity and serializability of a SPIR-V module and thus serves as |
| a clear-cut boundary. |
| |
| This op takes no operands and generates no results. This op should not |
| implicitly capture values from the enclosing environment. |
| |
| This op has only one region, which only contains one block. The block |
| has no terminator. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| addressing-model ::= `Logical` | `Physical32` | `Physical64` | ... |
| memory-model ::= `Simple` | `GLSL450` | `OpenCL` | `Vulkan` | ... |
| spv-module-op ::= `spv.module` addressing-model memory-model |
| (requires spirv-vce-attribute)? |
| (`attributes` attribute-dict)? |
| region |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| spv.module Logical GLSL450 {} |
| |
| spv.module Logical Vulkan |
| requires #spv.vce<v1.0, [Shader], [SPV_KHR_vulkan_memory_model]> |
| attributes { some_additional_attr = ... } { |
| spv.func @do_nothing() -> () { |
| spv.Return |
| } |
| } |
| ``` |
| }]; |
| |
| let arguments = (ins |
| SPV_AddressingModelAttr:$addressing_model, |
| SPV_MemoryModelAttr:$memory_model, |
| OptionalAttr<SPV_VerCapExtAttr>:$vce_triple, |
| OptionalAttr<StrAttr>:$sym_name |
| ); |
| |
| let results = (outs); |
| |
| let regions = (region AnyRegion); |
| |
| let builders = [ |
| OpBuilder<(ins CArg<"Optional<StringRef>", "llvm::None">:$name)>, |
| OpBuilder<(ins "spirv::AddressingModel":$addressing_model, |
| "spirv::MemoryModel":$memory_model, |
| CArg<"Optional<spirv::VerCapExtAttr>", "llvm::None">:$vce_triple, |
| CArg<"Optional<StringRef>", "llvm::None">:$name)> |
| ]; |
| |
| // We need to ensure the block inside the region is properly terminated; |
| // the auto-generated builders do not guarantee that. |
| let skipDefaultBuilders = 1; |
| |
| let hasOpcode = 0; |
| |
| let autogenSerialization = 0; |
| |
| let extraClassDeclaration = [{ |
| |
| bool isOptionalSymbol() { return true; } |
| |
| Optional<StringRef> getName() { return sym_name(); } |
| |
| static StringRef getVCETripleAttrName() { return "vce_triple"; } |
| }]; |
| } |
| |
| // ----- |
| |
| def SPV_ReferenceOfOp : SPV_Op<"mlir.referenceof", [NoSideEffect]> { |
| let summary = "Reference a specialization constant."; |
| |
| let description = [{ |
| Specialization constants in module scope are defined using symbol names. |
| This op generates an SSA value that can be used to refer to the symbol |
| within function scope for use in ops that expect an SSA value. |
| This operation has no corresponding SPIR-V instruction; it's merely used |
| for modelling purpose in the SPIR-V dialect. This op's return type is |
| the same as the specialization constant. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| spv-reference-of-op ::= ssa-id `=` `spv.mlir.referenceof` symbol-ref-id |
| `:` spirv-scalar-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.mlir.referenceof @spec_const : f32 |
| ``` |
| |
| TODO Add support for composite specialization constants. |
| }]; |
| |
| let arguments = (ins |
| FlatSymbolRefAttr:$spec_const |
| ); |
| |
| let results = (outs |
| SPV_Type:$reference |
| ); |
| |
| let hasOpcode = 0; |
| |
| let autogenSerialization = 0; |
| |
| let assemblyFormat = "$spec_const attr-dict `:` type($reference)"; |
| } |
| |
| // ----- |
| |
| def SPV_SpecConstantOp : SPV_Op<"SpecConstant", [InModuleScope, Symbol]> { |
| let summary = "The op that declares a SPIR-V specialization constant"; |
| |
| let description = [{ |
| This op declares a SPIR-V scalar specialization constant. SPIR-V has |
| multiple constant instructions covering different scalar types: |
| |
| * `OpSpecConstantTrue` and `OpSpecConstantFalse` for boolean constants |
| * `OpSpecConstant` for scalar constants |
| |
| Similar as `spv.Constant`, this op represents all of the above cases. |
| `OpSpecConstantComposite` and `OpSpecConstantOp` are modelled with |
| separate ops. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| spv-spec-constant-op ::= `spv.SpecConstant` symbol-ref-id |
| `spec_id(` integer `)` |
| `=` attribute-value (`:` spirv-type)? |
| ``` |
| |
| where `spec_id` specifies the SPIR-V SpecId decoration associated with |
| the op. |
| |
| #### Example: |
| |
| ```mlir |
| spv.SpecConstant @spec_const1 = true |
| spv.SpecConstant @spec_const2 spec_id(5) = 42 : i32 |
| ``` |
| }]; |
| |
| let arguments = (ins |
| StrAttr:$sym_name, |
| AnyAttr:$default_value |
| ); |
| |
| let results = (outs); |
| |
| let hasOpcode = 0; |
| |
| let autogenSerialization = 0; |
| } |
| |
| // ----- |
| |
| def SPV_SpecConstantCompositeOp : SPV_Op<"SpecConstantComposite", [ |
| InModuleScope, Symbol]> { |
| let summary = "Declare a new composite specialization constant."; |
| |
| let description = [{ |
| This op declares a SPIR-V composite specialization constant. This covers |
| the `OpSpecConstantComposite` SPIR-V instruction. Scalar constants are |
| covered by `spv.SpecConstant`. |
| |
| A constituent of a spec constant composite can be: |
| - A symbol referring of another spec constant. |
| - The SSA ID of a non-specialization constant (i.e. defined through |
| `spv.SpecConstant`). |
| - The SSA ID of a `spv.Undef`. |
| |
| ``` |
| spv-spec-constant-composite-op ::= `spv.SpecConstantComposite` symbol-ref-id ` (` |
| symbol-ref-id (`, ` symbol-ref-id)* |
| `) :` composite-type |
| ``` |
| |
| where `composite-type` is some non-scalar type that can be represented in the `spv` |
| dialect: `spv.struct`, `spv.array`, or `vector`. |
| |
| #### Example: |
| |
| ```mlir |
| spv.SpecConstant @sc1 = 1 : i32 |
| spv.SpecConstant @sc2 = 2.5 : f32 |
| spv.SpecConstant @sc3 = 3.5 : f32 |
| spv.SpecConstantComposite @scc (@sc1, @sc2, @sc3) : !spv.struct<i32, f32, f32> |
| ``` |
| |
| TODO Add support for constituents that are: |
| - regular constants. |
| - undef. |
| - spec constant composite. |
| }]; |
| |
| let arguments = (ins |
| TypeAttr:$type, |
| StrAttr:$sym_name, |
| SymbolRefArrayAttr:$constituents |
| ); |
| |
| let results = (outs); |
| |
| let hasOpcode = 0; |
| |
| let autogenSerialization = 0; |
| } |
| |
| // ----- |
| |
| def SPV_SpecConstantOperationOp : SPV_Op<"SpecConstantOperation", [ |
| NoSideEffect, InFunctionScope, |
| SingleBlockImplicitTerminator<"YieldOp">]> { |
| let summary = [{ |
| Declare a new specialization constant that results from doing an operation. |
| }]; |
| |
| let description = [{ |
| This op declares a SPIR-V specialization constant that results from |
| doing an operation on other constants (specialization or otherwise). |
| |
| In the `spv` dialect, this op is modelled as follows: |
| |
| ``` |
| spv-spec-constant-operation-op ::= `spv.SpecConstantOperation` `wraps` |
| generic-spirv-op `:` function-type |
| ``` |
| |
| In particular, an `spv.SpecConstantOperation` contains exactly one |
| region. In turn, that region, contains exactly 2 instructions: |
| - One of SPIR-V's instructions that are allowed within an |
| OpSpecConstantOp. |
| - An `spv.mlir.yield` instruction as the terminator. |
| |
| The following SPIR-V instructions are valid: |
| - OpSConvert, |
| - OpUConvert, |
| - OpFConvert, |
| - OpSNegate, |
| - OpNot, |
| - OpIAdd, |
| - OpISub, |
| - OpIMul, |
| - OpUDiv, |
| - OpSDiv, |
| - OpUMod, |
| - OpSRem, |
| - OpSMod |
| - OpShiftRightLogical, |
| - OpShiftRightArithmetic, |
| - OpShiftLeftLogical |
| - OpBitwiseOr, |
| - OpBitwiseXor, |
| - OpBitwiseAnd |
| - OpVectorShuffle, |
| - OpCompositeExtract, |
| - OpCompositeInsert |
| - OpLogicalOr, |
| - OpLogicalAnd, |
| - OpLogicalNot, |
| - OpLogicalEqual, |
| - OpLogicalNotEqual |
| - OpSelect |
| - OpIEqual, |
| - OpINotEqual |
| - OpULessThan, |
| - OpSLessThan |
| - OpUGreaterThan, |
| - OpSGreaterThan |
| - OpULessThanEqual, |
| - OpSLessThanEqual |
| - OpUGreaterThanEqual, |
| - OpSGreaterThanEqual |
| |
| TODO Add capability-specific ops when supported. |
| |
| #### Example: |
| ```mlir |
| %0 = spv.Constant 1: i32 |
| %1 = spv.Constant 1: i32 |
| |
| %2 = spv.SpecConstantOperation wraps "spv.IAdd"(%0, %1) : (i32, i32) -> i32 |
| ``` |
| }]; |
| |
| let arguments = (ins); |
| |
| let results = (outs AnyType:$result); |
| |
| let regions = (region SizedRegion<1>:$body); |
| |
| let hasOpcode = 0; |
| |
| let autogenSerialization = 0; |
| } |
| |
| // ----- |
| |
| def SPV_YieldOp : SPV_Op<"mlir.yield", [ |
| HasParent<"SpecConstantOperationOp">, NoSideEffect, Terminator]> { |
| let summary = [{ |
| Yields the result computed in `spv.SpecConstantOperation`'s |
| region back to the parent op. |
| }]; |
| |
| let description = [{ |
| This op is a special terminator whose only purpose is to terminate |
| an `spv.SpecConstantOperation`'s enclosed region. It accepts a |
| single operand produced by the preceeding (and only other) instruction |
| in its parent block (see SPV_SpecConstantOperation for further |
| details). This op has no corresponding SPIR-V instruction. |
| |
| ``` |
| spv.mlir.yield ::= `spv.mlir.yield` ssa-id : spirv-type |
| ``` |
| |
| #### Example: |
| ```mlir |
| %0 = ... (some op supported by SPIR-V OpSpecConstantOp) |
| spv.mlir.yield %0 |
| ``` |
| }]; |
| |
| let arguments = (ins AnyType:$operand); |
| |
| let results = (outs); |
| |
| let hasOpcode = 0; |
| |
| let autogenSerialization = 0; |
| |
| let assemblyFormat = "attr-dict $operand `:` type($operand)"; |
| |
| let verifier = [{ return success(); }]; |
| } |
| |
| // ----- |
| |
| #endif // MLIR_DIALECT_SPIRV_IR_STRUCTURE_OPS |