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 #include <utility>
21
22 #include "source/spirv_constant.h"
23 #include "spirv-tools/libspirv.h"
24
spvTargetEnvDescription(spv_target_env env)25 const char* spvTargetEnvDescription(spv_target_env env) {
26 switch (env) {
27 case SPV_ENV_UNIVERSAL_1_0:
28 return "SPIR-V 1.0";
29 case SPV_ENV_VULKAN_1_0:
30 return "SPIR-V 1.0 (under Vulkan 1.0 semantics)";
31 case SPV_ENV_UNIVERSAL_1_1:
32 return "SPIR-V 1.1";
33 case SPV_ENV_OPENCL_1_2:
34 return "SPIR-V 1.0 (under OpenCL 1.2 Full Profile semantics)";
35 case SPV_ENV_OPENCL_EMBEDDED_1_2:
36 return "SPIR-V 1.0 (under OpenCL 1.2 Embedded Profile semantics)";
37 case SPV_ENV_OPENCL_2_0:
38 return "SPIR-V 1.0 (under OpenCL 2.0 Full Profile semantics)";
39 case SPV_ENV_OPENCL_EMBEDDED_2_0:
40 return "SPIR-V 1.0 (under OpenCL 2.0 Embedded Profile semantics)";
41 case SPV_ENV_OPENCL_2_1:
42 return "SPIR-V 1.0 (under OpenCL 2.1 Full Profile semantics)";
43 case SPV_ENV_OPENCL_EMBEDDED_2_1:
44 return "SPIR-V 1.0 (under OpenCL 2.1 Embedded Profile semantics)";
45 case SPV_ENV_OPENCL_2_2:
46 return "SPIR-V 1.2 (under OpenCL 2.2 Full Profile semantics)";
47 case SPV_ENV_OPENCL_EMBEDDED_2_2:
48 return "SPIR-V 1.2 (under OpenCL 2.2 Embedded Profile semantics)";
49 case SPV_ENV_OPENGL_4_0:
50 return "SPIR-V 1.0 (under OpenGL 4.0 semantics)";
51 case SPV_ENV_OPENGL_4_1:
52 return "SPIR-V 1.0 (under OpenGL 4.1 semantics)";
53 case SPV_ENV_OPENGL_4_2:
54 return "SPIR-V 1.0 (under OpenGL 4.2 semantics)";
55 case SPV_ENV_OPENGL_4_3:
56 return "SPIR-V 1.0 (under OpenGL 4.3 semantics)";
57 case SPV_ENV_OPENGL_4_5:
58 return "SPIR-V 1.0 (under OpenGL 4.5 semantics)";
59 case SPV_ENV_UNIVERSAL_1_2:
60 return "SPIR-V 1.2";
61 case SPV_ENV_UNIVERSAL_1_3:
62 return "SPIR-V 1.3";
63 case SPV_ENV_VULKAN_1_1:
64 return "SPIR-V 1.3 (under Vulkan 1.1 semantics)";
65 case SPV_ENV_WEBGPU_0:
66 assert(false && "Deprecated target environment value.");
67 break;
68 case SPV_ENV_UNIVERSAL_1_4:
69 return "SPIR-V 1.4";
70 case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
71 return "SPIR-V 1.4 (under Vulkan 1.1 semantics)";
72 case SPV_ENV_UNIVERSAL_1_5:
73 return "SPIR-V 1.5";
74 case SPV_ENV_VULKAN_1_2:
75 return "SPIR-V 1.5 (under Vulkan 1.2 semantics)";
76 case SPV_ENV_UNIVERSAL_1_6:
77 return "SPIR-V 1.6";
78 case SPV_ENV_VULKAN_1_3:
79 return "SPIR-V 1.6 (under Vulkan 1.3 semantics)";
80 case SPV_ENV_MAX:
81 assert(false && "Invalid target environment value.");
82 break;
83 }
84 return "";
85 }
86
spvVersionForTargetEnv(spv_target_env env)87 uint32_t spvVersionForTargetEnv(spv_target_env env) {
88 switch (env) {
89 case SPV_ENV_UNIVERSAL_1_0:
90 case SPV_ENV_VULKAN_1_0:
91 case SPV_ENV_OPENCL_1_2:
92 case SPV_ENV_OPENCL_EMBEDDED_1_2:
93 case SPV_ENV_OPENCL_2_0:
94 case SPV_ENV_OPENCL_EMBEDDED_2_0:
95 case SPV_ENV_OPENCL_2_1:
96 case SPV_ENV_OPENCL_EMBEDDED_2_1:
97 case SPV_ENV_OPENGL_4_0:
98 case SPV_ENV_OPENGL_4_1:
99 case SPV_ENV_OPENGL_4_2:
100 case SPV_ENV_OPENGL_4_3:
101 case SPV_ENV_OPENGL_4_5:
102 return SPV_SPIRV_VERSION_WORD(1, 0);
103 case SPV_ENV_UNIVERSAL_1_1:
104 return SPV_SPIRV_VERSION_WORD(1, 1);
105 case SPV_ENV_UNIVERSAL_1_2:
106 case SPV_ENV_OPENCL_2_2:
107 case SPV_ENV_OPENCL_EMBEDDED_2_2:
108 return SPV_SPIRV_VERSION_WORD(1, 2);
109 case SPV_ENV_UNIVERSAL_1_3:
110 case SPV_ENV_VULKAN_1_1:
111 return SPV_SPIRV_VERSION_WORD(1, 3);
112 case SPV_ENV_WEBGPU_0:
113 assert(false && "Deprecated target environment value.");
114 break;
115 case SPV_ENV_UNIVERSAL_1_4:
116 case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
117 return SPV_SPIRV_VERSION_WORD(1, 4);
118 case SPV_ENV_UNIVERSAL_1_5:
119 case SPV_ENV_VULKAN_1_2:
120 return SPV_SPIRV_VERSION_WORD(1, 5);
121 case SPV_ENV_UNIVERSAL_1_6:
122 case SPV_ENV_VULKAN_1_3:
123 return SPV_SPIRV_VERSION_WORD(1, 6);
124 case SPV_ENV_MAX:
125 assert(false && "Invalid target environment value.");
126 break;
127 }
128 return SPV_SPIRV_VERSION_WORD(0, 0);
129 }
130
131 static const std::pair<const char*, spv_target_env> spvTargetEnvNameMap[] = {
132 {"vulkan1.1spv1.4", SPV_ENV_VULKAN_1_1_SPIRV_1_4},
133 {"vulkan1.0", SPV_ENV_VULKAN_1_0},
134 {"vulkan1.1", SPV_ENV_VULKAN_1_1},
135 {"vulkan1.2", SPV_ENV_VULKAN_1_2},
136 {"vulkan1.3", SPV_ENV_VULKAN_1_3},
137 {"spv1.0", SPV_ENV_UNIVERSAL_1_0},
138 {"spv1.1", SPV_ENV_UNIVERSAL_1_1},
139 {"spv1.2", SPV_ENV_UNIVERSAL_1_2},
140 {"spv1.3", SPV_ENV_UNIVERSAL_1_3},
141 {"spv1.4", SPV_ENV_UNIVERSAL_1_4},
142 {"spv1.5", SPV_ENV_UNIVERSAL_1_5},
143 {"spv1.6", SPV_ENV_UNIVERSAL_1_6},
144 {"opencl1.2embedded", SPV_ENV_OPENCL_EMBEDDED_1_2},
145 {"opencl1.2", SPV_ENV_OPENCL_1_2},
146 {"opencl2.0embedded", SPV_ENV_OPENCL_EMBEDDED_2_0},
147 {"opencl2.0", SPV_ENV_OPENCL_2_0},
148 {"opencl2.1embedded", SPV_ENV_OPENCL_EMBEDDED_2_1},
149 {"opencl2.1", SPV_ENV_OPENCL_2_1},
150 {"opencl2.2embedded", SPV_ENV_OPENCL_EMBEDDED_2_2},
151 {"opencl2.2", SPV_ENV_OPENCL_2_2},
152 {"opengl4.0", SPV_ENV_OPENGL_4_0},
153 {"opengl4.1", SPV_ENV_OPENGL_4_1},
154 {"opengl4.2", SPV_ENV_OPENGL_4_2},
155 {"opengl4.3", SPV_ENV_OPENGL_4_3},
156 {"opengl4.5", SPV_ENV_OPENGL_4_5},
157 };
158
spvParseTargetEnv(const char * s,spv_target_env * env)159 bool spvParseTargetEnv(const char* s, spv_target_env* env) {
160 auto match = [s](const char* b) {
161 return s && (0 == strncmp(s, b, strlen(b)));
162 };
163 for (auto& name_env : spvTargetEnvNameMap) {
164 if (match(name_env.first)) {
165 if (env) {
166 *env = name_env.second;
167 }
168 return true;
169 }
170 }
171 if (env) *env = SPV_ENV_UNIVERSAL_1_0;
172 return false;
173 }
174
175 #define VULKAN_VER(MAJOR, MINOR) ((MAJOR << 22) | (MINOR << 12))
176 #define SPIRV_VER(MAJOR, MINOR) ((MAJOR << 16) | (MINOR << 8))
177
178 struct VulkanEnv {
179 spv_target_env vulkan_env;
180 uint32_t vulkan_ver;
181 uint32_t spirv_ver;
182 };
183 // Maps each Vulkan target environment enum to the Vulkan version, and the
184 // maximum supported SPIR-V version for that Vulkan environment.
185 // Keep this ordered from least capable to most capable.
186 static const VulkanEnv ordered_vulkan_envs[] = {
187 {SPV_ENV_VULKAN_1_0, VULKAN_VER(1, 0), SPIRV_VER(1, 0)},
188 {SPV_ENV_VULKAN_1_1, VULKAN_VER(1, 1), SPIRV_VER(1, 3)},
189 {SPV_ENV_VULKAN_1_1_SPIRV_1_4, VULKAN_VER(1, 1), SPIRV_VER(1, 4)},
190 {SPV_ENV_VULKAN_1_2, VULKAN_VER(1, 2), SPIRV_VER(1, 5)},
191 {SPV_ENV_VULKAN_1_3, VULKAN_VER(1, 3), SPIRV_VER(1, 6)}};
192
spvParseVulkanEnv(uint32_t vulkan_ver,uint32_t spirv_ver,spv_target_env * env)193 bool spvParseVulkanEnv(uint32_t vulkan_ver, uint32_t spirv_ver,
194 spv_target_env* env) {
195 for (auto triple : ordered_vulkan_envs) {
196 if (triple.vulkan_ver >= vulkan_ver && triple.spirv_ver >= spirv_ver) {
197 *env = triple.vulkan_env;
198 return true;
199 }
200 }
201 return false;
202 }
203
spvIsVulkanEnv(spv_target_env env)204 bool spvIsVulkanEnv(spv_target_env env) {
205 switch (env) {
206 case SPV_ENV_UNIVERSAL_1_0:
207 case SPV_ENV_OPENCL_1_2:
208 case SPV_ENV_OPENCL_EMBEDDED_1_2:
209 case SPV_ENV_OPENCL_2_0:
210 case SPV_ENV_OPENCL_EMBEDDED_2_0:
211 case SPV_ENV_OPENCL_2_1:
212 case SPV_ENV_OPENCL_EMBEDDED_2_1:
213 case SPV_ENV_OPENGL_4_0:
214 case SPV_ENV_OPENGL_4_1:
215 case SPV_ENV_OPENGL_4_2:
216 case SPV_ENV_OPENGL_4_3:
217 case SPV_ENV_OPENGL_4_5:
218 case SPV_ENV_UNIVERSAL_1_1:
219 case SPV_ENV_UNIVERSAL_1_2:
220 case SPV_ENV_OPENCL_2_2:
221 case SPV_ENV_OPENCL_EMBEDDED_2_2:
222 case SPV_ENV_UNIVERSAL_1_3:
223 case SPV_ENV_UNIVERSAL_1_4:
224 case SPV_ENV_UNIVERSAL_1_5:
225 case SPV_ENV_UNIVERSAL_1_6:
226 return false;
227 case SPV_ENV_VULKAN_1_0:
228 case SPV_ENV_VULKAN_1_1:
229 case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
230 case SPV_ENV_VULKAN_1_2:
231 case SPV_ENV_VULKAN_1_3:
232 return true;
233 case SPV_ENV_WEBGPU_0:
234 assert(false && "Deprecated target environment value.");
235 break;
236 case SPV_ENV_MAX:
237 assert(false && "Invalid target environment value.");
238 break;
239 }
240 return false;
241 }
242
spvIsOpenCLEnv(spv_target_env env)243 bool spvIsOpenCLEnv(spv_target_env env) {
244 switch (env) {
245 case SPV_ENV_UNIVERSAL_1_0:
246 case SPV_ENV_VULKAN_1_0:
247 case SPV_ENV_UNIVERSAL_1_1:
248 case SPV_ENV_OPENGL_4_0:
249 case SPV_ENV_OPENGL_4_1:
250 case SPV_ENV_OPENGL_4_2:
251 case SPV_ENV_OPENGL_4_3:
252 case SPV_ENV_OPENGL_4_5:
253 case SPV_ENV_UNIVERSAL_1_2:
254 case SPV_ENV_UNIVERSAL_1_3:
255 case SPV_ENV_VULKAN_1_1:
256 case SPV_ENV_UNIVERSAL_1_4:
257 case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
258 case SPV_ENV_UNIVERSAL_1_5:
259 case SPV_ENV_VULKAN_1_2:
260 case SPV_ENV_UNIVERSAL_1_6:
261 case SPV_ENV_VULKAN_1_3:
262 return false;
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 return true;
272 case SPV_ENV_WEBGPU_0:
273 assert(false && "Deprecated target environment value.");
274 break;
275 case SPV_ENV_MAX:
276 assert(false && "Invalid target environment value.");
277 break;
278 }
279 return false;
280 }
281
spvIsOpenGLEnv(spv_target_env env)282 bool spvIsOpenGLEnv(spv_target_env env) {
283 switch (env) {
284 case SPV_ENV_UNIVERSAL_1_0:
285 case SPV_ENV_VULKAN_1_0:
286 case SPV_ENV_UNIVERSAL_1_1:
287 case SPV_ENV_UNIVERSAL_1_2:
288 case SPV_ENV_UNIVERSAL_1_3:
289 case SPV_ENV_VULKAN_1_1:
290 case SPV_ENV_OPENCL_1_2:
291 case SPV_ENV_OPENCL_EMBEDDED_1_2:
292 case SPV_ENV_OPENCL_2_0:
293 case SPV_ENV_OPENCL_EMBEDDED_2_0:
294 case SPV_ENV_OPENCL_EMBEDDED_2_1:
295 case SPV_ENV_OPENCL_EMBEDDED_2_2:
296 case SPV_ENV_OPENCL_2_1:
297 case SPV_ENV_OPENCL_2_2:
298 case SPV_ENV_UNIVERSAL_1_4:
299 case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
300 case SPV_ENV_UNIVERSAL_1_5:
301 case SPV_ENV_VULKAN_1_2:
302 case SPV_ENV_UNIVERSAL_1_6:
303 case SPV_ENV_VULKAN_1_3:
304 return false;
305 case SPV_ENV_OPENGL_4_0:
306 case SPV_ENV_OPENGL_4_1:
307 case SPV_ENV_OPENGL_4_2:
308 case SPV_ENV_OPENGL_4_3:
309 case SPV_ENV_OPENGL_4_5:
310 return true;
311 case SPV_ENV_WEBGPU_0:
312 assert(false && "Deprecated target environment value.");
313 break;
314 case SPV_ENV_MAX:
315 assert(false && "Invalid target environment value.");
316 break;
317 }
318 return false;
319 }
320
spvIsValidEnv(spv_target_env env)321 bool spvIsValidEnv(spv_target_env env) {
322 switch (env) {
323 case SPV_ENV_UNIVERSAL_1_0:
324 case SPV_ENV_VULKAN_1_0:
325 case SPV_ENV_UNIVERSAL_1_1:
326 case SPV_ENV_UNIVERSAL_1_2:
327 case SPV_ENV_UNIVERSAL_1_3:
328 case SPV_ENV_VULKAN_1_1:
329 case SPV_ENV_OPENCL_1_2:
330 case SPV_ENV_OPENCL_EMBEDDED_1_2:
331 case SPV_ENV_OPENCL_2_0:
332 case SPV_ENV_OPENCL_EMBEDDED_2_0:
333 case SPV_ENV_OPENCL_EMBEDDED_2_1:
334 case SPV_ENV_OPENCL_EMBEDDED_2_2:
335 case SPV_ENV_OPENCL_2_1:
336 case SPV_ENV_OPENCL_2_2:
337 case SPV_ENV_UNIVERSAL_1_4:
338 case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
339 case SPV_ENV_UNIVERSAL_1_5:
340 case SPV_ENV_VULKAN_1_2:
341 case SPV_ENV_UNIVERSAL_1_6:
342 case SPV_ENV_VULKAN_1_3:
343 case SPV_ENV_OPENGL_4_0:
344 case SPV_ENV_OPENGL_4_1:
345 case SPV_ENV_OPENGL_4_2:
346 case SPV_ENV_OPENGL_4_3:
347 case SPV_ENV_OPENGL_4_5:
348 return true;
349 case SPV_ENV_WEBGPU_0:
350 case SPV_ENV_MAX:
351 break;
352 }
353 return false;
354 }
355
spvLogStringForEnv(spv_target_env env)356 std::string spvLogStringForEnv(spv_target_env env) {
357 switch (env) {
358 case SPV_ENV_OPENCL_1_2:
359 case SPV_ENV_OPENCL_2_0:
360 case SPV_ENV_OPENCL_2_1:
361 case SPV_ENV_OPENCL_2_2:
362 case SPV_ENV_OPENCL_EMBEDDED_1_2:
363 case SPV_ENV_OPENCL_EMBEDDED_2_0:
364 case SPV_ENV_OPENCL_EMBEDDED_2_1:
365 case SPV_ENV_OPENCL_EMBEDDED_2_2: {
366 return "OpenCL";
367 }
368 case SPV_ENV_OPENGL_4_0:
369 case SPV_ENV_OPENGL_4_1:
370 case SPV_ENV_OPENGL_4_2:
371 case SPV_ENV_OPENGL_4_3:
372 case SPV_ENV_OPENGL_4_5: {
373 return "OpenGL";
374 }
375 case SPV_ENV_VULKAN_1_0:
376 case SPV_ENV_VULKAN_1_1:
377 case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
378 case SPV_ENV_VULKAN_1_2:
379 case SPV_ENV_VULKAN_1_3: {
380 return "Vulkan";
381 }
382 case SPV_ENV_UNIVERSAL_1_0:
383 case SPV_ENV_UNIVERSAL_1_1:
384 case SPV_ENV_UNIVERSAL_1_2:
385 case SPV_ENV_UNIVERSAL_1_3:
386 case SPV_ENV_UNIVERSAL_1_4:
387 case SPV_ENV_UNIVERSAL_1_5:
388 case SPV_ENV_UNIVERSAL_1_6: {
389 return "Universal";
390 }
391 case SPV_ENV_WEBGPU_0:
392 assert(false && "Deprecated target environment value.");
393 break;
394 case SPV_ENV_MAX:
395 assert(false && "Invalid target environment value.");
396 break;
397 }
398 return "Unknown";
399 }
400
spvTargetEnvList(const int pad,const int wrap)401 std::string spvTargetEnvList(const int pad, const int wrap) {
402 std::string ret;
403 size_t max_line_len = wrap - pad; // The first line isn't padded
404 std::string line;
405 std::string sep = "";
406
407 for (auto& name_env : spvTargetEnvNameMap) {
408 std::string word = sep + name_env.first;
409 if (line.length() + word.length() > max_line_len) {
410 // Adding one word wouldn't fit, commit the line in progress and
411 // start a new one.
412 ret += line + "\n";
413 line.assign(pad, ' ');
414 // The first line is done. The max length now comprises the
415 // padding.
416 max_line_len = wrap;
417 }
418 line += word;
419 sep = "|";
420 }
421
422 ret += line;
423
424 return ret;
425 }
426