diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBarrierOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBarrierOps.td new file mode 100644 --- /dev/null +++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBarrierOps.td @@ -0,0 +1,141 @@ +//===-- SPIRVBarrierOps.td - MLIR SPIR-V Barrier 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 barrier ops for the SPIR-V dialect. It corresponds +// to "3.32.20. Barrrier Instructions" of the SPIR-V spec. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_DIALECT_SPIRV_IR_BARRIER_OPS +#define MLIR_DIALECT_SPIRV_IR_BARRIER_OPS + +include "mlir/Dialect/SPIRV/IR/SPIRVBase.td" + +// ----- + +def SPV_ControlBarrierOp : SPV_Op<"ControlBarrier", []> { + let summary = [{ + Wait for other invocations of this module to reach the current point of + execution. + }]; + + let description = [{ + All invocations of this module within Execution scope must reach this + point of execution before any invocation will proceed beyond it. + + When Execution is Workgroup or larger, behavior is undefined if this + instruction is used in control flow that is non-uniform within + Execution. When Execution is Subgroup or Invocation, the behavior of + this instruction in non-uniform control flow is defined by the client + API. + + If Semantics is not None, this instruction also serves as an + OpMemoryBarrier instruction, and must also perform and adhere to the + description and semantics of an OpMemoryBarrier instruction with the + same Memory and Semantics operands. This allows atomically specifying + both a control barrier and a memory barrier (that is, without needing + two instructions). If Semantics is None, Memory is ignored. + + Before version 1.3, it is only valid to use this instruction with + TessellationControl, GLCompute, or Kernel execution models. There is no + such restriction starting with version 1.3. + + When used with the TessellationControl execution model, it also + implicitly synchronizes the Output Storage Class: Writes to Output + variables performed by any invocation executed prior to a + OpControlBarrier will be visible to any other invocation after return + from that OpControlBarrier. + + + + ``` + scope ::= `"CrossDevice"` | `"Device"` | `"Workgroup"` | ... + + memory-semantics ::= `"None"` | `"Acquire"` | "Release"` | ... + + control-barrier-op ::= `spv.ControlBarrier` scope, scope, memory-semantics + ``` + + #### Example: + + ```mlir + spv.ControlBarrier "Workgroup", "Device", "Acquire|UniformMemory" + + ``` + }]; + + let arguments = (ins + SPV_ScopeAttr:$execution_scope, + SPV_ScopeAttr:$memory_scope, + SPV_MemorySemanticsAttr:$memory_semantics + ); + + let results = (outs); + + let verifier = [{ return verifyMemorySemantics(*this); }]; + + let autogenSerialization = 0; + + let assemblyFormat = [{ + $execution_scope `,` $memory_scope `,` $memory_semantics attr-dict + }]; +} + +// ----- + +def SPV_MemoryBarrierOp : SPV_Op<"MemoryBarrier", []> { + let summary = "Control the order that memory accesses are observed."; + + let description = [{ + Ensures that memory accesses issued before this instruction will be + observed before memory accesses issued after this instruction. This + control is ensured only for memory accesses issued by this invocation + and observed by another invocation executing within Memory scope. If the + Vulkan memory model is declared, this ordering only applies to memory + accesses that use the NonPrivatePointer memory operand or + NonPrivateTexel image operand. + + Semantics declares what kind of memory is being controlled and what kind + of control to apply. + + To execute both a memory barrier and a control barrier, see + OpControlBarrier. + + + + ``` + scope ::= `"CrossDevice"` | `"Device"` | `"Workgroup"` | ... + + memory-semantics ::= `"None"` | `"Acquire"` | `"Release"` | ... + + memory-barrier-op ::= `spv.MemoryBarrier` scope, memory-semantics + ``` + + #### Example: + + ```mlir + spv.MemoryBarrier "Device", "Acquire|UniformMemory" + + ``` + }]; + + let arguments = (ins + SPV_ScopeAttr:$memory_scope, + SPV_MemorySemanticsAttr:$memory_semantics + ); + + let results = (outs); + + let verifier = [{ return verifyMemorySemantics(*this); }]; + + let autogenSerialization = 0; + + let assemblyFormat = "$memory_scope `,` $memory_semantics attr-dict"; +} + +#endif // MLIR_DIALECT_SPIRV_IR_BARRIER_OPS diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVMemoryOps.td copy from mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.td copy to mlir/include/mlir/Dialect/SPIRV/IR/SPIRVMemoryOps.td --- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.td +++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVMemoryOps.td @@ -1,4 +1,4 @@ -//===-- SPIRVOps.td - MLIR SPIR-V Op Definitions Spec ------*- tablegen -*-===// +//===-- SPIRVMemoryOps.td - MLIR SPIR-V Memory 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. @@ -6,37 +6,15 @@ // //===----------------------------------------------------------------------===// // -// This is the main operation definition specification file for SPIR-V -// operations. +// This file contains memory ops for the SPIR-V dialect. It corresponds +// to "3.32.8. Memory Instructions" of the SPIR-V spec. // //===----------------------------------------------------------------------===// -// Note that for each op in this file and the included files for specific op -// categories, we use a tool to automatically generate certain sections in its -// definition: basic structure, summary, description. So modifications to these -// sections will not be respected. Modifications to op traits, arguments, -// results, and sections after the results are retained. Besides, ops must be -// separated via the '// -----' marker. - -#ifndef MLIR_DIALECT_SPIRV_IR_OPS -#define MLIR_DIALECT_SPIRV_IR_OPS +#ifndef MLIR_DIALECT_SPIRV_IR_MEMORY_OPS +#define MLIR_DIALECT_SPIRV_IR_MEMORY_OPS include "mlir/Dialect/SPIRV/IR/SPIRVBase.td" -include "mlir/Dialect/SPIRV/IR/SPIRVArithmeticOps.td" -include "mlir/Dialect/SPIRV/IR/SPIRVAtomicOps.td" -include "mlir/Dialect/SPIRV/IR/SPIRVBitOps.td" -include "mlir/Dialect/SPIRV/IR/SPIRVCastOps.td" -include "mlir/Dialect/SPIRV/IR/SPIRVCompositeOps.td" -include "mlir/Dialect/SPIRV/IR/SPIRVControlFlowOps.td" -include "mlir/Dialect/SPIRV/IR/SPIRVCooperativeMatrixOps.td" -include "mlir/Dialect/SPIRV/IR/SPIRVGLSLOps.td" -include "mlir/Dialect/SPIRV/IR/SPIRVGroupOps.td" -include "mlir/Dialect/SPIRV/IR/SPIRVLogicalOps.td" -include "mlir/Dialect/SPIRV/IR/SPIRVMatrixOps.td" -include "mlir/Dialect/SPIRV/IR/SPIRVNonUniformOps.td" -include "mlir/Dialect/SPIRV/IR/SPIRVOCLOps.td" -include "mlir/Dialect/SPIRV/IR/SPIRVStructureOps.td" -include "mlir/Interfaces/SideEffectInterfaces.td" // ----- @@ -103,76 +81,6 @@ // ----- -def SPV_ControlBarrierOp : SPV_Op<"ControlBarrier", []> { - let summary = [{ - Wait for other invocations of this module to reach the current point of - execution. - }]; - - let description = [{ - All invocations of this module within Execution scope must reach this - point of execution before any invocation will proceed beyond it. - - When Execution is Workgroup or larger, behavior is undefined if this - instruction is used in control flow that is non-uniform within - Execution. When Execution is Subgroup or Invocation, the behavior of - this instruction in non-uniform control flow is defined by the client - API. - - If Semantics is not None, this instruction also serves as an - OpMemoryBarrier instruction, and must also perform and adhere to the - description and semantics of an OpMemoryBarrier instruction with the - same Memory and Semantics operands. This allows atomically specifying - both a control barrier and a memory barrier (that is, without needing - two instructions). If Semantics is None, Memory is ignored. - - Before version 1.3, it is only valid to use this instruction with - TessellationControl, GLCompute, or Kernel execution models. There is no - such restriction starting with version 1.3. - - When used with the TessellationControl execution model, it also - implicitly synchronizes the Output Storage Class: Writes to Output - variables performed by any invocation executed prior to a - OpControlBarrier will be visible to any other invocation after return - from that OpControlBarrier. - - - - ``` - scope ::= `"CrossDevice"` | `"Device"` | `"Workgroup"` | ... - - memory-semantics ::= `"None"` | `"Acquire"` | "Release"` | ... - - control-barrier-op ::= `spv.ControlBarrier` scope, scope, memory-semantics - ``` - - #### Example: - - ```mlir - spv.ControlBarrier "Workgroup", "Device", "Acquire|UniformMemory" - - ``` - }]; - - let arguments = (ins - SPV_ScopeAttr:$execution_scope, - SPV_ScopeAttr:$memory_scope, - SPV_MemorySemanticsAttr:$memory_semantics - ); - - let results = (outs); - - let verifier = [{ return verifyMemorySemantics(*this); }]; - - let autogenSerialization = 0; - - let assemblyFormat = [{ - $execution_scope `,` $memory_scope `,` $memory_semantics attr-dict - }]; -} - -// ----- - def SPV_CopyMemoryOp : SPV_Op<"CopyMemory", []> { let summary = [{ Copy from the memory pointed to by Source to the memory pointed to by @@ -229,56 +137,6 @@ // ----- -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 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 - operands. - - - - ``` - execution-mode ::= "Invocations" | "SpacingEqual" | - - - 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 = [ - OpBuilderDAG<(ins "spirv::FuncOp":$function, - "spirv::ExecutionMode":$executionMode, "ArrayRef":$params)>]; -} - -// ----- - def SPV_LoadOp : SPV_Op<"Load", []> { let summary = "Load through a pointer."; @@ -333,58 +191,6 @@ // ----- -def SPV_MemoryBarrierOp : SPV_Op<"MemoryBarrier", []> { - let summary = "Control the order that memory accesses are observed."; - - let description = [{ - Ensures that memory accesses issued before this instruction will be - observed before memory accesses issued after this instruction. This - control is ensured only for memory accesses issued by this invocation - and observed by another invocation executing within Memory scope. If the - Vulkan memory model is declared, this ordering only applies to memory - accesses that use the NonPrivatePointer memory operand or - NonPrivateTexel image operand. - - Semantics declares what kind of memory is being controlled and what kind - of control to apply. - - To execute both a memory barrier and a control barrier, see - OpControlBarrier. - - - - ``` - scope ::= `"CrossDevice"` | `"Device"` | `"Workgroup"` | ... - - memory-semantics ::= `"None"` | `"Acquire"` | `"Release"` | ... - - memory-barrier-op ::= `spv.MemoryBarrier` scope, memory-semantics - ``` - - #### Example: - - ```mlir - spv.MemoryBarrier "Device", "Acquire|UniformMemory" - - ``` - }]; - - let arguments = (ins - SPV_ScopeAttr:$memory_scope, - SPV_MemorySemanticsAttr:$memory_semantics - ); - - let results = (outs); - - let verifier = [{ return verifyMemorySemantics(*this); }]; - - let autogenSerialization = 0; - - let assemblyFormat = "$memory_scope `,` $memory_semantics attr-dict"; -} - -// ----- - def SPV_StoreOp : SPV_Op<"Store", []> { let summary = "Store through a pointer."; @@ -438,46 +244,6 @@ // ----- -def SPV_UndefOp : SPV_Op<"undef", []> { - let summary = "Make an intermediate object whose value is undefined."; - - let description = [{ - Result Type is the type of object to make. - - Each consumption of Result yields an arbitrary, possibly different - bit pattern or abstract value resulting in possibly different concrete, - abstract, or opaque values. - - - - ``` - undef-op ::= `spv.undef` `:` spirv-type - ``` - - #### Example: - - ```mlir - %0 = spv.undef : f32 - %1 = spv.undef : !spv.struct>> - ``` - }]; - - let arguments = (ins); - - let results = (outs - SPV_Type:$result - ); - - let verifier = [{ return success(); }]; - - let hasOpcode = 0; - let autogenSerialization = 0; - - let assemblyFormat = "attr-dict `:` type($result)"; -} - -// ----- - def SPV_VariableOp : SPV_Op<"Variable", []> { let summary = [{ Allocate an object in memory, resulting in a pointer to it, which can be @@ -527,6 +293,4 @@ ); } -// ----- - -#endif // MLIR_DIALECT_SPIRV_IR_OPS +#endif // MLIR_DIALECT_SPIRV_IR_MEMORY_OPS diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVMiscOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVMiscOps.td new file mode 100644 --- /dev/null +++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVMiscOps.td @@ -0,0 +1,61 @@ +//===-- SPIRVBarrierOps.td - MLIR SPIR-V Barrier 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 miscellaneous ops for the SPIR-V dialect. It corresponds +// to "3.32.1. Miscellaneous Instructions" of the SPIR-V spec. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_DIALECT_SPIRV_IR_MISC_OPS +#define MLIR_DIALECT_SPIRV_IR_MISC_OPS + +include "mlir/Dialect/SPIRV/IR/SPIRVBase.td" + +// ----- + +def SPV_UndefOp : SPV_Op<"undef", []> { + let summary = "Make an intermediate object whose value is undefined."; + + let description = [{ + Result Type is the type of object to make. + + Each consumption of Result yields an arbitrary, possibly different + bit pattern or abstract value resulting in possibly different concrete, + abstract, or opaque values. + + + + ``` + undef-op ::= `spv.undef` `:` spirv-type + ``` + + #### Example: + + ```mlir + %0 = spv.undef : f32 + %1 = spv.undef : !spv.struct>> + ``` + }]; + + let arguments = (ins); + + let results = (outs + SPV_Type:$result + ); + + let verifier = [{ return success(); }]; + + let hasOpcode = 0; + let autogenSerialization = 0; + + let assemblyFormat = "attr-dict `:` type($result)"; +} + +// ----- + +#endif // MLIR_DIALECT_SPIRV_IR_MISC_OPS diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.td --- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.td +++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.td @@ -24,6 +24,7 @@ include "mlir/Dialect/SPIRV/IR/SPIRVBase.td" include "mlir/Dialect/SPIRV/IR/SPIRVArithmeticOps.td" include "mlir/Dialect/SPIRV/IR/SPIRVAtomicOps.td" +include "mlir/Dialect/SPIRV/IR/SPIRVBarrierOps.td" include "mlir/Dialect/SPIRV/IR/SPIRVBitOps.td" include "mlir/Dialect/SPIRV/IR/SPIRVCastOps.td" include "mlir/Dialect/SPIRV/IR/SPIRVCompositeOps.td" @@ -33,500 +34,11 @@ include "mlir/Dialect/SPIRV/IR/SPIRVGroupOps.td" include "mlir/Dialect/SPIRV/IR/SPIRVLogicalOps.td" include "mlir/Dialect/SPIRV/IR/SPIRVMatrixOps.td" +include "mlir/Dialect/SPIRV/IR/SPIRVMemoryOps.td" +include "mlir/Dialect/SPIRV/IR/SPIRVMiscOps.td" include "mlir/Dialect/SPIRV/IR/SPIRVNonUniformOps.td" include "mlir/Dialect/SPIRV/IR/SPIRVOCLOps.td" include "mlir/Dialect/SPIRV/IR/SPIRVStructureOps.td" include "mlir/Interfaces/SideEffectInterfaces.td" -// ----- - -def SPV_AccessChainOp : SPV_Op<"AccessChain", [NoSideEffect]> { - let summary = [{ - Create a pointer into a composite object that can be used with OpLoad - and OpStore. - }]; - - let description = [{ - Result Type must be an OpTypePointer. Its Type operand must be the type - reached by walking the Base’s type hierarchy down to the last provided - index in Indexes, and its Storage Class operand must be the same as the - Storage Class of Base. - - Base must be a pointer, pointing to the base of a composite object. - - Indexes walk the type hierarchy to the desired depth, potentially down - to scalar granularity. The first index in Indexes will select the top- - level member/element/component/element of the base composite. All - composite constituents use zero-based numbering, as described by their - OpType… instruction. The second index will apply similarly to that - result, and so on. Once any non-composite type is reached, there must be - no remaining (unused) indexes. - - Each index in Indexes - - - must be a scalar integer type, - - - is treated as a signed count, and - - - must be an OpConstant when indexing into a structure. - - - ``` - access-chain-op ::= ssa-id `=` `spv.AccessChain` ssa-use - `[` ssa-use (',' ssa-use)* `]` - `:` pointer-type - ``` - - #### Example: - - ```mlir - %0 = "spv.constant"() { value = 1: i32} : () -> i32 - %1 = spv.Variable : !spv.ptr>, Function> - %2 = spv.AccessChain %1[%0] : !spv.ptr>, Function> - %3 = spv.Load "Function" %2 ["Volatile"] : !spv.array<4xf32> - ``` - }]; - - let arguments = (ins - SPV_AnyPtr:$base_ptr, - Variadic:$indices - ); - - let results = (outs - SPV_AnyPtr:$component_ptr - ); - - let builders = [OpBuilderDAG<(ins "Value":$basePtr, "ValueRange":$indices)>]; - - let hasCanonicalizer = 1; -} - -// ----- - -def SPV_ControlBarrierOp : SPV_Op<"ControlBarrier", []> { - let summary = [{ - Wait for other invocations of this module to reach the current point of - execution. - }]; - - let description = [{ - All invocations of this module within Execution scope must reach this - point of execution before any invocation will proceed beyond it. - - When Execution is Workgroup or larger, behavior is undefined if this - instruction is used in control flow that is non-uniform within - Execution. When Execution is Subgroup or Invocation, the behavior of - this instruction in non-uniform control flow is defined by the client - API. - - If Semantics is not None, this instruction also serves as an - OpMemoryBarrier instruction, and must also perform and adhere to the - description and semantics of an OpMemoryBarrier instruction with the - same Memory and Semantics operands. This allows atomically specifying - both a control barrier and a memory barrier (that is, without needing - two instructions). If Semantics is None, Memory is ignored. - - Before version 1.3, it is only valid to use this instruction with - TessellationControl, GLCompute, or Kernel execution models. There is no - such restriction starting with version 1.3. - - When used with the TessellationControl execution model, it also - implicitly synchronizes the Output Storage Class: Writes to Output - variables performed by any invocation executed prior to a - OpControlBarrier will be visible to any other invocation after return - from that OpControlBarrier. - - - - ``` - scope ::= `"CrossDevice"` | `"Device"` | `"Workgroup"` | ... - - memory-semantics ::= `"None"` | `"Acquire"` | "Release"` | ... - - control-barrier-op ::= `spv.ControlBarrier` scope, scope, memory-semantics - ``` - - #### Example: - - ```mlir - spv.ControlBarrier "Workgroup", "Device", "Acquire|UniformMemory" - - ``` - }]; - - let arguments = (ins - SPV_ScopeAttr:$execution_scope, - SPV_ScopeAttr:$memory_scope, - SPV_MemorySemanticsAttr:$memory_semantics - ); - - let results = (outs); - - let verifier = [{ return verifyMemorySemantics(*this); }]; - - let autogenSerialization = 0; - - let assemblyFormat = [{ - $execution_scope `,` $memory_scope `,` $memory_semantics attr-dict - }]; -} - -// ----- - -def SPV_CopyMemoryOp : SPV_Op<"CopyMemory", []> { - let summary = [{ - Copy from the memory pointed to by Source to the memory pointed to by - Target. Both operands must be non-void pointers and having the same - Type operand in their OpTypePointer type declaration. Matching Storage - Class is not required. The amount of memory copied is the size of the - type pointed to. The copied type must have a fixed size; i.e., it cannot - be, nor include, any OpTypeRuntimeArray types. - }]; - - let description = [{ - If present, any Memory Operands must begin with a memory operand - literal. If not present, it is the same as specifying the memory operand - None. Before version 1.4, at most one memory operands mask can be - provided. Starting with version 1.4 two masks can be provided, as - described in Memory Operands. If no masks or only one mask is present, - it applies to both Source and Target. If two masks are present, the - first applies to Target and cannot include MakePointerVisible, and the - second applies to Source and cannot include MakePointerAvailable. - - - - ``` - copy-memory-op ::= `spv.CopyMemory ` storage-class ssa-use - storage-class ssa-use - (`[` memory-access `]` (`, [` memory-access `]`)?)? - ` : ` spirv-element-type - ``` - - #### Example: - - ```mlir - %0 = spv.Variable : !spv.ptr - %1 = spv.Variable : !spv.ptr - spv.CopyMemory "Function" %0, "Function" %1 : f32 - ``` - }]; - - let arguments = (ins - SPV_AnyPtr:$target, - SPV_AnyPtr:$source, - OptionalAttr:$memory_access, - OptionalAttr:$alignment, - OptionalAttr:$source_memory_access, - OptionalAttr:$source_alignment - ); - - let results = (outs); - - let verifier = [{ return verifyCopyMemory(*this); }]; - - let autogenSerialization = 0; -} - -// ----- - -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 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 - operands. - - - - ``` - execution-mode ::= "Invocations" | "SpacingEqual" | - - - 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 = [ - OpBuilderDAG<(ins "spirv::FuncOp":$function, - "spirv::ExecutionMode":$executionMode, "ArrayRef":$params)>]; -} - -// ----- - -def SPV_LoadOp : SPV_Op<"Load", []> { - let summary = "Load through a pointer."; - - let description = [{ - Result Type is the type of the loaded object. It must be a type with - fixed size; i.e., it cannot be, nor include, any OpTypeRuntimeArray - types. - - Pointer is the pointer to load through. Its type must be an - OpTypePointer whose Type operand is the same as Result Type. - - If present, any Memory Operands must begin with a memory operand - literal. If not present, it is the same as specifying the memory operand - None. - - - - ``` - memory-access ::= `"None"` | `"Volatile"` | `"Aligned", ` integer-literal - | `"NonTemporal"` - - load-op ::= ssa-id ` = spv.Load ` storage-class ssa-use - (`[` memory-access `]`)? ` : ` spirv-element-type - ``` - - #### Example: - - ```mlir - %0 = spv.Variable : !spv.ptr - %1 = spv.Load "Function" %0 : f32 - %2 = spv.Load "Function" %0 ["Volatile"] : f32 - %3 = spv.Load "Function" %0 ["Aligned", 4] : f32 - ``` - }]; - - let arguments = (ins - SPV_AnyPtr:$ptr, - OptionalAttr:$memory_access, - OptionalAttr:$alignment - ); - - let results = (outs - SPV_Type:$value - ); - - let builders = [ - OpBuilderDAG<(ins "Value":$basePtr, - CArg<"IntegerAttr", "{}">:$memory_access, - CArg<"IntegerAttr", "{}">:$alignment)> - ]; -} - -// ----- - -def SPV_MemoryBarrierOp : SPV_Op<"MemoryBarrier", []> { - let summary = "Control the order that memory accesses are observed."; - - let description = [{ - Ensures that memory accesses issued before this instruction will be - observed before memory accesses issued after this instruction. This - control is ensured only for memory accesses issued by this invocation - and observed by another invocation executing within Memory scope. If the - Vulkan memory model is declared, this ordering only applies to memory - accesses that use the NonPrivatePointer memory operand or - NonPrivateTexel image operand. - - Semantics declares what kind of memory is being controlled and what kind - of control to apply. - - To execute both a memory barrier and a control barrier, see - OpControlBarrier. - - - - ``` - scope ::= `"CrossDevice"` | `"Device"` | `"Workgroup"` | ... - - memory-semantics ::= `"None"` | `"Acquire"` | `"Release"` | ... - - memory-barrier-op ::= `spv.MemoryBarrier` scope, memory-semantics - ``` - - #### Example: - - ```mlir - spv.MemoryBarrier "Device", "Acquire|UniformMemory" - - ``` - }]; - - let arguments = (ins - SPV_ScopeAttr:$memory_scope, - SPV_MemorySemanticsAttr:$memory_semantics - ); - - let results = (outs); - - let verifier = [{ return verifyMemorySemantics(*this); }]; - - let autogenSerialization = 0; - - let assemblyFormat = "$memory_scope `,` $memory_semantics attr-dict"; -} - -// ----- - -def SPV_StoreOp : SPV_Op<"Store", []> { - let summary = "Store through a pointer."; - - let description = [{ - Pointer is the pointer to store through. Its type must be an - OpTypePointer whose Type operand is the same as the type of Object. - - Object is the object to store. - - If present, any Memory Operands must begin with a memory operand - literal. If not present, it is the same as specifying the memory operand - None. - - - - ``` - store-op ::= `spv.Store ` storage-class ssa-use `, ` ssa-use `, ` - (`[` memory-access `]`)? `:` spirv-element-type - ``` - - #### Example: - - ```mlir - %0 = spv.Variable : !spv.ptr - %1 = spv.FMul ... : f32 - spv.Store "Function" %0, %1 : f32 - spv.Store "Function" %0, %1 ["Volatile"] : f32 - spv.Store "Function" %0, %1 ["Aligned", 4] : f32 - ``` - }]; - - let arguments = (ins - SPV_AnyPtr:$ptr, - SPV_Type:$value, - OptionalAttr:$memory_access, - OptionalAttr:$alignment - ); - - let results = (outs); - - let builders = [ - OpBuilderDAG<(ins "Value":$ptr, "Value":$value, - CArg<"ArrayRef", "{}">:$namedAttrs), - [{ - $_state.addOperands(ptr); - $_state.addOperands(value); - $_state.addAttributes(namedAttrs); - }]> - ]; -} - -// ----- - -def SPV_UndefOp : SPV_Op<"undef", []> { - let summary = "Make an intermediate object whose value is undefined."; - - let description = [{ - Result Type is the type of object to make. - - Each consumption of Result yields an arbitrary, possibly different - bit pattern or abstract value resulting in possibly different concrete, - abstract, or opaque values. - - - - ``` - undef-op ::= `spv.undef` `:` spirv-type - ``` - - #### Example: - - ```mlir - %0 = spv.undef : f32 - %1 = spv.undef : !spv.struct>> - ``` - }]; - - let arguments = (ins); - - let results = (outs - SPV_Type:$result - ); - - let verifier = [{ return success(); }]; - - let hasOpcode = 0; - let autogenSerialization = 0; - - let assemblyFormat = "attr-dict `:` type($result)"; -} - -// ----- - -def SPV_VariableOp : SPV_Op<"Variable", []> { - let summary = [{ - Allocate an object in memory, resulting in a pointer to it, which can be - used with OpLoad and OpStore. - }]; - - let description = [{ - Result 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. - Since the op is used to model function-level variables, the storage class - must be the `Function` Storage Class. - - Initializer is optional. If Initializer is present, it will be the - initial value of the variable’s memory content. Initializer must be an - from a constant instruction or a global (module scope) OpVariable - instruction. Initializer must have the same type as the type pointed to - by Result Type. - - - - ``` - variable-op ::= ssa-id `=` `spv.Variable` (`init(` ssa-use `)`)? - attribute-dict? `:` spirv-pointer-type - ``` - - where `init` specifies initializer. - - #### Example: - - ```mlir - %0 = spv.constant ... - - %1 = spv.Variable : !spv.ptr - %2 = spv.Variable init(%0): !spv.ptr - ``` - }]; - - let arguments = (ins - SPV_StorageClassAttr:$storage_class, - Optional:$initializer - ); - - let results = (outs - SPV_AnyPtr:$pointer - ); -} - -// ----- - #endif // MLIR_DIALECT_SPIRV_IR_OPS diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVStructureOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVStructureOps.td --- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVStructureOps.td +++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVStructureOps.td @@ -195,6 +195,56 @@ // ----- +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 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 + operands. + + + + ``` + execution-mode ::= "Invocations" | "SpacingEqual" | + + + 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 = [ + OpBuilderDAG<(ins "spirv::FuncOp":$function, + "spirv::ExecutionMode":$executionMode, "ArrayRef":$params)>]; +} + +// ----- + def SPV_FuncOp : SPV_Op<"func", [ AutomaticAllocationScope, DeclareOpInterfaceMethods, FunctionLike, InModuleScope, IsolatedFromAbove, Symbol diff --git a/mlir/test/Dialect/SPIRV/IR/barrier-ops.mlir b/mlir/test/Dialect/SPIRV/IR/barrier-ops.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/Dialect/SPIRV/IR/barrier-ops.mlir @@ -0,0 +1,49 @@ +// RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s + +//===----------------------------------------------------------------------===// +// spv.ControlBarrier +//===----------------------------------------------------------------------===// + +func @control_barrier_0() -> () { + // CHECK: spv.ControlBarrier "Workgroup", "Device", "Acquire|UniformMemory" + spv.ControlBarrier "Workgroup", "Device", "Acquire|UniformMemory" + return +} + +// ----- + +func @control_barrier_1() -> () { + // expected-error @+1 {{invalid execution_scope attribute specification: "Something"}} + spv.ControlBarrier "Something", "Device", "Acquire|UniformMemory" + return +} + + +// ----- + +//===----------------------------------------------------------------------===// +// spv.MemoryBarrier +//===----------------------------------------------------------------------===// + +func @memory_barrier_0() -> () { + // CHECK: spv.MemoryBarrier "Device", "Acquire|UniformMemory" + spv.MemoryBarrier "Device", "Acquire|UniformMemory" + return +} + +// ----- + +func @memory_barrier_1() -> () { + // CHECK: spv.MemoryBarrier "Workgroup", "Acquire" + spv.MemoryBarrier "Workgroup", "Acquire" + return +} + +// ----- + +func @memory_barrier_2() -> () { + // expected-error @+1 {{expected at most one of these four memory constraints to be set: `Acquire`, `Release`,`AcquireRelease` or `SequentiallyConsistent`}} + spv.MemoryBarrier "Device", "Acquire|Release" + return +} + diff --git a/mlir/test/Dialect/SPIRV/IR/bit-ops.mlir b/mlir/test/Dialect/SPIRV/IR/bit-ops.mlir --- a/mlir/test/Dialect/SPIRV/IR/bit-ops.mlir +++ b/mlir/test/Dialect/SPIRV/IR/bit-ops.mlir @@ -1,5 +1,79 @@ // RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s +//===----------------------------------------------------------------------===// +// spv.BitCount +//===----------------------------------------------------------------------===// + +func @bitcount(%arg: i32) -> i32 { + // CHECK: spv.BitCount {{%.*}} : i32 + %0 = spv.BitCount %arg : i32 + spv.ReturnValue %0 : i32 +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.BitFieldInsert +//===----------------------------------------------------------------------===// + +func @bit_field_insert_vec(%base: vector<3xi32>, %insert: vector<3xi32>, %offset: i32, %count: i16) -> vector<3xi32> { + // CHECK: {{%.*}} = spv.BitFieldInsert {{%.*}}, {{%.*}}, {{%.*}}, {{%.*}} : vector<3xi32>, i32, i16 + %0 = spv.BitFieldInsert %base, %insert, %offset, %count : vector<3xi32>, i32, i16 + spv.ReturnValue %0 : vector<3xi32> +} + +// ----- + +func @bit_field_insert_invalid_insert_type(%base: vector<3xi32>, %insert: vector<2xi32>, %offset: i32, %count: i16) -> vector<3xi32> { + // expected-error @+1 {{all of {base, insert, result} have same type}} + %0 = "spv.BitFieldInsert" (%base, %insert, %offset, %count) : (vector<3xi32>, vector<2xi32>, i32, i16) -> vector<3xi32> + spv.ReturnValue %0 : vector<3xi32> +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.BitFieldSExtract +//===----------------------------------------------------------------------===// + +func @bit_field_s_extract_vec(%base: vector<3xi32>, %offset: i8, %count: i8) -> vector<3xi32> { + // CHECK: {{%.*}} = spv.BitFieldSExtract {{%.*}}, {{%.*}}, {{%.*}} : vector<3xi32>, i8, i8 + %0 = spv.BitFieldSExtract %base, %offset, %count : vector<3xi32>, i8, i8 + spv.ReturnValue %0 : vector<3xi32> +} + +//===----------------------------------------------------------------------===// +// spv.BitFieldUExtract +//===----------------------------------------------------------------------===// + +func @bit_field_u_extract_vec(%base: vector<3xi32>, %offset: i8, %count: i8) -> vector<3xi32> { + // CHECK: {{%.*}} = spv.BitFieldUExtract {{%.*}}, {{%.*}}, {{%.*}} : vector<3xi32>, i8, i8 + %0 = spv.BitFieldUExtract %base, %offset, %count : vector<3xi32>, i8, i8 + spv.ReturnValue %0 : vector<3xi32> +} + +// ----- + +func @bit_field_u_extract_invalid_result_type(%base: vector<3xi32>, %offset: i32, %count: i16) -> vector<4xi32> { + // expected-error @+1 {{failed to verify that all of {base, result} have same type}} + %0 = "spv.BitFieldUExtract" (%base, %offset, %count) : (vector<3xi32>, i32, i16) -> vector<4xi32> + spv.ReturnValue %0 : vector<4xi32> +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.BitReverse +//===----------------------------------------------------------------------===// + +func @bitreverse(%arg: i32) -> i32 { + // CHECK: spv.BitReverse {{%.*}} : i32 + %0 = spv.BitReverse %arg : i32 + spv.ReturnValue %0 : i32 +} + +// ----- + //===----------------------------------------------------------------------===// // spv.BitwiseOr //===----------------------------------------------------------------------===// @@ -75,3 +149,59 @@ %0 = spv.BitwiseAnd %arg0, %arg1 : f16 return %0 : f16 } + +// ----- + +//===----------------------------------------------------------------------===// +// spv.Not +//===----------------------------------------------------------------------===// + +func @not(%arg: i32) -> i32 { + // CHECK: spv.Not {{%.*}} : i32 + %0 = spv.Not %arg : i32 + spv.ReturnValue %0 : i32 +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.ShiftLeftLogical +//===----------------------------------------------------------------------===// + +func @shift_left_logical(%arg0: i32, %arg1 : i16) -> i32 { + // CHECK: {{%.*}} = spv.ShiftLeftLogical {{%.*}}, {{%.*}} : i32, i16 + %0 = spv.ShiftLeftLogical %arg0, %arg1: i32, i16 + spv.ReturnValue %0 : i32 +} + +// ----- + +func @shift_left_logical_invalid_result_type(%arg0: i32, %arg1 : i16) -> i16 { + // expected-error @+1 {{expected the same type for the first operand and result, but provided 'i32' and 'i16'}} + %0 = "spv.ShiftLeftLogical" (%arg0, %arg1) : (i32, i16) -> (i16) + spv.ReturnValue %0 : i16 +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.ShiftRightArithmetic +//===----------------------------------------------------------------------===// + +func @shift_right_arithmetic(%arg0: vector<4xi32>, %arg1 : vector<4xi8>) -> vector<4xi32> { + // CHECK: {{%.*}} = spv.ShiftRightArithmetic {{%.*}}, {{%.*}} : vector<4xi32>, vector<4xi8> + %0 = spv.ShiftRightArithmetic %arg0, %arg1: vector<4xi32>, vector<4xi8> + spv.ReturnValue %0 : vector<4xi32> +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.ShiftRightLogical +//===----------------------------------------------------------------------===// + +func @shift_right_logical(%arg0: vector<2xi32>, %arg1 : vector<2xi8>) -> vector<2xi32> { + // CHECK: {{%.*}} = spv.ShiftRightLogical {{%.*}}, {{%.*}} : vector<2xi32>, vector<2xi8> + %0 = spv.ShiftRightLogical %arg0, %arg1: vector<2xi32>, vector<2xi8> + spv.ReturnValue %0 : vector<2xi32> +} diff --git a/mlir/test/Dialect/SPIRV/IR/cast-ops.mlir b/mlir/test/Dialect/SPIRV/IR/cast-ops.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/Dialect/SPIRV/IR/cast-ops.mlir @@ -0,0 +1,262 @@ +// RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s + +//===----------------------------------------------------------------------===// +// spv.Bitcast +//===----------------------------------------------------------------------===// + +func @cast1(%arg0 : f32) { + // CHECK: {{%.*}} = spv.Bitcast {{%.*}} : f32 to i32 + %0 = spv.Bitcast %arg0 : f32 to i32 + return +} + +func @cast2(%arg0 : vector<2xf32>) { + // CHECK: {{%.*}} = spv.Bitcast {{%.*}} : vector<2xf32> to vector<2xi32> + %0 = spv.Bitcast %arg0 : vector<2xf32> to vector<2xi32> + return +} + +func @cast3(%arg0 : vector<2xf32>) { + // CHECK: {{%.*}} = spv.Bitcast {{%.*}} : vector<2xf32> to i64 + %0 = spv.Bitcast %arg0 : vector<2xf32> to i64 + return +} + +func @cast4(%arg0 : !spv.ptr) { + // CHECK: {{%.*}} = spv.Bitcast {{%.*}} : !spv.ptr to !spv.ptr + %0 = spv.Bitcast %arg0 : !spv.ptr to !spv.ptr + return +} + +func @cast5(%arg0 : !spv.ptr) { + // CHECK: {{%.*}} = spv.Bitcast {{%.*}} : !spv.ptr to !spv.ptr, Function> + %0 = spv.Bitcast %arg0 : !spv.ptr to !spv.ptr, Function> + return +} + +func @cast6(%arg0 : vector<4xf32>) { + // CHECK: {{%.*}} = spv.Bitcast {{%.*}} : vector<4xf32> to vector<2xi64> + %0 = spv.Bitcast %arg0 : vector<4xf32> to vector<2xi64> + return +} + +// ----- + +func @cast1(%arg0 : f32) { + // expected-error @+1 {{result type must be different from operand type}} + %0 = spv.Bitcast %arg0 : f32 to f32 + return +} + +// ----- + +func @cast1(%arg0 : f32) { + // expected-error @+1 {{mismatch in result type bitwidth 64 and operand type bitwidth 32}} + %0 = spv.Bitcast %arg0 : f32 to i64 + return +} + +// ----- + +func @cast1(%arg0 : vector<2xf32>) { + // expected-error @+1 {{mismatch in result type bitwidth 96 and operand type bitwidth 64}} + %0 = spv.Bitcast %arg0 : vector<2xf32> to vector<3xf32> + return +} + +// ----- + +func @cast3(%arg0 : !spv.ptr) { + // expected-error @+1 {{unhandled bit cast conversion from pointer type to non-pointer type}} + %0 = spv.Bitcast %arg0 : !spv.ptr to i64 + return +} + +// ----- + +func @cast3(%arg0 : i64) { + // expected-error @+1 {{unhandled bit cast conversion from non-pointer type to pointer type}} + %0 = spv.Bitcast %arg0 : i64 to !spv.ptr + return +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.ConvertFToS +//===----------------------------------------------------------------------===// + +func @convert_f_to_s_scalar(%arg0 : f32) -> i32 { + // CHECK: {{%.*}} = spv.ConvertFToS {{%.*}} : f32 to i32 + %0 = spv.ConvertFToS %arg0 : f32 to i32 + spv.ReturnValue %0 : i32 +} + +// ----- + +func @convert_f64_to_s32_scalar(%arg0 : f64) -> i32 { + // CHECK: {{%.*}} = spv.ConvertFToS {{%.*}} : f64 to i32 + %0 = spv.ConvertFToS %arg0 : f64 to i32 + spv.ReturnValue %0 : i32 +} + +// ----- + +func @convert_f_to_s_vector(%arg0 : vector<3xf32>) -> vector<3xi32> { + // CHECK: {{%.*}} = spv.ConvertFToS {{%.*}} : vector<3xf32> to vector<3xi32> + %0 = spv.ConvertFToS %arg0 : vector<3xf32> to vector<3xi32> + spv.ReturnValue %0 : vector<3xi32> +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.ConvertFToU +//===----------------------------------------------------------------------===// + +func @convert_f_to_u_scalar(%arg0 : f32) -> i32 { + // CHECK: {{%.*}} = spv.ConvertFToU {{%.*}} : f32 to i32 + %0 = spv.ConvertFToU %arg0 : f32 to i32 + spv.ReturnValue %0 : i32 +} + +// ----- + +func @convert_f64_to_u32_scalar(%arg0 : f64) -> i32 { + // CHECK: {{%.*}} = spv.ConvertFToU {{%.*}} : f64 to i32 + %0 = spv.ConvertFToU %arg0 : f64 to i32 + spv.ReturnValue %0 : i32 +} + +// ----- + +func @convert_f_to_u_vector(%arg0 : vector<3xf32>) -> vector<3xi32> { + // CHECK: {{%.*}} = spv.ConvertFToU {{%.*}} : vector<3xf32> to vector<3xi32> + %0 = spv.ConvertFToU %arg0 : vector<3xf32> to vector<3xi32> + spv.ReturnValue %0 : vector<3xi32> +} + +// ----- + +func @convert_f_to_u_coopmatrix(%arg0 : !spv.coopmatrix<8x16xf32, Subgroup>) { + // CHECK: {{%.*}} = spv.ConvertFToU {{%.*}} : !spv.coopmatrix<8x16xf32, Subgroup> to !spv.coopmatrix<8x16xi32, Subgroup> + %0 = spv.ConvertFToU %arg0 : !spv.coopmatrix<8x16xf32, Subgroup> to !spv.coopmatrix<8x16xi32, Subgroup> + spv.Return +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.ConvertSToF +//===----------------------------------------------------------------------===// + +func @convert_s_to_f_scalar(%arg0 : i32) -> f32 { + // CHECK: {{%.*}} = spv.ConvertSToF {{%.*}} : i32 to f32 + %0 = spv.ConvertSToF %arg0 : i32 to f32 + spv.ReturnValue %0 : f32 +} + +// ----- + +func @convert_s64_to_f32_scalar(%arg0 : i64) -> f32 { + // CHECK: {{%.*}} = spv.ConvertSToF {{%.*}} : i64 to f32 + %0 = spv.ConvertSToF %arg0 : i64 to f32 + spv.ReturnValue %0 : f32 +} + +// ----- + +func @convert_s_to_f_vector(%arg0 : vector<3xi32>) -> vector<3xf32> { + // CHECK: {{%.*}} = spv.ConvertSToF {{%.*}} : vector<3xi32> to vector<3xf32> + %0 = spv.ConvertSToF %arg0 : vector<3xi32> to vector<3xf32> + spv.ReturnValue %0 : vector<3xf32> +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.ConvertUToF +//===----------------------------------------------------------------------===// + +func @convert_u_to_f_scalar(%arg0 : i32) -> f32 { + // CHECK: {{%.*}} = spv.ConvertUToF {{%.*}} : i32 to f32 + %0 = spv.ConvertUToF %arg0 : i32 to f32 + spv.ReturnValue %0 : f32 +} + +// ----- + +func @convert_u64_to_f32_scalar(%arg0 : i64) -> f32 { + // CHECK: {{%.*}} = spv.ConvertUToF {{%.*}} : i64 to f32 + %0 = spv.ConvertUToF %arg0 : i64 to f32 + spv.ReturnValue %0 : f32 +} + +// ----- + +func @convert_u_to_f_vector(%arg0 : vector<3xi32>) -> vector<3xf32> { + // CHECK: {{%.*}} = spv.ConvertUToF {{%.*}} : vector<3xi32> to vector<3xf32> + %0 = spv.ConvertUToF %arg0 : vector<3xi32> to vector<3xf32> + spv.ReturnValue %0 : vector<3xf32> +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.FConvert +//===----------------------------------------------------------------------===// + +func @f_convert_scalar(%arg0 : f32) -> f64 { + // CHECK: {{%.*}} = spv.FConvert {{%.*}} : f32 to f64 + %0 = spv.FConvert %arg0 : f32 to f64 + spv.ReturnValue %0 : f64 +} + +// ----- + +func @f_convert_vector(%arg0 : vector<3xf32>) -> vector<3xf64> { + // CHECK: {{%.*}} = spv.FConvert {{%.*}} : vector<3xf32> to vector<3xf64> + %0 = spv.FConvert %arg0 : vector<3xf32> to vector<3xf64> + spv.ReturnValue %0 : vector<3xf64> +} + +// ----- + +func @f_convert_coop_matrix(%arg0 : !spv.coopmatrix<8x16xf32, Subgroup>) { + // CHECK: {{%.*}} = spv.FConvert {{%.*}} : !spv.coopmatrix<8x16xf32, Subgroup> to !spv.coopmatrix<8x16xf64, Subgroup> + %0 = spv.FConvert %arg0 : !spv.coopmatrix<8x16xf32, Subgroup> to !spv.coopmatrix<8x16xf64, Subgroup> + spv.Return +} + +// ----- + +func @f_convert_vector(%arg0 : f32) -> f32 { + // expected-error @+1 {{expected the different bit widths for operand type and result type, but provided 'f32' and 'f32'}} + %0 = spv.FConvert %arg0 : f32 to f32 + spv.ReturnValue %0 : f32 +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.SConvert +//===----------------------------------------------------------------------===// + +func @s_convert_scalar(%arg0 : i32) -> i64 { + // CHECK: {{%.*}} = spv.SConvert {{%.*}} : i32 to i64 + %0 = spv.SConvert %arg0 : i32 to i64 + spv.ReturnValue %0 : i64 +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.UConvert +//===----------------------------------------------------------------------===// + +func @u_convert_scalar(%arg0 : i32) -> i64 { + // CHECK: {{%.*}} = spv.UConvert {{%.*}} : i32 to i64 + %0 = spv.UConvert %arg0 : i32 to i64 + spv.ReturnValue %0 : i64 +} + diff --git a/mlir/test/Dialect/SPIRV/IR/group-ops.mlir b/mlir/test/Dialect/SPIRV/IR/group-ops.mlir --- a/mlir/test/Dialect/SPIRV/IR/group-ops.mlir +++ b/mlir/test/Dialect/SPIRV/IR/group-ops.mlir @@ -64,6 +64,17 @@ // ----- +//===----------------------------------------------------------------------===// +// spv.SubgroupBallotKHR +//===----------------------------------------------------------------------===// + +func @subgroup_ballot(%predicate: i1) -> vector<4xi32> { + %0 = spv.SubgroupBallotKHR %predicate: vector<4xi32> + return %0: vector<4xi32> +} + +// ----- + //===----------------------------------------------------------------------===// // spv.SubgroupBlockReadINTEL //===----------------------------------------------------------------------===// @@ -100,4 +111,4 @@ // CHECK: spv.SubgroupBlockWriteINTEL %{{.*}}, %{{.*}} : vector<3xi32> spv.SubgroupBlockWriteINTEL "StorageBuffer" %ptr, %value : vector<3xi32> return -} \ No newline at end of file +} diff --git a/mlir/test/Dialect/SPIRV/IR/logical-ops.mlir b/mlir/test/Dialect/SPIRV/IR/logical-ops.mlir --- a/mlir/test/Dialect/SPIRV/IR/logical-ops.mlir +++ b/mlir/test/Dialect/SPIRV/IR/logical-ops.mlir @@ -32,6 +32,217 @@ // ----- +//===----------------------------------------------------------------------===// +// spv.LogicalAnd +//===----------------------------------------------------------------------===// + +func @logicalBinary(%arg0 : i1, %arg1 : i1, %arg2 : i1) +{ + // CHECK: [[TMP:%.*]] = spv.LogicalAnd {{%.*}}, {{%.*}} : i1 + %0 = spv.LogicalAnd %arg0, %arg1 : i1 + // CHECK: {{%.*}} = spv.LogicalAnd [[TMP]], {{%.*}} : i1 + %1 = spv.LogicalAnd %0, %arg2 : i1 + return +} + +func @logicalBinary2(%arg0 : vector<4xi1>, %arg1 : vector<4xi1>) +{ + // CHECK: {{%.*}} = spv.LogicalAnd {{%.*}}, {{%.*}} : vector<4xi1> + %0 = spv.LogicalAnd %arg0, %arg1 : vector<4xi1> + return +} + +// ----- + +func @logicalBinary(%arg0 : i1, %arg1 : i1) +{ + // expected-error @+2 {{expected ':'}} + %0 = spv.LogicalAnd %arg0, %arg1 + return +} + +// ----- + +func @logicalBinary(%arg0 : i1, %arg1 : i1) +{ + // expected-error @+2 {{expected non-function type}} + %0 = spv.LogicalAnd %arg0, %arg1 : + return +} + +// ----- + +func @logicalBinary(%arg0 : i1, %arg1 : i1) +{ + // expected-error @+1 {{custom op 'spv.LogicalAnd' expected 2 operands}} + %0 = spv.LogicalAnd %arg0 : i1 + return +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.LogicalNot +//===----------------------------------------------------------------------===// + +func @logicalUnary(%arg0 : i1, %arg1 : i1) +{ + // CHECK: [[TMP:%.*]] = spv.LogicalNot {{%.*}} : i1 + %0 = spv.LogicalNot %arg0 : i1 + // CHECK: {{%.*}} = spv.LogicalNot [[TMP]] : i1 + %1 = spv.LogicalNot %0 : i1 + return +} + +func @logicalUnary2(%arg0 : vector<4xi1>) +{ + // CHECK: {{%.*}} = spv.LogicalNot {{%.*}} : vector<4xi1> + %0 = spv.LogicalNot %arg0 : vector<4xi1> + return +} + +// ----- + +func @logicalUnary(%arg0 : i1) +{ + // expected-error @+2 {{expected ':'}} + %0 = spv.LogicalNot %arg0 + return +} + +// ----- + +func @logicalUnary(%arg0 : i1) +{ + // expected-error @+2 {{expected non-function type}} + %0 = spv.LogicalNot %arg0 : + return +} + +// ----- + +func @logicalUnary(%arg0 : i1) +{ + // expected-error @+1 {{expected SSA operand}} + %0 = spv.LogicalNot : i1 + return +} + +// ----- + +func @logicalUnary(%arg0 : i32) +{ + // expected-error @+1 {{operand #0 must be bool or vector of bool values of length 2/3/4/8/16, but got 'i32'}} + %0 = spv.LogicalNot %arg0 : i32 + return +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.SelectOp +//===----------------------------------------------------------------------===// + +func @select_op_bool(%arg0: i1) -> () { + %0 = spv.constant true + %1 = spv.constant false + // CHECK : spv.Select {{%.*}}, {{%.*}}, {{%.*}} : i1, i1 + %2 = spv.Select %arg0, %0, %1 : i1, i1 + return +} + +func @select_op_int(%arg0: i1) -> () { + %0 = spv.constant 2 : i32 + %1 = spv.constant 3 : i32 + // CHECK : spv.Select {{%.*}}, {{%.*}}, {{%.*}} : i1, i32 + %2 = spv.Select %arg0, %0, %1 : i1, i32 + return +} + +func @select_op_float(%arg0: i1) -> () { + %0 = spv.constant 2.0 : f32 + %1 = spv.constant 3.0 : f32 + // CHECK : spv.Select {{%.*}}, {{%.*}}, {{%.*}} : i1, f32 + %2 = spv.Select %arg0, %0, %1 : i1, f32 + return +} + +func @select_op_ptr(%arg0: i1) -> () { + %0 = spv.Variable : !spv.ptr + %1 = spv.Variable : !spv.ptr + // CHECK : spv.Select {{%.*}}, {{%.*}}, {{%.*}} : i1, !spv.ptr + %2 = spv.Select %arg0, %0, %1 : i1, !spv.ptr + return +} + +func @select_op_vec(%arg0: i1) -> () { + %0 = spv.constant dense<[2.0, 3.0, 4.0]> : vector<3xf32> + %1 = spv.constant dense<[5.0, 6.0, 7.0]> : vector<3xf32> + // CHECK : spv.Select {{%.*}}, {{%.*}}, {{%.*}} : i1, vector<3xf32> + %2 = spv.Select %arg0, %0, %1 : i1, vector<3xf32> + return +} + +func @select_op_vec_condn_vec(%arg0: vector<3xi1>) -> () { + %0 = spv.constant dense<[2.0, 3.0, 4.0]> : vector<3xf32> + %1 = spv.constant dense<[5.0, 6.0, 7.0]> : vector<3xf32> + // CHECK : spv.Select {{%.*}}, {{%.*}}, {{%.*}} : vector<3xi1>, vector<3xf32> + %2 = spv.Select %arg0, %0, %1 : vector<3xi1>, vector<3xf32> + return +} + +// ----- + +func @select_op(%arg0: i1) -> () { + %0 = spv.constant 2 : i32 + %1 = spv.constant 3 : i32 + // expected-error @+2 {{expected ','}} + %2 = spv.Select %arg0, %0, %1 : i1 + return +} + +// ----- + +func @select_op(%arg1: vector<3xi1>) -> () { + %0 = spv.constant 2 : i32 + %1 = spv.constant 3 : i32 + // expected-error @+1 {{result expected to be of vector type when condition is of vector type}} + %2 = spv.Select %arg1, %0, %1 : vector<3xi1>, i32 + return +} + +// ----- + +func @select_op(%arg1: vector<4xi1>) -> () { + %0 = spv.constant dense<[2, 3, 4]> : vector<3xi32> + %1 = spv.constant dense<[5, 6, 7]> : vector<3xi32> + // expected-error @+1 {{result should have the same number of elements as the condition when condition is of vector type}} + %2 = spv.Select %arg1, %0, %1 : vector<4xi1>, vector<3xi32> + return +} + +// ----- + +func @select_op(%arg1: vector<4xi1>) -> () { + %0 = spv.constant dense<[2.0, 3.0, 4.0]> : vector<3xf32> + %1 = spv.constant dense<[5, 6, 7]> : vector<3xi32> + // expected-error @+1 {{all of {true_value, false_value, result} have same type}} + %2 = "spv.Select"(%arg1, %0, %1) : (vector<4xi1>, vector<3xf32>, vector<3xi32>) -> vector<3xi32> + return +} + +// ----- + +func @select_op(%arg1: vector<4xi1>) -> () { + %0 = spv.constant dense<[2.0, 3.0, 4.0]> : vector<3xf32> + %1 = spv.constant dense<[5, 6, 7]> : vector<3xi32> + // expected-error @+1 {{all of {true_value, false_value, result} have same type}} + %2 = "spv.Select"(%arg1, %1, %0) : (vector<4xi1>, vector<3xi32>, vector<3xf32>) -> vector<3xi32> + return +} + +// ----- + //===----------------------------------------------------------------------===// // spv.SGreaterThan //===----------------------------------------------------------------------===// diff --git a/mlir/test/Dialect/SPIRV/IR/memory-ops.mlir b/mlir/test/Dialect/SPIRV/IR/memory-ops.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/Dialect/SPIRV/IR/memory-ops.mlir @@ -0,0 +1,629 @@ +// RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s + +//===----------------------------------------------------------------------===// +// spv.AccessChain +//===----------------------------------------------------------------------===// + +func @access_chain_struct() -> () { + %0 = spv.constant 1: i32 + %1 = spv.Variable : !spv.ptr)>, Function> + // CHECK: spv.AccessChain {{.*}}[{{.*}}, {{.*}}] : !spv.ptr)>, Function> + %2 = spv.AccessChain %1[%0, %0] : !spv.ptr)>, Function>, i32, i32 + return +} + +func @access_chain_1D_array(%arg0 : i32) -> () { + %0 = spv.Variable : !spv.ptr, Function> + // CHECK: spv.AccessChain {{.*}}[{{.*}}] : !spv.ptr, Function> + %1 = spv.AccessChain %0[%arg0] : !spv.ptr, Function>, i32 + return +} + +func @access_chain_2D_array_1(%arg0 : i32) -> () { + %0 = spv.Variable : !spv.ptr>, Function> + // CHECK: spv.AccessChain {{.*}}[{{.*}}, {{.*}}] : !spv.ptr>, Function> + %1 = spv.AccessChain %0[%arg0, %arg0] : !spv.ptr>, Function>, i32, i32 + %2 = spv.Load "Function" %1 ["Volatile"] : f32 + return +} + +func @access_chain_2D_array_2(%arg0 : i32) -> () { + %0 = spv.Variable : !spv.ptr>, Function> + // CHECK: spv.AccessChain {{.*}}[{{.*}}] : !spv.ptr>, Function> + %1 = spv.AccessChain %0[%arg0] : !spv.ptr>, Function>, i32 + %2 = spv.Load "Function" %1 ["Volatile"] : !spv.array<4xf32> + return +} + +func @access_chain_rtarray(%arg0 : i32) -> () { + %0 = spv.Variable : !spv.ptr, Function> + // CHECK: spv.AccessChain {{.*}}[{{.*}}] : !spv.ptr, Function> + %1 = spv.AccessChain %0[%arg0] : !spv.ptr, Function>, i32 + %2 = spv.Load "Function" %1 ["Volatile"] : f32 + return +} + +// ----- + +func @access_chain_non_composite() -> () { + %0 = spv.constant 1: i32 + %1 = spv.Variable : !spv.ptr + // expected-error @+1 {{cannot extract from non-composite type 'f32' with index 0}} + %2 = spv.AccessChain %1[%0] : !spv.ptr, i32 + return +} + +// ----- + +func @access_chain_no_indices(%index0 : i32) -> () { + %0 = spv.Variable : !spv.ptr>, Function> + // expected-error @+1 {{expected at least one index}} + %1 = spv.AccessChain %0[] : !spv.ptr>, Function>, i32 + return +} + +// ----- + +func @access_chain_missing_comma(%index0 : i32) -> () { + %0 = spv.Variable : !spv.ptr>, Function> + // expected-error @+1 {{expected ','}} + %1 = spv.AccessChain %0[%index0] : !spv.ptr>, Function> i32 + return +} + +// ----- + +func @access_chain_invalid_indices_types_count(%index0 : i32) -> () { + %0 = spv.Variable : !spv.ptr>, Function> + // expected-error @+1 {{'spv.AccessChain' op indices types' count must be equal to indices info count}} + %1 = spv.AccessChain %0[%index0] : !spv.ptr>, Function>, i32, i32 + return +} + +// ----- + +func @access_chain_missing_indices_type(%index0 : i32) -> () { + %0 = spv.Variable : !spv.ptr>, Function> + // expected-error @+1 {{'spv.AccessChain' op indices types' count must be equal to indices info count}} + %1 = spv.AccessChain %0[%index0, %index0] : !spv.ptr>, Function>, i32 + return +} + +// ----- + +func @access_chain_invalid_type(%index0 : i32) -> () { + %0 = spv.Variable : !spv.ptr>, Function> + %1 = spv.Load "Function" %0 ["Volatile"] : !spv.array<4x!spv.array<4xf32>> + // expected-error @+1 {{expected a pointer to composite type, but provided '!spv.array<4 x !spv.array<4 x f32>>'}} + %2 = spv.AccessChain %1[%index0] : !spv.array<4x!spv.array<4xf32>>, i32 + return +} + +// ----- + +func @access_chain_invalid_index_1(%index0 : i32) -> () { + %0 = spv.Variable : !spv.ptr>, Function> + // expected-error @+1 {{expected SSA operand}} + %1 = spv.AccessChain %0[%index, 4] : !spv.ptr>, Function>, i32, i32 + return +} + +// ----- + +func @access_chain_invalid_index_2(%index0 : i32) -> () { + %0 = spv.Variable : !spv.ptr)>, Function> + // expected-error @+1 {{index must be an integer spv.constant to access element of spv.struct}} + %1 = spv.AccessChain %0[%index0, %index0] : !spv.ptr)>, Function>, i32, i32 + return +} + +// ----- + +func @access_chain_invalid_constant_type_1() -> () { + %0 = std.constant 1: i32 + %1 = spv.Variable : !spv.ptr)>, Function> + // expected-error @+1 {{index must be an integer spv.constant to access element of spv.struct, but provided std.constant}} + %2 = spv.AccessChain %1[%0, %0] : !spv.ptr)>, Function>, i32, i32 + return +} + +// ----- + +func @access_chain_out_of_bounds() -> () { + %index0 = "spv.constant"() { value = 12: i32} : () -> i32 + %0 = spv.Variable : !spv.ptr)>, Function> + // expected-error @+1 {{'spv.AccessChain' op index 12 out of bounds for '!spv.struct<(f32, !spv.array<4 x f32>)>'}} + %1 = spv.AccessChain %0[%index0, %index0] : !spv.ptr)>, Function>, i32, i32 + return +} + +// ----- + +func @access_chain_invalid_accessing_type(%index0 : i32) -> () { + %0 = spv.Variable : !spv.ptr>, Function> + // expected-error @+1 {{cannot extract from non-composite type 'f32' with index 0}} + %1 = spv.AccessChain %0[%index, %index0, %index0] : !spv.ptr>, Function>, i32, i32, i32 + return + +// ----- + +//===----------------------------------------------------------------------===// +// spv.LoadOp +//===----------------------------------------------------------------------===// + +// CHECK-LABEL: @simple_load +func @simple_load() -> () { + %0 = spv.Variable : !spv.ptr + // CHECK: spv.Load "Function" %{{.*}} : f32 + %1 = spv.Load "Function" %0 : f32 + return +} + +// CHECK-LABEL: @load_none_access +func @load_none_access() -> () { + %0 = spv.Variable : !spv.ptr + // CHECK: spv.Load "Function" %{{.*}} ["None"] : f32 + %1 = spv.Load "Function" %0 ["None"] : f32 + return +} + +// CHECK-LABEL: @volatile_load +func @volatile_load() -> () { + %0 = spv.Variable : !spv.ptr + // CHECK: spv.Load "Function" %{{.*}} ["Volatile"] : f32 + %1 = spv.Load "Function" %0 ["Volatile"] : f32 + return +} + +// CHECK-LABEL: @aligned_load +func @aligned_load() -> () { + %0 = spv.Variable : !spv.ptr + // CHECK: spv.Load "Function" %{{.*}} ["Aligned", 4] : f32 + %1 = spv.Load "Function" %0 ["Aligned", 4] : f32 + return +} + +// CHECK-LABEL: @volatile_aligned_load +func @volatile_aligned_load() -> () { + %0 = spv.Variable : !spv.ptr + // CHECK: spv.Load "Function" %{{.*}} ["Volatile|Aligned", 4] : f32 + %1 = spv.Load "Function" %0 ["Volatile|Aligned", 4] : f32 + return +} + +// ----- + +// CHECK-LABEL: load_none_access +func @load_none_access() -> () { + %0 = spv.Variable : !spv.ptr + // CHECK: spv.Load + // CHECK-SAME: ["None"] + %1 = "spv.Load"(%0) {memory_access = 0 : i32} : (!spv.ptr) -> (f32) + return +} + +// CHECK-LABEL: volatile_load +func @volatile_load() -> () { + %0 = spv.Variable : !spv.ptr + // CHECK: spv.Load + // CHECK-SAME: ["Volatile"] + %1 = "spv.Load"(%0) {memory_access = 1 : i32} : (!spv.ptr) -> (f32) + return +} + +// CHECK-LABEL: aligned_load +func @aligned_load() -> () { + %0 = spv.Variable : !spv.ptr + // CHECK: spv.Load + // CHECK-SAME: ["Aligned", 4] + %1 = "spv.Load"(%0) {memory_access = 2 : i32, alignment = 4 : i32} : (!spv.ptr) -> (f32) + return +} + +// CHECK-LABEL: volatile_aligned_load +func @volatile_aligned_load() -> () { + %0 = spv.Variable : !spv.ptr + // CHECK: spv.Load + // CHECK-SAME: ["Volatile|Aligned", 4] + %1 = "spv.Load"(%0) {memory_access = 3 : i32, alignment = 4 : i32} : (!spv.ptr) -> (f32) + return +} + +// ----- + +func @simple_load_missing_storageclass() -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected non-function type}} + %1 = spv.Load %0 : f32 + return +} + +// ----- + +func @simple_load_missing_operand() -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected SSA operand}} + %1 = spv.Load "Function" : f32 + return +} + +// ----- + +func @simple_load_missing_rettype() -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+2 {{expected ':'}} + %1 = spv.Load "Function" %0 + return +} + +// ----- + +func @volatile_load_missing_lbrace() -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected ':'}} + %1 = spv.Load "Function" %0 "Volatile"] : f32 + return +} + +// ----- + +func @volatile_load_missing_rbrace() -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected ']'}} + %1 = spv.Load "Function" %0 ["Volatile"} : f32 + return +} + +// ----- + +func @aligned_load_missing_alignment() -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected ','}} + %1 = spv.Load "Function" %0 ["Aligned"] : f32 + return +} + +// ----- + +func @aligned_load_missing_comma() -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected ','}} + %1 = spv.Load "Function" %0 ["Aligned" 4] : f32 + return +} + +// ----- + +func @load_incorrect_attributes() -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected ']'}} + %1 = spv.Load "Function" %0 ["Volatile", 4] : f32 + return +} + +// ----- + +func @load_unknown_memory_access() -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{custom op 'spv.Load' invalid memory_access attribute specification: "Something"}} + %1 = spv.Load "Function" %0 ["Something"] : f32 + return +} + +// ----- + +func @load_unknown_memory_access() -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{custom op 'spv.Load' invalid memory_access attribute specification: "Volatile|Something"}} + %1 = spv.Load "Function" %0 ["Volatile|Something"] : f32 + return +} + +// ----- + +func @load_unknown_memory_access() -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{failed to satisfy constraint: valid SPIR-V MemoryAccess}} + %1 = "spv.Load"(%0) {memory_access = 0x80000000 : i32} : (!spv.ptr) -> (f32) + return +} + +// ----- + +func @aligned_load_incorrect_attributes() -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected ']'}} + %1 = spv.Load "Function" %0 ["Aligned", 4, 23] : f32 + return +} + +// ----- + +spv.module Logical GLSL450 { + spv.globalVariable @var0 : !spv.ptr + // CHECK_LABEL: @simple_load + spv.func @simple_load() -> () "None" { + // CHECK: spv.Load "Input" {{%.*}} : f32 + %0 = spv.mlir.addressof @var0 : !spv.ptr + %1 = spv.Load "Input" %0 : f32 + spv.Return + } +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.StoreOp +//===----------------------------------------------------------------------===// + +func @simple_store(%arg0 : f32) -> () { + %0 = spv.Variable : !spv.ptr + // CHECK: spv.Store "Function" %0, %arg0 : f32 + spv.Store "Function" %0, %arg0 : f32 + return +} + +// CHECK_LABEL: @volatile_store +func @volatile_store(%arg0 : f32) -> () { + %0 = spv.Variable : !spv.ptr + // CHECK: spv.Store "Function" %0, %arg0 ["Volatile"] : f32 + spv.Store "Function" %0, %arg0 ["Volatile"] : f32 + return +} + +// CHECK_LABEL: @aligned_store +func @aligned_store(%arg0 : f32) -> () { + %0 = spv.Variable : !spv.ptr + // CHECK: spv.Store "Function" %0, %arg0 ["Aligned", 4] : f32 + spv.Store "Function" %0, %arg0 ["Aligned", 4] : f32 + return +} + +// ----- + +func @simple_store_missing_ptr_type(%arg0 : f32) -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected non-function type}} + spv.Store %0, %arg0 : f32 + return +} + +// ----- + +func @simple_store_missing_operand(%arg0 : f32) -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{custom op 'spv.Store' invalid operand}} : f32 + spv.Store "Function" , %arg0 : f32 + return +} + +// ----- + +func @simple_store_missing_operand(%arg0 : f32) -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{custom op 'spv.Store' expected 2 operands}} : f32 + spv.Store "Function" %0 : f32 + return +} + +// ----- + +func @volatile_store_missing_lbrace(%arg0 : f32) -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected ':'}} + spv.Store "Function" %0, %arg0 "Volatile"] : f32 + return +} + +// ----- + +func @volatile_store_missing_rbrace(%arg0 : f32) -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected ']'}} + spv.Store "Function" %0, %arg0 ["Volatile"} : f32 + return +} + +// ----- + +func @aligned_store_missing_alignment(%arg0 : f32) -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected ','}} + spv.Store "Function" %0, %arg0 ["Aligned"] : f32 + return +} + +// ----- + +func @aligned_store_missing_comma(%arg0 : f32) -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected ','}} + spv.Store "Function" %0, %arg0 ["Aligned" 4] : f32 + return +} + +// ----- + +func @load_incorrect_attributes(%arg0 : f32) -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected ']'}} + spv.Store "Function" %0, %arg0 ["Volatile", 4] : f32 + return +} + +// ----- + +func @aligned_store_incorrect_attributes(%arg0 : f32) -> () { + %0 = spv.Variable : !spv.ptr + // expected-error @+1 {{expected ']'}} + spv.Store "Function" %0, %arg0 ["Aligned", 4, 23] : f32 + return +} + +// ----- + +spv.module Logical GLSL450 { + spv.globalVariable @var0 : !spv.ptr + spv.func @simple_store(%arg0 : f32) -> () "None" { + %0 = spv.mlir.addressof @var0 : !spv.ptr + // CHECK: spv.Store "Input" {{%.*}}, {{%.*}} : f32 + spv.Store "Input" %0, %arg0 : f32 + spv.Return + } +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.Variable +//===----------------------------------------------------------------------===// + +func @variable(%arg0: f32) -> () { + // CHECK: spv.Variable : !spv.ptr + %0 = spv.Variable : !spv.ptr + return +} + +// ----- + +func @variable_init_normal_constant() -> () { + %0 = spv.constant 4.0 : f32 + // CHECK: spv.Variable init(%0) : !spv.ptr + %1 = spv.Variable init(%0) : !spv.ptr + return +} + +// ----- + +spv.module Logical GLSL450 { + spv.globalVariable @global : !spv.ptr + spv.func @variable_init_global_variable() -> () "None" { + %0 = spv.mlir.addressof @global : !spv.ptr + // CHECK: spv.Variable init({{.*}}) : !spv.ptr, Function> + %1 = spv.Variable init(%0) : !spv.ptr, Function> + spv.Return + } +} + +// ----- + +spv.module Logical GLSL450 { + spv.specConstant @sc = 42 : i32 + // CHECK-LABEL: @variable_init_spec_constant + spv.func @variable_init_spec_constant() -> () "None" { + %0 = spv.mlir.referenceof @sc : i32 + // CHECK: spv.Variable init(%0) : !spv.ptr + %1 = spv.Variable init(%0) : !spv.ptr + spv.Return + } +} + +// ----- + +func @variable_bind() -> () { + // expected-error @+1 {{cannot have 'descriptor_set' attribute (only allowed in spv.globalVariable)}} + %0 = spv.Variable bind(1, 2) : !spv.ptr + return +} + +// ----- + +func @variable_init_bind() -> () { + %0 = spv.constant 4.0 : f32 + // expected-error @+1 {{cannot have 'binding' attribute (only allowed in spv.globalVariable)}} + %1 = spv.Variable init(%0) {binding = 5 : i32} : !spv.ptr + return +} + +// ----- + +func @variable_builtin() -> () { + // expected-error @+1 {{cannot have 'built_in' attribute (only allowed in spv.globalVariable)}} + %1 = spv.Variable built_in("GlobalInvocationID") : !spv.ptr, Function> + return +} + +// ----- + +func @expect_ptr_result_type(%arg0: f32) -> () { + // expected-error @+1 {{expected spv.ptr type}} + %0 = spv.Variable : f32 + return +} + +// ----- + +func @variable_init(%arg0: f32) -> () { + // expected-error @+1 {{op initializer must be the result of a constant or spv.globalVariable op}} + %0 = spv.Variable init(%arg0) : !spv.ptr + return +} + +// ----- + +func @cannot_be_generic_storage_class(%arg0: f32) -> () { + // expected-error @+1 {{op can only be used to model function-level variables. Use spv.globalVariable for module-level variables}} + %0 = spv.Variable : !spv.ptr + return +} + +// ----- + +func @copy_memory_incompatible_ptrs() { + %0 = spv.Variable : !spv.ptr + %1 = spv.Variable : !spv.ptr + // expected-error @+1 {{both operands must be pointers to the same type}} + "spv.CopyMemory"(%0, %1) {} : (!spv.ptr, !spv.ptr) -> () + spv.Return +} + +// ----- + +func @copy_memory_invalid_maa() { + %0 = spv.Variable : !spv.ptr + %1 = spv.Variable : !spv.ptr + // expected-error @+1 {{missing alignment value}} + "spv.CopyMemory"(%0, %1) {memory_access=0x0002 : i32} : (!spv.ptr, !spv.ptr) -> () + spv.Return +} + +// ----- + +func @copy_memory_invalid_source_maa() { + %0 = spv.Variable : !spv.ptr + %1 = spv.Variable : !spv.ptr + // expected-error @+1 {{invalid alignment specification with non-aligned memory access specification}} + "spv.CopyMemory"(%0, %1) {source_memory_access=0x0001 : i32, memory_access=0x0002 : i32, source_alignment=8 : i32, alignment=4 : i32} : (!spv.ptr, !spv.ptr) -> () + spv.Return +} + +// ----- + +func @copy_memory_invalid_source_maa2() { + %0 = spv.Variable : !spv.ptr + %1 = spv.Variable : !spv.ptr + // expected-error @+1 {{missing alignment value}} + "spv.CopyMemory"(%0, %1) {source_memory_access=0x0002 : i32, memory_access=0x0002 : i32, alignment=4 : i32} : (!spv.ptr, !spv.ptr) -> () + spv.Return +} + +// ----- + +func @copy_memory_print_maa() { + %0 = spv.Variable : !spv.ptr + %1 = spv.Variable : !spv.ptr + + // CHECK: spv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Volatile"] : f32 + "spv.CopyMemory"(%0, %1) {memory_access=0x0001 : i32} : (!spv.ptr, !spv.ptr) -> () + + // CHECK: spv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Aligned", 4] : f32 + "spv.CopyMemory"(%0, %1) {memory_access=0x0002 : i32, alignment=4 : i32} : (!spv.ptr, !spv.ptr) -> () + + // CHECK: spv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Aligned", 4], ["Volatile"] : f32 + "spv.CopyMemory"(%0, %1) {source_memory_access=0x0001 : i32, memory_access=0x0002 : i32, alignment=4 : i32} : (!spv.ptr, !spv.ptr) -> () + + // CHECK: spv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Aligned", 4], ["Aligned", 8] : f32 + "spv.CopyMemory"(%0, %1) {source_memory_access=0x0002 : i32, memory_access=0x0002 : i32, source_alignment=8 : i32, alignment=4 : i32} : (!spv.ptr, !spv.ptr) -> () + + spv.Return +} diff --git a/mlir/test/Dialect/SPIRV/IR/misc-ops.mlir b/mlir/test/Dialect/SPIRV/IR/misc-ops.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/Dialect/SPIRV/IR/misc-ops.mlir @@ -0,0 +1,29 @@ +// RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s + +//===----------------------------------------------------------------------===// +// spv.undef +//===----------------------------------------------------------------------===// + +func @undef() -> () { + // CHECK: %{{.*}} = spv.undef : f32 + %0 = spv.undef : f32 + // CHECK: %{{.*}} = spv.undef : vector<4xf32> + %1 = spv.undef : vector<4xf32> + spv.Return +} + +// ----- + +func @undef() -> () { + // expected-error @+2{{expected non-function type}} + %0 = spv.undef : + spv.Return +} + +// ----- + +func @undef() -> () { + // expected-error @+2{{expected ':'}} + %0 = spv.undef + spv.Return +} diff --git a/mlir/test/Dialect/SPIRV/IR/ops.mlir b/mlir/test/Dialect/SPIRV/IR/ops.mlir deleted file mode 100644 --- a/mlir/test/Dialect/SPIRV/IR/ops.mlir +++ /dev/null @@ -1,1355 +0,0 @@ -// RUN: mlir-opt -allow-unregistered-dialect -split-input-file -verify-diagnostics %s | FileCheck %s - -//===----------------------------------------------------------------------===// -// spv.AccessChain -//===----------------------------------------------------------------------===// - -func @access_chain_struct() -> () { - %0 = spv.constant 1: i32 - %1 = spv.Variable : !spv.ptr)>, Function> - // CHECK: spv.AccessChain {{.*}}[{{.*}}, {{.*}}] : !spv.ptr)>, Function> - %2 = spv.AccessChain %1[%0, %0] : !spv.ptr)>, Function>, i32, i32 - return -} - -func @access_chain_1D_array(%arg0 : i32) -> () { - %0 = spv.Variable : !spv.ptr, Function> - // CHECK: spv.AccessChain {{.*}}[{{.*}}] : !spv.ptr, Function> - %1 = spv.AccessChain %0[%arg0] : !spv.ptr, Function>, i32 - return -} - -func @access_chain_2D_array_1(%arg0 : i32) -> () { - %0 = spv.Variable : !spv.ptr>, Function> - // CHECK: spv.AccessChain {{.*}}[{{.*}}, {{.*}}] : !spv.ptr>, Function> - %1 = spv.AccessChain %0[%arg0, %arg0] : !spv.ptr>, Function>, i32, i32 - %2 = spv.Load "Function" %1 ["Volatile"] : f32 - return -} - -func @access_chain_2D_array_2(%arg0 : i32) -> () { - %0 = spv.Variable : !spv.ptr>, Function> - // CHECK: spv.AccessChain {{.*}}[{{.*}}] : !spv.ptr>, Function> - %1 = spv.AccessChain %0[%arg0] : !spv.ptr>, Function>, i32 - %2 = spv.Load "Function" %1 ["Volatile"] : !spv.array<4xf32> - return -} - -func @access_chain_rtarray(%arg0 : i32) -> () { - %0 = spv.Variable : !spv.ptr, Function> - // CHECK: spv.AccessChain {{.*}}[{{.*}}] : !spv.ptr, Function> - %1 = spv.AccessChain %0[%arg0] : !spv.ptr, Function>, i32 - %2 = spv.Load "Function" %1 ["Volatile"] : f32 - return -} - -// ----- - -func @access_chain_non_composite() -> () { - %0 = spv.constant 1: i32 - %1 = spv.Variable : !spv.ptr - // expected-error @+1 {{cannot extract from non-composite type 'f32' with index 0}} - %2 = spv.AccessChain %1[%0] : !spv.ptr, i32 - return -} - -// ----- - -func @access_chain_no_indices(%index0 : i32) -> () { - %0 = spv.Variable : !spv.ptr>, Function> - // expected-error @+1 {{expected at least one index}} - %1 = spv.AccessChain %0[] : !spv.ptr>, Function>, i32 - return -} - -// ----- - -func @access_chain_missing_comma(%index0 : i32) -> () { - %0 = spv.Variable : !spv.ptr>, Function> - // expected-error @+1 {{expected ','}} - %1 = spv.AccessChain %0[%index0] : !spv.ptr>, Function> i32 - return -} - -// ----- - -func @access_chain_invalid_indices_types_count(%index0 : i32) -> () { - %0 = spv.Variable : !spv.ptr>, Function> - // expected-error @+1 {{'spv.AccessChain' op indices types' count must be equal to indices info count}} - %1 = spv.AccessChain %0[%index0] : !spv.ptr>, Function>, i32, i32 - return -} - -// ----- - -func @access_chain_missing_indices_type(%index0 : i32) -> () { - %0 = spv.Variable : !spv.ptr>, Function> - // expected-error @+1 {{'spv.AccessChain' op indices types' count must be equal to indices info count}} - %1 = spv.AccessChain %0[%index0, %index0] : !spv.ptr>, Function>, i32 - return -} - -// ----- - -func @access_chain_invalid_type(%index0 : i32) -> () { - %0 = spv.Variable : !spv.ptr>, Function> - %1 = spv.Load "Function" %0 ["Volatile"] : !spv.array<4x!spv.array<4xf32>> - // expected-error @+1 {{expected a pointer to composite type, but provided '!spv.array<4 x !spv.array<4 x f32>>'}} - %2 = spv.AccessChain %1[%index0] : !spv.array<4x!spv.array<4xf32>>, i32 - return -} - -// ----- - -func @access_chain_invalid_index_1(%index0 : i32) -> () { - %0 = spv.Variable : !spv.ptr>, Function> - // expected-error @+1 {{expected SSA operand}} - %1 = spv.AccessChain %0[%index, 4] : !spv.ptr>, Function>, i32, i32 - return -} - -// ----- - -func @access_chain_invalid_index_2(%index0 : i32) -> () { - %0 = spv.Variable : !spv.ptr)>, Function> - // expected-error @+1 {{index must be an integer spv.constant to access element of spv.struct}} - %1 = spv.AccessChain %0[%index0, %index0] : !spv.ptr)>, Function>, i32, i32 - return -} - -// ----- - -func @access_chain_invalid_constant_type_1() -> () { - %0 = std.constant 1: i32 - %1 = spv.Variable : !spv.ptr)>, Function> - // expected-error @+1 {{index must be an integer spv.constant to access element of spv.struct, but provided std.constant}} - %2 = spv.AccessChain %1[%0, %0] : !spv.ptr)>, Function>, i32, i32 - return -} - -// ----- - -func @access_chain_out_of_bounds() -> () { - %index0 = "spv.constant"() { value = 12: i32} : () -> i32 - %0 = spv.Variable : !spv.ptr)>, Function> - // expected-error @+1 {{'spv.AccessChain' op index 12 out of bounds for '!spv.struct<(f32, !spv.array<4 x f32>)>'}} - %1 = spv.AccessChain %0[%index0, %index0] : !spv.ptr)>, Function>, i32, i32 - return -} - -// ----- - -func @access_chain_invalid_accessing_type(%index0 : i32) -> () { - %0 = spv.Variable : !spv.ptr>, Function> - // expected-error @+1 {{cannot extract from non-composite type 'f32' with index 0}} - %1 = spv.AccessChain %0[%index, %index0, %index0] : !spv.ptr>, Function>, i32, i32, i32 - return - -// ----- - -//===----------------------------------------------------------------------===// -// spv.Bitcast -//===----------------------------------------------------------------------===// - -func @cast1(%arg0 : f32) { - // CHECK: {{%.*}} = spv.Bitcast {{%.*}} : f32 to i32 - %0 = spv.Bitcast %arg0 : f32 to i32 - return -} - -func @cast2(%arg0 : vector<2xf32>) { - // CHECK: {{%.*}} = spv.Bitcast {{%.*}} : vector<2xf32> to vector<2xi32> - %0 = spv.Bitcast %arg0 : vector<2xf32> to vector<2xi32> - return -} - -func @cast3(%arg0 : vector<2xf32>) { - // CHECK: {{%.*}} = spv.Bitcast {{%.*}} : vector<2xf32> to i64 - %0 = spv.Bitcast %arg0 : vector<2xf32> to i64 - return -} - -func @cast4(%arg0 : !spv.ptr) { - // CHECK: {{%.*}} = spv.Bitcast {{%.*}} : !spv.ptr to !spv.ptr - %0 = spv.Bitcast %arg0 : !spv.ptr to !spv.ptr - return -} - -func @cast5(%arg0 : !spv.ptr) { - // CHECK: {{%.*}} = spv.Bitcast {{%.*}} : !spv.ptr to !spv.ptr, Function> - %0 = spv.Bitcast %arg0 : !spv.ptr to !spv.ptr, Function> - return -} - -func @cast6(%arg0 : vector<4xf32>) { - // CHECK: {{%.*}} = spv.Bitcast {{%.*}} : vector<4xf32> to vector<2xi64> - %0 = spv.Bitcast %arg0 : vector<4xf32> to vector<2xi64> - return -} - -// ----- - -func @cast1(%arg0 : f32) { - // expected-error @+1 {{result type must be different from operand type}} - %0 = spv.Bitcast %arg0 : f32 to f32 - return -} - -// ----- - -func @cast1(%arg0 : f32) { - // expected-error @+1 {{mismatch in result type bitwidth 64 and operand type bitwidth 32}} - %0 = spv.Bitcast %arg0 : f32 to i64 - return -} - -// ----- - -func @cast1(%arg0 : vector<2xf32>) { - // expected-error @+1 {{mismatch in result type bitwidth 96 and operand type bitwidth 64}} - %0 = spv.Bitcast %arg0 : vector<2xf32> to vector<3xf32> - return -} - -// ----- - -func @cast3(%arg0 : !spv.ptr) { - // expected-error @+1 {{unhandled bit cast conversion from pointer type to non-pointer type}} - %0 = spv.Bitcast %arg0 : !spv.ptr to i64 - return -} - -// ----- - -func @cast3(%arg0 : i64) { - // expected-error @+1 {{unhandled bit cast conversion from non-pointer type to pointer type}} - %0 = spv.Bitcast %arg0 : i64 to !spv.ptr - return -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.BitCount -//===----------------------------------------------------------------------===// - -func @bitcount(%arg: i32) -> i32 { - // CHECK: spv.BitCount {{%.*}} : i32 - %0 = spv.BitCount %arg : i32 - spv.ReturnValue %0 : i32 -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.BitFieldInsert -//===----------------------------------------------------------------------===// - -func @bit_field_insert_vec(%base: vector<3xi32>, %insert: vector<3xi32>, %offset: i32, %count: i16) -> vector<3xi32> { - // CHECK: {{%.*}} = spv.BitFieldInsert {{%.*}}, {{%.*}}, {{%.*}}, {{%.*}} : vector<3xi32>, i32, i16 - %0 = spv.BitFieldInsert %base, %insert, %offset, %count : vector<3xi32>, i32, i16 - spv.ReturnValue %0 : vector<3xi32> -} - -// ----- - -func @bit_field_insert_invalid_insert_type(%base: vector<3xi32>, %insert: vector<2xi32>, %offset: i32, %count: i16) -> vector<3xi32> { - // expected-error @+1 {{all of {base, insert, result} have same type}} - %0 = "spv.BitFieldInsert" (%base, %insert, %offset, %count) : (vector<3xi32>, vector<2xi32>, i32, i16) -> vector<3xi32> - spv.ReturnValue %0 : vector<3xi32> -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.BitFieldSExtract -//===----------------------------------------------------------------------===// - -func @bit_field_s_extract_vec(%base: vector<3xi32>, %offset: i8, %count: i8) -> vector<3xi32> { - // CHECK: {{%.*}} = spv.BitFieldSExtract {{%.*}}, {{%.*}}, {{%.*}} : vector<3xi32>, i8, i8 - %0 = spv.BitFieldSExtract %base, %offset, %count : vector<3xi32>, i8, i8 - spv.ReturnValue %0 : vector<3xi32> -} - -//===----------------------------------------------------------------------===// -// spv.BitFieldUExtract -//===----------------------------------------------------------------------===// - -func @bit_field_u_extract_vec(%base: vector<3xi32>, %offset: i8, %count: i8) -> vector<3xi32> { - // CHECK: {{%.*}} = spv.BitFieldUExtract {{%.*}}, {{%.*}}, {{%.*}} : vector<3xi32>, i8, i8 - %0 = spv.BitFieldUExtract %base, %offset, %count : vector<3xi32>, i8, i8 - spv.ReturnValue %0 : vector<3xi32> -} - -// ----- - -func @bit_field_u_extract_invalid_result_type(%base: vector<3xi32>, %offset: i32, %count: i16) -> vector<4xi32> { - // expected-error @+1 {{failed to verify that all of {base, result} have same type}} - %0 = "spv.BitFieldUExtract" (%base, %offset, %count) : (vector<3xi32>, i32, i16) -> vector<4xi32> - spv.ReturnValue %0 : vector<4xi32> -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.BitReverse -//===----------------------------------------------------------------------===// - -func @bitreverse(%arg: i32) -> i32 { - // CHECK: spv.BitReverse {{%.*}} : i32 - %0 = spv.BitReverse %arg : i32 - spv.ReturnValue %0 : i32 -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.ControlBarrier -//===----------------------------------------------------------------------===// - -func @control_barrier_0() -> () { - // CHECK: spv.ControlBarrier "Workgroup", "Device", "Acquire|UniformMemory" - spv.ControlBarrier "Workgroup", "Device", "Acquire|UniformMemory" - return -} - -// ----- - -func @control_barrier_1() -> () { - // expected-error @+1 {{invalid execution_scope attribute specification: "Something"}} - spv.ControlBarrier "Something", "Device", "Acquire|UniformMemory" - return -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.ConvertFToS -//===----------------------------------------------------------------------===// - -func @convert_f_to_s_scalar(%arg0 : f32) -> i32 { - // CHECK: {{%.*}} = spv.ConvertFToS {{%.*}} : f32 to i32 - %0 = spv.ConvertFToS %arg0 : f32 to i32 - spv.ReturnValue %0 : i32 -} - -// ----- - -func @convert_f64_to_s32_scalar(%arg0 : f64) -> i32 { - // CHECK: {{%.*}} = spv.ConvertFToS {{%.*}} : f64 to i32 - %0 = spv.ConvertFToS %arg0 : f64 to i32 - spv.ReturnValue %0 : i32 -} - -// ----- - -func @convert_f_to_s_vector(%arg0 : vector<3xf32>) -> vector<3xi32> { - // CHECK: {{%.*}} = spv.ConvertFToS {{%.*}} : vector<3xf32> to vector<3xi32> - %0 = spv.ConvertFToS %arg0 : vector<3xf32> to vector<3xi32> - spv.ReturnValue %0 : vector<3xi32> -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.ConvertFToU -//===----------------------------------------------------------------------===// - -func @convert_f_to_u_scalar(%arg0 : f32) -> i32 { - // CHECK: {{%.*}} = spv.ConvertFToU {{%.*}} : f32 to i32 - %0 = spv.ConvertFToU %arg0 : f32 to i32 - spv.ReturnValue %0 : i32 -} - -// ----- - -func @convert_f64_to_u32_scalar(%arg0 : f64) -> i32 { - // CHECK: {{%.*}} = spv.ConvertFToU {{%.*}} : f64 to i32 - %0 = spv.ConvertFToU %arg0 : f64 to i32 - spv.ReturnValue %0 : i32 -} - -// ----- - -func @convert_f_to_u_vector(%arg0 : vector<3xf32>) -> vector<3xi32> { - // CHECK: {{%.*}} = spv.ConvertFToU {{%.*}} : vector<3xf32> to vector<3xi32> - %0 = spv.ConvertFToU %arg0 : vector<3xf32> to vector<3xi32> - spv.ReturnValue %0 : vector<3xi32> -} - -// ----- - -func @convert_f_to_u_coopmatrix(%arg0 : !spv.coopmatrix<8x16xf32, Subgroup>) { - // CHECK: {{%.*}} = spv.ConvertFToU {{%.*}} : !spv.coopmatrix<8x16xf32, Subgroup> to !spv.coopmatrix<8x16xi32, Subgroup> - %0 = spv.ConvertFToU %arg0 : !spv.coopmatrix<8x16xf32, Subgroup> to !spv.coopmatrix<8x16xi32, Subgroup> - spv.Return -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.ConvertSToF -//===----------------------------------------------------------------------===// - -func @convert_s_to_f_scalar(%arg0 : i32) -> f32 { - // CHECK: {{%.*}} = spv.ConvertSToF {{%.*}} : i32 to f32 - %0 = spv.ConvertSToF %arg0 : i32 to f32 - spv.ReturnValue %0 : f32 -} - -// ----- - -func @convert_s64_to_f32_scalar(%arg0 : i64) -> f32 { - // CHECK: {{%.*}} = spv.ConvertSToF {{%.*}} : i64 to f32 - %0 = spv.ConvertSToF %arg0 : i64 to f32 - spv.ReturnValue %0 : f32 -} - -// ----- - -func @convert_s_to_f_vector(%arg0 : vector<3xi32>) -> vector<3xf32> { - // CHECK: {{%.*}} = spv.ConvertSToF {{%.*}} : vector<3xi32> to vector<3xf32> - %0 = spv.ConvertSToF %arg0 : vector<3xi32> to vector<3xf32> - spv.ReturnValue %0 : vector<3xf32> -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.ConvertUToF -//===----------------------------------------------------------------------===// - -func @convert_u_to_f_scalar(%arg0 : i32) -> f32 { - // CHECK: {{%.*}} = spv.ConvertUToF {{%.*}} : i32 to f32 - %0 = spv.ConvertUToF %arg0 : i32 to f32 - spv.ReturnValue %0 : f32 -} - -// ----- - -func @convert_u64_to_f32_scalar(%arg0 : i64) -> f32 { - // CHECK: {{%.*}} = spv.ConvertUToF {{%.*}} : i64 to f32 - %0 = spv.ConvertUToF %arg0 : i64 to f32 - spv.ReturnValue %0 : f32 -} - -// ----- - -func @convert_u_to_f_vector(%arg0 : vector<3xi32>) -> vector<3xf32> { - // CHECK: {{%.*}} = spv.ConvertUToF {{%.*}} : vector<3xi32> to vector<3xf32> - %0 = spv.ConvertUToF %arg0 : vector<3xi32> to vector<3xf32> - spv.ReturnValue %0 : vector<3xf32> -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.FConvert -//===----------------------------------------------------------------------===// - -func @f_convert_scalar(%arg0 : f32) -> f64 { - // CHECK: {{%.*}} = spv.FConvert {{%.*}} : f32 to f64 - %0 = spv.FConvert %arg0 : f32 to f64 - spv.ReturnValue %0 : f64 -} - -// ----- - -func @f_convert_vector(%arg0 : vector<3xf32>) -> vector<3xf64> { - // CHECK: {{%.*}} = spv.FConvert {{%.*}} : vector<3xf32> to vector<3xf64> - %0 = spv.FConvert %arg0 : vector<3xf32> to vector<3xf64> - spv.ReturnValue %0 : vector<3xf64> -} - -// ----- - -func @f_convert_coop_matrix(%arg0 : !spv.coopmatrix<8x16xf32, Subgroup>) { - // CHECK: {{%.*}} = spv.FConvert {{%.*}} : !spv.coopmatrix<8x16xf32, Subgroup> to !spv.coopmatrix<8x16xf64, Subgroup> - %0 = spv.FConvert %arg0 : !spv.coopmatrix<8x16xf32, Subgroup> to !spv.coopmatrix<8x16xf64, Subgroup> - spv.Return -} - -// ----- - -func @f_convert_vector(%arg0 : f32) -> f32 { - // expected-error @+1 {{expected the different bit widths for operand type and result type, but provided 'f32' and 'f32'}} - %0 = spv.FConvert %arg0 : f32 to f32 - spv.ReturnValue %0 : f32 -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.SConvert -//===----------------------------------------------------------------------===// - -func @s_convert_scalar(%arg0 : i32) -> i64 { - // CHECK: {{%.*}} = spv.SConvert {{%.*}} : i32 to i64 - %0 = spv.SConvert %arg0 : i32 to i64 - spv.ReturnValue %0 : i64 -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.UConvert -//===----------------------------------------------------------------------===// - -func @u_convert_scalar(%arg0 : i32) -> i64 { - // CHECK: {{%.*}} = spv.UConvert {{%.*}} : i32 to i64 - %0 = spv.UConvert %arg0 : i32 to i64 - spv.ReturnValue %0 : i64 -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.ExecutionMode -//===----------------------------------------------------------------------===// - -spv.module Logical GLSL450 { - spv.func @do_nothing() -> () "None" { - spv.Return - } - spv.EntryPoint "GLCompute" @do_nothing - // CHECK: spv.ExecutionMode {{@.*}} "ContractionOff" - spv.ExecutionMode @do_nothing "ContractionOff" -} - -spv.module Logical GLSL450 { - spv.func @do_nothing() -> () "None" { - spv.Return - } - spv.EntryPoint "GLCompute" @do_nothing - // CHECK: spv.ExecutionMode {{@.*}} "LocalSizeHint", 3, 4, 5 - spv.ExecutionMode @do_nothing "LocalSizeHint", 3, 4, 5 -} - -// ----- - -spv.module Logical GLSL450 { - spv.func @do_nothing() -> () "None" { - spv.Return - } - spv.EntryPoint "GLCompute" @do_nothing - // expected-error @+1 {{custom op 'spv.ExecutionMode' invalid execution_mode attribute specification: "GLCompute"}} - spv.ExecutionMode @do_nothing "GLCompute", 3, 4, 5 -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.LoadOp -//===----------------------------------------------------------------------===// - -// CHECK-LABEL: @simple_load -func @simple_load() -> () { - %0 = spv.Variable : !spv.ptr - // CHECK: spv.Load "Function" %{{.*}} : f32 - %1 = spv.Load "Function" %0 : f32 - return -} - -// CHECK-LABEL: @load_none_access -func @load_none_access() -> () { - %0 = spv.Variable : !spv.ptr - // CHECK: spv.Load "Function" %{{.*}} ["None"] : f32 - %1 = spv.Load "Function" %0 ["None"] : f32 - return -} - -// CHECK-LABEL: @volatile_load -func @volatile_load() -> () { - %0 = spv.Variable : !spv.ptr - // CHECK: spv.Load "Function" %{{.*}} ["Volatile"] : f32 - %1 = spv.Load "Function" %0 ["Volatile"] : f32 - return -} - -// CHECK-LABEL: @aligned_load -func @aligned_load() -> () { - %0 = spv.Variable : !spv.ptr - // CHECK: spv.Load "Function" %{{.*}} ["Aligned", 4] : f32 - %1 = spv.Load "Function" %0 ["Aligned", 4] : f32 - return -} - -// CHECK-LABEL: @volatile_aligned_load -func @volatile_aligned_load() -> () { - %0 = spv.Variable : !spv.ptr - // CHECK: spv.Load "Function" %{{.*}} ["Volatile|Aligned", 4] : f32 - %1 = spv.Load "Function" %0 ["Volatile|Aligned", 4] : f32 - return -} - -// ----- - -// CHECK-LABEL: load_none_access -func @load_none_access() -> () { - %0 = spv.Variable : !spv.ptr - // CHECK: spv.Load - // CHECK-SAME: ["None"] - %1 = "spv.Load"(%0) {memory_access = 0 : i32} : (!spv.ptr) -> (f32) - return -} - -// CHECK-LABEL: volatile_load -func @volatile_load() -> () { - %0 = spv.Variable : !spv.ptr - // CHECK: spv.Load - // CHECK-SAME: ["Volatile"] - %1 = "spv.Load"(%0) {memory_access = 1 : i32} : (!spv.ptr) -> (f32) - return -} - -// CHECK-LABEL: aligned_load -func @aligned_load() -> () { - %0 = spv.Variable : !spv.ptr - // CHECK: spv.Load - // CHECK-SAME: ["Aligned", 4] - %1 = "spv.Load"(%0) {memory_access = 2 : i32, alignment = 4 : i32} : (!spv.ptr) -> (f32) - return -} - -// CHECK-LABEL: volatile_aligned_load -func @volatile_aligned_load() -> () { - %0 = spv.Variable : !spv.ptr - // CHECK: spv.Load - // CHECK-SAME: ["Volatile|Aligned", 4] - %1 = "spv.Load"(%0) {memory_access = 3 : i32, alignment = 4 : i32} : (!spv.ptr) -> (f32) - return -} - -// ----- - -func @simple_load_missing_storageclass() -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected non-function type}} - %1 = spv.Load %0 : f32 - return -} - -// ----- - -func @simple_load_missing_operand() -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected SSA operand}} - %1 = spv.Load "Function" : f32 - return -} - -// ----- - -func @simple_load_missing_rettype() -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+2 {{expected ':'}} - %1 = spv.Load "Function" %0 - return -} - -// ----- - -func @volatile_load_missing_lbrace() -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected ':'}} - %1 = spv.Load "Function" %0 "Volatile"] : f32 - return -} - -// ----- - -func @volatile_load_missing_rbrace() -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected ']'}} - %1 = spv.Load "Function" %0 ["Volatile"} : f32 - return -} - -// ----- - -func @aligned_load_missing_alignment() -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected ','}} - %1 = spv.Load "Function" %0 ["Aligned"] : f32 - return -} - -// ----- - -func @aligned_load_missing_comma() -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected ','}} - %1 = spv.Load "Function" %0 ["Aligned" 4] : f32 - return -} - -// ----- - -func @load_incorrect_attributes() -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected ']'}} - %1 = spv.Load "Function" %0 ["Volatile", 4] : f32 - return -} - -// ----- - -func @load_unknown_memory_access() -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{custom op 'spv.Load' invalid memory_access attribute specification: "Something"}} - %1 = spv.Load "Function" %0 ["Something"] : f32 - return -} - -// ----- - -func @load_unknown_memory_access() -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{custom op 'spv.Load' invalid memory_access attribute specification: "Volatile|Something"}} - %1 = spv.Load "Function" %0 ["Volatile|Something"] : f32 - return -} - -// ----- - -func @load_unknown_memory_access() -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{failed to satisfy constraint: valid SPIR-V MemoryAccess}} - %1 = "spv.Load"(%0) {memory_access = 0x80000000 : i32} : (!spv.ptr) -> (f32) - return -} - -// ----- - -func @aligned_load_incorrect_attributes() -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected ']'}} - %1 = spv.Load "Function" %0 ["Aligned", 4, 23] : f32 - return -} - -// ----- - -spv.module Logical GLSL450 { - spv.globalVariable @var0 : !spv.ptr - // CHECK_LABEL: @simple_load - spv.func @simple_load() -> () "None" { - // CHECK: spv.Load "Input" {{%.*}} : f32 - %0 = spv.mlir.addressof @var0 : !spv.ptr - %1 = spv.Load "Input" %0 : f32 - spv.Return - } -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.LogicalAnd -//===----------------------------------------------------------------------===// - -func @logicalBinary(%arg0 : i1, %arg1 : i1, %arg2 : i1) -{ - // CHECK: [[TMP:%.*]] = spv.LogicalAnd {{%.*}}, {{%.*}} : i1 - %0 = spv.LogicalAnd %arg0, %arg1 : i1 - // CHECK: {{%.*}} = spv.LogicalAnd [[TMP]], {{%.*}} : i1 - %1 = spv.LogicalAnd %0, %arg2 : i1 - return -} - -func @logicalBinary2(%arg0 : vector<4xi1>, %arg1 : vector<4xi1>) -{ - // CHECK: {{%.*}} = spv.LogicalAnd {{%.*}}, {{%.*}} : vector<4xi1> - %0 = spv.LogicalAnd %arg0, %arg1 : vector<4xi1> - return -} - -// ----- - -func @logicalBinary(%arg0 : i1, %arg1 : i1) -{ - // expected-error @+2 {{expected ':'}} - %0 = spv.LogicalAnd %arg0, %arg1 - return -} - -// ----- - -func @logicalBinary(%arg0 : i1, %arg1 : i1) -{ - // expected-error @+2 {{expected non-function type}} - %0 = spv.LogicalAnd %arg0, %arg1 : - return -} - -// ----- - -func @logicalBinary(%arg0 : i1, %arg1 : i1) -{ - // expected-error @+1 {{custom op 'spv.LogicalAnd' expected 2 operands}} - %0 = spv.LogicalAnd %arg0 : i1 - return -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.LogicalNot -//===----------------------------------------------------------------------===// - -func @logicalUnary(%arg0 : i1, %arg1 : i1) -{ - // CHECK: [[TMP:%.*]] = spv.LogicalNot {{%.*}} : i1 - %0 = spv.LogicalNot %arg0 : i1 - // CHECK: {{%.*}} = spv.LogicalNot [[TMP]] : i1 - %1 = spv.LogicalNot %0 : i1 - return -} - -func @logicalUnary2(%arg0 : vector<4xi1>) -{ - // CHECK: {{%.*}} = spv.LogicalNot {{%.*}} : vector<4xi1> - %0 = spv.LogicalNot %arg0 : vector<4xi1> - return -} - -// ----- - -func @logicalUnary(%arg0 : i1) -{ - // expected-error @+2 {{expected ':'}} - %0 = spv.LogicalNot %arg0 - return -} - -// ----- - -func @logicalUnary(%arg0 : i1) -{ - // expected-error @+2 {{expected non-function type}} - %0 = spv.LogicalNot %arg0 : - return -} - -// ----- - -func @logicalUnary(%arg0 : i1) -{ - // expected-error @+1 {{expected SSA operand}} - %0 = spv.LogicalNot : i1 - return -} - -// ----- - -func @logicalUnary(%arg0 : i32) -{ - // expected-error @+1 {{operand #0 must be bool or vector of bool values of length 2/3/4/8/16, but got 'i32'}} - %0 = spv.LogicalNot %arg0 : i32 - return -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.MemoryBarrier -//===----------------------------------------------------------------------===// - -func @memory_barrier_0() -> () { - // CHECK: spv.MemoryBarrier "Device", "Acquire|UniformMemory" - spv.MemoryBarrier "Device", "Acquire|UniformMemory" - return -} - -// ----- - -func @memory_barrier_1() -> () { - // CHECK: spv.MemoryBarrier "Workgroup", "Acquire" - spv.MemoryBarrier "Workgroup", "Acquire" - return -} - -// ----- - -func @memory_barrier_2() -> () { - // expected-error @+1 {{expected at most one of these four memory constraints to be set: `Acquire`, `Release`,`AcquireRelease` or `SequentiallyConsistent`}} - spv.MemoryBarrier "Device", "Acquire|Release" - return -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.Not -//===----------------------------------------------------------------------===// - -func @not(%arg: i32) -> i32 { - // CHECK: spv.Not {{%.*}} : i32 - %0 = spv.Not %arg : i32 - spv.ReturnValue %0 : i32 -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.SelectOp -//===----------------------------------------------------------------------===// - -func @select_op_bool(%arg0: i1) -> () { - %0 = spv.constant true - %1 = spv.constant false - // CHECK : spv.Select {{%.*}}, {{%.*}}, {{%.*}} : i1, i1 - %2 = spv.Select %arg0, %0, %1 : i1, i1 - return -} - -func @select_op_int(%arg0: i1) -> () { - %0 = spv.constant 2 : i32 - %1 = spv.constant 3 : i32 - // CHECK : spv.Select {{%.*}}, {{%.*}}, {{%.*}} : i1, i32 - %2 = spv.Select %arg0, %0, %1 : i1, i32 - return -} - -func @select_op_float(%arg0: i1) -> () { - %0 = spv.constant 2.0 : f32 - %1 = spv.constant 3.0 : f32 - // CHECK : spv.Select {{%.*}}, {{%.*}}, {{%.*}} : i1, f32 - %2 = spv.Select %arg0, %0, %1 : i1, f32 - return -} - -func @select_op_ptr(%arg0: i1) -> () { - %0 = spv.Variable : !spv.ptr - %1 = spv.Variable : !spv.ptr - // CHECK : spv.Select {{%.*}}, {{%.*}}, {{%.*}} : i1, !spv.ptr - %2 = spv.Select %arg0, %0, %1 : i1, !spv.ptr - return -} - -func @select_op_vec(%arg0: i1) -> () { - %0 = spv.constant dense<[2.0, 3.0, 4.0]> : vector<3xf32> - %1 = spv.constant dense<[5.0, 6.0, 7.0]> : vector<3xf32> - // CHECK : spv.Select {{%.*}}, {{%.*}}, {{%.*}} : i1, vector<3xf32> - %2 = spv.Select %arg0, %0, %1 : i1, vector<3xf32> - return -} - -func @select_op_vec_condn_vec(%arg0: vector<3xi1>) -> () { - %0 = spv.constant dense<[2.0, 3.0, 4.0]> : vector<3xf32> - %1 = spv.constant dense<[5.0, 6.0, 7.0]> : vector<3xf32> - // CHECK : spv.Select {{%.*}}, {{%.*}}, {{%.*}} : vector<3xi1>, vector<3xf32> - %2 = spv.Select %arg0, %0, %1 : vector<3xi1>, vector<3xf32> - return -} - -// ----- - -func @select_op(%arg0: i1) -> () { - %0 = spv.constant 2 : i32 - %1 = spv.constant 3 : i32 - // expected-error @+2 {{expected ','}} - %2 = spv.Select %arg0, %0, %1 : i1 - return -} - -// ----- - -func @select_op(%arg1: vector<3xi1>) -> () { - %0 = spv.constant 2 : i32 - %1 = spv.constant 3 : i32 - // expected-error @+1 {{result expected to be of vector type when condition is of vector type}} - %2 = spv.Select %arg1, %0, %1 : vector<3xi1>, i32 - return -} - -// ----- - -func @select_op(%arg1: vector<4xi1>) -> () { - %0 = spv.constant dense<[2, 3, 4]> : vector<3xi32> - %1 = spv.constant dense<[5, 6, 7]> : vector<3xi32> - // expected-error @+1 {{result should have the same number of elements as the condition when condition is of vector type}} - %2 = spv.Select %arg1, %0, %1 : vector<4xi1>, vector<3xi32> - return -} - -// ----- - -func @select_op(%arg1: vector<4xi1>) -> () { - %0 = spv.constant dense<[2.0, 3.0, 4.0]> : vector<3xf32> - %1 = spv.constant dense<[5, 6, 7]> : vector<3xi32> - // expected-error @+1 {{all of {true_value, false_value, result} have same type}} - %2 = "spv.Select"(%arg1, %0, %1) : (vector<4xi1>, vector<3xf32>, vector<3xi32>) -> vector<3xi32> - return -} - -// ----- - -func @select_op(%arg1: vector<4xi1>) -> () { - %0 = spv.constant dense<[2.0, 3.0, 4.0]> : vector<3xf32> - %1 = spv.constant dense<[5, 6, 7]> : vector<3xi32> - // expected-error @+1 {{all of {true_value, false_value, result} have same type}} - %2 = "spv.Select"(%arg1, %1, %0) : (vector<4xi1>, vector<3xi32>, vector<3xf32>) -> vector<3xi32> - return -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.ShiftLeftLogical -//===----------------------------------------------------------------------===// - -func @shift_left_logical(%arg0: i32, %arg1 : i16) -> i32 { - // CHECK: {{%.*}} = spv.ShiftLeftLogical {{%.*}}, {{%.*}} : i32, i16 - %0 = spv.ShiftLeftLogical %arg0, %arg1: i32, i16 - spv.ReturnValue %0 : i32 -} - -// ----- - -func @shift_left_logical_invalid_result_type(%arg0: i32, %arg1 : i16) -> i16 { - // expected-error @+1 {{expected the same type for the first operand and result, but provided 'i32' and 'i16'}} - %0 = "spv.ShiftLeftLogical" (%arg0, %arg1) : (i32, i16) -> (i16) - spv.ReturnValue %0 : i16 -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.ShiftRightArithmetic -//===----------------------------------------------------------------------===// - -func @shift_right_arithmetic(%arg0: vector<4xi32>, %arg1 : vector<4xi8>) -> vector<4xi32> { - // CHECK: {{%.*}} = spv.ShiftRightArithmetic {{%.*}}, {{%.*}} : vector<4xi32>, vector<4xi8> - %0 = spv.ShiftRightArithmetic %arg0, %arg1: vector<4xi32>, vector<4xi8> - spv.ReturnValue %0 : vector<4xi32> -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.ShiftRightLogical -//===----------------------------------------------------------------------===// - -func @shift_right_logical(%arg0: vector<2xi32>, %arg1 : vector<2xi8>) -> vector<2xi32> { - // CHECK: {{%.*}} = spv.ShiftRightLogical {{%.*}}, {{%.*}} : vector<2xi32>, vector<2xi8> - %0 = spv.ShiftRightLogical %arg0, %arg1: vector<2xi32>, vector<2xi8> - spv.ReturnValue %0 : vector<2xi32> -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.StoreOp -//===----------------------------------------------------------------------===// - -func @simple_store(%arg0 : f32) -> () { - %0 = spv.Variable : !spv.ptr - // CHECK: spv.Store "Function" %0, %arg0 : f32 - spv.Store "Function" %0, %arg0 : f32 - return -} - -// CHECK_LABEL: @volatile_store -func @volatile_store(%arg0 : f32) -> () { - %0 = spv.Variable : !spv.ptr - // CHECK: spv.Store "Function" %0, %arg0 ["Volatile"] : f32 - spv.Store "Function" %0, %arg0 ["Volatile"] : f32 - return -} - -// CHECK_LABEL: @aligned_store -func @aligned_store(%arg0 : f32) -> () { - %0 = spv.Variable : !spv.ptr - // CHECK: spv.Store "Function" %0, %arg0 ["Aligned", 4] : f32 - spv.Store "Function" %0, %arg0 ["Aligned", 4] : f32 - return -} - -// ----- - -func @simple_store_missing_ptr_type(%arg0 : f32) -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected non-function type}} - spv.Store %0, %arg0 : f32 - return -} - -// ----- - -func @simple_store_missing_operand(%arg0 : f32) -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{custom op 'spv.Store' invalid operand}} : f32 - spv.Store "Function" , %arg0 : f32 - return -} - -// ----- - -func @simple_store_missing_operand(%arg0 : f32) -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{custom op 'spv.Store' expected 2 operands}} : f32 - spv.Store "Function" %0 : f32 - return -} - -// ----- - -func @volatile_store_missing_lbrace(%arg0 : f32) -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected ':'}} - spv.Store "Function" %0, %arg0 "Volatile"] : f32 - return -} - -// ----- - -func @volatile_store_missing_rbrace(%arg0 : f32) -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected ']'}} - spv.Store "Function" %0, %arg0 ["Volatile"} : f32 - return -} - -// ----- - -func @aligned_store_missing_alignment(%arg0 : f32) -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected ','}} - spv.Store "Function" %0, %arg0 ["Aligned"] : f32 - return -} - -// ----- - -func @aligned_store_missing_comma(%arg0 : f32) -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected ','}} - spv.Store "Function" %0, %arg0 ["Aligned" 4] : f32 - return -} - -// ----- - -func @load_incorrect_attributes(%arg0 : f32) -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected ']'}} - spv.Store "Function" %0, %arg0 ["Volatile", 4] : f32 - return -} - -// ----- - -func @aligned_store_incorrect_attributes(%arg0 : f32) -> () { - %0 = spv.Variable : !spv.ptr - // expected-error @+1 {{expected ']'}} - spv.Store "Function" %0, %arg0 ["Aligned", 4, 23] : f32 - return -} - -// ----- - -spv.module Logical GLSL450 { - spv.globalVariable @var0 : !spv.ptr - spv.func @simple_store(%arg0 : f32) -> () "None" { - %0 = spv.mlir.addressof @var0 : !spv.ptr - // CHECK: spv.Store "Input" {{%.*}}, {{%.*}} : f32 - spv.Store "Input" %0, %arg0 : f32 - spv.Return - } -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.SubgroupBallotKHR -//===----------------------------------------------------------------------===// - -func @subgroup_ballot(%predicate: i1) -> vector<4xi32> { - %0 = spv.SubgroupBallotKHR %predicate: vector<4xi32> - return %0: vector<4xi32> -} - -// ----- - -//===----------------------------------------------------------------------===// -// spv.undef -//===----------------------------------------------------------------------===// - -func @undef() -> () { - %0 = spv.undef : f32 - %1 = spv.undef : vector<4xf32> - spv.Return -} - -// ----- - -func @undef() -> () { - // expected-error @+2{{expected non-function type}} - %0 = spv.undef : - spv.Return -} - -// ----- - -func @undef() -> () { - // expected-error @+2{{expected ':'}} - %0 = spv.undef - spv.Return -} - -// ----- - - -//===----------------------------------------------------------------------===// -// spv.Variable -//===----------------------------------------------------------------------===// - -func @variable(%arg0: f32) -> () { - // CHECK: spv.Variable : !spv.ptr - %0 = spv.Variable : !spv.ptr - return -} - -// ----- - -func @variable_init_normal_constant() -> () { - %0 = spv.constant 4.0 : f32 - // CHECK: spv.Variable init(%0) : !spv.ptr - %1 = spv.Variable init(%0) : !spv.ptr - return -} - -// ----- - -spv.module Logical GLSL450 { - spv.globalVariable @global : !spv.ptr - spv.func @variable_init_global_variable() -> () "None" { - %0 = spv.mlir.addressof @global : !spv.ptr - // CHECK: spv.Variable init({{.*}}) : !spv.ptr, Function> - %1 = spv.Variable init(%0) : !spv.ptr, Function> - spv.Return - } -} - -// ----- - -spv.module Logical GLSL450 { - spv.specConstant @sc = 42 : i32 - // CHECK-LABEL: @variable_init_spec_constant - spv.func @variable_init_spec_constant() -> () "None" { - %0 = spv.mlir.referenceof @sc : i32 - // CHECK: spv.Variable init(%0) : !spv.ptr - %1 = spv.Variable init(%0) : !spv.ptr - spv.Return - } -} - -// ----- - -func @variable_bind() -> () { - // expected-error @+1 {{cannot have 'descriptor_set' attribute (only allowed in spv.globalVariable)}} - %0 = spv.Variable bind(1, 2) : !spv.ptr - return -} - -// ----- - -func @variable_init_bind() -> () { - %0 = spv.constant 4.0 : f32 - // expected-error @+1 {{cannot have 'binding' attribute (only allowed in spv.globalVariable)}} - %1 = spv.Variable init(%0) {binding = 5 : i32} : !spv.ptr - return -} - -// ----- - -func @variable_builtin() -> () { - // expected-error @+1 {{cannot have 'built_in' attribute (only allowed in spv.globalVariable)}} - %1 = spv.Variable built_in("GlobalInvocationID") : !spv.ptr, Function> - return -} - -// ----- - -func @expect_ptr_result_type(%arg0: f32) -> () { - // expected-error @+1 {{expected spv.ptr type}} - %0 = spv.Variable : f32 - return -} - -// ----- - -func @variable_init(%arg0: f32) -> () { - // expected-error @+1 {{op initializer must be the result of a constant or spv.globalVariable op}} - %0 = spv.Variable init(%arg0) : !spv.ptr - return -} - -// ----- - -func @cannot_be_generic_storage_class(%arg0: f32) -> () { - // expected-error @+1 {{op can only be used to model function-level variables. Use spv.globalVariable for module-level variables}} - %0 = spv.Variable : !spv.ptr - return -} - -// ----- - -func @copy_memory_incompatible_ptrs() { - %0 = spv.Variable : !spv.ptr - %1 = spv.Variable : !spv.ptr - // expected-error @+1 {{both operands must be pointers to the same type}} - "spv.CopyMemory"(%0, %1) {} : (!spv.ptr, !spv.ptr) -> () - spv.Return -} - -// ----- - -func @copy_memory_invalid_maa() { - %0 = spv.Variable : !spv.ptr - %1 = spv.Variable : !spv.ptr - // expected-error @+1 {{missing alignment value}} - "spv.CopyMemory"(%0, %1) {memory_access=0x0002 : i32} : (!spv.ptr, !spv.ptr) -> () - spv.Return -} - -// ----- - -func @copy_memory_invalid_source_maa() { - %0 = spv.Variable : !spv.ptr - %1 = spv.Variable : !spv.ptr - // expected-error @+1 {{invalid alignment specification with non-aligned memory access specification}} - "spv.CopyMemory"(%0, %1) {source_memory_access=0x0001 : i32, memory_access=0x0002 : i32, source_alignment=8 : i32, alignment=4 : i32} : (!spv.ptr, !spv.ptr) -> () - spv.Return -} - -// ----- - -func @copy_memory_invalid_source_maa2() { - %0 = spv.Variable : !spv.ptr - %1 = spv.Variable : !spv.ptr - // expected-error @+1 {{missing alignment value}} - "spv.CopyMemory"(%0, %1) {source_memory_access=0x0002 : i32, memory_access=0x0002 : i32, alignment=4 : i32} : (!spv.ptr, !spv.ptr) -> () - spv.Return -} - -// ----- - -func @copy_memory_print_maa() { - %0 = spv.Variable : !spv.ptr - %1 = spv.Variable : !spv.ptr - - // CHECK: spv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Volatile"] : f32 - "spv.CopyMemory"(%0, %1) {memory_access=0x0001 : i32} : (!spv.ptr, !spv.ptr) -> () - - // CHECK: spv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Aligned", 4] : f32 - "spv.CopyMemory"(%0, %1) {memory_access=0x0002 : i32, alignment=4 : i32} : (!spv.ptr, !spv.ptr) -> () - - // CHECK: spv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Aligned", 4], ["Volatile"] : f32 - "spv.CopyMemory"(%0, %1) {source_memory_access=0x0001 : i32, memory_access=0x0002 : i32, alignment=4 : i32} : (!spv.ptr, !spv.ptr) -> () - - // CHECK: spv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Aligned", 4], ["Aligned", 8] : f32 - "spv.CopyMemory"(%0, %1) {source_memory_access=0x0002 : i32, memory_access=0x0002 : i32, source_alignment=8 : i32, alignment=4 : i32} : (!spv.ptr, !spv.ptr) -> () - - spv.Return -} diff --git a/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir b/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir --- a/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir +++ b/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir @@ -213,6 +213,41 @@ // ----- +//===----------------------------------------------------------------------===// +// spv.ExecutionMode +//===----------------------------------------------------------------------===// + +spv.module Logical GLSL450 { + spv.func @do_nothing() -> () "None" { + spv.Return + } + spv.EntryPoint "GLCompute" @do_nothing + // CHECK: spv.ExecutionMode {{@.*}} "ContractionOff" + spv.ExecutionMode @do_nothing "ContractionOff" +} + +spv.module Logical GLSL450 { + spv.func @do_nothing() -> () "None" { + spv.Return + } + spv.EntryPoint "GLCompute" @do_nothing + // CHECK: spv.ExecutionMode {{@.*}} "LocalSizeHint", 3, 4, 5 + spv.ExecutionMode @do_nothing "LocalSizeHint", 3, 4, 5 +} + +// ----- + +spv.module Logical GLSL450 { + spv.func @do_nothing() -> () "None" { + spv.Return + } + spv.EntryPoint "GLCompute" @do_nothing + // expected-error @+1 {{custom op 'spv.ExecutionMode' invalid execution_mode attribute specification: "GLCompute"}} + spv.ExecutionMode @do_nothing "GLCompute", 3, 4, 5 +} + +// ----- + //===----------------------------------------------------------------------===// // spv.func //===----------------------------------------------------------------------===// diff --git a/mlir/test/Target/SPIRV/barrier.mlir b/mlir/test/Target/SPIRV/barrier-ops.mlir rename from mlir/test/Target/SPIRV/barrier.mlir rename to mlir/test/Target/SPIRV/barrier-ops.mlir