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 "llvm/ADT/StringRef.h"
16#include <algorithm>
17#include <map>
18
19#define DEBUG_TYPE "spirv-commandline"
20
21using namespace llvm;
22
23static const std::map<std::string, SPIRV::Extension::Extension, std::less<>>
24 SPIRVExtensionMap = {
25 {"SPV_EXT_shader_atomic_float_add",
26 SPIRV::Extension::Extension::SPV_EXT_shader_atomic_float_add},
27 {"SPV_EXT_shader_atomic_float16_add",
28 SPIRV::Extension::Extension::SPV_EXT_shader_atomic_float16_add},
29 {"SPV_EXT_shader_atomic_float_min_max",
30 SPIRV::Extension::Extension::SPV_EXT_shader_atomic_float_min_max},
31 {"SPV_EXT_arithmetic_fence",
32 SPIRV::Extension::Extension::SPV_EXT_arithmetic_fence},
33 {"SPV_EXT_demote_to_helper_invocation",
34 SPIRV::Extension::Extension::SPV_EXT_demote_to_helper_invocation},
35 {"SPV_INTEL_arbitrary_precision_integers",
36 SPIRV::Extension::Extension::SPV_INTEL_arbitrary_precision_integers},
37 {"SPV_INTEL_cache_controls",
38 SPIRV::Extension::Extension::SPV_INTEL_cache_controls},
39 {"SPV_INTEL_float_controls2",
40 SPIRV::Extension::Extension::SPV_INTEL_float_controls2},
41 {"SPV_INTEL_global_variable_fpga_decorations",
42 SPIRV::Extension::Extension::
43 SPV_INTEL_global_variable_fpga_decorations},
44 {"SPV_INTEL_global_variable_host_access",
45 SPIRV::Extension::Extension::SPV_INTEL_global_variable_host_access},
46 {"SPV_INTEL_optnone", SPIRV::Extension::Extension::SPV_INTEL_optnone},
47 {"SPV_EXT_optnone", SPIRV::Extension::Extension::SPV_EXT_optnone},
48 {"SPV_INTEL_usm_storage_classes",
49 SPIRV::Extension::Extension::SPV_INTEL_usm_storage_classes},
50 {"SPV_INTEL_split_barrier",
51 SPIRV::Extension::Extension::SPV_INTEL_split_barrier},
52 {"SPV_INTEL_subgroups",
53 SPIRV::Extension::Extension::SPV_INTEL_subgroups},
54 {"SPV_INTEL_media_block_io",
55 SPIRV::Extension::Extension::SPV_INTEL_media_block_io},
56 {"SPV_INTEL_memory_access_aliasing",
57 SPIRV::Extension::Extension::SPV_INTEL_memory_access_aliasing},
58 {"SPV_INTEL_joint_matrix",
59 SPIRV::Extension::Extension::SPV_INTEL_joint_matrix},
60 {"SPV_KHR_uniform_group_instructions",
61 SPIRV::Extension::Extension::SPV_KHR_uniform_group_instructions},
62 {"SPV_KHR_no_integer_wrap_decoration",
63 SPIRV::Extension::Extension::SPV_KHR_no_integer_wrap_decoration},
64 {"SPV_KHR_float_controls",
65 SPIRV::Extension::Extension::SPV_KHR_float_controls},
66 {"SPV_KHR_expect_assume",
67 SPIRV::Extension::Extension::SPV_KHR_expect_assume},
68 {"SPV_KHR_bit_instructions",
69 SPIRV::Extension::Extension::SPV_KHR_bit_instructions},
70 {"SPV_KHR_integer_dot_product",
71 SPIRV::Extension::Extension::SPV_KHR_integer_dot_product},
72 {"SPV_KHR_linkonce_odr",
73 SPIRV::Extension::Extension::SPV_KHR_linkonce_odr},
74 {"SPV_INTEL_inline_assembly",
75 SPIRV::Extension::Extension::SPV_INTEL_inline_assembly},
76 {"SPV_INTEL_bindless_images",
77 SPIRV::Extension::Extension::SPV_INTEL_bindless_images},
78 {"SPV_INTEL_bfloat16_conversion",
79 SPIRV::Extension::Extension::SPV_INTEL_bfloat16_conversion},
80 {"SPV_KHR_subgroup_rotate",
81 SPIRV::Extension::Extension::SPV_KHR_subgroup_rotate},
82 {"SPV_INTEL_variable_length_array",
83 SPIRV::Extension::Extension::SPV_INTEL_variable_length_array},
84 {"SPV_INTEL_function_pointers",
85 SPIRV::Extension::Extension::SPV_INTEL_function_pointers},
86 {"SPV_KHR_shader_clock",
87 SPIRV::Extension::Extension::SPV_KHR_shader_clock},
88 {"SPV_KHR_cooperative_matrix",
89 SPIRV::Extension::Extension::SPV_KHR_cooperative_matrix},
90 {"SPV_KHR_non_semantic_info",
91 SPIRV::Extension::Extension::SPV_KHR_non_semantic_info},
92 {"SPV_INTEL_long_composites",
93 SPIRV::Extension::Extension::SPV_INTEL_long_composites},
94 {"SPV_INTEL_fp_max_error",
95 SPIRV::Extension::Extension::SPV_INTEL_fp_max_error},
96 {"SPV_INTEL_subgroup_matrix_multiply_accumulate",
97 SPIRV::Extension::Extension::
98 SPV_INTEL_subgroup_matrix_multiply_accumulate},
99 {"SPV_INTEL_ternary_bitwise_function",
100 SPIRV::Extension::Extension::SPV_INTEL_ternary_bitwise_function},
101 {"SPV_INTEL_2d_block_io",
102 SPIRV::Extension::Extension::SPV_INTEL_2d_block_io},
103 {"SPV_INTEL_int4", SPIRV::Extension::Extension::SPV_INTEL_int4},
104 {"SPV_KHR_float_controls2",
105 SPIRV::Extension::Extension::SPV_KHR_float_controls2}};
106
107bool SPIRVExtensionsParser::parse(cl::Option &O, StringRef ArgName,
108 StringRef ArgValue,
109 std::set<SPIRV::Extension::Extension> &Vals) {
110 SmallVector<StringRef, 10> Tokens;
111 ArgValue.split(A&: Tokens, Separator: ",", MaxSplit: -1, KeepEmpty: false);
112 std::sort(first: Tokens.begin(), last: Tokens.end());
113
114 std::set<SPIRV::Extension::Extension> EnabledExtensions;
115
116 for (const auto &Token : Tokens) {
117 if (Token == "all") {
118 for (const auto &[ExtensionName, ExtensionEnum] : SPIRVExtensionMap)
119 EnabledExtensions.insert(x: ExtensionEnum);
120
121 continue;
122 }
123
124 if (Token.size() == 3 && Token.upper() == "KHR") {
125 for (const auto &[ExtensionName, ExtensionEnum] : SPIRVExtensionMap)
126 if (StringRef(ExtensionName).starts_with(Prefix: "SPV_KHR_"))
127 EnabledExtensions.insert(x: ExtensionEnum);
128 continue;
129 }
130
131 if (Token.empty() || (!Token.starts_with(Prefix: "+") && !Token.starts_with(Prefix: "-")))
132 return O.error(Message: "Invalid extension list format: " + Token.str());
133
134 StringRef ExtensionName = Token.substr(Start: 1);
135 auto NameValuePair = SPIRVExtensionMap.find(x: ExtensionName);
136
137 if (NameValuePair == SPIRVExtensionMap.end())
138 return O.error(Message: "Unknown SPIR-V extension: " + Token.str());
139
140 if (Token.starts_with(Prefix: "+")) {
141 EnabledExtensions.insert(x: NameValuePair->second);
142 } else if (EnabledExtensions.count(x: NameValuePair->second)) {
143 if (llvm::is_contained(Range&: Tokens, Element: "+" + ExtensionName.str()))
144 return O.error(
145 Message: "Extension cannot be allowed and disallowed at the same time: " +
146 ExtensionName.str());
147
148 EnabledExtensions.erase(x: NameValuePair->second);
149 }
150 }
151
152 Vals = std::move(EnabledExtensions);
153 return false;
154}
155
156StringRef SPIRVExtensionsParser::checkExtensions(
157 const std::vector<std::string> &ExtNames,
158 std::set<SPIRV::Extension::Extension> &AllowedExtensions) {
159 for (const auto &Ext : ExtNames) {
160 if (Ext == "all") {
161 for (const auto &[ExtensionName, ExtensionEnum] : SPIRVExtensionMap)
162 AllowedExtensions.insert(x: ExtensionEnum);
163 break;
164 }
165 auto It = SPIRVExtensionMap.find(x: Ext);
166 if (It == SPIRVExtensionMap.end())
167 return Ext;
168 AllowedExtensions.insert(x: It->second);
169 }
170 return StringRef();
171}
172