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