xref: /llvm-project/mlir/test/Dialect/SPIRV/IR/target-env.mlir (revision c63febb1025564b078a5c8e52e6df638e8a1d808)
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