1 /*
2   Copyright (c) 2019-2021, Intel Corporation
3   All rights reserved.
4 
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions are
7   met:
8 
9     * Redistributions of source code must retain the above copyright
10       notice, this list of conditions and the following disclaimer.
11 
12     * Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in the
14       documentation and/or other materials provided with the distribution.
15 
16     * Neither the name of Intel Corporation nor the names of its
17       contributors may be used to endorse or promote products derived from
18       this software without specific prior written permission.
19 
20 
21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 /** @file target_enums.cpp
35     @brief Define enums describing target platform.
36 */
37 
38 #include "target_enums.h"
39 
40 #include "ispc.h"
41 #include "util.h"
42 
43 #include <cstring>
44 
45 namespace ispc {
46 
ParseArch(std::string arch)47 Arch ParseArch(std::string arch) {
48     if (arch == "x86") {
49         return Arch::x86;
50     } else if (arch == "x86_64" || arch == "x86-64") {
51         return Arch::x86_64;
52     } else if (arch == "arm") {
53         return Arch::arm;
54     } else if (arch == "aarch64") {
55         return Arch::aarch64;
56     } else if (arch == "wasm32") {
57         return Arch::wasm32;
58     } else if (arch == "genx32") {
59         return Arch::genx32;
60     } else if (arch == "genx64") {
61         return Arch::genx64;
62     }
63     return Arch::error;
64 }
65 
ArchToString(Arch arch)66 std::string ArchToString(Arch arch) {
67     switch (arch) {
68     case Arch::none:
69         return "none";
70     case Arch::x86:
71         return "x86";
72     case Arch::x86_64:
73         return "x86-64";
74     case Arch::arm:
75         return "arm";
76     case Arch::aarch64:
77         return "aarch64";
78     case Arch::wasm32:
79         return "wasm32";
80     case Arch::genx32:
81         return "genx32";
82     case Arch::genx64:
83         return "genx64";
84     case Arch::error:
85         return "error";
86     default:
87         // none and error are not supposed to be printed.
88         Error(SourcePos(), "Invalid arch is processed");
89         exit(1);
90     }
91     return "error";
92 }
93 
ParseISPCTarget(std::string target)94 ISPCTarget ParseISPCTarget(std::string target) {
95     // TODO: ensure skx-i32x8 is not enabled and linked for earli LLVM version.
96 
97     // The first matching string for each target is the canonical way to name the target,
98     // all other strings are aliases.
99     if (target == "host") {
100         return ISPCTarget::host;
101     } else if (target == "sse2-i32x4" || target == "sse2") {
102         return ISPCTarget::sse2_i32x4;
103     } else if (target == "sse2-i32x8" || target == "sse2-x2") {
104         return ISPCTarget::sse2_i32x8;
105     } else if (target == "sse4-i8x16") {
106         return ISPCTarget::sse4_i8x16;
107     } else if (target == "sse4-i16x8") {
108         return ISPCTarget::sse4_i16x8;
109     } else if (target == "sse4-i32x4" || target == "sse4") {
110         return ISPCTarget::sse4_i32x4;
111     } else if (target == "sse4-i32x8" || target == "sse4-x2" || target == "sse4x2") {
112         return ISPCTarget::sse4_i32x8;
113     } else if (target == "avx1-i32x4") {
114         return ISPCTarget::avx1_i32x4;
115     } else if (target == "avx1-i32x8" || target == "avx" || target == "avx1") {
116         return ISPCTarget::avx1_i32x8;
117     } else if (target == "avx1-i64x4" || target == "avx-i64x4") {
118         return ISPCTarget::avx1_i64x4;
119     } else if (target == "avx1-i32x16" || target == "avx-x2" || target == "avx1-x2") {
120         return ISPCTarget::avx1_i32x16;
121     } else if (target == "avx2-i8x32") {
122         return ISPCTarget::avx2_i8x32;
123     } else if (target == "avx2-i16x16") {
124         return ISPCTarget::avx2_i16x16;
125     } else if (target == "avx2-i32x4") {
126         return ISPCTarget::avx2_i32x4;
127     } else if (target == "avx2-i32x8" || target == "avx2") {
128         return ISPCTarget::avx2_i32x8;
129     } else if (target == "avx2-i64x4") {
130         return ISPCTarget::avx2_i64x4;
131     } else if (target == "avx2-i32x16" || target == "avx2-x2") {
132         return ISPCTarget::avx2_i32x16;
133     } else if (target == "avx512knl-i32x16") {
134         return ISPCTarget::avx512knl_i32x16;
135     } else if (target == "avx512skx-i32x16") {
136         return ISPCTarget::avx512skx_i32x16;
137     } else if (target == "avx512skx-i32x8") {
138         return ISPCTarget::avx512skx_i32x8;
139     } else if (target == "avx512skx-i8x64") {
140         return ISPCTarget::avx512skx_i8x64;
141     } else if (target == "avx512skx-i16x32") {
142         return ISPCTarget::avx512skx_i16x32;
143     } else if (target == "neon-i8x16") {
144         return ISPCTarget::neon_i8x16;
145     } else if (target == "neon-i16x8") {
146         return ISPCTarget::neon_i8x16;
147     } else if (target == "neon-i32x4" || target == "neon") {
148         return ISPCTarget::neon_i32x4;
149     } else if (target == "neon-i32x8") {
150         return ISPCTarget::neon_i32x8;
151     } else if (target == "wasm-i32x4") {
152         return ISPCTarget::wasm_i32x4;
153     } else if (target == "genx-x8") {
154         return ISPCTarget::genx_x8;
155     } else if (target == "genx-x16" || target == "genx") {
156         return ISPCTarget::genx_x16;
157     }
158 
159     return ISPCTarget::error;
160 }
161 
162 // Given a comma-delimited string with one or more compilation targets of
163 // the form "sse4-i32x4,avx2-i32x8", return a pair. First element of the pair is a vector
164 // of correctly parsed targets, second element of the pair is a strings with targets, which
165 // were not recognized.
ParseISPCTargets(const char * target)166 std::pair<std::vector<ISPCTarget>, std::string> ParseISPCTargets(const char *target) {
167     std::vector<ISPCTarget> targets;
168     std::string error_target;
169     const char *tstart = target;
170     bool done = false;
171     while (!done) {
172         const char *tend = strchr(tstart, ',');
173         if (tend == NULL) {
174             done = true;
175             tend = strchr(tstart, '\0');
176         }
177         std::string target_string = std::string(tstart, tend);
178         ISPCTarget target_parsed = ParseISPCTarget(target_string);
179         if (target_parsed == ISPCTarget::error) {
180             if (!error_target.empty()) {
181                 error_target += ",";
182             }
183             error_target += target_string;
184         } else {
185             targets.push_back(target_parsed);
186         }
187         tstart = tend + 1;
188     }
189     return std::make_pair(targets, error_target);
190 }
191 
ISPCTargetToString(ISPCTarget target)192 std::string ISPCTargetToString(ISPCTarget target) {
193     switch (target) {
194     case ISPCTarget::host:
195         return "host";
196     case ISPCTarget::sse2_i32x4:
197         return "sse2-i32x4";
198     case ISPCTarget::sse2_i32x8:
199         return "sse2-i32x8";
200     case ISPCTarget::sse4_i8x16:
201         return "sse4-i8x16";
202     case ISPCTarget::sse4_i16x8:
203         return "sse4-i16x8";
204     case ISPCTarget::sse4_i32x4:
205         return "sse4-i32x4";
206     case ISPCTarget::sse4_i32x8:
207         return "sse4-i32x8";
208     case ISPCTarget::avx1_i32x4:
209         return "avx1-i32x4";
210     case ISPCTarget::avx1_i32x8:
211         return "avx1-i32x8";
212     case ISPCTarget::avx1_i32x16:
213         return "avx1-i32x16";
214     case ISPCTarget::avx1_i64x4:
215         return "avx1-i64x4";
216     case ISPCTarget::avx2_i8x32:
217         return "avx2-i8x32";
218     case ISPCTarget::avx2_i16x16:
219         return "avx2-i16x16";
220     case ISPCTarget::avx2_i32x4:
221         return "avx2-i32x4";
222     case ISPCTarget::avx2_i32x8:
223         return "avx2-i32x8";
224     case ISPCTarget::avx2_i32x16:
225         return "avx2-i32x16";
226     case ISPCTarget::avx2_i64x4:
227         return "avx2-i64x4";
228     case ISPCTarget::avx512knl_i32x16:
229         return "avx512knl-i32x16";
230     case ISPCTarget::avx512skx_i32x8:
231         return "avx512skx-i32x8";
232     case ISPCTarget::avx512skx_i32x16:
233         return "avx512skx-i32x16";
234     case ISPCTarget::avx512skx_i8x64:
235         return "avx512skx-i8x64";
236     case ISPCTarget::avx512skx_i16x32:
237         return "avx512skx-i16x32";
238     case ISPCTarget::neon_i8x16:
239         return "neon-i8x16";
240     case ISPCTarget::neon_i16x8:
241         return "neon-i16x8";
242     case ISPCTarget::neon_i32x4:
243         return "neon-i32x4";
244     case ISPCTarget::neon_i32x8:
245         return "neon-i32x8";
246     case ISPCTarget::wasm_i32x4:
247         return "wasm-i32x4";
248     case ISPCTarget::genx_x8:
249         return "genx-x8";
250     case ISPCTarget::genx_x16:
251         return "genx-x16";
252     case ISPCTarget::none:
253     case ISPCTarget::error:
254         // Fall through
255         ;
256     }
257     Error(SourcePos(), "Invalid ISPCTarget is processed");
258     exit(1);
259 }
260 
ISPCTargetIsX86(ISPCTarget target)261 bool ISPCTargetIsX86(ISPCTarget target) {
262     switch (target) {
263     case ISPCTarget::sse2_i32x4:
264     case ISPCTarget::sse2_i32x8:
265     case ISPCTarget::sse4_i8x16:
266     case ISPCTarget::sse4_i16x8:
267     case ISPCTarget::sse4_i32x4:
268     case ISPCTarget::sse4_i32x8:
269     case ISPCTarget::avx1_i32x4:
270     case ISPCTarget::avx1_i32x8:
271     case ISPCTarget::avx1_i32x16:
272     case ISPCTarget::avx1_i64x4:
273     case ISPCTarget::avx2_i8x32:
274     case ISPCTarget::avx2_i16x16:
275     case ISPCTarget::avx2_i32x4:
276     case ISPCTarget::avx2_i32x8:
277     case ISPCTarget::avx2_i32x16:
278     case ISPCTarget::avx2_i64x4:
279     case ISPCTarget::avx512knl_i32x16:
280     case ISPCTarget::avx512skx_i32x8:
281     case ISPCTarget::avx512skx_i32x16:
282     case ISPCTarget::avx512skx_i8x64:
283     case ISPCTarget::avx512skx_i16x32:
284         return true;
285     default:
286         return false;
287     }
288 }
289 
ISPCTargetIsNeon(ISPCTarget target)290 bool ISPCTargetIsNeon(ISPCTarget target) {
291     switch (target) {
292     case ISPCTarget::neon_i8x16:
293     case ISPCTarget::neon_i16x8:
294     case ISPCTarget::neon_i32x4:
295     case ISPCTarget::neon_i32x8:
296         return true;
297     default:
298         return false;
299     }
300 }
301 
ISPCTargetIsWasm(ISPCTarget target)302 bool ISPCTargetIsWasm(ISPCTarget target) {
303     switch (target) {
304     case ISPCTarget::wasm_i32x4:
305         return true;
306     default:
307         return false;
308     }
309 }
310 
ISPCTargetIsGen(ISPCTarget target)311 bool ISPCTargetIsGen(ISPCTarget target) {
312     switch (target) {
313     case ISPCTarget::genx_x8:
314     case ISPCTarget::genx_x16:
315         return true;
316     default:
317         return false;
318     }
319 }
320 
ParseOS(std::string os)321 TargetOS ParseOS(std::string os) {
322     std::string supportedOses = g->target_registry->getSupportedOSes().c_str();
323     if (supportedOses.find(os) == std::string::npos) {
324         return TargetOS::error;
325     }
326     if (os == "windows") {
327         return TargetOS::windows;
328     } else if (os == "linux") {
329         return TargetOS::linux;
330     } else if (os == "custom_linux") {
331         return TargetOS::custom_linux;
332     } else if (os == "freebsd") {
333         return TargetOS::freebsd;
334     } else if (os == "dragonfly") {
335         return TargetOS::dragonfly;
336     } else if (os == "macos") {
337         return TargetOS::macos;
338     } else if (os == "android") {
339         return TargetOS::android;
340     } else if (os == "ios") {
341         return TargetOS::ios;
342     } else if (os == "ps4") {
343         return TargetOS::ps4;
344     } else if (os == "web") {
345         return TargetOS::web;
346     }
347     return TargetOS::error;
348 }
349 
OSToString(TargetOS os)350 std::string OSToString(TargetOS os) {
351     switch (os) {
352     case TargetOS::windows:
353         return "Windows";
354     case TargetOS::linux:
355         return "Linux";
356     case TargetOS::custom_linux:
357         return "Linux (custom)";
358     case TargetOS::freebsd:
359         return "FreeBSD";
360     case TargetOS::dragonfly:
361         return "DragonFly";
362     case TargetOS::macos:
363         return "macOS";
364     case TargetOS::android:
365         return "Android";
366     case TargetOS::ios:
367         return "iOS";
368     case TargetOS::ps4:
369         return "PS4";
370     case TargetOS::web:
371         return "web";
372     case TargetOS::error:
373         return "error";
374     }
375     UNREACHABLE();
376 }
377 
OSToLowerString(TargetOS os)378 std::string OSToLowerString(TargetOS os) {
379     switch (os) {
380     case TargetOS::windows:
381         return "windows";
382     case TargetOS::linux:
383         return "linux";
384     case TargetOS::custom_linux:
385         return "custom_linux";
386     case TargetOS::freebsd:
387         return "freebsd";
388     case TargetOS::dragonfly:
389         return "dragonfly";
390     case TargetOS::macos:
391         return "macos";
392     case TargetOS::android:
393         return "android";
394     case TargetOS::ios:
395         return "ios";
396     case TargetOS::ps4:
397         return "ps4";
398     case TargetOS::web:
399         return "web";
400     case TargetOS::error:
401         return "error";
402     }
403     UNREACHABLE();
404 }
405 
GetHostOS()406 TargetOS GetHostOS() {
407 #if defined(ISPC_HOST_IS_WINDOWS) && !defined(ISPC_WINDOWS_TARGET_OFF)
408     return TargetOS::windows;
409 #elif defined(ISPC_HOST_IS_LINUX) && !defined(ISPC_LINUX_TARGET_OFF)
410     return TargetOS::linux;
411 #elif defined(ISPC_HOST_IS_FREEBSD) && !defined(ISPC_FREEBSD_TARGET_OFF)
412     return TargetOS::freebsd;
413 #elif defined(ISPC_HOST_IS_DRAGONFLY) && !defined(ISPC_DRAGONFLY_TARGET_OFF)
414     return TargetOS::dragonfly;
415 #elif defined(ISPC_HOST_IS_APPLE) && !defined(ISPC_MACOS_TARGET_OFF)
416     return TargetOS::macos;
417 #else
418     return TargetOS::error;
419 #endif
420 }
421 } // namespace ispc
422