1 // Copyright (c) 2015-2016 The Khronos Group Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "source/spirv_target_env.h"
16
17 #include <cassert>
18 #include <cstring>
19 #include <string>
20
21 #include "source/spirv_constant.h"
22 #include "spirv-tools/libspirv.h"
23
spvTargetEnvDescription(spv_target_env env)24 const char* spvTargetEnvDescription(spv_target_env env) {
25 switch (env) {
26 case SPV_ENV_UNIVERSAL_1_0:
27 return "SPIR-V 1.0";
28 case SPV_ENV_VULKAN_1_0:
29 return "SPIR-V 1.0 (under Vulkan 1.0 semantics)";
30 case SPV_ENV_UNIVERSAL_1_1:
31 return "SPIR-V 1.1";
32 case SPV_ENV_OPENCL_1_2:
33 return "SPIR-V 1.0 (under OpenCL 1.2 Full Profile semantics)";
34 case SPV_ENV_OPENCL_EMBEDDED_1_2:
35 return "SPIR-V 1.0 (under OpenCL 1.2 Embedded Profile semantics)";
36 case SPV_ENV_OPENCL_2_0:
37 return "SPIR-V 1.0 (under OpenCL 2.0 Full Profile semantics)";
38 case SPV_ENV_OPENCL_EMBEDDED_2_0:
39 return "SPIR-V 1.0 (under OpenCL 2.0 Embedded Profile semantics)";
40 case SPV_ENV_OPENCL_2_1:
41 return "SPIR-V 1.0 (under OpenCL 2.1 Full Profile semantics)";
42 case SPV_ENV_OPENCL_EMBEDDED_2_1:
43 return "SPIR-V 1.0 (under OpenCL 2.1 Embedded Profile semantics)";
44 case SPV_ENV_OPENCL_2_2:
45 return "SPIR-V 1.2 (under OpenCL 2.2 Full Profile semantics)";
46 case SPV_ENV_OPENCL_EMBEDDED_2_2:
47 return "SPIR-V 1.2 (under OpenCL 2.2 Embedded Profile semantics)";
48 case SPV_ENV_OPENGL_4_0:
49 return "SPIR-V 1.0 (under OpenGL 4.0 semantics)";
50 case SPV_ENV_OPENGL_4_1:
51 return "SPIR-V 1.0 (under OpenGL 4.1 semantics)";
52 case SPV_ENV_OPENGL_4_2:
53 return "SPIR-V 1.0 (under OpenGL 4.2 semantics)";
54 case SPV_ENV_OPENGL_4_3:
55 return "SPIR-V 1.0 (under OpenGL 4.3 semantics)";
56 case SPV_ENV_OPENGL_4_5:
57 return "SPIR-V 1.0 (under OpenGL 4.5 semantics)";
58 case SPV_ENV_UNIVERSAL_1_2:
59 return "SPIR-V 1.2";
60 case SPV_ENV_UNIVERSAL_1_3:
61 return "SPIR-V 1.3";
62 case SPV_ENV_VULKAN_1_1:
63 return "SPIR-V 1.3 (under Vulkan 1.1 semantics)";
64 case SPV_ENV_WEBGPU_0:
65 assert(false);
66 break;
67 case SPV_ENV_UNIVERSAL_1_4:
68 return "SPIR-V 1.4";
69 case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
70 return "SPIR-V 1.4 (under Vulkan 1.1 semantics)";
71 case SPV_ENV_UNIVERSAL_1_5:
72 return "SPIR-V 1.5";
73 case SPV_ENV_VULKAN_1_2:
74 return "SPIR-V 1.5 (under Vulkan 1.2 semantics)";
75 }
76 return "";
77 }
78
spvVersionForTargetEnv(spv_target_env env)79 uint32_t spvVersionForTargetEnv(spv_target_env env) {
80 switch (env) {
81 case SPV_ENV_UNIVERSAL_1_0:
82 case SPV_ENV_VULKAN_1_0:
83 case SPV_ENV_OPENCL_1_2:
84 case SPV_ENV_OPENCL_EMBEDDED_1_2:
85 case SPV_ENV_OPENCL_2_0:
86 case SPV_ENV_OPENCL_EMBEDDED_2_0:
87 case SPV_ENV_OPENCL_2_1:
88 case SPV_ENV_OPENCL_EMBEDDED_2_1:
89 case SPV_ENV_OPENGL_4_0:
90 case SPV_ENV_OPENGL_4_1:
91 case SPV_ENV_OPENGL_4_2:
92 case SPV_ENV_OPENGL_4_3:
93 case SPV_ENV_OPENGL_4_5:
94 return SPV_SPIRV_VERSION_WORD(1, 0);
95 case SPV_ENV_UNIVERSAL_1_1:
96 return SPV_SPIRV_VERSION_WORD(1, 1);
97 case SPV_ENV_UNIVERSAL_1_2:
98 case SPV_ENV_OPENCL_2_2:
99 case SPV_ENV_OPENCL_EMBEDDED_2_2:
100 return SPV_SPIRV_VERSION_WORD(1, 2);
101 case SPV_ENV_UNIVERSAL_1_3:
102 case SPV_ENV_VULKAN_1_1:
103 return SPV_SPIRV_VERSION_WORD(1, 3);
104 case SPV_ENV_WEBGPU_0:
105 assert(false);
106 break;
107 case SPV_ENV_UNIVERSAL_1_4:
108 case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
109 return SPV_SPIRV_VERSION_WORD(1, 4);
110 case SPV_ENV_UNIVERSAL_1_5:
111 case SPV_ENV_VULKAN_1_2:
112 return SPV_SPIRV_VERSION_WORD(1, 5);
113 }
114 return SPV_SPIRV_VERSION_WORD(0, 0);
115 }
116
117 static const std::pair<const char*, spv_target_env> spvTargetEnvNameMap[] = {
118 {"vulkan1.1spv1.4", SPV_ENV_VULKAN_1_1_SPIRV_1_4},
119 {"vulkan1.0", SPV_ENV_VULKAN_1_0},
120 {"vulkan1.1", SPV_ENV_VULKAN_1_1},
121 {"vulkan1.2", SPV_ENV_VULKAN_1_2},
122 {"spv1.0", SPV_ENV_UNIVERSAL_1_0},
123 {"spv1.1", SPV_ENV_UNIVERSAL_1_1},
124 {"spv1.2", SPV_ENV_UNIVERSAL_1_2},
125 {"spv1.3", SPV_ENV_UNIVERSAL_1_3},
126 {"spv1.4", SPV_ENV_UNIVERSAL_1_4},
127 {"spv1.5", SPV_ENV_UNIVERSAL_1_5},
128 {"opencl1.2embedded", SPV_ENV_OPENCL_EMBEDDED_1_2},
129 {"opencl1.2", SPV_ENV_OPENCL_1_2},
130 {"opencl2.0embedded", SPV_ENV_OPENCL_EMBEDDED_2_0},
131 {"opencl2.0", SPV_ENV_OPENCL_2_0},
132 {"opencl2.1embedded", SPV_ENV_OPENCL_EMBEDDED_2_1},
133 {"opencl2.1", SPV_ENV_OPENCL_2_1},
134 {"opencl2.2embedded", SPV_ENV_OPENCL_EMBEDDED_2_2},
135 {"opencl2.2", SPV_ENV_OPENCL_2_2},
136 {"opengl4.0", SPV_ENV_OPENGL_4_0},
137 {"opengl4.1", SPV_ENV_OPENGL_4_1},
138 {"opengl4.2", SPV_ENV_OPENGL_4_2},
139 {"opengl4.3", SPV_ENV_OPENGL_4_3},
140 {"opengl4.5", SPV_ENV_OPENGL_4_5},
141 };
142
spvParseTargetEnv(const char * s,spv_target_env * env)143 bool spvParseTargetEnv(const char* s, spv_target_env* env) {
144 auto match = [s](const char* b) {
145 return s && (0 == strncmp(s, b, strlen(b)));
146 };
147 for (auto& name_env : spvTargetEnvNameMap) {
148 if (match(name_env.first)) {
149 if (env) {
150 *env = name_env.second;
151 }
152 return true;
153 }
154 }
155 if (env) *env = SPV_ENV_UNIVERSAL_1_0;
156 return false;
157 }
158
159 #define VULKAN_VER(MAJOR, MINOR) ((MAJOR << 22) | (MINOR << 12))
160 #define SPIRV_VER(MAJOR, MINOR) ((MAJOR << 16) | (MINOR << 8))
161
162 struct VulkanEnv {
163 spv_target_env vulkan_env;
164 uint32_t vulkan_ver;
165 uint32_t spirv_ver;
166 };
167 // Maps each Vulkan target environment enum to the Vulkan version, and the
168 // maximum supported SPIR-V version for that Vulkan environment.
169 // Keep this ordered from least capable to most capable.
170 static const VulkanEnv ordered_vulkan_envs[] = {
171 {SPV_ENV_VULKAN_1_0, VULKAN_VER(1, 0), SPIRV_VER(1, 0)},
172 {SPV_ENV_VULKAN_1_1, VULKAN_VER(1, 1), SPIRV_VER(1, 3)},
173 {SPV_ENV_VULKAN_1_1_SPIRV_1_4, VULKAN_VER(1, 1), SPIRV_VER(1, 4)},
174 {SPV_ENV_VULKAN_1_2, VULKAN_VER(1, 2), SPIRV_VER(1, 5)}};
175
spvParseVulkanEnv(uint32_t vulkan_ver,uint32_t spirv_ver,spv_target_env * env)176 bool spvParseVulkanEnv(uint32_t vulkan_ver, uint32_t spirv_ver,
177 spv_target_env* env) {
178 for (auto triple : ordered_vulkan_envs) {
179 if (triple.vulkan_ver >= vulkan_ver && triple.spirv_ver >= spirv_ver) {
180 *env = triple.vulkan_env;
181 return true;
182 }
183 }
184 return false;
185 }
186
spvIsVulkanEnv(spv_target_env env)187 bool spvIsVulkanEnv(spv_target_env env) {
188 switch (env) {
189 case SPV_ENV_UNIVERSAL_1_0:
190 case SPV_ENV_OPENCL_1_2:
191 case SPV_ENV_OPENCL_EMBEDDED_1_2:
192 case SPV_ENV_OPENCL_2_0:
193 case SPV_ENV_OPENCL_EMBEDDED_2_0:
194 case SPV_ENV_OPENCL_2_1:
195 case SPV_ENV_OPENCL_EMBEDDED_2_1:
196 case SPV_ENV_OPENGL_4_0:
197 case SPV_ENV_OPENGL_4_1:
198 case SPV_ENV_OPENGL_4_2:
199 case SPV_ENV_OPENGL_4_3:
200 case SPV_ENV_OPENGL_4_5:
201 case SPV_ENV_UNIVERSAL_1_1:
202 case SPV_ENV_UNIVERSAL_1_2:
203 case SPV_ENV_OPENCL_2_2:
204 case SPV_ENV_OPENCL_EMBEDDED_2_2:
205 case SPV_ENV_UNIVERSAL_1_3:
206 case SPV_ENV_UNIVERSAL_1_4:
207 case SPV_ENV_UNIVERSAL_1_5:
208 return false;
209 case SPV_ENV_VULKAN_1_0:
210 case SPV_ENV_VULKAN_1_1:
211 case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
212 case SPV_ENV_VULKAN_1_2:
213 return true;
214 case SPV_ENV_WEBGPU_0:
215 assert(false);
216 break;
217 }
218 return false;
219 }
220
spvIsOpenCLEnv(spv_target_env env)221 bool spvIsOpenCLEnv(spv_target_env env) {
222 switch (env) {
223 case SPV_ENV_UNIVERSAL_1_0:
224 case SPV_ENV_VULKAN_1_0:
225 case SPV_ENV_UNIVERSAL_1_1:
226 case SPV_ENV_OPENGL_4_0:
227 case SPV_ENV_OPENGL_4_1:
228 case SPV_ENV_OPENGL_4_2:
229 case SPV_ENV_OPENGL_4_3:
230 case SPV_ENV_OPENGL_4_5:
231 case SPV_ENV_UNIVERSAL_1_2:
232 case SPV_ENV_UNIVERSAL_1_3:
233 case SPV_ENV_VULKAN_1_1:
234 case SPV_ENV_UNIVERSAL_1_4:
235 case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
236 case SPV_ENV_UNIVERSAL_1_5:
237 case SPV_ENV_VULKAN_1_2:
238 return false;
239 case SPV_ENV_OPENCL_1_2:
240 case SPV_ENV_OPENCL_EMBEDDED_1_2:
241 case SPV_ENV_OPENCL_2_0:
242 case SPV_ENV_OPENCL_EMBEDDED_2_0:
243 case SPV_ENV_OPENCL_EMBEDDED_2_1:
244 case SPV_ENV_OPENCL_EMBEDDED_2_2:
245 case SPV_ENV_OPENCL_2_1:
246 case SPV_ENV_OPENCL_2_2:
247 return true;
248 case SPV_ENV_WEBGPU_0:
249 assert(false);
250 break;
251 }
252 return false;
253 }
254
spvIsOpenGLEnv(spv_target_env env)255 bool spvIsOpenGLEnv(spv_target_env env) {
256 switch (env) {
257 case SPV_ENV_UNIVERSAL_1_0:
258 case SPV_ENV_VULKAN_1_0:
259 case SPV_ENV_UNIVERSAL_1_1:
260 case SPV_ENV_UNIVERSAL_1_2:
261 case SPV_ENV_UNIVERSAL_1_3:
262 case SPV_ENV_VULKAN_1_1:
263 case SPV_ENV_OPENCL_1_2:
264 case SPV_ENV_OPENCL_EMBEDDED_1_2:
265 case SPV_ENV_OPENCL_2_0:
266 case SPV_ENV_OPENCL_EMBEDDED_2_0:
267 case SPV_ENV_OPENCL_EMBEDDED_2_1:
268 case SPV_ENV_OPENCL_EMBEDDED_2_2:
269 case SPV_ENV_OPENCL_2_1:
270 case SPV_ENV_OPENCL_2_2:
271 case SPV_ENV_UNIVERSAL_1_4:
272 case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
273 case SPV_ENV_UNIVERSAL_1_5:
274 case SPV_ENV_VULKAN_1_2:
275 return false;
276 case SPV_ENV_OPENGL_4_0:
277 case SPV_ENV_OPENGL_4_1:
278 case SPV_ENV_OPENGL_4_2:
279 case SPV_ENV_OPENGL_4_3:
280 case SPV_ENV_OPENGL_4_5:
281 return true;
282 case SPV_ENV_WEBGPU_0:
283 assert(false);
284 break;
285 }
286 return false;
287 }
288
spvLogStringForEnv(spv_target_env env)289 std::string spvLogStringForEnv(spv_target_env env) {
290 switch (env) {
291 case SPV_ENV_OPENCL_1_2:
292 case SPV_ENV_OPENCL_2_0:
293 case SPV_ENV_OPENCL_2_1:
294 case SPV_ENV_OPENCL_2_2:
295 case SPV_ENV_OPENCL_EMBEDDED_1_2:
296 case SPV_ENV_OPENCL_EMBEDDED_2_0:
297 case SPV_ENV_OPENCL_EMBEDDED_2_1:
298 case SPV_ENV_OPENCL_EMBEDDED_2_2: {
299 return "OpenCL";
300 }
301 case SPV_ENV_OPENGL_4_0:
302 case SPV_ENV_OPENGL_4_1:
303 case SPV_ENV_OPENGL_4_2:
304 case SPV_ENV_OPENGL_4_3:
305 case SPV_ENV_OPENGL_4_5: {
306 return "OpenGL";
307 }
308 case SPV_ENV_VULKAN_1_0:
309 case SPV_ENV_VULKAN_1_1:
310 case SPV_ENV_VULKAN_1_1_SPIRV_1_4: {
311 case SPV_ENV_VULKAN_1_2:
312 return "Vulkan";
313 }
314 case SPV_ENV_UNIVERSAL_1_0:
315 case SPV_ENV_UNIVERSAL_1_1:
316 case SPV_ENV_UNIVERSAL_1_2:
317 case SPV_ENV_UNIVERSAL_1_3:
318 case SPV_ENV_UNIVERSAL_1_4:
319 case SPV_ENV_UNIVERSAL_1_5: {
320 return "Universal";
321 }
322 case SPV_ENV_WEBGPU_0:
323 assert(false);
324 break;
325 }
326 return "Unknown";
327 }
328
spvTargetEnvList(const int pad,const int wrap)329 std::string spvTargetEnvList(const int pad, const int wrap) {
330 std::string ret;
331 size_t max_line_len = wrap - pad; // The first line isn't padded
332 std::string line;
333 std::string sep = "";
334
335 for (auto& name_env : spvTargetEnvNameMap) {
336 std::string word = sep + name_env.first;
337 if (line.length() + word.length() > max_line_len) {
338 // Adding one word wouldn't fit, commit the line in progress and
339 // start a new one.
340 ret += line + "\n";
341 line.assign(pad, ' ');
342 // The first line is done. The max length now comprises the
343 // padding.
344 max_line_len = wrap;
345 }
346 line += word;
347 sep = "|";
348 }
349
350 ret += line;
351
352 return ret;
353 }
354