// RUN: mlir-opt --split-input-file -pass-pipeline="builtin.module(convert-memref-to-spirv{bool-num-bits=8}, cse)" %s | FileCheck %s // RUN: mlir-opt --split-input-file -pass-pipeline="builtin.module(convert-memref-to-spirv{bool-num-bits=8 use-64bit-index=true}, cse)" %s \ // RUN: | FileCheck --check-prefix=CHECK64 %s // Check that with proper compute and storage extensions, we don't need to // perform special tricks. module attributes { spirv.target_env = #spirv.target_env< #spirv.vce, #spirv.resource_limits<>> } { // CHECK-LABEL: @load_store_zero_rank_float( // CHECK-SAME: %[[OARG0:.*]]: memref{{.*}}, %[[OARG1:.*]]: memref func.func @load_store_zero_rank_float(%arg0: memref>, %arg1: memref>) { // CHECK-DAG: [[ARG0:%.*]] = builtin.unrealized_conversion_cast %[[OARG0]] : memref> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: [[ARG1:%.*]] = builtin.unrealized_conversion_cast %[[OARG1]] : memref> to !spirv.ptr [0])>, StorageBuffer> // CHECK: [[ZERO:%.*]] = spirv.Constant 0 : i32 // CHECK: spirv.AccessChain [[ARG0]][ // CHECK-SAME: [[ZERO]], [[ZERO]] // CHECK-SAME: ] : // CHECK: spirv.Load "StorageBuffer" %{{.*}} : f32 %0 = memref.load %arg0[] : memref> // CHECK: spirv.AccessChain [[ARG1]][ // CHECK-SAME: [[ZERO]], [[ZERO]] // CHECK-SAME: ] : // CHECK: spirv.Store "StorageBuffer" %{{.*}} : f32 memref.store %0, %arg1[] : memref> return } // CHECK-LABEL: @load_store_zero_rank_int // CHECK-SAME: %[[OARG0:.*]]: memref{{.*}}, %[[OARG1:.*]]: memref func.func @load_store_zero_rank_int(%arg0: memref>, %arg1: memref>) { // CHECK-DAG: [[ARG0:%.*]] = builtin.unrealized_conversion_cast %[[OARG0]] : memref> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: [[ARG1:%.*]] = builtin.unrealized_conversion_cast %[[OARG1]] : memref> to !spirv.ptr [0])>, StorageBuffer> // CHECK: [[ZERO:%.*]] = spirv.Constant 0 : i32 // CHECK: spirv.AccessChain [[ARG0]][ // CHECK-SAME: [[ZERO]], [[ZERO]] // CHECK-SAME: ] : // CHECK: spirv.Load "StorageBuffer" %{{.*}} : i32 %0 = memref.load %arg0[] : memref> // CHECK: spirv.AccessChain [[ARG1]][ // CHECK-SAME: [[ZERO]], [[ZERO]] // CHECK-SAME: ] : // CHECK: spirv.Store "StorageBuffer" %{{.*}} : i32 memref.store %0, %arg1[] : memref> return } // CHECK-LABEL: func @load_store_unknown_dim // CHECK-SAME: %[[OARG0:.*]]: index, %[[OARG1:.*]]: memref{{.*}}, %[[OARG2:.*]]: memref func.func @load_store_unknown_dim(%i: index, %source: memref>, %dest: memref>) { // CHECK-DAG: %[[SRC:.+]] = builtin.unrealized_conversion_cast %[[OARG1]] : memref> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: %[[DST:.+]] = builtin.unrealized_conversion_cast %[[OARG2]] : memref> to !spirv.ptr [0])>, StorageBuffer> // CHECK: %[[AC0:.+]] = spirv.AccessChain %[[SRC]] // CHECK: spirv.Load "StorageBuffer" %[[AC0]] %0 = memref.load %source[%i] : memref> // CHECK: %[[AC1:.+]] = spirv.AccessChain %[[DST]] // CHECK: spirv.Store "StorageBuffer" %[[AC1]] memref.store %0, %dest[%i]: memref> return } // CHECK-LABEL: func @load_i1 // CHECK-SAME: (%[[SRC:.+]]: memref<4xi1, #spirv.storage_class>, %[[IDX:.+]]: index) func.func @load_i1(%src: memref<4xi1, #spirv.storage_class>, %i : index) -> i1 { // CHECK-DAG: %[[SRC_CAST:.+]] = builtin.unrealized_conversion_cast %[[SRC]] : memref<4xi1, #spirv.storage_class> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: %[[IDX_CAST:.+]] = builtin.unrealized_conversion_cast %[[IDX]] // CHECK: %[[ZERO:.*]] = spirv.Constant 0 : i32 // CHECK: %[[ADDR:.+]] = spirv.AccessChain %[[SRC_CAST]][%[[ZERO]], %[[IDX_CAST]]] // CHECK: %[[VAL:.+]] = spirv.Load "StorageBuffer" %[[ADDR]] : i8 // CHECK: %[[ZERO_I8:.+]] = spirv.Constant 0 : i8 // CHECK: %[[BOOL:.+]] = spirv.INotEqual %[[VAL]], %[[ZERO_I8]] : i8 %0 = memref.load %src[%i] : memref<4xi1, #spirv.storage_class> // CHECK: return %[[BOOL]] return %0: i1 } // CHECK-LABEL: func @load_aligned // CHECK-SAME: (%[[SRC:.+]]: memref<4xi1, #spirv.storage_class>, %[[IDX:.+]]: index) func.func @load_aligned(%src: memref<4xi1, #spirv.storage_class>, %i : index) -> i1 { // CHECK: spirv.Load "StorageBuffer" {{.*}} ["Aligned", 32] : i8 %0 = memref.load %src[%i] { alignment = 32 } : memref<4xi1, #spirv.storage_class> return %0: i1 } // CHECK-LABEL: func @load_aligned_nontemporal func.func @load_aligned_nontemporal(%src: memref<4xi1, #spirv.storage_class>, %i : index) -> i1 { // CHECK: spirv.Load "StorageBuffer" {{.*}} ["Aligned|Nontemporal", 32] : i8 %0 = memref.load %src[%i] { alignment = 32, nontemporal = true } : memref<4xi1, #spirv.storage_class> return %0: i1 } // CHECK-LABEL: func @load_aligned_psb func.func @load_aligned_psb(%src: memref<4xi1, #spirv.storage_class>, %i : index) -> i1 { // CHECK: %[[VAL:.+]] = spirv.Load "PhysicalStorageBuffer" {{.*}} ["Aligned", 32] : i8 %0 = memref.load %src[%i] { alignment = 32 } : memref<4xi1, #spirv.storage_class> return %0: i1 } // CHECK-LABEL: func @store_i1 // CHECK-SAME: %[[DST:.+]]: memref<4xi1, #spirv.storage_class>, // CHECK-SAME: %[[IDX:.+]]: index func.func @store_i1(%dst: memref<4xi1, #spirv.storage_class>, %i: index) { %true = arith.constant true // CHECK-DAG: %[[DST_CAST:.+]] = builtin.unrealized_conversion_cast %[[DST]] : memref<4xi1, #spirv.storage_class> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: %[[IDX_CAST:.+]] = builtin.unrealized_conversion_cast %[[IDX]] // CHECK: %[[ZERO:.*]] = spirv.Constant 0 : i32 // CHECK: %[[ADDR:.+]] = spirv.AccessChain %[[DST_CAST]][%[[ZERO]], %[[IDX_CAST]]] // CHECK: %[[ONE_I8:.+]] = spirv.Constant 1 : i8 // CHECK: spirv.Store "StorageBuffer" %[[ADDR]], %[[ONE_I8]] : i8 memref.store %true, %dst[%i]: memref<4xi1, #spirv.storage_class> return } // CHECK-LABEL: @load_i16 func.func @load_i16(%arg0: memref>) { // CHECK-NOT: spirv.SDiv // CHECK: spirv.Load // CHECK-NOT: spirv.ShiftRightArithmetic %0 = memref.load %arg0[] : memref> return } // CHECK-LABEL: @store_i16 func.func @store_i16(%arg0: memref<10xi16, #spirv.storage_class>, %index: index, %value: i16) { // CHECK: spirv.Store // CHECK-NOT: spirv.AtomicAnd // CHECK-NOT: spirv.AtomicOr memref.store %value, %arg0[%index] : memref<10xi16, #spirv.storage_class> return } // CHECK-LABEL: @load_store_i32_physical func.func @load_store_i32_physical(%arg0: memref>) { // CHECK: spirv.Load "PhysicalStorageBuffer" %{{.+}} ["Aligned", 4] : i32 // CHECK: spirv.Store "PhysicalStorageBuffer" %{{.+}}, %{{.+}} ["Aligned", 4] : i32 %0 = memref.load %arg0[] : memref> memref.store %0, %arg0[] : memref> return } // CHECK-LABEL: @load_store_i8_physical func.func @load_store_i8_physical(%arg0: memref>) { // CHECK: spirv.Load "PhysicalStorageBuffer" %{{.+}} ["Aligned", 1] : i8 // CHECK: spirv.Store "PhysicalStorageBuffer" %{{.+}}, %{{.+}} ["Aligned", 1] : i8 %0 = memref.load %arg0[] : memref> memref.store %0, %arg0[] : memref> return } // CHECK-LABEL: @load_store_i1_physical func.func @load_store_i1_physical(%arg0: memref>) { // CHECK: spirv.Load "PhysicalStorageBuffer" %{{.+}} ["Aligned", 1] : i8 // CHECK: spirv.Store "PhysicalStorageBuffer" %{{.+}}, %{{.+}} ["Aligned", 1] : i8 %0 = memref.load %arg0[] : memref> memref.store %0, %arg0[] : memref> return } // CHECK-LABEL: @load_store_f32_physical func.func @load_store_f32_physical(%arg0: memref>) { // CHECK: spirv.Load "PhysicalStorageBuffer" %{{.+}} ["Aligned", 4] : f32 // CHECK: spirv.Store "PhysicalStorageBuffer" %{{.+}}, %{{.+}} ["Aligned", 4] : f32 %0 = memref.load %arg0[] : memref> memref.store %0, %arg0[] : memref> return } // CHECK-LABEL: @load_store_f16_physical func.func @load_store_f16_physical(%arg0: memref>) { // CHECK: spirv.Load "PhysicalStorageBuffer" %{{.+}} ["Aligned", 2] : f16 // CHECK: spirv.Store "PhysicalStorageBuffer" %{{.+}}, %{{.+}} ["Aligned", 2] : f16 %0 = memref.load %arg0[] : memref> memref.store %0, %arg0[] : memref> return } // CHECK-LABEL: @load_store_vec4f16_physical func.func @load_store_vec4f16_physical(%arg0: memref<5xvector<4xf16>, #spirv.storage_class>, %i: index) { // Alignment = 4 elements * 2 bytes = 8 bytes // CHECK: spirv.Load "PhysicalStorageBuffer" %{{.+}} ["Aligned", 8] : vector<4xf16> // CHECK: spirv.Store "PhysicalStorageBuffer" %{{.+}}, %{{.+}} ["Aligned", 8] : vector<4xf16> %0 = memref.load %arg0[%i] : memref<5xvector<4xf16>, #spirv.storage_class> memref.store %0, %arg0[%i] : memref<5xvector<4xf16>, #spirv.storage_class> return } // CHECK-LABEL: @load_store_vec4f32_physical func.func @load_store_vec4f32_physical(%arg0: memref<8xvector<4xf32>, #spirv.storage_class>, %i: index) { // Alignment = 4 elements * 4 bytes = 16 bytes // CHECK: spirv.Load "PhysicalStorageBuffer" %{{.+}} ["Aligned", 16] : vector<4xf32> // CHECK: spirv.Store "PhysicalStorageBuffer" %{{.+}}, %{{.+}} ["Aligned", 16] : vector<4xf32> %0 = memref.load %arg0[%i] : memref<8xvector<4xf32>, #spirv.storage_class> memref.store %0, %arg0[%i] : memref<8xvector<4xf32>, #spirv.storage_class> return } // CHECK-LABEL: @load_store_vec4f32_dynamic_physical // CHECK-SAME: (%[[ARG0:.+]]: memref, #spirv.storage_class>, func.func @load_store_vec4f32_dynamic_physical(%arg0: memref, #spirv.storage_class>, %i: index) { // CHECK: builtin.unrealized_conversion_cast %[[ARG0]] {{.*}} to !spirv.ptr, stride=16> // CHECK: spirv.Load "PhysicalStorageBuffer" %{{.+}} ["Aligned", 16] : vector<4xf32> // CHECK: spirv.Store "PhysicalStorageBuffer" %{{.+}}, %{{.+}} ["Aligned", 16] : vector<4xf32> %0 = memref.load %arg0[%i] : memref, #spirv.storage_class> memref.store %0, %arg0[%i] : memref, #spirv.storage_class> return } } // end module // ----- // Check for Kernel capability, that with proper compute and storage extensions, we don't need to // perform special tricks. module attributes { spirv.target_env = #spirv.target_env< #spirv.vce, #spirv.resource_limits<>> } { // CHECK-LABEL: @load_store_zero_rank_float // CHECK-SAME: %[[OARG0:.*]]: memref{{.*}}, %[[OARG1:.*]]: memref func.func @load_store_zero_rank_float(%arg0: memref>, %arg1: memref>) { // CHECK-DAG: [[ARG0:%.*]] = builtin.unrealized_conversion_cast %[[OARG0]] : memref> to !spirv.ptr, CrossWorkgroup> // CHECK-DAG: [[ARG1:%.*]] = builtin.unrealized_conversion_cast %[[OARG1]] : memref> to !spirv.ptr, CrossWorkgroup> // CHECK: [[ZERO:%.*]] = spirv.Constant 0 : i32 // CHECK: spirv.AccessChain [[ARG0]][ // CHECK-SAME: [[ZERO]] // CHECK-SAME: ] : // CHECK: spirv.Load "CrossWorkgroup" %{{.*}} : f32 %0 = memref.load %arg0[] : memref> // CHECK: spirv.AccessChain [[ARG1]][ // CHECK-SAME: [[ZERO]] // CHECK-SAME: ] : // CHECK: spirv.Store "CrossWorkgroup" %{{.*}} : f32 memref.store %0, %arg1[] : memref> return } // CHECK-LABEL: @load_store_zero_rank_int // CHECK-SAME: %[[OARG0:.*]]: memref{{.*}}, %[[OARG1:.*]]: memref func.func @load_store_zero_rank_int(%arg0: memref>, %arg1: memref>) { // CHECK-DAG: [[ARG0:%.*]] = builtin.unrealized_conversion_cast %[[OARG0]] : memref> to !spirv.ptr, CrossWorkgroup> // CHECK-DAG: [[ARG1:%.*]] = builtin.unrealized_conversion_cast %[[OARG1]] : memref> to !spirv.ptr, CrossWorkgroup> // CHECK: [[ZERO:%.*]] = spirv.Constant 0 : i32 // CHECK: spirv.AccessChain [[ARG0]][ // CHECK-SAME: [[ZERO]] // CHECK-SAME: ] : // CHECK: spirv.Load "CrossWorkgroup" %{{.*}} : i32 %0 = memref.load %arg0[] : memref> // CHECK: spirv.AccessChain [[ARG1]][ // CHECK-SAME: [[ZERO]] // CHECK-SAME: ] : // CHECK: spirv.Store "CrossWorkgroup" %{{.*}} : i32 memref.store %0, %arg1[] : memref> return } // CHECK-LABEL: func @load_store_unknown_dim // CHECK-SAME: %[[OARG0:.*]]: index, %[[OARG1:.*]]: memref{{.*}}, %[[OARG2:.*]]: memref func.func @load_store_unknown_dim(%i: index, %source: memref>, %dest: memref>) { // CHECK-DAG: %[[SRC:.+]] = builtin.unrealized_conversion_cast %[[OARG1]] : memref> to !spirv.ptr // CHECK-DAG: %[[DST:.+]] = builtin.unrealized_conversion_cast %[[OARG2]] : memref> to !spirv.ptr // CHECK: %[[AC0:.+]] = spirv.PtrAccessChain %[[SRC]] // CHECK: spirv.Load "CrossWorkgroup" %[[AC0]] %0 = memref.load %source[%i] : memref> // CHECK: %[[AC1:.+]] = spirv.PtrAccessChain %[[DST]] // CHECK: spirv.Store "CrossWorkgroup" %[[AC1]] memref.store %0, %dest[%i]: memref> return } // CHECK-LABEL: func @load_i1 // CHECK-SAME: (%[[SRC:.+]]: memref<4xi1, #spirv.storage_class>, %[[IDX:.+]]: index) func.func @load_i1(%src: memref<4xi1, #spirv.storage_class>, %i : index) -> i1 { // CHECK-DAG: %[[SRC_CAST:.+]] = builtin.unrealized_conversion_cast %[[SRC]] : memref<4xi1, #spirv.storage_class> to !spirv.ptr, CrossWorkgroup> // CHECK-DAG: %[[IDX_CAST:.+]] = builtin.unrealized_conversion_cast %[[IDX]] // CHECK: %[[ADDR:.+]] = spirv.AccessChain %[[SRC_CAST]][%[[IDX_CAST]]] // CHECK: %[[VAL:.+]] = spirv.Load "CrossWorkgroup" %[[ADDR]] : i8 // CHECK: %[[ZERO_I8:.+]] = spirv.Constant 0 : i8 // CHECK: %[[BOOL:.+]] = spirv.INotEqual %[[VAL]], %[[ZERO_I8]] : i8 %0 = memref.load %src[%i] : memref<4xi1, #spirv.storage_class> // CHECK: return %[[BOOL]] return %0: i1 } // CHECK-LABEL: func @store_i1 // CHECK-SAME: %[[DST:.+]]: memref<4xi1, #spirv.storage_class>, // CHECK-SAME: %[[IDX:.+]]: index func.func @store_i1(%dst: memref<4xi1, #spirv.storage_class>, %i: index) { %true = arith.constant true // CHECK-DAG: %[[DST_CAST:.+]] = builtin.unrealized_conversion_cast %[[DST]] : memref<4xi1, #spirv.storage_class> to !spirv.ptr, CrossWorkgroup> // CHECK-DAG: %[[IDX_CAST:.+]] = builtin.unrealized_conversion_cast %[[IDX]] // CHECK: %[[ADDR:.+]] = spirv.AccessChain %[[DST_CAST]][%[[IDX_CAST]]] // CHECK: %[[ONE_I8:.+]] = spirv.Constant 1 : i8 // CHECK: spirv.Store "CrossWorkgroup" %[[ADDR]], %[[ONE_I8]] : i8 memref.store %true, %dst[%i]: memref<4xi1, #spirv.storage_class> return } } // end module // ----- // Check address space casts module attributes { spirv.target_env = #spirv.target_env< #spirv.vce, #spirv.resource_limits<>> } { // CHECK-LABEL: func.func @memory_space_cast func.func @memory_space_cast(%arg: memref<4xf32, #spirv.storage_class>) -> memref<4xf32, #spirv.storage_class> { // CHECK: %[[ARG_CAST:.+]] = builtin.unrealized_conversion_cast {{.*}} to !spirv.ptr, CrossWorkgroup> // CHECK: %[[TO_GENERIC:.+]] = spirv.PtrCastToGeneric %[[ARG_CAST]] : !spirv.ptr, CrossWorkgroup> to !spirv.ptr, Generic> // CHECK: %[[TO_PRIVATE:.+]] = spirv.GenericCastToPtr %[[TO_GENERIC]] : !spirv.ptr, Generic> to !spirv.ptr, Function> // CHECK: %[[RET:.+]] = builtin.unrealized_conversion_cast %[[TO_PRIVATE]] // CHECK: return %[[RET]] %ret = memref.memory_space_cast %arg : memref<4xf32, #spirv.storage_class> to memref<4xf32, #spirv.storage_class> return %ret : memref<4xf32, #spirv.storage_class> } } // end module // ----- // Check that casts are properly inserted if the corresponding **compute** // capability is allowed. module attributes { spirv.target_env = #spirv.target_env< #spirv.vce, #spirv.resource_limits<>> } { // CHECK-LABEL: @load_i1 func.func @load_i1(%arg0: memref>) -> i1 { // CHECK: %[[ONE:.+]] = spirv.Constant 1 : i32 // CHECK: %[[RES:.+]] = spirv.IEqual %{{.+}}, %[[ONE]] : i32 // CHECK: return %[[RES]] %0 = memref.load %arg0[] : memref> return %0 : i1 } // CHECK-LABEL: @load_i8 func.func @load_i8(%arg0: memref>) -> i8 { // CHECK: %[[RES:.+]] = spirv.UConvert %{{.+}} : i32 to i8 // CHECK: return %[[RES]] %0 = memref.load %arg0[] : memref> return %0 : i8 } // CHECK-LABEL: @load_i16 func.func @load_i16(%arg0: memref<10xi16, #spirv.storage_class>, %index : index) -> i16 { // CHECK: %[[RES:.+]] = spirv.UConvert %{{.+}} : i32 to i16 // CHECK: return %[[RES]] %0 = memref.load %arg0[%index] : memref<10xi16, #spirv.storage_class> return %0: i16 } } // end module // ----- // Check reinterpret_casts module attributes { spirv.target_env = #spirv.target_env< #spirv.vce, #spirv.resource_limits<>> } { // CHECK-LABEL: func.func @reinterpret_cast // CHECK-SAME: (%[[MEM:.*]]: memref>, %[[OFF:.*]]: index) func.func @reinterpret_cast(%arg: memref>, %arg1: index) -> memref, #spirv.storage_class> { // CHECK-DAG: %[[MEM1:.*]] = builtin.unrealized_conversion_cast %[[MEM]] : memref> to !spirv.ptr // CHECK-DAG: %[[OFF1:.*]] = builtin.unrealized_conversion_cast %[[OFF]] : index to i32 // CHECK: %[[RET:.*]] = spirv.InBoundsPtrAccessChain %[[MEM1]][%[[OFF1]]] : !spirv.ptr, i32 // CHECK: %[[RET1:.*]] = builtin.unrealized_conversion_cast %[[RET]] : !spirv.ptr to memref, #spirv.storage_class> // CHECK: return %[[RET1]] %ret = memref.reinterpret_cast %arg to offset: [%arg1], sizes: [10], strides: [1] : memref> to memref, #spirv.storage_class> return %ret : memref, #spirv.storage_class> } // CHECK-LABEL: func.func @reinterpret_cast_0 // CHECK-SAME: (%[[MEM:.*]]: memref>) func.func @reinterpret_cast_0(%arg: memref>) -> memref, #spirv.storage_class> { // CHECK-DAG: %[[MEM1:.*]] = builtin.unrealized_conversion_cast %[[MEM]] : memref> to !spirv.ptr // CHECK-DAG: %[[RET:.*]] = builtin.unrealized_conversion_cast %[[MEM1]] : !spirv.ptr to memref, #spirv.storage_class> // CHECK: return %[[RET]] %ret = memref.reinterpret_cast %arg to offset: [0], sizes: [10], strides: [1] : memref> to memref, #spirv.storage_class> return %ret : memref, #spirv.storage_class> } // CHECK-LABEL: func.func @reinterpret_cast_5 // CHECK-SAME: (%[[MEM:.*]]: memref>) func.func @reinterpret_cast_5(%arg: memref>) -> memref, #spirv.storage_class> { // CHECK: %[[MEM1:.*]] = builtin.unrealized_conversion_cast %[[MEM]] : memref> to !spirv.ptr // CHECK: %[[OFF:.*]] = spirv.Constant 5 : i32 // CHECK: %[[RET:.*]] = spirv.InBoundsPtrAccessChain %[[MEM1]][%[[OFF]]] : !spirv.ptr, i32 // CHECK: %[[RET1:.*]] = builtin.unrealized_conversion_cast %[[RET]] : !spirv.ptr to memref, #spirv.storage_class> // CHECK: return %[[RET1]] %ret = memref.reinterpret_cast %arg to offset: [5], sizes: [10], strides: [1] : memref> to memref, #spirv.storage_class> return %ret : memref, #spirv.storage_class> } } // end module // ----- // Check casts module attributes { spirv.target_env = #spirv.target_env< #spirv.vce, #spirv.resource_limits<>> } { // CHECK-LABEL: func.func @cast // CHECK-SAME: (%[[MEM:.*]]: memref<4x?xf32, #spirv.storage_class>) func.func @cast(%arg: memref<4x?xf32, #spirv.storage_class>) -> memref> { // CHECK-DAG: %[[MEM1:.*]] = builtin.unrealized_conversion_cast %[[MEM]] : memref<4x?xf32, #spirv.storage_class> to !spirv.ptr // CHECK-DAG: %[[MEM2:.*]] = builtin.unrealized_conversion_cast %[[MEM1]] : !spirv.ptr to memref> // CHECK: return %[[MEM2]] %ret = memref.cast %arg : memref<4x?xf32, #spirv.storage_class> to memref> return %ret : memref> } // TODO: Not supported yet // CHECK-LABEL: func.func @cast_from_static // CHECK-SAME: (%[[MEM:.*]]: memref<4x4xf32, #spirv.storage_class>) func.func @cast_from_static(%arg: memref<4x4xf32, #spirv.storage_class>) -> memref> { // CHECK: %[[MEM1:.*]] = memref.cast %[[MEM]] : memref<4x4xf32, #spirv.storage_class> to memref> // CHECK: return %[[MEM1]] %ret = memref.cast %arg : memref<4x4xf32, #spirv.storage_class> to memref> return %ret : memref> } // TODO: Not supported yet // CHECK-LABEL: func.func @cast_to_static // CHECK-SAME: (%[[MEM:.*]]: memref<4x?xf32, #spirv.storage_class>) func.func @cast_to_static(%arg: memref<4x?xf32, #spirv.storage_class>) -> memref<4x4xf32, #spirv.storage_class> { // CHECK: %[[MEM1:.*]] = memref.cast %[[MEM]] : memref<4x?xf32, #spirv.storage_class> to memref<4x4xf32, #spirv.storage_class> // CHECK: return %[[MEM1]] %ret = memref.cast %arg : memref<4x?xf32, #spirv.storage_class> to memref<4x4xf32, #spirv.storage_class> return %ret : memref<4x4xf32, #spirv.storage_class> } // TODO: Not supported yet // CHECK-LABEL: func.func @cast_to_static_zero_elems // CHECK-SAME: (%[[MEM:.*]]: memref>) func.func @cast_to_static_zero_elems(%arg: memref>) -> memref<0xf32, #spirv.storage_class> { // CHECK: %[[MEM1:.*]] = memref.cast %[[MEM]] : memref> to memref<0xf32, #spirv.storage_class> // CHECK: return %[[MEM1]] %ret = memref.cast %arg : memref> to memref<0xf32, #spirv.storage_class> return %ret : memref<0xf32, #spirv.storage_class> } } // ----- module attributes { spirv.target_env = #spirv.target_env<#spirv.vce, #spirv.resource_limits<>> } { // CHECK-LABEL: func @extract_aligned_pointer_as_index_kernel func.func @extract_aligned_pointer_as_index_kernel(%m: memref>) -> index { %0 = memref.extract_aligned_pointer_as_index %m: memref> -> index // CHECK: %[[I32:.*]] = spirv.ConvertPtrToU {{%.*}} : !spirv.ptr to i32 // CHECK: %[[R:.*]] = builtin.unrealized_conversion_cast %[[I32]] : i32 to index // CHECK64: %[[I64:.*]] = spirv.ConvertPtrToU {{%.*}} : !spirv.ptr to i64 // CHECK64: %[[R:.*]] = builtin.unrealized_conversion_cast %[[I64]] : i64 to index // CHECK: return %[[R:.*]] : index return %0: index } } // ----- module attributes { spirv.target_env = #spirv.target_env<#spirv.vce, #spirv.resource_limits<>> } { // CHECK-LABEL: func @extract_aligned_pointer_as_index_shader func.func @extract_aligned_pointer_as_index_shader(%m: memref>) -> index { %0 = memref.extract_aligned_pointer_as_index %m: memref> -> index // CHECK: %[[I32:.*]] = spirv.ConvertPtrToU {{%.*}} : !spirv.ptr)>, CrossWorkgroup> to i32 // CHECK: %[[R:.*]] = builtin.unrealized_conversion_cast %[[I32]] : i32 to index // CHECK64: %[[I64:.*]] = spirv.ConvertPtrToU {{%.*}} : !spirv.ptr)>, CrossWorkgroup> to i64 // CHECK64: %[[R:.*]] = builtin.unrealized_conversion_cast %[[I64]] : i64 to index // CHECK: return %[[R:.*]] : index return %0: index } } // ----- // Check nontemporal attribute module attributes { spirv.target_env = #spirv.target_env<#spirv.vce, #spirv.resource_limits<>> } { func.func @load_nontemporal(%arg0: memref>) { %0 = memref.load %arg0[] {nontemporal = true} : memref> // CHECK: spirv.Load "StorageBuffer" %{{.+}} ["Nontemporal"] : f32 memref.store %0, %arg0[] {nontemporal = true} : memref> // CHECK: spirv.Store "StorageBuffer" %{{.+}}, %{{.+}} ["Nontemporal"] : f32 return } func.func @load_nontemporal_aligned(%arg0: memref>) { %0 = memref.load %arg0[] {nontemporal = true} : memref> // CHECK: spirv.Load "PhysicalStorageBuffer" %{{.+}} ["Aligned|Nontemporal", 4] : f32 memref.store %0, %arg0[] {nontemporal = true} : memref> // CHECK: spirv.Store "PhysicalStorageBuffer" %{{.+}}, %{{.+}} ["Aligned|Nontemporal", 4] : f32 return } } // ----- // Check Image Support. // CHECK: #[[$COLMAJMAP:.*]] = affine_map<(d0, d1) -> (d1, d0)> #col_major = affine_map<(d0, d1) -> (d1, d0)> // CHECK: #[[$CUSTOMLAYOUTMAP:.*]] = affine_map<(d0, d1, d2) -> (d2, d1, d0)> #custom = affine_map<(d0, d1, d2) -> (d2, d1, d0)> // CHECK: #[[$NONPERMMAP:.*]] = affine_map<(d0, d1) -> (d0, d1 mod 2)> #non_permutation = affine_map<(d0, d1) -> (d0, d1 mod 2)> module attributes { spirv.target_env = #spirv.target_env<#spirv.vce, #spirv.resource_limits<>> } { // CHECK-LABEL: @load_from_image_1D( // CHECK-SAME: %[[ARG0:.*]]: memref<1xf32, #spirv.storage_class>, %[[ARG1:.*]]: memref<1xf32, #spirv.storage_class> func.func @load_from_image_1D(%arg0: memref<1xf32, #spirv.storage_class>, %arg1: memref<1xf32, #spirv.storage_class>) { // CHECK-DAG: %[[SB:.*]] = builtin.unrealized_conversion_cast %[[ARG1]] : memref<1xf32, #spirv.storage_class> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: %[[IMAGE_PTR:.*]] = builtin.unrealized_conversion_cast %[[ARG0]] : memref<1xf32, #spirv.storage_class> to !spirv.ptr>, UniformConstant> %cst = arith.constant 0 : index // CHECK: %[[COORDS:.*]] = builtin.unrealized_conversion_cast %{{.*}} : index to i32 // CHECK: %[[SIMAGE:.*]] = spirv.Load "UniformConstant" %[[IMAGE_PTR]] : !spirv.sampled_image> // CHECK: %[[IMAGE:.*]] = spirv.Image %[[SIMAGE]] : !spirv.sampled_image> // CHECK-NOT: spirv.CompositeConstruct // CHECK: %[[RES_VEC:.*]] = spirv.ImageFetch %[[IMAGE]], %[[COORDS]] : !spirv.image, i32 -> vector<4xf32> // CHECK: %[[RESULT:.*]] = spirv.CompositeExtract %[[RES_VEC]][0 : i32] : vector<4xf32> %0 = memref.load %arg0[%cst] : memref<1xf32, #spirv.storage_class> // CHECK: spirv.Store "StorageBuffer" %{{.*}}, %[[RESULT]] : f32 memref.store %0, %arg1[%cst] : memref<1xf32, #spirv.storage_class> return } // CHECK-LABEL: @load_from_image_2D( // CHECK-SAME: %[[ARG0:.*]]: memref<2x4xf32, #spirv.storage_class>, %[[ARG1:.*]]: memref<2x4xf32, #spirv.storage_class> func.func @load_from_image_2D(%arg0: memref<2x4xf32, #spirv.storage_class>, %arg1: memref<2x4xf32, #spirv.storage_class>) { // CHECK-DAG: %[[SB:.*]] = builtin.unrealized_conversion_cast %[[ARG1]] : memref<2x4xf32, #spirv.storage_class> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: %[[IMAGE_PTR:.*]] = builtin.unrealized_conversion_cast %[[ARG0]] : memref<2x4xf32, #spirv.storage_class> to !spirv.ptr>, UniformConstant> // CHECK: %[[X:.*]] = arith.constant 3 : index // CHECK: %[[X32:.*]] = builtin.unrealized_conversion_cast %[[X]] : index to i32 %x = arith.constant 3 : index // CHECK: %[[Y:.*]] = arith.constant 1 : index // CHECK: %[[Y32:.*]] = builtin.unrealized_conversion_cast %[[Y]] : index to i32 %y = arith.constant 1 : index // CHECK: %[[SIMAGE:.*]] = spirv.Load "UniformConstant" %[[IMAGE_PTR]] : !spirv.sampled_image> // CHECK: %[[IMAGE:.*]] = spirv.Image %[[SIMAGE]] : !spirv.sampled_image> // CHECK: %[[COORDS:.*]] = spirv.CompositeConstruct %[[X32]], %[[Y32]] : (i32, i32) -> vector<2xi32> // CHECK: %[[RES_VEC:.*]] = spirv.ImageFetch %[[IMAGE]], %[[COORDS]] : !spirv.image, vector<2xi32> -> vector<4xf32> // CHECK: %[[RESULT:.*]] = spirv.CompositeExtract %[[RES_VEC]][0 : i32] : vector<4xf32> %0 = memref.load %arg0[%y, %x] : memref<2x4xf32, #spirv.storage_class> // CHECK: spirv.Store "StorageBuffer" %{{.*}}, %[[RESULT]] : f32 memref.store %0, %arg1[%y, %x] : memref<2x4xf32, #spirv.storage_class> return } // CHECK-LABEL: @load_from_col_major_image_2D( // CHECK-SAME: %[[ARG0:.*]]: memref<2x4xf32, #[[$COLMAJMAP]], #spirv.storage_class>, %[[ARG1:.*]]: memref<2x4xf32, #spirv.storage_class> func.func @load_from_col_major_image_2D(%arg0: memref<2x4xf32, #col_major, #spirv.storage_class>, %arg1: memref<2x4xf32, #spirv.storage_class>) { // CHECK-DAG: %[[SB:.*]] = builtin.unrealized_conversion_cast %[[ARG1]] : memref<2x4xf32, #spirv.storage_class> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: %[[IMAGE_PTR:.*]] = builtin.unrealized_conversion_cast %[[ARG0]] : memref<2x4xf32, #[[$COLMAJMAP]], #spirv.storage_class> to !spirv.ptr>, UniformConstant> // CHECK: %[[X:.*]] = arith.constant 3 : index // CHECK: %[[X32:.*]] = builtin.unrealized_conversion_cast %[[X]] : index to i32 %x = arith.constant 3 : index // CHECK: %[[Y:.*]] = arith.constant 1 : index // CHECK: %[[Y32:.*]] = builtin.unrealized_conversion_cast %[[Y]] : index to i32 %y = arith.constant 1 : index // CHECK: %[[SIMAGE:.*]] = spirv.Load "UniformConstant" %[[IMAGE_PTR]] : !spirv.sampled_image> // CHECK: %[[IMAGE:.*]] = spirv.Image %[[SIMAGE]] : !spirv.sampled_image> // CHECK: %[[COORDS:.*]] = spirv.CompositeConstruct %[[X32]], %[[Y32]] : (i32, i32) -> vector<2xi32> // CHECK: %[[RES_VEC:.*]] = spirv.ImageFetch %[[IMAGE]], %[[COORDS]] : !spirv.image, vector<2xi32> -> vector<4xf32> // CHECK: %[[RESULT:.*]] = spirv.CompositeExtract %[[RES_VEC]][0 : i32] : vector<4xf32> %0 = memref.load %arg0[%x, %y] : memref<2x4xf32, #col_major, #spirv.storage_class> // CHECK: spirv.Store "StorageBuffer" %{{.*}}, %[[RESULT]] : f32 memref.store %0, %arg1[%y, %x] : memref<2x4xf32, #spirv.storage_class> return } // CHECK-LABEL: @load_from_image_3D( // CHECK-SAME: %[[ARG0:.*]]: memref<2x3x4xf32, #spirv.storage_class>, %[[ARG1:.*]]: memref<2x3x4xf32, #spirv.storage_class> func.func @load_from_image_3D(%arg0: memref<2x3x4xf32, #spirv.storage_class>, %arg1: memref<2x3x4xf32, #spirv.storage_class>) { // CHECK-DAG: %[[SB:.*]] = builtin.unrealized_conversion_cast %[[ARG1]] : memref<2x3x4xf32, #spirv.storage_class> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: %[[IMAGE_PTR:.*]] = builtin.unrealized_conversion_cast %[[ARG0]] : memref<2x3x4xf32, #spirv.storage_class> to !spirv.ptr>, UniformConstant> // CHECK: %[[X:.*]] = arith.constant 3 : index // CHECK: %[[X32:.*]] = builtin.unrealized_conversion_cast %[[X]] : index to i32 %x = arith.constant 3 : index // CHECK: %[[Y:.*]] = arith.constant 2 : index // CHECK: %[[Y32:.*]] = builtin.unrealized_conversion_cast %[[Y]] : index to i32 %y = arith.constant 2 : index // CHECK: %[[Z:.*]] = arith.constant 1 : index // CHECK: %[[Z32:.*]] = builtin.unrealized_conversion_cast %[[Z]] : index to i32 %z = arith.constant 1 : index // CHECK: %[[SIMAGE:.*]] = spirv.Load "UniformConstant" %[[IMAGE_PTR]] : !spirv.sampled_image> // CHECK: %[[IMAGE:.*]] = spirv.Image %[[SIMAGE]] : !spirv.sampled_image> // CHECK: %[[COORDS:.*]] = spirv.CompositeConstruct %[[X32]], %[[Y32]], %[[Z32]] : (i32, i32, i32) -> vector<3xi32> // CHECK: %[[RES_VEC:.*]] = spirv.ImageFetch %[[IMAGE]], %[[COORDS]] : !spirv.image, vector<3xi32> -> vector<4xf32> // CHECK: %[[RESULT:.*]] = spirv.CompositeExtract %[[RES_VEC]][0 : i32] : vector<4xf32> %0 = memref.load %arg0[%z, %y, %x] : memref<2x3x4xf32, #spirv.storage_class> // CHECK: spirv.Store "StorageBuffer" %{{.*}}, %[[RESULT]] : f32 memref.store %0, %arg1[%z, %y, %x] : memref<2x3x4xf32, #spirv.storage_class> return } // CHECK-LABEL: @load_from_custom_layout_image_3D( // CHECK-SAME: %[[ARG0:.*]]: memref<2x3x4xf32, #[[$CUSTOMLAYOUTMAP]], #spirv.storage_class>, %[[ARG1:.*]]: memref<2x3x4xf32, #spirv.storage_class> func.func @load_from_custom_layout_image_3D(%arg0: memref<2x3x4xf32, #custom, #spirv.storage_class>, %arg1: memref<2x3x4xf32, #spirv.storage_class>) { // CHECK-DAG: %[[SB:.*]] = builtin.unrealized_conversion_cast %[[ARG1]] : memref<2x3x4xf32, #spirv.storage_class> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: %[[IMAGE_PTR:.*]] = builtin.unrealized_conversion_cast %[[ARG0]] : memref<2x3x4xf32, #[[$CUSTOMLAYOUTMAP]], #spirv.storage_class> to !spirv.ptr>, UniformConstant> // CHECK: %[[X:.*]] = arith.constant 3 : index // CHECK: %[[X32:.*]] = builtin.unrealized_conversion_cast %[[X]] : index to i32 %x = arith.constant 3 : index // CHECK: %[[Y:.*]] = arith.constant 2 : index // CHECK: %[[Y32:.*]] = builtin.unrealized_conversion_cast %[[Y]] : index to i32 %y = arith.constant 2 : index // CHECK: %[[Z:.*]] = arith.constant 1 : index // CHECK: %[[Z32:.*]] = builtin.unrealized_conversion_cast %[[Z]] : index to i32 %z = arith.constant 1 : index // CHECK: %[[SIMAGE:.*]] = spirv.Load "UniformConstant" %[[IMAGE_PTR]] : !spirv.sampled_image> // CHECK: %[[IMAGE:.*]] = spirv.Image %[[SIMAGE]] : !spirv.sampled_image> // CHECK: %[[COORDS:.*]] = spirv.CompositeConstruct %[[X32]], %[[Y32]], %[[Z32]] : (i32, i32, i32) -> vector<3xi32> // CHECK: %[[RES_VEC:.*]] = spirv.ImageFetch %[[IMAGE]], %[[COORDS]] : !spirv.image, vector<3xi32> -> vector<4xf32> // CHECK: %[[RESULT:.*]] = spirv.CompositeExtract %[[RES_VEC]][0 : i32] : vector<4xf32> %0 = memref.load %arg0[%x, %y, %z] : memref<2x3x4xf32, #custom, #spirv.storage_class> // CHECK: spirv.Store "StorageBuffer" %{{.*}}, %[[RESULT]] : f32 memref.store %0, %arg1[%z, %y, %x] : memref<2x3x4xf32, #spirv.storage_class> return } // CHECK-LABEL: @load_from_image_2D_f16( // CHECK-SAME: %[[ARG0:.*]]: memref<2x3xf16, #spirv.storage_class>, %[[ARG1:.*]]: memref<2x3xf16, #spirv.storage_class> func.func @load_from_image_2D_f16(%arg0: memref<2x3xf16, #spirv.storage_class>, %arg1: memref<2x3xf16, #spirv.storage_class>) { // CHECK-DAG: %[[SB:.*]] = builtin.unrealized_conversion_cast %[[ARG1]] : memref<2x3xf16, #spirv.storage_class> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: %[[IMAGE_PTR:.*]] = builtin.unrealized_conversion_cast %[[ARG0]] : memref<2x3xf16, #spirv.storage_class> to !spirv.ptr>, UniformConstant> // CHECK: %[[X:.*]] = arith.constant 2 : index // CHECK: %[[X32:.*]] = builtin.unrealized_conversion_cast %[[X]] : index to i32 %x = arith.constant 2 : index // CHECK: %[[Y:.*]] = arith.constant 1 : index // CHECK: %[[Y32:.*]] = builtin.unrealized_conversion_cast %[[Y]] : index to i32 %y = arith.constant 1 : index // CHECK: %[[SIMAGE:.*]] = spirv.Load "UniformConstant" %[[IMAGE_PTR]] : !spirv.sampled_image> // CHECK: %[[IMAGE:.*]] = spirv.Image %[[SIMAGE]] : !spirv.sampled_image> // CHECK: %[[COORDS:.*]] = spirv.CompositeConstruct %[[X32]], %[[Y32]] : (i32, i32) -> vector<2xi32> // CHECK: %[[RES_VEC:.*]] = spirv.ImageFetch %[[IMAGE]], %[[COORDS]] : !spirv.image, vector<2xi32> -> vector<4xf16> // CHECK: %[[RESULT:.*]] = spirv.CompositeExtract %[[RES_VEC]][0 : i32] : vector<4xf16> %0 = memref.load %arg0[%y, %x] : memref<2x3xf16, #spirv.storage_class> // CHECK: spirv.Store "StorageBuffer" %{{.*}}, %[[RESULT]] : f16 memref.store %0, %arg1[%y, %x] : memref<2x3xf16, #spirv.storage_class> return } // CHECK-LABEL: @load_from_image_2D_i32( // CHECK-SAME: %[[ARG0:.*]]: memref<2x3xi32, #spirv.storage_class>, %[[ARG1:.*]]: memref<2x3xi32, #spirv.storage_class> func.func @load_from_image_2D_i32(%arg0: memref<2x3xi32, #spirv.storage_class>, %arg1: memref<2x3xi32, #spirv.storage_class>) { // CHECK-DAG: %[[SB:.*]] = builtin.unrealized_conversion_cast %[[ARG1]] : memref<2x3xi32, #spirv.storage_class> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: %[[IMAGE_PTR:.*]] = builtin.unrealized_conversion_cast %[[ARG0]] : memref<2x3xi32, #spirv.storage_class> to !spirv.ptr>, UniformConstant> // CHECK: %[[X:.*]] = arith.constant 2 : index // CHECK: %[[X32:.*]] = builtin.unrealized_conversion_cast %[[X]] : index to i32 %x = arith.constant 2 : index // CHECK: %[[Y:.*]] = arith.constant 1 : index // CHECK: %[[Y32:.*]] = builtin.unrealized_conversion_cast %[[Y]] : index to i32 %y = arith.constant 1 : index // CHECK: %[[SIMAGE:.*]] = spirv.Load "UniformConstant" %[[IMAGE_PTR]] : !spirv.sampled_image> // CHECK: %[[IMAGE:.*]] = spirv.Image %[[SIMAGE]] : !spirv.sampled_image> // CHECK: %[[COORDS:.*]] = spirv.CompositeConstruct %[[X32]], %[[Y32]] : (i32, i32) -> vector<2xi32> // CHECK: %[[RES_VEC:.*]] = spirv.ImageFetch %[[IMAGE]], %[[COORDS]] : !spirv.image, vector<2xi32> -> vector<4xi32> // CHECK: %[[RESULT:.*]] = spirv.CompositeExtract %[[RES_VEC]][0 : i32] : vector<4xi32> %0 = memref.load %arg0[%y, %x] : memref<2x3xi32, #spirv.storage_class> // CHECK: spirv.Store "StorageBuffer" %{{.*}}, %[[RESULT]] : i32 memref.store %0, %arg1[%y, %x] : memref<2x3xi32, #spirv.storage_class> return } // CHECK-LABEL: @load_from_image_2D_ui32( // CHECK-SAME: %[[ARG0:.*]]: memref<2x3xui32, #spirv.storage_class>, %[[ARG1:.*]]: memref<2x3xui32, #spirv.storage_class> func.func @load_from_image_2D_ui32(%arg0: memref<2x3xui32, #spirv.storage_class>, %arg1: memref<2x3xui32, #spirv.storage_class>) { // CHECK-DAG: %[[SB:.*]] = builtin.unrealized_conversion_cast %[[ARG1]] : memref<2x3xui32, #spirv.storage_class> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: %[[IMAGE_PTR:.*]] = builtin.unrealized_conversion_cast %[[ARG0]] : memref<2x3xui32, #spirv.storage_class> to !spirv.ptr>, UniformConstant> // CHECK: %[[X:.*]] = arith.constant 2 : index // CHECK: %[[X32:.*]] = builtin.unrealized_conversion_cast %[[X]] : index to i32 %x = arith.constant 2 : index // CHECK: %[[Y:.*]] = arith.constant 1 : index // CHECK: %[[Y32:.*]] = builtin.unrealized_conversion_cast %[[Y]] : index to i32 %y = arith.constant 1 : index // CHECK: %[[SIMAGE:.*]] = spirv.Load "UniformConstant" %[[IMAGE_PTR]] : !spirv.sampled_image> // CHECK: %[[IMAGE:.*]] = spirv.Image %[[SIMAGE]] : !spirv.sampled_image> // CHECK: %[[COORDS:.*]] = spirv.CompositeConstruct %[[X32]], %[[Y32]] : (i32, i32) -> vector<2xi32> // CHECK: %[[RES_VEC:.*]] = spirv.ImageFetch %[[IMAGE]], %[[COORDS]] : !spirv.image, vector<2xi32> -> vector<4xui32> // CHECK: %[[RESULT:.*]] = spirv.CompositeExtract %[[RES_VEC]][0 : i32] : vector<4xui32> %0 = memref.load %arg0[%y, %x] : memref<2x3xui32, #spirv.storage_class> // CHECK: spirv.Store "StorageBuffer" %{{.*}}, %[[RESULT]] : ui32 memref.store %0, %arg1[%y, %x] : memref<2x3xui32, #spirv.storage_class> return } // CHECK-LABEL: @load_from_image_2D_i16( // CHECK-SAME: %[[ARG0:.*]]: memref<2x3xi16, #spirv.storage_class>, %[[ARG1:.*]]: memref<2x3xi16, #spirv.storage_class> func.func @load_from_image_2D_i16(%arg0: memref<2x3xi16, #spirv.storage_class>, %arg1: memref<2x3xi16, #spirv.storage_class>) { // CHECK-DAG: %[[SB:.*]] = builtin.unrealized_conversion_cast %[[ARG1]] : memref<2x3xi16, #spirv.storage_class> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: %[[IMAGE_PTR:.*]] = builtin.unrealized_conversion_cast %[[ARG0]] : memref<2x3xi16, #spirv.storage_class> to !spirv.ptr>, UniformConstant> // CHECK: %[[X:.*]] = arith.constant 2 : index // CHECK: %[[X32:.*]] = builtin.unrealized_conversion_cast %[[X]] : index to i32 %x = arith.constant 2 : index // CHECK: %[[Y:.*]] = arith.constant 1 : index // CHECK: %[[Y32:.*]] = builtin.unrealized_conversion_cast %[[Y]] : index to i32 %y = arith.constant 1 : index // CHECK: %[[SIMAGE:.*]] = spirv.Load "UniformConstant" %[[IMAGE_PTR]] : !spirv.sampled_image> // CHECK: %[[IMAGE:.*]] = spirv.Image %[[SIMAGE]] : !spirv.sampled_image> // CHECK: %[[COORDS:.*]] = spirv.CompositeConstruct %[[X32]], %[[Y32]] : (i32, i32) -> vector<2xi32> // CHECK: %[[RES_VEC:.*]] = spirv.ImageFetch %[[IMAGE]], %[[COORDS]] : !spirv.image, vector<2xi32> -> vector<4xi16> // CHECK: %[[RESULT:.*]] = spirv.CompositeExtract %[[RES_VEC]][0 : i32] : vector<4xi16> %0 = memref.load %arg0[%y, %x] : memref<2x3xi16, #spirv.storage_class> // CHECK: spirv.Store "StorageBuffer" %{{.*}}, %[[RESULT]] : i16 memref.store %0, %arg1[%y, %x] : memref<2x3xi16, #spirv.storage_class> return } // CHECK-LABEL: @load_from_image_2D_ui16( // CHECK-SAME: %[[ARG0:.*]]: memref<2x3xui16, #spirv.storage_class>, %[[ARG1:.*]]: memref<2x3xui16, #spirv.storage_class> func.func @load_from_image_2D_ui16(%arg0: memref<2x3xui16, #spirv.storage_class>, %arg1: memref<2x3xui16, #spirv.storage_class>) { // CHECK-DAG: %[[SB:.*]] = builtin.unrealized_conversion_cast %[[ARG1]] : memref<2x3xui16, #spirv.storage_class> to !spirv.ptr [0])>, StorageBuffer> // CHECK-DAG: %[[IMAGE_PTR:.*]] = builtin.unrealized_conversion_cast %[[ARG0]] : memref<2x3xui16, #spirv.storage_class> to !spirv.ptr>, UniformConstant> // CHECK: %[[X:.*]] = arith.constant 2 : index // CHECK: %[[X32:.*]] = builtin.unrealized_conversion_cast %[[X]] : index to i32 %x = arith.constant 2 : index // CHECK: %[[Y:.*]] = arith.constant 1 : index // CHECK: %[[Y32:.*]] = builtin.unrealized_conversion_cast %[[Y]] : index to i32 %y = arith.constant 1 : index // CHECK: %[[SIMAGE:.*]] = spirv.Load "UniformConstant" %[[IMAGE_PTR]] : !spirv.sampled_image> // CHECK: %[[IMAGE:.*]] = spirv.Image %[[SIMAGE]] : !spirv.sampled_image> // CHECK: %[[COORDS:.*]] = spirv.CompositeConstruct %[[X32]], %[[Y32]] : (i32, i32) -> vector<2xi32> // CHECK: %[[RES_VEC:.*]] = spirv.ImageFetch %[[IMAGE]], %[[COORDS]] : !spirv.image, vector<2xi32> -> vector<4xui16> // CHECK: %[[RESULT:.*]] = spirv.CompositeExtract %[[RES_VEC]][0 : i32] : vector<4xui16> %0 = memref.load %arg0[%y, %x] : memref<2x3xui16, #spirv.storage_class> // CHECK: spirv.Store "StorageBuffer" %{{.*}}, %[[RESULT]] : ui16 memref.store %0, %arg1[%y, %x] : memref<2x3xui16, #spirv.storage_class> return } // CHECK-LABEL: @load_from_image_2D_rank0( func.func @load_from_image_2D_rank0(%arg0: memref>, %arg1: memref>) { %cst = arith.constant 0 : index // CHECK-NOT: spirv.Image // CHECK-NOT: spirv.ImageFetch %0 = memref.load %arg0[] : memref> memref.store %0, %arg1[] : memref> return } // CHECK-LABEL: @load_from_image_2D_rank4( func.func @load_from_image_2D_rank4(%arg0: memref<1x1x1x1xf32, #spirv.storage_class>, %arg1: memref<1x1x1x1xf32, #spirv.storage_class>) { %cst = arith.constant 0 : index // CHECK-NOT: spirv.Image // CHECK-NOT: spirv.ImageFetch %0 = memref.load %arg0[%cst, %cst, %cst, %cst] : memref<1x1x1x1xf32, #spirv.storage_class> memref.store %0, %arg1[%cst, %cst, %cst, %cst] : memref<1x1x1x1xf32, #spirv.storage_class> return } // CHECK-LABEL: @load_from_image_2D_vector( func.func @load_from_image_2D_vector(%arg0: memref<1xvector<1xf32>, #spirv.storage_class>, %arg1: memref<1xvector<1xf32>, #spirv.storage_class>) { %cst = arith.constant 0 : index // CHECK-NOT: spirv.Image // CHECK-NOT: spirv.ImageFetch %0 = memref.load %arg0[%cst] : memref<1xvector<1xf32>, #spirv.storage_class> memref.store %0, %arg1[%cst] : memref<1xvector<1xf32>, #spirv.storage_class> return } // CHECK-LABEL: @load_non_perm_layout( func.func @load_non_perm_layout(%arg0: memref<2x4xf32, #non_permutation, #spirv.storage_class>, %arg1: memref<2x4xf32, #spirv.storage_class>) { %x = arith.constant 3 : index %y = arith.constant 1 : index // CHECK-NOT: spirv.Image // CHECK-NOT: spirv.ImageFetch %0 = memref.load %arg0[%y, %x] : memref<2x4xf32, #non_permutation, #spirv.storage_class> memref.store %0, %arg1[%y, %x] : memref<2x4xf32, #spirv.storage_class> return } }