// RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s //===----------------------------------------------------------------------===// // spirv.AccessChain //===----------------------------------------------------------------------===// func.func @access_chain_struct() -> () { %0 = spirv.Constant 1: i32 %1 = spirv.Variable : !spirv.ptr)>, Function> // CHECK: spirv.AccessChain {{.*}}[{{.*}}, {{.*}}] : !spirv.ptr)>, Function> %2 = spirv.AccessChain %1[%0, %0] : !spirv.ptr)>, Function>, i32, i32 return } func.func @access_chain_1D_array(%arg0 : i32) -> () { %0 = spirv.Variable : !spirv.ptr, Function> // CHECK: spirv.AccessChain {{.*}}[{{.*}}] : !spirv.ptr, Function> %1 = spirv.AccessChain %0[%arg0] : !spirv.ptr, Function>, i32 return } func.func @access_chain_2D_array_1(%arg0 : i32) -> () { %0 = spirv.Variable : !spirv.ptr>, Function> // CHECK: spirv.AccessChain {{.*}}[{{.*}}, {{.*}}] : !spirv.ptr>, Function> %1 = spirv.AccessChain %0[%arg0, %arg0] : !spirv.ptr>, Function>, i32, i32 %2 = spirv.Load "Function" %1 ["Volatile"] : f32 return } func.func @access_chain_2D_array_2(%arg0 : i32) -> () { %0 = spirv.Variable : !spirv.ptr>, Function> // CHECK: spirv.AccessChain {{.*}}[{{.*}}] : !spirv.ptr>, Function> %1 = spirv.AccessChain %0[%arg0] : !spirv.ptr>, Function>, i32 %2 = spirv.Load "Function" %1 ["Volatile"] : !spirv.array<4xf32> return } func.func @access_chain_rtarray(%arg0 : i32) -> () { %0 = spirv.Variable : !spirv.ptr, Function> // CHECK: spirv.AccessChain {{.*}}[{{.*}}] : !spirv.ptr, Function> %1 = spirv.AccessChain %0[%arg0] : !spirv.ptr, Function>, i32 %2 = spirv.Load "Function" %1 ["Volatile"] : f32 return } // ----- func.func @access_chain_non_composite() -> () { %0 = spirv.Constant 1: i32 %1 = spirv.Variable : !spirv.ptr // expected-error @+1 {{cannot extract from non-composite type 'f32' with index 0}} %2 = spirv.AccessChain %1[%0] : !spirv.ptr, i32 return } // ----- func.func @access_chain_no_indices(%index0 : i32) -> () { %0 = spirv.Variable : !spirv.ptr>, Function> // expected-error @+1 {{expected at least one index}} %1 = spirv.AccessChain %0[] : !spirv.ptr>, Function>, i32 return } // ----- func.func @access_chain_missing_comma(%index0 : i32) -> () { %0 = spirv.Variable : !spirv.ptr>, Function> // expected-error @+1 {{expected ','}} %1 = spirv.AccessChain %0[%index0] : !spirv.ptr>, Function> i32 return } // ----- func.func @access_chain_invalid_indices_types_count(%index0 : i32) -> () { %0 = spirv.Variable : !spirv.ptr>, Function> // expected-error @+1 {{'spirv.AccessChain' op indices types' count must be equal to indices info count}} %1 = spirv.AccessChain %0[%index0] : !spirv.ptr>, Function>, i32, i32 return } // ----- func.func @access_chain_missing_indices_type(%index0 : i32) -> () { %0 = spirv.Variable : !spirv.ptr>, Function> // expected-error @+1 {{'spirv.AccessChain' op indices types' count must be equal to indices info count}} %1 = spirv.AccessChain %0[%index0, %index0] : !spirv.ptr>, Function>, i32 return } // ----- func.func @access_chain_invalid_type(%index0 : i32) -> () { %0 = spirv.Variable : !spirv.ptr>, Function> %1 = spirv.Load "Function" %0 ["Volatile"] : !spirv.array<4x!spirv.array<4xf32>> // expected-error @+1 {{expected a pointer to composite type, but provided '!spirv.array<4 x !spirv.array<4 x f32>>'}} %2 = spirv.AccessChain %1[%index0] : !spirv.array<4x!spirv.array<4xf32>>, i32 return } // ----- func.func @access_chain_invalid_index_1(%index0 : i32) -> () { %0 = spirv.Variable : !spirv.ptr>, Function> // expected-error @+1 {{expected SSA operand}} %1 = spirv.AccessChain %0[%index, 4] : !spirv.ptr>, Function>, i32, i32 return } // ----- func.func @access_chain_invalid_index_2(%index0 : i32) -> () { %0 = spirv.Variable : !spirv.ptr)>, Function> // expected-error @+1 {{index must be an integer spirv.Constant to access element of spirv.struct}} %1 = spirv.AccessChain %0[%index0, %index0] : !spirv.ptr)>, Function>, i32, i32 return } // ----- func.func @access_chain_invalid_constant_type_1() -> () { %0 = arith.constant 1: i32 %1 = spirv.Variable : !spirv.ptr)>, Function> // expected-error @+1 {{index must be an integer spirv.Constant to access element of spirv.struct, but provided arith.constant}} %2 = spirv.AccessChain %1[%0, %0] : !spirv.ptr)>, Function>, i32, i32 return } // ----- func.func @access_chain_out_of_bounds() -> () { %index0 = "spirv.Constant"() { value = 12: i32} : () -> i32 %0 = spirv.Variable : !spirv.ptr)>, Function> // expected-error @+1 {{'spirv.AccessChain' op index 12 out of bounds for '!spirv.struct<(f32, !spirv.array<4 x f32>)>'}} %1 = spirv.AccessChain %0[%index0, %index0] : !spirv.ptr)>, Function>, i32, i32 return } // ----- func.func @access_chain_invalid_accessing_type(%index0 : i32) -> () { %0 = spirv.Variable : !spirv.ptr>, Function> // expected-error @+1 {{cannot extract from non-composite type 'f32' with index 0}} %1 = spirv.AccessChain %0[%index, %index0, %index0] : !spirv.ptr>, Function>, i32, i32, i32 return // ----- //===----------------------------------------------------------------------===// // spirv.LoadOp //===----------------------------------------------------------------------===// // CHECK-LABEL: @simple_load func.func @simple_load() -> () { %0 = spirv.Variable : !spirv.ptr // CHECK: spirv.Load "Function" %{{.*}} : f32 %1 = spirv.Load "Function" %0 : f32 return } // CHECK-LABEL: @load_none_access func.func @load_none_access() -> () { %0 = spirv.Variable : !spirv.ptr // CHECK: spirv.Load "Function" %{{.*}} ["None"] : f32 %1 = spirv.Load "Function" %0 ["None"] : f32 return } // CHECK-LABEL: @volatile_load func.func @volatile_load() -> () { %0 = spirv.Variable : !spirv.ptr // CHECK: spirv.Load "Function" %{{.*}} ["Volatile"] : f32 %1 = spirv.Load "Function" %0 ["Volatile"] : f32 return } // CHECK-LABEL: @aligned_load func.func @aligned_load() -> () { %0 = spirv.Variable : !spirv.ptr // CHECK: spirv.Load "Function" %{{.*}} ["Aligned", 4] : f32 %1 = spirv.Load "Function" %0 ["Aligned", 4] : f32 return } // CHECK-LABEL: @volatile_aligned_load func.func @volatile_aligned_load() -> () { %0 = spirv.Variable : !spirv.ptr // CHECK: spirv.Load "Function" %{{.*}} ["Volatile|Aligned", 4] : f32 %1 = spirv.Load "Function" %0 ["Volatile|Aligned", 4] : f32 return } // ----- // CHECK-LABEL: load_none_access func.func @load_none_access() -> () { %0 = spirv.Variable : !spirv.ptr // CHECK: spirv.Load // CHECK-SAME: ["None"] %1 = "spirv.Load"(%0) {memory_access = #spirv.memory_access} : (!spirv.ptr) -> (f32) return } // CHECK-LABEL: volatile_load func.func @volatile_load() -> () { %0 = spirv.Variable : !spirv.ptr // CHECK: spirv.Load // CHECK-SAME: ["Volatile"] %1 = "spirv.Load"(%0) {memory_access = #spirv.memory_access} : (!spirv.ptr) -> (f32) return } // CHECK-LABEL: aligned_load func.func @aligned_load() -> () { %0 = spirv.Variable : !spirv.ptr // CHECK: spirv.Load // CHECK-SAME: ["Aligned", 4] %1 = "spirv.Load"(%0) {memory_access = #spirv.memory_access, alignment = 4 : i32} : (!spirv.ptr) -> (f32) return } // CHECK-LABEL: volatile_aligned_load func.func @volatile_aligned_load() -> () { %0 = spirv.Variable : !spirv.ptr // CHECK: spirv.Load // CHECK-SAME: ["Volatile|Aligned", 4] %1 = "spirv.Load"(%0) {memory_access = #spirv.memory_access, alignment = 4 : i32} : (!spirv.ptr) -> (f32) return } // ----- func.func @simple_load_missing_storageclass() -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected attribute value}} %1 = spirv.Load %0 : f32 return } // ----- func.func @simple_load_missing_operand() -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected SSA operand}} %1 = spirv.Load "Function" : f32 return } // ----- func.func @simple_load_missing_rettype() -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected ':'}} %1 = spirv.Load "Function" %0 return } // ----- func.func @volatile_load_missing_lbrace() -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected ':'}} %1 = spirv.Load "Function" %0 "Volatile"] : f32 return } // ----- func.func @volatile_load_missing_rbrace() -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected ']'}} %1 = spirv.Load "Function" %0 ["Volatile"} : f32 return } // ----- func.func @aligned_load_missing_alignment() -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected ','}} %1 = spirv.Load "Function" %0 ["Aligned"] : f32 return } // ----- func.func @aligned_load_missing_comma() -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected ','}} %1 = spirv.Load "Function" %0 ["Aligned" 4] : f32 return } // ----- func.func @load_incorrect_attributes() -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected ']'}} %1 = spirv.Load "Function" %0 ["Volatile", 4] : f32 return } // ----- func.func @load_unknown_memory_access() -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{custom op 'spirv.Load' invalid memory_access attribute specification: "Something"}} %1 = spirv.Load "Function" %0 ["Something"] : f32 return } // ----- func.func @load_unknown_memory_access() -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{custom op 'spirv.Load' invalid memory_access attribute specification: "Volatile|Something"}} %1 = spirv.Load "Function" %0 ["Volatile|Something"] : f32 return } // ----- func.func @load_unknown_memory_access() -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{failed to satisfy constraint: valid SPIR-V MemoryAccess}} %1 = "spirv.Load"(%0) {memory_access = 0x80000000 : i32} : (!spirv.ptr) -> (f32) return } // ----- func.func @aligned_load_incorrect_attributes() -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected ']'}} %1 = spirv.Load "Function" %0 ["Aligned", 4, 23] : f32 return } // ----- spirv.module Logical GLSL450 { spirv.GlobalVariable @var0 : !spirv.ptr spirv.GlobalVariable @var1 : !spirv.ptr>, UniformConstant> // CHECK-LABEL: @simple_load spirv.func @simple_load() -> () "None" { // CHECK: spirv.Load "Input" {{%.*}} : f32 %0 = spirv.mlir.addressof @var0 : !spirv.ptr %1 = spirv.Load "Input" %0 : f32 %2 = spirv.mlir.addressof @var1 : !spirv.ptr>, UniformConstant> // CHECK: spirv.Load "UniformConstant" {{%.*}} : !spirv.sampled_image %3 = spirv.Load "UniformConstant" %2 : !spirv.sampled_image> spirv.Return } } // ----- //===----------------------------------------------------------------------===// // spirv.StoreOp //===----------------------------------------------------------------------===// func.func @simple_store(%arg0 : f32) -> () { %0 = spirv.Variable : !spirv.ptr // CHECK: spirv.Store "Function" %0, %arg0 : f32 spirv.Store "Function" %0, %arg0 : f32 return } // CHECK-LABEL: @volatile_store func.func @volatile_store(%arg0 : f32) -> () { %0 = spirv.Variable : !spirv.ptr // CHECK: spirv.Store "Function" %0, %arg0 ["Volatile"] : f32 spirv.Store "Function" %0, %arg0 ["Volatile"] : f32 return } // CHECK-LABEL: @aligned_store func.func @aligned_store(%arg0 : f32) -> () { %0 = spirv.Variable : !spirv.ptr // CHECK: spirv.Store "Function" %0, %arg0 ["Aligned", 4] : f32 spirv.Store "Function" %0, %arg0 ["Aligned", 4] : f32 return } // ----- func.func @simple_store_missing_ptr_type(%arg0 : f32) -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected attribute value}} spirv.Store %0, %arg0 : f32 return } // ----- func.func @simple_store_missing_operand(%arg0 : f32) -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected operand}} spirv.Store "Function" , %arg0 : f32 return } // ----- func.func @simple_store_missing_operand(%arg0 : f32) -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{custom op 'spirv.Store' expected 2 operands}} spirv.Store "Function" %0 : f32 return } // ----- func.func @volatile_store_missing_lbrace(%arg0 : f32) -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected ':'}} spirv.Store "Function" %0, %arg0 "Volatile"] : f32 return } // ----- func.func @volatile_store_missing_rbrace(%arg0 : f32) -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected ']'}} spirv.Store "Function" %0, %arg0 ["Volatile"} : f32 return } // ----- func.func @aligned_store_missing_alignment(%arg0 : f32) -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected ','}} spirv.Store "Function" %0, %arg0 ["Aligned"] : f32 return } // ----- func.func @aligned_store_missing_comma(%arg0 : f32) -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected ','}} spirv.Store "Function" %0, %arg0 ["Aligned" 4] : f32 return } // ----- func.func @load_incorrect_attributes(%arg0 : f32) -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected ']'}} spirv.Store "Function" %0, %arg0 ["Volatile", 4] : f32 return } // ----- func.func @aligned_store_incorrect_attributes(%arg0 : f32) -> () { %0 = spirv.Variable : !spirv.ptr // expected-error @+1 {{expected ']'}} spirv.Store "Function" %0, %arg0 ["Aligned", 4, 23] : f32 return } // ----- spirv.module Logical GLSL450 { spirv.GlobalVariable @var0 : !spirv.ptr spirv.func @simple_store(%arg0 : f32) -> () "None" { %0 = spirv.mlir.addressof @var0 : !spirv.ptr // CHECK: spirv.Store "Input" {{%.*}}, {{%.*}} : f32 spirv.Store "Input" %0, %arg0 : f32 spirv.Return } } // ----- //===----------------------------------------------------------------------===// // spirv.Variable //===----------------------------------------------------------------------===// func.func @variable(%arg0: f32) -> () { // CHECK: spirv.Variable : !spirv.ptr %0 = spirv.Variable : !spirv.ptr return } // ----- func.func @variable_init_normal_constant() -> () { // CHECK: %[[cst:.*]] = spirv.Constant %0 = spirv.Constant 4.0 : f32 // CHECK: spirv.Variable init(%[[cst]]) : !spirv.ptr %1 = spirv.Variable init(%0) : !spirv.ptr return } // ----- spirv.module Logical GLSL450 { spirv.GlobalVariable @global : !spirv.ptr spirv.func @variable_init_global_variable() -> () "None" { %0 = spirv.mlir.addressof @global : !spirv.ptr // CHECK: spirv.Variable init({{.*}}) : !spirv.ptr, Function> %1 = spirv.Variable init(%0) : !spirv.ptr, Function> spirv.Return } } // ----- spirv.module Logical GLSL450 { spirv.SpecConstant @sc = 42 : i32 // CHECK-LABEL: @variable_init_spec_constant spirv.func @variable_init_spec_constant() -> () "None" { %0 = spirv.mlir.referenceof @sc : i32 // CHECK: spirv.Variable init(%0) : !spirv.ptr %1 = spirv.Variable init(%0) : !spirv.ptr spirv.Return } } // ----- func.func @variable_ptr_physical_buffer() -> () { %0 = spirv.Variable {aliased_pointer} : !spirv.ptr, Function> %1 = spirv.Variable {restrict_pointer} : !spirv.ptr, Function> return } // ----- func.func @variable_ptr_physical_buffer_no_decoration() -> () { // expected-error @+1 {{must be decorated either 'AliasedPointer' or 'RestrictPointer'}} %0 = spirv.Variable : !spirv.ptr, Function> return } // ----- func.func @variable_ptr_physical_buffer_two_alias_decorations() -> () { // expected-error @+1 {{must have exactly one aliasing decoration}} %0 = spirv.Variable {aliased_pointer, restrict_pointer} : !spirv.ptr, Function> return } // ----- func.func @variable_ptr_array_physical_buffer() -> () { %0 = spirv.Variable {aliased_pointer} : !spirv.ptr>, Function> %1 = spirv.Variable {restrict_pointer} : !spirv.ptr>, Function> return } // ----- func.func @variable_ptr_array_physical_buffer_no_decoration() -> () { // expected-error @+1 {{must be decorated either 'AliasedPointer' or 'RestrictPointer'}} %0 = spirv.Variable : !spirv.ptr>, Function> return } // ----- func.func @variable_ptr_array_physical_buffer_two_alias_decorations() -> () { // expected-error @+1 {{must have exactly one aliasing decoration}} %0 = spirv.Variable {aliased_pointer, restrict_pointer} : !spirv.ptr>, Function> return } // ----- func.func @variable_bind() -> () { // expected-error @+1 {{cannot have 'descriptor_set' attribute (only allowed in spirv.GlobalVariable)}} %0 = spirv.Variable bind(1, 2) : !spirv.ptr return } // ----- func.func @variable_init_bind() -> () { %0 = spirv.Constant 4.0 : f32 // expected-error @+1 {{cannot have 'binding' attribute (only allowed in spirv.GlobalVariable)}} %1 = spirv.Variable init(%0) {binding = 5 : i32} : !spirv.ptr return } // ----- func.func @variable_builtin() -> () { // expected-error @+1 {{cannot have 'built_in' attribute (only allowed in spirv.GlobalVariable)}} %1 = spirv.Variable built_in("GlobalInvocationID") : !spirv.ptr, Function> return } // ----- func.func @expect_ptr_result_type(%arg0: f32) -> () { // expected-error @+1 {{expected spirv.ptr type}} %0 = spirv.Variable : f32 return } // ----- func.func @variable_init(%arg0: f32) -> () { // expected-error @+1 {{op initializer must be the result of a constant or spirv.GlobalVariable op}} %0 = spirv.Variable init(%arg0) : !spirv.ptr return } // ----- func.func @cannot_be_generic_storage_class(%arg0: f32) -> () { // expected-error @+1 {{op can only be used to model function-level variables. Use spirv.GlobalVariable for module-level variables}} %0 = spirv.Variable : !spirv.ptr return } // ----- func.func @copy_memory_incompatible_ptrs() { %0 = spirv.Variable : !spirv.ptr %1 = spirv.Variable : !spirv.ptr // expected-error @+1 {{both operands must be pointers to the same type}} "spirv.CopyMemory"(%0, %1) {} : (!spirv.ptr, !spirv.ptr) -> () spirv.Return } // ----- func.func @copy_memory_invalid_maa() { %0 = spirv.Variable : !spirv.ptr %1 = spirv.Variable : !spirv.ptr // expected-error @+1 {{missing alignment value}} "spirv.CopyMemory"(%0, %1) {memory_access=#spirv.memory_access} : (!spirv.ptr, !spirv.ptr) -> () spirv.Return } // ----- func.func @copy_memory_invalid_source_maa() { %0 = spirv.Variable : !spirv.ptr %1 = spirv.Variable : !spirv.ptr // expected-error @+1 {{invalid alignment specification with non-aligned memory access specification}} "spirv.CopyMemory"(%0, %1) {source_memory_access=#spirv.memory_access, memory_access=#spirv.memory_access, source_alignment=8 : i32, alignment=4 : i32} : (!spirv.ptr, !spirv.ptr) -> () spirv.Return } // ----- func.func @copy_memory_invalid_source_maa2() { %0 = spirv.Variable : !spirv.ptr %1 = spirv.Variable : !spirv.ptr // expected-error @+1 {{missing alignment value}} "spirv.CopyMemory"(%0, %1) {source_memory_access=#spirv.memory_access, memory_access=#spirv.memory_access, alignment=4 : i32} : (!spirv.ptr, !spirv.ptr) -> () spirv.Return } // ----- func.func @copy_memory_print_maa() { %0 = spirv.Variable : !spirv.ptr %1 = spirv.Variable : !spirv.ptr // CHECK: spirv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Volatile"] : f32 "spirv.CopyMemory"(%0, %1) {memory_access=#spirv.memory_access} : (!spirv.ptr, !spirv.ptr) -> () // CHECK: spirv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Aligned", 4] : f32 "spirv.CopyMemory"(%0, %1) {memory_access=#spirv.memory_access, alignment=4 : i32} : (!spirv.ptr, !spirv.ptr) -> () // CHECK: spirv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Aligned", 4], ["Volatile"] : f32 "spirv.CopyMemory"(%0, %1) {source_memory_access=#spirv.memory_access, memory_access=#spirv.memory_access, alignment=4 : i32} : (!spirv.ptr, !spirv.ptr) -> () // CHECK: spirv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Aligned", 4], ["Aligned", 8] : f32 "spirv.CopyMemory"(%0, %1) {source_memory_access=#spirv.memory_access, memory_access=#spirv.memory_access, source_alignment=8 : i32, alignment=4 : i32} : (!spirv.ptr, !spirv.ptr) -> () spirv.Return } // ----- //===----------------------------------------------------------------------===// // spirv.PtrAccessChain //===----------------------------------------------------------------------===// // CHECK-LABEL: func @ptr_access_chain1( // CHECK-SAME: %[[ARG0:.*]]: !spirv.ptr, // CHECK-SAME: %[[ARG1:.*]]: i64) // CHECK: spirv.PtrAccessChain %[[ARG0]][%[[ARG1]]] : !spirv.ptr, i64 func.func @ptr_access_chain1(%arg0: !spirv.ptr, %arg1 : i64) -> () { %0 = spirv.PtrAccessChain %arg0[%arg1] : !spirv.ptr, i64 return } // ----- //===----------------------------------------------------------------------===// // spirv.InBoundsPtrAccessChain //===----------------------------------------------------------------------===// // CHECK-LABEL: func @inbounds_ptr_access_chain1( // CHECK-SAME: %[[ARG0:.*]]: !spirv.ptr, // CHECK-SAME: %[[ARG1:.*]]: i64) // CHECK: spirv.InBoundsPtrAccessChain %[[ARG0]][%[[ARG1]]] : !spirv.ptr, i64 func.func @inbounds_ptr_access_chain1(%arg0: !spirv.ptr, %arg1 : i64) -> () { %0 = spirv.InBoundsPtrAccessChain %arg0[%arg1] : !spirv.ptr, i64 return }