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