• 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 <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