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