1//===--- SPIRVCommandLine.cpp ---- Command Line Options ---------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains definitions of classes and functions needed for
10// processing, parsing, and using CLI options for the SPIR-V backend.
11//
12//===----------------------------------------------------------------------===//
13
14#include "SPIRVCommandLine.h"
15#include "MCTargetDesc/SPIRVBaseInfo.h"
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/StringMap.h"
18#include "llvm/TargetParser/Triple.h"
19
20#include <string>
21
22#define DEBUG_TYPE "spirv-commandline"
23
24using namespace llvm;
25
26ExtensionSet SPIRVExtensionsParser::DisabledExtensions;
27
28static const StringMap<SPIRV::Extension::Extension> SPIRVExtensionMap = {
29 {"SPV_EXT_shader_atomic_float_add",
30 SPIRV::Extension::Extension::SPV_EXT_shader_atomic_float_add},
31 {"SPV_EXT_shader_atomic_float16_add",
32 SPIRV::Extension::Extension::SPV_EXT_shader_atomic_float16_add},
33 {"SPV_EXT_shader_atomic_float_min_max",
34 SPIRV::Extension::Extension::SPV_EXT_shader_atomic_float_min_max},
35 {"SPV_INTEL_16bit_atomics",
36 SPIRV::Extension::Extension::SPV_INTEL_16bit_atomics},
37 {"SPV_NV_shader_atomic_fp16_vector",
38 SPIRV::Extension::Extension::SPV_NV_shader_atomic_fp16_vector},
39 {"SPV_EXT_arithmetic_fence",
40 SPIRV::Extension::Extension::SPV_EXT_arithmetic_fence},
41 {"SPV_EXT_demote_to_helper_invocation",
42 SPIRV::Extension::Extension::SPV_EXT_demote_to_helper_invocation},
43 {"SPV_EXT_descriptor_indexing",
44 SPIRV::Extension::Extension::SPV_EXT_descriptor_indexing},
45 {"SPV_EXT_fragment_fully_covered",
46 SPIRV::Extension::Extension::SPV_EXT_fragment_fully_covered},
47 {"SPV_EXT_fragment_invocation_density",
48 SPIRV::Extension::Extension::SPV_EXT_fragment_invocation_density},
49 {"SPV_EXT_fragment_shader_interlock",
50 SPIRV::Extension::Extension::SPV_EXT_fragment_shader_interlock},
51 {"SPV_EXT_mesh_shader", SPIRV::Extension::Extension::SPV_EXT_mesh_shader},
52 {"SPV_EXT_shader_stencil_export",
53 SPIRV::Extension::Extension::SPV_EXT_shader_stencil_export},
54 {"SPV_EXT_shader_viewport_index_layer",
55 SPIRV::Extension::Extension::SPV_EXT_shader_viewport_index_layer},
56 {"SPV_GOOGLE_hlsl_functionality1",
57 SPIRV::Extension::Extension::SPV_GOOGLE_hlsl_functionality1},
58 {"SPV_GOOGLE_user_type", SPIRV::Extension::Extension::SPV_GOOGLE_user_type},
59 {"SPV_ALTERA_arbitrary_precision_integers",
60 SPIRV::Extension::Extension::SPV_ALTERA_arbitrary_precision_integers},
61 {"SPV_ALTERA_arbitrary_precision_floating_point",
62 SPIRV::Extension::Extension::
63 SPV_ALTERA_arbitrary_precision_floating_point},
64 {"SPV_INTEL_cache_controls",
65 SPIRV::Extension::Extension::SPV_INTEL_cache_controls},
66 {"SPV_INTEL_float_controls2",
67 SPIRV::Extension::Extension::SPV_INTEL_float_controls2},
68 {"SPV_INTEL_global_variable_fpga_decorations",
69 SPIRV::Extension::Extension::SPV_INTEL_global_variable_fpga_decorations},
70 {"SPV_INTEL_global_variable_host_access",
71 SPIRV::Extension::Extension::SPV_INTEL_global_variable_host_access},
72 {"SPV_INTEL_optnone", SPIRV::Extension::Extension::SPV_INTEL_optnone},
73 {"SPV_EXT_optnone", SPIRV::Extension::Extension::SPV_EXT_optnone},
74 {"SPV_INTEL_usm_storage_classes",
75 SPIRV::Extension::Extension::SPV_INTEL_usm_storage_classes},
76 {"SPV_INTEL_split_barrier",
77 SPIRV::Extension::Extension::SPV_INTEL_split_barrier},
78 {"SPV_INTEL_subgroups", SPIRV::Extension::Extension::SPV_INTEL_subgroups},
79 {"SPV_INTEL_media_block_io",
80 SPIRV::Extension::Extension::SPV_INTEL_media_block_io},
81 {"SPV_INTEL_memory_access_aliasing",
82 SPIRV::Extension::Extension::SPV_INTEL_memory_access_aliasing},
83 {"SPV_INTEL_joint_matrix",
84 SPIRV::Extension::Extension::SPV_INTEL_joint_matrix},
85 {"SPV_INTEL_masked_gather_scatter",
86 SPIRV::Extension::Extension::SPV_INTEL_masked_gather_scatter},
87 {"SPV_KHR_16bit_storage",
88 SPIRV::Extension::Extension::SPV_KHR_16bit_storage},
89 {"SPV_KHR_device_group", SPIRV::Extension::Extension::SPV_KHR_device_group},
90 {"SPV_KHR_fragment_shading_rate",
91 SPIRV::Extension::Extension::SPV_KHR_fragment_shading_rate},
92 {"SPV_KHR_multiview", SPIRV::Extension::Extension::SPV_KHR_multiview},
93 {"SPV_KHR_post_depth_coverage",
94 SPIRV::Extension::Extension::SPV_KHR_post_depth_coverage},
95 {"SPV_KHR_shader_draw_parameters",
96 SPIRV::Extension::Extension::SPV_KHR_shader_draw_parameters},
97 {"SPV_KHR_ray_tracing", SPIRV::Extension::Extension::SPV_KHR_ray_tracing},
98 {"SPV_KHR_uniform_group_instructions",
99 SPIRV::Extension::Extension::SPV_KHR_uniform_group_instructions},
100 {"SPV_KHR_no_integer_wrap_decoration",
101 SPIRV::Extension::Extension::SPV_KHR_no_integer_wrap_decoration},
102 {"SPV_KHR_float_controls",
103 SPIRV::Extension::Extension::SPV_KHR_float_controls},
104 {"SPV_KHR_expect_assume",
105 SPIRV::Extension::Extension::SPV_KHR_expect_assume},
106 {"SPV_KHR_bit_instructions",
107 SPIRV::Extension::Extension::SPV_KHR_bit_instructions},
108 {"SPV_KHR_integer_dot_product",
109 SPIRV::Extension::Extension::SPV_KHR_integer_dot_product},
110 {"SPV_KHR_linkonce_odr", SPIRV::Extension::Extension::SPV_KHR_linkonce_odr},
111 {"SPV_KHR_fma", SPIRV::Extension::Extension::SPV_KHR_fma},
112 {"SPV_INTEL_inline_assembly",
113 SPIRV::Extension::Extension::SPV_INTEL_inline_assembly},
114 {"SPV_INTEL_bindless_images",
115 SPIRV::Extension::Extension::SPV_INTEL_bindless_images},
116 {"SPV_INTEL_bfloat16_arithmetic",
117 SPIRV::Extension::Extension::SPV_INTEL_bfloat16_arithmetic},
118 {"SPV_INTEL_bfloat16_conversion",
119 SPIRV::Extension::Extension::SPV_INTEL_bfloat16_conversion},
120 {"SPV_KHR_subgroup_rotate",
121 SPIRV::Extension::Extension::SPV_KHR_subgroup_rotate},
122 {"SPV_INTEL_variable_length_array",
123 SPIRV::Extension::Extension::SPV_INTEL_variable_length_array},
124 {"SPV_INTEL_function_pointers",
125 SPIRV::Extension::Extension::SPV_INTEL_function_pointers},
126 {"SPV_KHR_shader_clock", SPIRV::Extension::Extension::SPV_KHR_shader_clock},
127 {"SPV_KHR_cooperative_matrix",
128 SPIRV::Extension::Extension::SPV_KHR_cooperative_matrix},
129 {"SPV_KHR_non_semantic_info",
130 SPIRV::Extension::Extension::SPV_KHR_non_semantic_info},
131 {"SPV_KHR_ray_query", SPIRV::Extension::Extension::SPV_KHR_ray_query},
132 {"SPV_EXT_shader_image_int64",
133 SPIRV::Extension::Extension::SPV_EXT_shader_image_int64},
134 {"SPV_KHR_fragment_shader_barycentric",
135 SPIRV::Extension::Extension::SPV_KHR_fragment_shader_barycentric},
136 {"SPV_KHR_physical_storage_buffer",
137 SPIRV::Extension::Extension::SPV_KHR_physical_storage_buffer},
138 {"SPV_KHR_vulkan_memory_model",
139 SPIRV::Extension::Extension::SPV_KHR_vulkan_memory_model},
140 {"SPV_NV_shader_subgroup_partitioned",
141 SPIRV::Extension::Extension::SPV_NV_shader_subgroup_partitioned},
142 {"SPV_INTEL_long_composites",
143 SPIRV::Extension::Extension::SPV_INTEL_long_composites},
144 {"SPV_INTEL_fp_max_error",
145 SPIRV::Extension::Extension::SPV_INTEL_fp_max_error},
146 {"SPV_INTEL_subgroup_matrix_multiply_accumulate",
147 SPIRV::Extension::Extension::
148 SPV_INTEL_subgroup_matrix_multiply_accumulate},
149 {"SPV_INTEL_ternary_bitwise_function",
150 SPIRV::Extension::Extension::SPV_INTEL_ternary_bitwise_function},
151 {"SPV_INTEL_2d_block_io",
152 SPIRV::Extension::Extension::SPV_INTEL_2d_block_io},
153 {"SPV_INTEL_int4", SPIRV::Extension::Extension::SPV_INTEL_int4},
154 {"SPV_KHR_float_controls2",
155 SPIRV::Extension::Extension::SPV_KHR_float_controls2},
156 {"SPV_INTEL_tensor_float32_conversion",
157 SPIRV::Extension::Extension::SPV_INTEL_tensor_float32_conversion},
158 {"SPV_KHR_bfloat16", SPIRV::Extension::Extension::SPV_KHR_bfloat16},
159 {"SPV_EXT_relaxed_printf_string_address_space",
160 SPIRV::Extension::Extension::SPV_EXT_relaxed_printf_string_address_space},
161 {"SPV_INTEL_predicated_io",
162 SPIRV::Extension::Extension::SPV_INTEL_predicated_io},
163 {"SPV_KHR_maximal_reconvergence",
164 SPIRV::Extension::Extension::SPV_KHR_maximal_reconvergence},
165 {"SPV_INTEL_kernel_attributes",
166 SPIRV::Extension::Extension::SPV_INTEL_kernel_attributes},
167 {"SPV_ALTERA_blocking_pipes",
168 SPIRV::Extension::Extension::SPV_ALTERA_blocking_pipes},
169 {"SPV_ALTERA_arbitrary_precision_fixed_point",
170 SPIRV::Extension::Extension::SPV_ALTERA_arbitrary_precision_fixed_point},
171 {"SPV_EXT_image_raw10_raw12",
172 SPIRV::Extension::Extension::SPV_EXT_image_raw10_raw12},
173 {"SPV_INTEL_unstructured_loop_controls",
174 SPIRV::Extension::Extension::SPV_INTEL_unstructured_loop_controls},
175 {"SPV_AMD_weak_linkage", SPIRV::Extension::Extension::SPV_AMD_weak_linkage},
176 {"SPV_KHR_abort", SPIRV::Extension::Extension::SPV_KHR_abort},
177 {"SPV_KHR_poison_freeze",
178 SPIRV::Extension::Extension::SPV_KHR_poison_freeze},
179 {"SPV_KHR_untyped_pointers",
180 SPIRV::Extension::Extension::SPV_KHR_untyped_pointers},
181 {"SPV_EXT_long_vector", SPIRV::Extension::Extension::SPV_EXT_long_vector}};
182
183bool SPIRVExtensionsParser::parse(cl::Option &O, StringRef ArgName,
184 StringRef ArgValue, ExtensionSet &Vals) {
185 SmallVector<StringRef, 10> Tokens;
186 ArgValue.split(A&: Tokens, Separator: ",", MaxSplit: -1, KeepEmpty: false);
187
188 ExtensionSet EnabledExtensions;
189
190 auto M = partition(Range&: Tokens, P: [](auto &&T) { return T.starts_with('+'); });
191
192 if (std::any_of(first: M, last: Tokens.end(), pred: equal_to(Arg: "all")))
193 for (auto &&El : make_second_range(c: SPIRVExtensionMap))
194 Vals.insert(V: El);
195
196 for (auto &&Token : make_range(x: Tokens.begin(), y: M)) {
197 StringRef ExtensionName = Token.substr(Start: 1);
198 auto NameValuePair = SPIRVExtensionMap.find(Key: ExtensionName);
199
200 if (NameValuePair == SPIRVExtensionMap.end())
201 return O.error(Message: "Unknown SPIR-V extension: " + Token);
202
203 EnabledExtensions.insert(V: NameValuePair->second);
204 }
205
206 for (auto &&Token : make_range(x: M, y: Tokens.end())) {
207 if (Token == "all")
208 continue;
209
210 if (Token.size() == 3 && Token.upper() == "KHR") {
211 for (const auto &[ExtensionName, ExtensionEnum] : SPIRVExtensionMap)
212 if (StringRef(ExtensionName).starts_with(Prefix: "SPV_KHR_"))
213 Vals.insert(V: ExtensionEnum);
214 continue;
215 }
216
217 if (Token.empty() || (!Token.starts_with(Prefix: "+") && !Token.starts_with(Prefix: "-")))
218 return O.error(Message: "Invalid extension list format: " + Token);
219
220 auto NameValuePair = SPIRVExtensionMap.find(Key: Token.substr(Start: 1));
221
222 if (NameValuePair == SPIRVExtensionMap.end())
223 return O.error(Message: "Unknown SPIR-V extension: " + Token);
224 if (EnabledExtensions.count(V: NameValuePair->second))
225 return O.error(
226 Message: "Extension cannot be allowed and disallowed at the same time: " +
227 NameValuePair->first());
228 DisabledExtensions.insert(V: NameValuePair->second);
229 Vals.erase(V: NameValuePair->second);
230 }
231
232 Vals.insert(I: EnabledExtensions.begin(), E: EnabledExtensions.end());
233
234 return false;
235}
236
237StringRef
238SPIRVExtensionsParser::checkExtensions(ArrayRef<std::string> ExtNames,
239 ExtensionSet &AllowedExtensions) {
240 for (const auto &Ext : ExtNames) {
241 if (Ext == "all") {
242 for (const auto &[ExtensionName, ExtensionEnum] : SPIRVExtensionMap)
243 AllowedExtensions.insert(V: ExtensionEnum);
244 break;
245 }
246 auto It = SPIRVExtensionMap.find(Key: Ext);
247 if (It == SPIRVExtensionMap.end())
248 return Ext;
249 AllowedExtensions.insert(V: It->second);
250 }
251 return StringRef();
252}
253
254ExtensionSet SPIRVExtensionsParser::getValidExtensions(const Triple &TT) {
255 ExtensionSet R;
256 SPIRV::Environment::Environment CurrentEnvironment =
257 SPIRV::Environment::Environment::EnvOpenCL;
258 if (TT.getOS() == Triple::Vulkan)
259 CurrentEnvironment = SPIRV::Environment::Environment::EnvVulkan;
260
261 for (const auto &[ExtensionName, ExtensionEnum] : SPIRVExtensionMap) {
262 EnvironmentList AllowedEnv = getSymbolicOperandAllowedEnvironments(
263 Category: SPIRV::OperandCategory::OperandCategory::ExtensionOperand,
264 Value: ExtensionEnum);
265
266 if (llvm::is_contained(Range&: AllowedEnv, Element: CurrentEnvironment) &&
267 !llvm::is_contained(Range&: DisabledExtensions, Element: ExtensionEnum))
268 R.insert(V: ExtensionEnum);
269 }
270
271 return R;
272}
273