1// RUN: mlir-opt --split-input-file --verify-diagnostics --mlir-disable-threading \ 2// RUN: --test-spirv-target-env %s | FileCheck %s 3 4// Note: The following tests check that a spirv.target_env can properly control 5// the conversion target and filter unavailable ops during the conversion. 6// We don't care about the op argument consistency too much; so certain enum 7// values for enum attributes may not make much sense for the test op. 8 9// spirv.AtomicCompareExchangeWeak is available from SPIR-V 1.0 to 1.3 under 10// Kernel capability. 11// spirv.AtomicCompareExchangeWeak has two memory semantics enum attribute, 12// whose value, if containing AtomicCounterMemory bit, additionally requires 13// AtomicStorage capability. 14 15// spirv.BitReverse is available in all SPIR-V versions under Shader capability. 16 17// spirv.GroupNonUniformBallot is available starting from SPIR-V 1.3 under 18// GroupNonUniform capability. 19 20// spirv.KHR.SubgroupBallot is available under in all SPIR-V versions under 21// SubgroupBallotKHR capability and SPV_KHR_shader_ballot extension. 22 23// Integer Dot Product ops (spirv.*Dot*) require the 24// SPV_KHR_integer_dot_product extension and a number of related capabilities. 25 26// The GeometryPointSize capability implies the Geometry capability, which 27// implies the Shader capability. 28 29// PhysicalStorageBuffer64 addressing model is available via extension 30// SPV_EXT_physical_storage_buffer or SPV_KHR_physical_storage_buffer; 31// both extensions are incorporated into SPIR-V 1.5. 32 33// Vulkan memory model is available via extension SPV_KHR_vulkan_memory_model, 34// which extensions are incorporated into SPIR-V 1.5. 35 36 37// expected-error @+1 {{missing 'spirv.target_env' attribute}} 38func.func @main() { 39 return 40} 41 42// ----- 43 44//===----------------------------------------------------------------------===// 45// MaxVersion 46//===----------------------------------------------------------------------===// 47 48// CHECK-LABEL: @cmp_exchange_weak_suitable_version_capabilities 49func.func @cmp_exchange_weak_suitable_version_capabilities(%ptr: !spirv.ptr<i32, Workgroup>, %value: i32, %comparator: i32) -> i32 attributes { 50 spirv.target_env = #spirv.target_env<#spirv.vce<v1.1, [Kernel, AtomicStorage], []>, #spirv.resource_limits<>> 51} { 52 // CHECK: spirv.AtomicCompareExchangeWeak <Workgroup> <AcquireRelease|AtomicCounterMemory> <Acquire> 53 %0 = "test.convert_to_atomic_compare_exchange_weak_op"(%ptr, %value, %comparator): (!spirv.ptr<i32, Workgroup>, i32, i32) -> (i32) 54 return %0: i32 55} 56 57// CHECK-LABEL: @cmp_exchange_weak_unsupported_version 58func.func @cmp_exchange_weak_unsupported_version(%ptr: !spirv.ptr<i32, Workgroup>, %value: i32, %comparator: i32) -> i32 attributes { 59 spirv.target_env = #spirv.target_env<#spirv.vce<v1.4, [Kernel, AtomicStorage], []>, #spirv.resource_limits<>> 60} { 61 // CHECK: test.convert_to_atomic_compare_exchange_weak_op 62 %0 = "test.convert_to_atomic_compare_exchange_weak_op"(%ptr, %value, %comparator): (!spirv.ptr<i32, Workgroup>, i32, i32) -> (i32) 63 return %0: i32 64} 65 66//===----------------------------------------------------------------------===// 67// MinVersion 68//===----------------------------------------------------------------------===// 69 70// CHECK-LABEL: @group_non_uniform_ballot_suitable_version 71func.func @group_non_uniform_ballot_suitable_version(%predicate: i1) -> vector<4xi32> attributes { 72 spirv.target_env = #spirv.target_env<#spirv.vce<v1.4, [GroupNonUniformBallot], []>, #spirv.resource_limits<>> 73} { 74 // CHECK: spirv.GroupNonUniformBallot <Workgroup> 75 %0 = "test.convert_to_group_non_uniform_ballot_op"(%predicate): (i1) -> (vector<4xi32>) 76 return %0: vector<4xi32> 77} 78 79// CHECK-LABEL: @group_non_uniform_ballot_unsupported_version 80func.func @group_non_uniform_ballot_unsupported_version(%predicate: i1) -> vector<4xi32> attributes { 81 spirv.target_env = #spirv.target_env<#spirv.vce<v1.1, [GroupNonUniformBallot], []>, #spirv.resource_limits<>> 82} { 83 // CHECK: test.convert_to_group_non_uniform_ballot_op 84 %0 = "test.convert_to_group_non_uniform_ballot_op"(%predicate): (i1) -> (vector<4xi32>) 85 return %0: vector<4xi32> 86} 87 88//===----------------------------------------------------------------------===// 89// Capability 90//===----------------------------------------------------------------------===// 91 92// CHECK-LABEL: @cmp_exchange_weak_missing_capability_kernel 93func.func @cmp_exchange_weak_missing_capability_kernel(%ptr: !spirv.ptr<i32, Workgroup>, %value: i32, %comparator: i32) -> i32 attributes { 94 spirv.target_env = #spirv.target_env<#spirv.vce<v1.3, [AtomicStorage], []>, #spirv.resource_limits<>> 95} { 96 // CHECK: test.convert_to_atomic_compare_exchange_weak_op 97 %0 = "test.convert_to_atomic_compare_exchange_weak_op"(%ptr, %value, %comparator): (!spirv.ptr<i32, Workgroup>, i32, i32) -> (i32) 98 return %0: i32 99} 100 101// CHECK-LABEL: @cmp_exchange_weak_missing_capability_atomic_storage 102func.func @cmp_exchange_weak_missing_capability_atomic_storage(%ptr: !spirv.ptr<i32, Workgroup>, %value: i32, %comparator: i32) -> i32 attributes { 103 spirv.target_env = #spirv.target_env<#spirv.vce<v1.3, [Kernel], []>, #spirv.resource_limits<>> 104} { 105 // CHECK: test.convert_to_atomic_compare_exchange_weak_op 106 %0 = "test.convert_to_atomic_compare_exchange_weak_op"(%ptr, %value, %comparator): (!spirv.ptr<i32, Workgroup>, i32, i32) -> (i32) 107 return %0: i32 108} 109 110// CHECK-LABEL: @subgroup_ballot_missing_capability 111func.func @subgroup_ballot_missing_capability(%predicate: i1) -> vector<4xi32> attributes { 112 spirv.target_env = #spirv.target_env<#spirv.vce<v1.4, [], [SPV_KHR_shader_ballot]>, #spirv.resource_limits<>> 113} { 114 // CHECK: test.convert_to_subgroup_ballot_op 115 %0 = "test.convert_to_subgroup_ballot_op"(%predicate): (i1) -> (vector<4xi32>) 116 return %0: vector<4xi32> 117} 118 119// CHECK-LABEL: @bit_reverse_directly_implied_capability 120func.func @bit_reverse_directly_implied_capability(%operand: i32) -> i32 attributes { 121 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [Geometry], []>, #spirv.resource_limits<>> 122} { 123 // CHECK: spirv.BitReverse 124 %0 = "test.convert_to_bit_reverse_op"(%operand): (i32) -> (i32) 125 return %0: i32 126} 127 128// CHECK-LABEL: @bit_reverse_recursively_implied_capability 129func.func @bit_reverse_recursively_implied_capability(%operand: i32) -> i32 attributes { 130 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [GeometryPointSize], []>, #spirv.resource_limits<>> 131} { 132 // CHECK: spirv.BitReverse 133 %0 = "test.convert_to_bit_reverse_op"(%operand): (i32) -> (i32) 134 return %0: i32 135} 136 137// CHECK-LABEL: @sdot_scalar_i32_i32_capabilities 138func.func @sdot_scalar_i32_i32_capabilities(%operand: i32) -> i32 attributes { 139 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 140 [DotProduct, DotProductInput4x8BitPacked], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 141} { 142 // CHECK: spirv.SDot 143 %0 = "test.convert_to_sdot_op"(%operand, %operand) {format = #spirv.packed_vector_format<PackedVectorFormat4x8Bit>}: (i32, i32) -> (i32) 144 return %0: i32 145} 146 147// CHECK-LABEL: @sdot_scalar_i32_i32_missing_capability1 148func.func @sdot_scalar_i32_i32_missing_capability1(%operand: i32) -> i32 attributes { 149 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 150 [DotProduct], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 151} { 152 // CHECK: test.convert_to_sdot_op 153 %0 = "test.convert_to_sdot_op"(%operand, %operand) {format = #spirv.packed_vector_format<PackedVectorFormat4x8Bit>}: (i32, i32) -> (i32) 154 return %0: i32 155} 156 157// CHECK-LABEL: @sdot_scalar_i32_i32_missing_capability2 158func.func @sdot_scalar_i32_i32_missing_capability2(%operand: i32) -> i32 attributes { 159 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 160 [DotProductInput4x8BitPacked], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 161} { 162 // CHECK: test.convert_to_sdot_op 163 %0 = "test.convert_to_sdot_op"(%operand, %operand) {format = #spirv.packed_vector_format<PackedVectorFormat4x8Bit>}: (i32, i32) -> (i32) 164 return %0: i32 165} 166 167// CHECK-LABEL: @sudot_vector_4xi8_i32_capabilities 168func.func @sudot_vector_4xi8_i32_capabilities(%operand: vector<4xi8>) -> i32 attributes { 169 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 170 [DotProduct, DotProductInput4x8Bit], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 171} { 172 // CHECK: spirv.SUDot 173 %0 = "test.convert_to_sudot_op"(%operand, %operand): (vector<4xi8>, vector<4xi8>) -> (i32) 174 return %0: i32 175} 176 177// CHECK-LABEL: @sudot_vector_4xi8_i32_missing_capability1 178func.func @sudot_vector_4xi8_i32_missing_capability1(%operand: vector<4xi8>) -> i32 attributes { 179 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 180 [DotProduct], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 181} { 182 // CHECK: test.convert_to_sudot_op 183 %0 = "test.convert_to_sudot_op"(%operand, %operand): (vector<4xi8>, vector<4xi8>) -> (i32) 184 return %0: i32 185} 186 187// CHECK-LABEL: @sudot_vector_4xi8_i32_missing_capability2 188func.func @sudot_vector_4xi8_i32_missing_capability2(%operand: vector<4xi8>) -> i32 attributes { 189 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 190 [DotProductInput4x8Bit], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 191} { 192 // CHECK: test.convert_to_sudot_op 193 %0 = "test.convert_to_sudot_op"(%operand, %operand): (vector<4xi8>, vector<4xi8>) -> (i32) 194 return %0: i32 195} 196 197// CHECK-LABEL: @udot_vector_4xi16_i64_capabilities 198func.func @udot_vector_4xi16_i64_capabilities(%operand: vector<4xi16>) -> i64 attributes { 199 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 200 [DotProduct, DotProductInputAll, Int16, Int64], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 201} { 202 // CHECK: spirv.UDot 203 %0 = "test.convert_to_udot_op"(%operand, %operand): (vector<4xi16>, vector<4xi16>) -> (i64) 204 return %0: i64 205} 206 207// CHECK-LABEL: @udot_vector_4xi16_i64_missing_capability1 208func.func @udot_vector_4xi16_i64_missing_capability1(%operand: vector<4xi16>) -> i64 attributes { 209 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 210 [DotProduct, Int16, Int64], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 211} { 212 // CHECK: test.convert_to_udot_op 213 %0 = "test.convert_to_udot_op"(%operand, %operand): (vector<4xi16>, vector<4xi16>) -> (i64) 214 return %0: i64 215} 216 217// CHECK-LABEL: @udot_vector_4xi16_i64_missing_capability2 218func.func @udot_vector_4xi16_i64_missing_capability2(%operand: vector<4xi16>) -> i64 attributes { 219 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 220 [DotProductInputAll, Int16, Int64], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 221} { 222 // CHECK: test.convert_to_udot_op 223 %0 = "test.convert_to_udot_op"(%operand, %operand): (vector<4xi16>, vector<4xi16>) -> (i64) 224 return %0 : i64 225} 226 227// CHECK-LABEL: @sdot_acc_sat_scalar_i32_i32_capabilities 228func.func @sdot_acc_sat_scalar_i32_i32_capabilities(%operand: i32) -> i32 attributes { 229 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 230 [DotProduct, DotProductInput4x8BitPacked], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 231} { 232 // CHECK: spirv.SDotAccSat 233 %0 = "test.convert_to_sdot_acc_sat_op"(%operand, %operand, %operand) 234 {format = #spirv.packed_vector_format<PackedVectorFormat4x8Bit>}: (i32, i32, i32) -> (i32) 235 return %0: i32 236} 237 238// CHECK-LABEL: @sudot_acc_sat_vector_4xi8_i32_capabilities 239func.func @sudot_acc_sat_vector_4xi8_i32_capabilities(%operand: vector<4xi8>, %acc: i32) -> i32 attributes { 240 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 241 [DotProduct, DotProductInput4x8Bit], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 242} { 243 // CHECK: spirv.SUDotAccSat 244 %0 = "test.convert_to_sudot_acc_sat_op"(%operand, %operand, %acc): (vector<4xi8>, vector<4xi8>, i32) -> (i32) 245 return %0: i32 246} 247 248// CHECK-LABEL: @udot_acc_sat_vector_4xi8_i32_missing_capability1 249func.func @udot_acc_sat_vector_4xi8_i32_missing_capability1(%operand: vector<4xi8>, %acc: i32) -> i32 attributes { 250 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 251 [DotProduct, DotProductInputAll, Int16, Int64], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 252} { 253 // CHECK: test.convert_to_udot_acc_sat_op 254 %0 = "test.convert_to_udot_acc_sat_op"(%operand, %operand, %acc): (vector<4xi8>, vector<4xi8>, i32) -> (i32) 255 return %0: i32 256} 257 258// CHECK-LABEL: @udot_acc_sat_vector_4xi8_i32_missing_capability2 259func.func @udot_acc_sat_vector_4xi8_i32_missing_capability2(%operand: vector<4xi8>, %acc: i32) -> i32 attributes { 260 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 261 [DotProductInputAll, DotProductInput4x8Bit, Int16, Int64], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 262} { 263 // CHECK: test.convert_to_udot_acc_sat_op 264 %0 = "test.convert_to_udot_acc_sat_op"(%operand, %operand, %acc): (vector<4xi8>, vector<4xi8>, i32) -> (i32) 265 return %0: i32 266} 267 268// CHECK-LABEL: @udot_acc_sat_vector_4xi16_i64_capabilities 269func.func @udot_acc_sat_vector_4xi16_i64_capabilities(%operand: vector<4xi16>, %acc: i64) -> i64 attributes { 270 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 271 [DotProduct, DotProductInputAll, Int16, Int64], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 272} { 273 // CHECK: spirv.UDotAccSat 274 %0 = "test.convert_to_udot_acc_sat_op"(%operand, %operand, %acc): (vector<4xi16>, vector<4xi16>, i64) -> (i64) 275 return %0: i64 276} 277 278// CHECK-LABEL: @udot_acc_sat_vector_4xi16_i64_missing_capability1 279func.func @udot_acc_sat_vector_4xi16_i64_missing_capability1(%operand: vector<4xi16>, %acc: i64) -> i64 attributes { 280 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 281 [DotProductInputAll, Int16, Int64], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 282} { 283 // CHECK: test.convert_to_udot_acc_sat_op 284 %0 = "test.convert_to_udot_acc_sat_op"(%operand, %operand, %acc): (vector<4xi16>, vector<4xi16>, i64) -> (i64) 285 return %0: i64 286} 287 288// CHECK-LABEL: @udot_acc_sat_vector_4xi16_i64_missing_capability2 289func.func @udot_acc_sat_vector_4xi16_i64_missing_capability2(%operand: vector<4xi16>, %acc: i64) -> i64 attributes { 290 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, 291 [DotProduct, Int16, Int64], [SPV_KHR_integer_dot_product]>, #spirv.resource_limits<>> 292} { 293 // CHECK: test.convert_to_udot_acc_sat_op 294 %0 = "test.convert_to_udot_acc_sat_op"(%operand, %operand, %acc): (vector<4xi16>, vector<4xi16>, i64) -> (i64) 295 return %0: i64 296} 297 298//===----------------------------------------------------------------------===// 299// Extension 300//===----------------------------------------------------------------------===// 301 302// CHECK-LABEL: @subgroup_ballot_suitable_extension 303func.func @subgroup_ballot_suitable_extension(%predicate: i1) -> vector<4xi32> attributes { 304 spirv.target_env = #spirv.target_env<#spirv.vce<v1.4, [SubgroupBallotKHR], [SPV_KHR_shader_ballot]>, #spirv.resource_limits<>> 305} { 306 // CHECK: spirv.KHR.SubgroupBallot 307 %0 = "test.convert_to_subgroup_ballot_op"(%predicate): (i1) -> (vector<4xi32>) 308 return %0: vector<4xi32> 309} 310 311// CHECK-LABEL: @subgroup_ballot_missing_extension 312func.func @subgroup_ballot_missing_extension(%predicate: i1) -> vector<4xi32> attributes { 313 spirv.target_env = #spirv.target_env<#spirv.vce<v1.4, [SubgroupBallotKHR], []>, #spirv.resource_limits<>> 314} { 315 // CHECK: test.convert_to_subgroup_ballot_op 316 %0 = "test.convert_to_subgroup_ballot_op"(%predicate): (i1) -> (vector<4xi32>) 317 return %0: vector<4xi32> 318} 319 320// CHECK-LABEL: @module_suitable_extension1 321func.func @module_suitable_extension1() attributes { 322 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [VulkanMemoryModel, PhysicalStorageBufferAddresses], [SPV_KHR_vulkan_memory_model, SPV_EXT_physical_storage_buffer]>, #spirv.resource_limits<>> 323} { 324 // CHECK: spirv.module PhysicalStorageBuffer64 Vulkan 325 "test.convert_to_module_op"() : () ->() 326 return 327} 328 329// CHECK-LABEL: @module_suitable_extension2 330func.func @module_suitable_extension2() attributes { 331 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [VulkanMemoryModel, PhysicalStorageBufferAddresses], [SPV_KHR_vulkan_memory_model, SPV_KHR_physical_storage_buffer]>, #spirv.resource_limits<>> 332} { 333 // CHECK: spirv.module PhysicalStorageBuffer64 Vulkan 334 "test.convert_to_module_op"() : () -> () 335 return 336} 337 338// CHECK-LABEL: @module_missing_extension_mm 339func.func @module_missing_extension_mm() attributes { 340 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [VulkanMemoryModel, PhysicalStorageBufferAddresses], [SPV_KHR_physical_storage_buffer]>, #spirv.resource_limits<>> 341} { 342 // CHECK: test.convert_to_module_op 343 "test.convert_to_module_op"() : () -> () 344 return 345} 346 347// CHECK-LABEL: @module_missing_extension_am 348func.func @module_missing_extension_am() attributes { 349 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [VulkanMemoryModel, PhysicalStorageBufferAddresses], [SPV_KHR_vulkan_memory_model]>, #spirv.resource_limits<>> 350} { 351 // CHECK: test.convert_to_module_op 352 "test.convert_to_module_op"() : () -> () 353 return 354} 355 356// CHECK-LABEL: @module_implied_extension 357func.func @module_implied_extension() attributes { 358 // Version 1.5 implies SPV_KHR_vulkan_memory_model and SPV_KHR_physical_storage_buffer. 359 spirv.target_env = #spirv.target_env<#spirv.vce<v1.5, [VulkanMemoryModel, PhysicalStorageBufferAddresses], []>, #spirv.resource_limits<>> 360} { 361 // CHECK: spirv.module PhysicalStorageBuffer64 Vulkan 362 "test.convert_to_module_op"() : () -> () 363 return 364} 365 366// CHECK-LABEL: @udot_vector_4xi16_i64_implied_extension 367func.func @udot_vector_4xi16_i64_implied_extension(%operand: vector<4xi16>) -> i64 attributes { 368 // Version 1.6 implies SPV_KHR_integer_to_product. 369 spirv.target_env = #spirv.target_env<#spirv.vce<v1.6, 370 [DotProduct, DotProductInputAll, Int16, Int64], []>, #spirv.resource_limits<>> 371} { 372 // CHECK: spirv.UDot 373 %0 = "test.convert_to_udot_op"(%operand, %operand): (vector<4xi16>, vector<4xi16>) -> (i64) 374 return %0: i64 375} 376 377// CHECK-LABEL: @udot_vector_4xi16_i64_missing_extension 378func.func @udot_vector_4xi16_i64_missing_extension(%operand: vector<4xi16>) -> i64 attributes { 379 // Version 1.5 does not imply SPV_KHR_integer_to_product. 380 spirv.target_env = #spirv.target_env<#spirv.vce<v1.5, 381 [DotProduct, DotProductInputAll, Int16, Int64], []>, #spirv.resource_limits<>> 382} { 383 // CHECK: test.convert_to_udot_op 384 %0 = "test.convert_to_udot_op"(%operand, %operand): (vector<4xi16>, vector<4xi16>) -> (i64) 385 return %0: i64 386} 387 388// CHECK-LABEL: @sdot_acc_sat_vector_4xi16_i64_implied_extension 389func.func @sdot_acc_sat_vector_4xi16_i64_implied_extension(%operand: vector<4xi16>, %acc: i64) -> i64 attributes { 390 // Version 1.6 implies SPV_KHR_integer_to_product. 391 spirv.target_env = #spirv.target_env<#spirv.vce<v1.6, 392 [DotProduct, DotProductInputAll, Int16, Int64], []>, #spirv.resource_limits<>> 393} { 394 // CHECK: spirv.SDotAccSat 395 %0 = "test.convert_to_sdot_acc_sat_op"(%operand, %operand, %acc): (vector<4xi16>, vector<4xi16>, i64) -> (i64) 396 return %0: i64 397} 398 399// CHECK-LABEL: @sdot_acc_sat_vector_4xi16_i64_missing_extension 400func.func @sdot_acc_sat_vector_4xi16_i64_missing_extension(%operand: vector<4xi16>, %acc: i64) -> i64 attributes { 401 // Version 1.5 does not imply SPV_KHR_integer_to_product. 402 spirv.target_env = #spirv.target_env<#spirv.vce<v1.5, 403 [DotProduct, DotProductInputAll, Int16, Int64], []>, #spirv.resource_limits<>> 404} { 405 // CHECK: test.convert_to_sdot_acc_sat_op 406 %0 = "test.convert_to_sdot_acc_sat_op"(%operand, %operand, %acc): (vector<4xi16>, vector<4xi16>, i64) -> (i64) 407 return %0: i64 408} 409