1//! All the details about the machine that will be executing code.
2//! Unlike `Query` which might leave some things as "default" or "host", this
3//! data is fully resolved into a concrete set of OS versions, CPU features,
4//! etc.
5
6cpu: Cpu,
7os: Os,
8abi: Abi,
9ofmt: ObjectFormat,
10dynamic_linker: DynamicLinker = DynamicLinker.none,
11
12pub const Query = @import("Target/Query.zig");
13
14pub const Os = struct {
15 tag: Tag,
16 version_range: VersionRange,
17
18 pub const Tag = enum {
19 freestanding,
20 other,
21
22 contiki,
23 fuchsia,
24 hermit,
25 managarm,
26
27 haiku,
28 hurd,
29 illumos,
30 linux,
31 plan9,
32 rtems,
33 serenity,
34
35 dragonfly,
36 freebsd,
37 netbsd,
38 openbsd,
39
40 driverkit,
41 ios,
42 maccatalyst,
43 macos,
44 tvos,
45 visionos,
46 watchos,
47
48 windows,
49 uefi,
50
51 @"3ds",
52 wiiu,
53 @"switch",
54 gba,
55
56 psx,
57 ps3,
58 ps4,
59 ps5,
60 psp,
61 vita,
62
63 emscripten,
64 wasi,
65
66 amdhsa,
67 amdpal,
68 cuda,
69 mesa3d,
70 nvcl,
71 opencl,
72 opengl,
73 vulkan,
74
75 tios,
76
77 ashetos,
78
79 pub inline fn isDarwin(tag: Tag) bool {
80 return switch (tag) {
81 .driverkit,
82 .ios,
83 .maccatalyst,
84 .macos,
85 .tvos,
86 .visionos,
87 .watchos,
88 => true,
89 else => false,
90 };
91 }
92
93 /// Deprecated; to be removed in 0.18.0. Check for relevant tags instead.
94 pub inline fn isBSD(tag: Tag) bool {
95 return tag.isDarwin() or switch (tag) {
96 .freebsd, .openbsd, .netbsd, .dragonfly => true,
97 else => false,
98 };
99 }
100
101 pub fn exeFileExt(tag: Tag, arch: Cpu.Arch) [:0]const u8 {
102 return switch (tag) {
103 .windows => ".exe",
104 .uefi => ".efi",
105 .plan9 => arch.plan9Ext(),
106 else => switch (arch) {
107 .wasm32, .wasm64 => ".wasm",
108 .spork8 => ".bin",
109 else => "",
110 },
111 };
112 }
113
114 pub fn staticLibSuffix(tag: Tag, abi: Abi) [:0]const u8 {
115 return switch (abi) {
116 .msvc, .itanium => ".lib",
117 else => switch (tag) {
118 .windows, .uefi => ".lib",
119 else => ".a",
120 },
121 };
122 }
123
124 pub fn dynamicLibSuffix(tag: Tag) [:0]const u8 {
125 return switch (tag) {
126 .windows, .uefi => ".dll",
127 .driverkit,
128 .ios,
129 .maccatalyst,
130 .macos,
131 .tvos,
132 .visionos,
133 .watchos,
134 => ".dylib",
135 else => ".so",
136 };
137 }
138
139 pub fn libPrefix(tag: Os.Tag, abi: Abi) [:0]const u8 {
140 return switch (abi) {
141 .msvc, .itanium => "",
142 else => switch (tag) {
143 .windows, .uefi => "",
144 else => "lib",
145 },
146 };
147 }
148
149 pub fn defaultVersionRange(tag: Tag, arch: Cpu.Arch, abi: Abi) Os {
150 return .{
151 .tag = tag,
152 .version_range = .default(arch, tag, abi),
153 };
154 }
155
156 pub inline fn versionRangeTag(tag: Tag) @typeInfo(TaggedVersionRange).@"union".tag_type.? {
157 return switch (tag) {
158 .freestanding,
159 .other,
160
161 .managarm,
162
163 .haiku,
164 .illumos,
165 .plan9,
166 .serenity,
167
168 .psx,
169 .ps3,
170 .ps4,
171 .ps5,
172 .gba,
173
174 .emscripten,
175
176 .mesa3d,
177
178 .ashetos,
179 => .none,
180
181 .contiki,
182 .fuchsia,
183 .hermit,
184
185 .rtems,
186
187 .dragonfly,
188 .freebsd,
189 .netbsd,
190 .openbsd,
191
192 .driverkit,
193 .ios,
194 .maccatalyst,
195 .macos,
196 .tvos,
197 .visionos,
198 .watchos,
199
200 .uefi,
201
202 .@"3ds",
203 .wiiu,
204 .@"switch",
205
206 .psp,
207 .vita,
208
209 .wasi,
210
211 .amdhsa,
212 .amdpal,
213 .cuda,
214 .nvcl,
215 .opencl,
216 .opengl,
217 .vulkan,
218
219 .tios,
220 => .semver,
221
222 .hurd => .hurd,
223 .linux => .linux,
224
225 .windows => .windows,
226 };
227 }
228 };
229
230 /// Based on NTDDI version constants from
231 /// https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt
232 pub const WindowsVersion = enum(u32) {
233 nt4 = 0x04000000,
234 win2k = 0x05000000,
235 xp = 0x05010000,
236 ws2003 = 0x05020000,
237 vista = 0x06000000,
238 win7 = 0x06010000,
239 win8 = 0x06020000,
240 win8_1 = 0x06030000,
241 win10 = 0x0A000000, //aka win10_th1
242 win10_th2 = 0x0A000001,
243 win10_rs1 = 0x0A000002,
244 win10_rs2 = 0x0A000003,
245 win10_rs3 = 0x0A000004,
246 win10_rs4 = 0x0A000005,
247 win10_rs5 = 0x0A000006,
248 win10_19h1 = 0x0A000007,
249 win10_vb = 0x0A000008, //aka win10_19h2
250 win10_mn = 0x0A000009, //aka win10_20h1
251 win10_fe = 0x0A00000A, //aka win10_20h2
252 win10_co = 0x0A00000B, //aka win10_21h1
253 win10_ni = 0x0A00000C, //aka win10_21h2
254 win10_cu = 0x0A00000D, //aka win10_22h2
255 win11_zn = 0x0A00000E, //aka win11_21h2
256 win11_ga = 0x0A00000F, //aka win11_22h2
257 win11_ge = 0x0A000010, //aka win11_23h2
258 win11_dt = 0x0A000011, //aka win11_24h2
259 win11_br = 0x0A000012, //aka win11_25h2
260 win11_kr = 0x0A000013, //aka win11_26h1
261 _,
262
263 /// Latest Windows version that the Zig Standard Library is aware of
264 pub const latest = WindowsVersion.win11_kr;
265
266 /// Compared against build numbers reported by the runtime to distinguish win10 versions,
267 /// where 0x0A000000 + index corresponds to the WindowsVersion u32 value.
268 pub const known_win10_build_numbers = [_]u32{
269 10240, //win10 aka win10_th1
270 10586, //win10_th2
271 14393, //win10_rs1
272 15063, //win10_rs2
273 16299, //win10_rs3
274 17134, //win10_rs4
275 17763, //win10_rs5
276 18362, //win10_19h1
277 18363, //win10_vb aka win10_19h2
278 19041, //win10_mn aka win10_20h1
279 19042, //win10_fe aka win10_20h2
280 19043, //win10_co aka win10_21h1
281 19044, //win10_ni aka win10_21h2
282 19045, //win10_cu aka win10_22h2
283 22000, //win11_zn aka win11_21h2
284 22621, //win11_ga aka win11_22h2
285 22631, //win11_ge aka win11_23h2
286 26100, //win11_dt aka win11_24h2
287 26200, //win11_br aka win11_25h2
288 28000, //win11_kr aka win11_26h1
289 };
290
291 /// Returns whether the first version `ver` is newer (greater) than or equal to the second version `ver`.
292 pub inline fn isAtLeast(ver: WindowsVersion, min_ver: WindowsVersion) bool {
293 return @backingInt(ver) >= @backingInt(min_ver);
294 }
295
296 pub const Range = struct {
297 min: WindowsVersion,
298 max: WindowsVersion,
299
300 pub inline fn includesVersion(range: Range, ver: WindowsVersion) bool {
301 return @backingInt(ver) >= @backingInt(range.min) and
302 @backingInt(ver) <= @backingInt(range.max);
303 }
304
305 /// Checks if system is guaranteed to be at least `version` or older than `version`.
306 /// Returns `null` if a runtime check is required.
307 pub inline fn isAtLeast(range: Range, min_ver: WindowsVersion) ?bool {
308 if (@backingInt(range.min) >= @backingInt(min_ver)) return true;
309 if (@backingInt(range.max) < @backingInt(min_ver)) return false;
310 return null;
311 }
312 };
313
314 pub fn parse(str: []const u8) !WindowsVersion {
315 return std.meta.stringToEnum(WindowsVersion, str) orelse
316 @fromBackingInt(@intCast(std.fmt.parseInt(u32, str, 0) catch
317 return error.InvalidOperatingSystemVersion));
318 }
319
320 /// This function is defined to serialize a Zig source code representation of this
321 /// type, that, when parsed, will deserialize into the same data.
322 pub fn format(wv: WindowsVersion, w: *std.Io.Writer) std.Io.Writer.Error!void {
323 if (std.enums.tagName(WindowsVersion, wv)) |name| {
324 var vecs: [2][]const u8 = .{ ".", name };
325 return w.writeVecAll(&vecs);
326 } else {
327 return w.print("@enumFromInt(0x{X:0>8})", .{wv});
328 }
329 }
330 };
331
332 pub const HurdVersionRange = struct {
333 range: std.SemanticVersion.Range,
334 glibc: std.SemanticVersion,
335
336 pub inline fn includesVersion(range: HurdVersionRange, ver: std.SemanticVersion) bool {
337 return range.range.includesVersion(ver);
338 }
339
340 /// Checks if system is guaranteed to be at least `version` or older than `version`.
341 /// Returns `null` if a runtime check is required.
342 pub inline fn isAtLeast(range: HurdVersionRange, ver: std.SemanticVersion) ?bool {
343 return range.range.isAtLeast(ver);
344 }
345 };
346
347 pub const LinuxVersionRange = struct {
348 range: std.SemanticVersion.Range,
349 glibc: std.SemanticVersion,
350 /// Android API level.
351 android: u32,
352
353 pub inline fn includesVersion(range: LinuxVersionRange, ver: std.SemanticVersion) bool {
354 return range.range.includesVersion(ver);
355 }
356
357 /// Checks if system is guaranteed to be at least `version` or older than `version`.
358 /// Returns `null` if a runtime check is required.
359 pub inline fn isAtLeast(range: LinuxVersionRange, ver: std.SemanticVersion) ?bool {
360 return range.range.isAtLeast(ver);
361 }
362 };
363
364 /// The version ranges here represent the minimum OS version to be supported
365 /// and the maximum OS version to be supported. The default values represent
366 /// the range that the Zig Standard Library bases its abstractions on.
367 ///
368 /// The minimum version of the range is the main setting to tweak for a target.
369 /// Usually, the maximum target OS version will remain the default, which is
370 /// the latest released version of the OS.
371 ///
372 /// To test at compile time if the target is guaranteed to support a given OS feature,
373 /// one should check that the minimum version of the range is greater than or equal to
374 /// the version the feature was introduced in.
375 ///
376 /// To test at compile time if the target certainly will not support a given OS feature,
377 /// one should check that the maximum version of the range is less than the version the
378 /// feature was introduced in.
379 ///
380 /// If neither of these cases apply, a runtime check should be used to determine if the
381 /// target supports a given OS feature.
382 ///
383 /// Binaries built with a given maximum version will continue to function on newer
384 /// operating system versions. However, such a binary may not take full advantage of the
385 /// newer operating system APIs.
386 ///
387 /// See `Os.isAtLeast`.
388 pub const VersionRange = union {
389 none: void,
390 semver: std.SemanticVersion.Range,
391 hurd: HurdVersionRange,
392 linux: LinuxVersionRange,
393 windows: WindowsVersion.Range,
394
395 /// The default `VersionRange` represents the range that the Zig Standard Library
396 /// bases its abstractions on.
397 pub fn default(arch: Cpu.Arch, tag: Tag, abi: Abi) VersionRange {
398 return switch (tag) {
399 .freestanding,
400 .other,
401
402 .managarm,
403
404 .haiku,
405 .illumos,
406 .plan9,
407 .serenity,
408
409 .psx,
410 .ps3,
411 .ps4,
412 .ps5,
413 .gba,
414
415 .emscripten,
416
417 .mesa3d,
418
419 .ashetos,
420 => .{ .none = {} },
421
422 .contiki => .{
423 .semver = .{
424 .min = .{ .major = 5, .minor = 0, .patch = 0 },
425 .max = .{ .major = 5, .minor = 1, .patch = 0 },
426 },
427 },
428 .fuchsia => .{
429 .semver = .{
430 .min = .{ .major = 27, .minor = 0, .patch = 0 },
431 .max = .{ .major = 30, .minor = 0, .patch = 0 },
432 },
433 },
434 .hermit => .{
435 .semver = .{
436 .min = .{ .major = 0, .minor = 8, .patch = 0 },
437 .max = .{ .major = 0, .minor = 13, .patch = 2 },
438 },
439 },
440
441 .hurd => .{
442 .hurd = .{
443 .range = .{
444 .min = .{ .major = 0, .minor = 9, .patch = 0 },
445 .max = .{ .major = 0, .minor = 9, .patch = 0 },
446 },
447 .glibc = .{ .major = 2, .minor = 31, .patch = 0 },
448 },
449 },
450 .linux => .{
451 .linux = .{
452 .range = .{
453 .min = blk: {
454 const default_min: std.SemanticVersion = .{ .major = 5, .minor = 10, .patch = 0 };
455
456 for (std.zig.target.available_libcs) |libc| {
457 if (libc.arch != arch or libc.os != tag or libc.abi != abi) continue;
458
459 if (libc.os_ver) |min| {
460 if (min.order(default_min) == .gt) break :blk min;
461 }
462 }
463
464 break :blk default_min;
465 },
466 .max = .{ .major = 7, .minor = 2, .patch = 0 },
467 },
468 .glibc = blk: {
469 // For 32-bit targets that traditionally used 32-bit time, we require
470 // glibc 2.34 for full 64-bit time support. For everything else, we only
471 // require glibc 2.31.
472 const default_min: std.SemanticVersion = switch (arch) {
473 .arm,
474 .armeb,
475 .csky,
476 .m68k,
477 .mips,
478 .mipsel,
479 .powerpc,
480 .sparc,
481 .x86,
482 => .{ .major = 2, .minor = 34, .patch = 0 },
483 .mips64,
484 .mips64el,
485 => if (abi == .gnuabin32)
486 .{ .major = 2, .minor = 34, .patch = 0 }
487 else
488 .{ .major = 2, .minor = 31, .patch = 0 },
489 else => .{ .major = 2, .minor = 31, .patch = 0 },
490 };
491
492 for (std.zig.target.available_libcs) |libc| {
493 if (libc.os != tag or libc.arch != arch or libc.abi != abi) continue;
494
495 if (libc.glibc_min) |min| {
496 if (min.order(default_min) == .gt) break :blk min;
497 }
498 }
499
500 break :blk default_min;
501 },
502 .android = 29,
503 },
504 },
505 .rtems => .{
506 .semver = .{
507 .min = .{ .major = 5, .minor = 3, .patch = 0 },
508 .max = .{ .major = 6, .minor = 2, .patch = 0 },
509 },
510 },
511
512 .dragonfly => .{
513 .semver = .{
514 .min = .{ .major = 6, .minor = 4, .patch = 0 },
515 .max = .{ .major = 6, .minor = 4, .patch = 2 },
516 },
517 },
518 .freebsd => .{
519 .semver = .{
520 .min = blk: {
521 const default_min: std.SemanticVersion = .{ .major = 14, .minor = 0, .patch = 0 };
522
523 for (std.zig.target.available_libcs) |libc| {
524 if (libc.arch != arch or libc.os != tag or libc.abi != abi) continue;
525
526 if (libc.os_ver) |min| {
527 if (min.order(default_min) == .gt) break :blk min;
528 }
529 }
530
531 break :blk default_min;
532 },
533 .max = .{ .major = 15, .minor = 1, .patch = 0 },
534 },
535 },
536 .netbsd => .{
537 .semver = .{
538 .min = blk: {
539 const default_min: std.SemanticVersion = .{ .major = 10, .minor = 1, .patch = 0 };
540
541 for (std.zig.target.available_libcs) |libc| {
542 if (libc.arch != arch or libc.os != tag or libc.abi != abi) continue;
543
544 if (libc.os_ver) |min| {
545 if (min.order(default_min) == .gt) break :blk min;
546 }
547 }
548
549 break :blk default_min;
550 },
551 .max = .{ .major = 11, .minor = 0, .patch = 0 },
552 },
553 },
554 .openbsd => .{
555 .semver = .{
556 .min = blk: {
557 const default_min: std.SemanticVersion = .{ .major = 7, .minor = 8, .patch = 0 };
558
559 for (std.zig.target.available_libcs) |libc| {
560 if (libc.arch != arch or libc.os != tag or libc.abi != abi) continue;
561
562 if (libc.os_ver) |min| {
563 if (min.order(default_min) == .gt) break :blk min;
564 }
565 }
566
567 break :blk default_min;
568 },
569 .max = .{ .major = 7, .minor = 9, .patch = 0 },
570 },
571 },
572
573 .driverkit => .{
574 .semver = .{
575 .min = .{ .major = 20, .minor = 0, .patch = 0 },
576 .max = .{ .major = 25, .minor = 5, .patch = 0 },
577 },
578 },
579 .macos => .{
580 .semver = .{
581 .min = .{ .major = 14, .minor = 0, .patch = 0 },
582 .max = .{ .major = 26, .minor = 5, .patch = 0 },
583 },
584 },
585 .ios, .maccatalyst => .{
586 .semver = .{
587 .min = .{ .major = 15, .minor = 0, .patch = 0 },
588 .max = .{ .major = 26, .minor = 5, .patch = 0 },
589 },
590 },
591 .tvos => .{
592 .semver = .{
593 .min = .{ .major = 26, .minor = 0, .patch = 0 },
594 .max = .{ .major = 26, .minor = 5, .patch = 0 },
595 },
596 },
597 .visionos => .{
598 .semver = .{
599 .min = .{ .major = 26, .minor = 0, .patch = 0 },
600 .max = .{ .major = 26, .minor = 5, .patch = 0 },
601 },
602 },
603 .watchos => .{
604 .semver = .{
605 .min = .{ .major = 11, .minor = 0, .patch = 0 },
606 .max = .{ .major = 26, .minor = 5, .patch = 0 },
607 },
608 },
609
610 .windows => .{
611 .windows = .{
612 .min = .win10,
613 .max = WindowsVersion.latest,
614 },
615 },
616 .uefi => .{
617 .semver = .{
618 .min = .{ .major = 2, .minor = 0, .patch = 0 },
619 .max = .{ .major = 2, .minor = 11, .patch = 0 },
620 },
621 },
622
623 .@"3ds" => .{
624 .semver = .{
625 // These signify release versions (https://www.3dbrew.org/wiki/NCCH/Extended_Header#ARM11_Kernel_Capabilities)
626 // which are different from user-facing system versions (https://www.3dbrew.org/wiki/Home_Menu#System_Versions_List).
627 //
628 // Multiple system versions could refer to the same release version.
629 // The comment indicates the system version that release version was introduced (for minimum) and the latest (for maximum).
630 .min = .{ .major = 2, .minor = 27, .patch = 0 }, // 1.0.0-0
631 .max = .{ .major = 2, .minor = 58, .patch = 0 }, // 11.17.0-50
632 },
633 },
634
635 .wiiu => .{
636 .semver = .{
637 .min = .{ .major = 5, .minor = 5, .patch = 5 }, // Latest global release
638 .max = .{ .major = 5, .minor = 5, .patch = 6 }, // Latest US only release
639 },
640 },
641
642 .@"switch" => .{
643 .semver = .{
644 .min = .{ .major = 1, .minor = 0, .patch = 0 },
645 .max = .{ .major = 22, .minor = 5, .patch = 0 },
646 },
647 },
648
649 .psp => .{
650 .semver = .{
651 // https://www.psdevwiki.com/psp/Official_Firmware_(OFW)#1.XX_Kernel
652 // It appears that the kernel started with semver for 1.XX before later changing to MAJ.MINPATCH in later releases (e.g. 3.60, 6.61)
653 .min = .{ .major = 1, .minor = 0, .patch = 3 },
654 .max = .{ .major = 6, .minor = 61, .patch = 0 },
655 },
656 },
657
658 .vita => .{
659 .semver = .{
660 // 1.3 is the first public release
661 .min = .{ .major = 1, .minor = 3, .patch = 0 },
662 .max = .{ .major = 3, .minor = 60, .patch = 0 },
663 },
664 },
665
666 .wasi => .{
667 .semver = .{
668 .min = .{ .major = 0, .minor = 1, .patch = 0 },
669 .max = .{ .major = 0, .minor = 3, .patch = 0 },
670 },
671 },
672
673 .amdhsa => .{
674 .semver = .{
675 .min = .{ .major = 6, .minor = 1, .patch = 0 },
676 .max = .{ .major = 7, .minor = 2, .patch = 3 },
677 },
678 },
679 .amdpal => .{
680 .semver = .{
681 .min = .{ .major = 1, .minor = 1, .patch = 0 },
682 .max = .{ .major = 3, .minor = 5, .patch = 0 },
683 },
684 },
685 .cuda => .{
686 .semver = .{
687 .min = .{ .major = 12, .minor = 5, .patch = 0 },
688 .max = .{ .major = 13, .minor = 2, .patch = 0 },
689 },
690 },
691 .nvcl,
692 .opencl,
693 => .{
694 .semver = .{
695 .min = .{ .major = 2, .minor = 2, .patch = 0 },
696 .max = .{ .major = 3, .minor = 0, .patch = 19 },
697 },
698 },
699 .opengl => .{
700 .semver = .{
701 .min = .{ .major = 4, .minor = 5, .patch = 0 },
702 .max = .{ .major = 4, .minor = 6, .patch = 0 },
703 },
704 },
705 .tios => .{
706 .semver = .{
707 .min = .{ .major = 5, .minor = 0, .patch = 0 },
708 .max = .{ .major = 5, .minor = 8, .patch = 4 },
709 },
710 },
711 .vulkan => .{
712 .semver = .{
713 .min = .{ .major = 1, .minor = 2, .patch = 0 },
714 .max = .{ .major = 1, .minor = 4, .patch = 352 },
715 },
716 },
717 };
718 }
719 };
720
721 pub const TaggedVersionRange = union(enum) {
722 none: void,
723 semver: std.SemanticVersion.Range,
724 hurd: HurdVersionRange,
725 linux: LinuxVersionRange,
726 windows: WindowsVersion.Range,
727
728 pub fn gnuLibCVersion(range: TaggedVersionRange) ?std.SemanticVersion {
729 return switch (range) {
730 .none, .semver, .windows => null,
731 .hurd => |h| h.glibc,
732 .linux => |l| l.glibc,
733 };
734 }
735 };
736
737 /// Provides a tagged union. `Target` does not store the tag because it is
738 /// redundant with the OS tag; this function abstracts that part away.
739 pub inline fn versionRange(os: Os) TaggedVersionRange {
740 return switch (os.tag.versionRangeTag()) {
741 .none => .{ .none = {} },
742 .semver => .{ .semver = os.version_range.semver },
743 .hurd => .{ .hurd = os.version_range.hurd },
744 .linux => .{ .linux = os.version_range.linux },
745 .windows => .{ .windows = os.version_range.windows },
746 };
747 }
748
749 /// Checks if system is guaranteed to be at least `version` or older than `version`.
750 /// Returns `null` if a runtime check is required.
751 pub inline fn isAtLeast(os: Os, comptime tag: Tag, ver: switch (tag.versionRangeTag()) {
752 .none => void,
753 .semver, .hurd, .linux => std.SemanticVersion,
754 .windows => WindowsVersion,
755 }) ?bool {
756 return if (os.tag != tag) false else switch (tag.versionRangeTag()) {
757 .none => true,
758 inline .semver,
759 .hurd,
760 .linux,
761 .windows,
762 => |field| @field(os.version_range, @tagName(field)).isAtLeast(ver),
763 };
764 }
765};
766
767pub const aarch64 = @import("Target/aarch64.zig");
768pub const alpha = @import("Target/alpha.zig");
769pub const amdgcn = @import("Target/amdgcn.zig");
770pub const arc = @import("Target/arc.zig");
771pub const arm = @import("Target/arm.zig");
772pub const avr = @import("Target/avr.zig");
773pub const bpf = @import("Target/bpf.zig");
774pub const csky = @import("Target/csky.zig");
775pub const hexagon = @import("Target/hexagon.zig");
776pub const hppa = @import("Target/hppa.zig");
777pub const kalimba = @import("Target/generic.zig");
778pub const kvx = @import("Target/kvx.zig");
779pub const lanai = @import("Target/lanai.zig");
780pub const loongarch = @import("Target/loongarch.zig");
781pub const m68k = @import("Target/m68k.zig");
782pub const m88k = @import("Target/generic.zig");
783pub const microblaze = @import("Target/generic.zig");
784pub const mips = @import("Target/mips.zig");
785pub const msp430 = @import("Target/msp430.zig");
786pub const nvptx = @import("Target/nvptx.zig");
787pub const or1k = @import("Target/generic.zig");
788pub const powerpc = @import("Target/powerpc.zig");
789pub const propeller = @import("Target/propeller.zig");
790pub const riscv = @import("Target/riscv.zig");
791pub const s390x = @import("Target/s390x.zig");
792pub const sh = @import("Target/generic.zig");
793pub const sparc = @import("Target/sparc.zig");
794pub const spirv = @import("Target/spirv.zig");
795pub const spork8 = @import("Target/generic.zig");
796pub const ve = @import("Target/ve.zig");
797pub const wasm = @import("Target/wasm.zig");
798pub const x86 = @import("Target/x86.zig");
799pub const xcore = @import("Target/xcore.zig");
800pub const xtensa = @import("Target/xtensa.zig");
801pub const z80 = @import("Target/generic.zig");
802
803pub const Abi = enum {
804 none,
805 gnu,
806 gnuabin32,
807 gnuabi64,
808 gnueabi,
809 gnueabihf,
810 gnuf32,
811 gnusf,
812 gnux32,
813 eabi,
814 eabihf,
815 abin32,
816 x32,
817 ilp32,
818 android,
819 androideabi,
820 musl,
821 muslabin32,
822 muslabi64,
823 musleabi,
824 musleabihf,
825 muslf32,
826 muslsf,
827 muslx32,
828 msvc,
829 itanium,
830 simulator,
831 ohos,
832 ohoseabi,
833 call0,
834
835 pub fn default(arch: Cpu.Arch, os_tag: Os.Tag) Abi {
836 return switch (os_tag) {
837 .freestanding, .other => switch (arch) {
838 // Soft float is usually a sane default for freestanding.
839 .arm,
840 .armeb,
841 .csky,
842 .hppa,
843 .mips,
844 .mipsel,
845 .powerpc,
846 .powerpcle,
847 .sh,
848 .sheb,
849 .thumb,
850 .thumbeb,
851 => .eabi,
852 else => .none,
853 },
854 .fuchsia => switch (arch) {
855 .arm,
856 .thumb,
857 => .eabihf,
858 else => .none,
859 },
860 .haiku => switch (arch) {
861 .arm => .eabihf,
862 else => .none,
863 },
864 .hurd => .gnu,
865 .linux => switch (arch) {
866 .arm,
867 .armeb,
868 .powerpc,
869 .powerpcle,
870 .thumb,
871 .thumbeb,
872 => .musleabihf,
873 .mips,
874 .mipsel,
875 => .musleabi,
876 .mips64,
877 .mips64el,
878 => .muslabi64,
879
880 // No musl support.
881 .alpha,
882 .arc,
883 .arceb,
884 .or1k,
885 .sparc,
886 .sparc64,
887 => .gnu,
888 .csky,
889 => .gnueabi,
890 .hppa,
891 .sh,
892 .sheb,
893 => .gnueabihf,
894
895 // No glibc or musl support.
896 .xtensa,
897 .xtensaeb,
898 => .none,
899
900 else => .musl,
901 },
902 .rtems => switch (arch) {
903 .arm,
904 .armeb,
905 .thumb,
906 .thumbeb,
907 .mips,
908 .mipsel,
909 => .eabi,
910 .powerpc,
911 => .eabihf,
912 else => .none,
913 },
914 .freebsd => switch (arch) {
915 .arm,
916 => .eabihf,
917 else => .none,
918 },
919 .netbsd => switch (arch) {
920 .arm,
921 .armeb,
922 .powerpc,
923 => .eabihf,
924 // Soft float tends to be more common for MIPS.
925 .mips,
926 .mipsel,
927 => .eabi,
928 else => .none,
929 },
930 .openbsd => switch (arch) {
931 .arm,
932 => .eabi,
933 .powerpc,
934 => .eabihf,
935 else => .none,
936 },
937 .windows => .gnu,
938 .uefi => .msvc,
939 .@"3ds" => .eabihf,
940 .wiiu => .eabihf,
941 .gba => .eabi,
942 .psx => .eabi,
943 .psp => .eabihf,
944 .vita => .eabihf,
945 .wasi, .emscripten => .musl,
946
947 .ashetos => .eabi,
948
949 .contiki,
950 .hermit,
951 .illumos,
952 .managarm,
953 .plan9,
954 .serenity,
955 .dragonfly,
956 .driverkit,
957 .ios,
958 .maccatalyst,
959 .macos,
960 .tvos,
961 .visionos,
962 .watchos,
963 .@"switch",
964 .ps3,
965 .ps4,
966 .ps5,
967 .amdhsa,
968 .amdpal,
969 .cuda,
970 .mesa3d,
971 .nvcl,
972 .opencl,
973 .opengl,
974 .vulkan,
975 .tios,
976 => .none,
977 };
978 }
979
980 pub inline fn isGnu(abi: Abi) bool {
981 return switch (abi) {
982 .gnu,
983 .gnuabin32,
984 .gnuabi64,
985 .gnueabi,
986 .gnueabihf,
987 .gnuf32,
988 .gnusf,
989 .gnux32,
990 => true,
991 else => false,
992 };
993 }
994
995 pub inline fn isMusl(abi: Abi) bool {
996 return switch (abi) {
997 .musl,
998 .muslabin32,
999 .muslabi64,
1000 .musleabi,
1001 .musleabihf,
1002 .muslf32,
1003 .muslsf,
1004 .muslx32,
1005 => true,
1006 else => abi.isOpenHarmony(),
1007 };
1008 }
1009
1010 pub inline fn isOpenHarmony(abi: Abi) bool {
1011 return switch (abi) {
1012 .ohos, .ohoseabi => true,
1013 else => false,
1014 };
1015 }
1016
1017 pub inline fn isAndroid(abi: Abi) bool {
1018 return switch (abi) {
1019 .android, .androideabi => true,
1020 else => false,
1021 };
1022 }
1023
1024 pub const Float = enum {
1025 hard,
1026 soft,
1027 };
1028
1029 pub inline fn float(abi: Abi) Float {
1030 return switch (abi) {
1031 .androideabi,
1032 .eabi,
1033 .gnueabi,
1034 .musleabi,
1035 .gnusf,
1036 .muslsf,
1037 .ohoseabi,
1038 => .soft,
1039 else => .hard,
1040 };
1041 }
1042};
1043
1044pub const ObjectFormat = enum {
1045 /// C source code.
1046 c,
1047 /// The Common Object File Format used by Windows and UEFI.
1048 coff,
1049 /// The Executable and Linkable Format used by many Unixes.
1050 elf,
1051 /// The Intel HEX format for storing binary code in ASCII text.
1052 hex,
1053 /// The Mach object format used by macOS and other Apple platforms.
1054 macho,
1055 /// The a.out format used by Plan 9 from Bell Labs.
1056 plan9,
1057 /// Machine code with no metadata.
1058 raw,
1059 /// The Khronos Group's Standard Portable Intermediate Representation V.
1060 spirv,
1061 /// The WebAssembly binary format.
1062 wasm,
1063
1064 pub fn fileExt(of: ObjectFormat, arch: Cpu.Arch) [:0]const u8 {
1065 return switch (of) {
1066 .c => ".c",
1067 .coff => ".obj",
1068 .elf, .macho, .wasm => ".o",
1069 .hex => ".ihex",
1070 .plan9 => arch.plan9Ext(),
1071 .raw => ".bin",
1072 .spirv => ".spv",
1073 };
1074 }
1075
1076 pub fn default(os_tag: Os.Tag, arch: Cpu.Arch) ObjectFormat {
1077 return switch (os_tag) {
1078 .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => .macho,
1079 .plan9 => .plan9,
1080 .uefi, .windows => .coff,
1081 else => switch (arch) {
1082 .spirv32, .spirv64 => .spirv,
1083 .wasm32, .wasm64 => .wasm,
1084 .spork8 => .raw,
1085 else => .elf,
1086 },
1087 };
1088 }
1089};
1090
1091pub fn toElfMachine(target: *const Target) std.elf.EM {
1092 return switch (target.cpu.arch) {
1093 .aarch64, .aarch64_be => .AARCH64,
1094 .alpha => .ALPHA,
1095 .amdgcn => .AMDGPU,
1096 .arc, .arceb => .ARC_COMPACT2,
1097 .arm, .armeb, .thumb, .thumbeb => .ARM,
1098 .avr => .AVR,
1099 .bpfeb, .bpfel => .BPF,
1100 .csky => .CSKY,
1101 .ez80 => .Z80,
1102 .hexagon => .QDSP6,
1103 .hppa, .hppa64 => .PARISC,
1104 .kalimba => .CSR_KALIMBA,
1105 .kvx => .KVX,
1106 .lanai => .LANAI,
1107 .loongarch32, .loongarch64 => .LOONGARCH,
1108 .m88k => .@"88K",
1109 .m68k => .@"68K",
1110 .microblaze, .microblazeel => .MICROBLAZE,
1111 .mips, .mips64, .mipsel, .mips64el => .MIPS,
1112 .msp430 => .MSP430,
1113 .or1k => .OR1K,
1114 .powerpc, .powerpcle => .PPC,
1115 .powerpc64, .powerpc64le => .PPC64,
1116 .propeller => .PROPELLER,
1117 .riscv32, .riscv32be, .riscv64, .riscv64be => .RISCV,
1118 .s390x => .S390,
1119 .sh, .sheb => .SH,
1120 .sparc => if (target.cpu.hasAny(.sparc, &.{ .v8plus, .v9 })) .SPARC32PLUS else .SPARC,
1121 .sparc64 => .SPARCV9,
1122 .ve => .VE,
1123 .x86_16, .x86 => .@"386",
1124 .x86_64 => .X86_64,
1125 .xcore => .XCORE,
1126 .xtensa, .xtensaeb => .XTENSA,
1127
1128 .nvptx,
1129 .nvptx64,
1130 .spirv32,
1131 .spirv64,
1132 .wasm32,
1133 .wasm64,
1134 .spork8,
1135 => .NONE,
1136 };
1137}
1138
1139pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE {
1140 return switch (target.cpu.arch) {
1141 .alpha => .ALPHA64,
1142 .arm => .ARM,
1143 .thumb => .ARMNT,
1144 .aarch64 => .ARM64,
1145 .loongarch32 => .LOONGARCH32,
1146 .loongarch64 => .LOONGARCH64,
1147 .mips => .R3000BE,
1148 .mipsel => .R3000,
1149 .mips64el => .R4000,
1150 .powerpcle => .POWERPC,
1151 .riscv32 => .RISCV32,
1152 .riscv64 => .RISCV64,
1153 .sh => .SH3,
1154 .x86 => .I386,
1155 .x86_64 => .AMD64,
1156
1157 .aarch64_be,
1158 .amdgcn,
1159 .arc,
1160 .arceb,
1161 .armeb,
1162 .avr,
1163 .bpfeb,
1164 .bpfel,
1165 .csky,
1166 .ez80,
1167 .hexagon,
1168 .hppa,
1169 .hppa64,
1170 .kalimba,
1171 .kvx,
1172 .lanai,
1173 .m88k,
1174 .m68k,
1175 .microblaze,
1176 .microblazeel,
1177 .mips64,
1178 .msp430,
1179 .nvptx,
1180 .nvptx64,
1181 .or1k,
1182 .powerpc,
1183 .powerpc64,
1184 .powerpc64le,
1185 .propeller,
1186 .riscv32be,
1187 .riscv64be,
1188 .s390x,
1189 .sheb,
1190 .sparc,
1191 .sparc64,
1192 .spirv32,
1193 .spirv64,
1194 .thumbeb,
1195 .ve,
1196 .wasm32,
1197 .wasm64,
1198 .x86_16,
1199 .xcore,
1200 .xtensa,
1201 .xtensaeb,
1202 .spork8,
1203 => .UNKNOWN,
1204 };
1205}
1206
1207pub const Cpu = struct {
1208 /// Architecture
1209 arch: Arch,
1210
1211 /// The CPU model to target. It has a set of features
1212 /// which are overridden with the `features` field.
1213 model: *const Model,
1214
1215 /// An explicit list of the entire CPU feature set. It may differ from the specific CPU model's features.
1216 features: Feature.Set,
1217
1218 pub const Feature = struct {
1219 /// The bit index into `Set`. Has a default value of `undefined` because the canonical
1220 /// structures are populated via comptime logic.
1221 index: Set.Index = undefined,
1222
1223 /// Has a default value of `undefined` because the canonical
1224 /// structures are populated via comptime logic.
1225 name: []const u8 = undefined,
1226
1227 /// If this corresponds to an LLVM-recognized feature, this will be populated;
1228 /// otherwise null.
1229 llvm_name: ?[:0]const u8,
1230
1231 /// Human-friendly UTF-8 text.
1232 description: []const u8,
1233
1234 /// Sparse `Set` of features this depends on.
1235 dependencies: Set,
1236
1237 /// A bit set of all the features.
1238 pub const Set = struct {
1239 ints: [usize_count]usize,
1240
1241 pub const needed_bit_count = 347;
1242 pub const byte_count = @divCeil(needed_bit_count, 8);
1243 pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize);
1244 pub const Index = std.math.Log2Int(@Int(.unsigned, usize_count * @bitSizeOf(usize)));
1245 pub const ShiftInt = std.math.Log2Int(usize);
1246
1247 pub const empty: Set = .{ .ints = @splat(0) };
1248
1249 pub fn isEmpty(set: Set) bool {
1250 return for (set.ints) |x| {
1251 if (x != 0) break false;
1252 } else true;
1253 }
1254
1255 pub fn count(set: Set) std.math.IntFittingRange(0, needed_bit_count) {
1256 var sum: usize = 0;
1257 for (set.ints) |x| sum += @popCount(x);
1258 return @intCast(sum);
1259 }
1260
1261 pub fn isEnabled(set: Set, arch_feature_index: Index) bool {
1262 const usize_index = arch_feature_index / @bitSizeOf(usize);
1263 const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
1264 return (set.ints[usize_index] & (@as(usize, 1) << bit_index)) != 0;
1265 }
1266
1267 /// Adds the specified feature but not its dependencies.
1268 pub fn addFeature(set: *Set, arch_feature_index: Index) void {
1269 const usize_index = arch_feature_index / @bitSizeOf(usize);
1270 const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
1271 set.ints[usize_index] |= @as(usize, 1) << bit_index;
1272 }
1273
1274 /// Adds the specified feature set but not its dependencies.
1275 pub fn addFeatureSet(set: *Set, other_set: Set) void {
1276 set.ints = @as(@Vector(usize_count, usize), set.ints) | @as(@Vector(usize_count, usize), other_set.ints);
1277 }
1278
1279 /// Removes the specified feature but not its dependents.
1280 pub fn removeFeature(set: *Set, arch_feature_index: Index) void {
1281 const usize_index = arch_feature_index / @bitSizeOf(usize);
1282 const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
1283 set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);
1284 }
1285
1286 /// Removes the specified feature but not its dependents.
1287 pub fn removeFeatureSet(set: *Set, other_set: Set) void {
1288 set.ints = @as(@Vector(usize_count, usize), set.ints) & ~@as(@Vector(usize_count, usize), other_set.ints);
1289 }
1290
1291 pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void {
1292 @setEvalBranchQuota(1000000);
1293
1294 var old = set.ints;
1295 while (true) {
1296 for (all_features_list, 0..) |feature, index_usize| {
1297 const index: Index = @intCast(index_usize);
1298 if (set.isEnabled(index)) {
1299 set.addFeatureSet(feature.dependencies);
1300 }
1301 }
1302 const nothing_changed = std.mem.eql(usize, &old, &set.ints);
1303 if (nothing_changed) return;
1304 old = set.ints;
1305 }
1306 }
1307
1308 pub fn asBytes(set: *const Set) *const [byte_count]u8 {
1309 return std.mem.sliceAsBytes(&set.ints)[0..byte_count];
1310 }
1311
1312 pub fn eql(set: Set, other_set: Set) bool {
1313 return std.mem.eql(usize, &set.ints, &other_set.ints);
1314 }
1315
1316 pub fn isSuperSetOf(set: Set, other_set: Set) bool {
1317 const V = @Vector(usize_count, usize);
1318 const set_v: V = set.ints;
1319 const other_v: V = other_set.ints;
1320 return @reduce(.And, (set_v & other_v) == other_v);
1321 }
1322 };
1323
1324 pub fn FeatureSetFns(comptime F: type) type {
1325 return struct {
1326 /// Populates only the feature bits specified.
1327 pub fn featureSet(features: []const F) Set {
1328 var x = Set.empty;
1329 for (features) |feature| {
1330 x.addFeature(@backingInt(feature));
1331 }
1332 return x;
1333 }
1334
1335 /// Returns true if the specified feature is enabled.
1336 pub fn featureSetHas(set: Set, feature: F) bool {
1337 return set.isEnabled(@backingInt(feature));
1338 }
1339
1340 /// Returns true if any specified feature is enabled.
1341 pub fn featureSetHasAny(set: Set, features: anytype) bool {
1342 inline for (features) |feature| {
1343 if (set.isEnabled(@backingInt(@as(F, feature)))) return true;
1344 }
1345 return false;
1346 }
1347
1348 /// Returns true if every specified feature is enabled.
1349 pub fn featureSetHasAll(set: Set, features: anytype) bool {
1350 inline for (features) |feature| {
1351 if (!set.isEnabled(@backingInt(@as(F, feature)))) return false;
1352 }
1353 return true;
1354 }
1355 };
1356 }
1357 };
1358
1359 pub const Arch = enum {
1360 aarch64,
1361 aarch64_be,
1362 alpha,
1363 amdgcn,
1364 arc,
1365 arceb,
1366 arm,
1367 armeb,
1368 avr,
1369 bpfeb,
1370 bpfel,
1371 csky,
1372 ez80,
1373 hexagon,
1374 hppa,
1375 hppa64,
1376 kalimba,
1377 kvx,
1378 lanai,
1379 loongarch32,
1380 loongarch64,
1381 m68k,
1382 m88k,
1383 microblaze,
1384 microblazeel,
1385 mips,
1386 mipsel,
1387 mips64,
1388 mips64el,
1389 msp430,
1390 nvptx,
1391 nvptx64,
1392 or1k,
1393 powerpc,
1394 powerpcle,
1395 powerpc64,
1396 powerpc64le,
1397 propeller,
1398 riscv32,
1399 riscv32be,
1400 riscv64,
1401 riscv64be,
1402 s390x,
1403 sh,
1404 sheb,
1405 sparc,
1406 sparc64,
1407 spork8,
1408 spirv32,
1409 spirv64,
1410 thumb,
1411 thumbeb,
1412 ve,
1413 wasm32,
1414 wasm64,
1415 x86_16,
1416 x86,
1417 x86_64,
1418 xcore,
1419 xtensa,
1420 xtensaeb,
1421
1422 /// An architecture family can encompass multiple architectures as represented by `Arch`.
1423 /// For a given family tag, it is guaranteed that an `std.Target.<tag>` namespace exists
1424 /// containing CPU model and feature data.
1425 pub const Family = enum {
1426 aarch64,
1427 alpha,
1428 amdgcn,
1429 arc,
1430 arm,
1431 avr,
1432 bpf,
1433 csky,
1434 hexagon,
1435 hppa,
1436 kalimba,
1437 kvx,
1438 lanai,
1439 loongarch,
1440 m68k,
1441 m88k,
1442 microblaze,
1443 mips,
1444 msp430,
1445 nvptx,
1446 or1k,
1447 powerpc,
1448 propeller,
1449 riscv,
1450 s390x,
1451 sh,
1452 sparc,
1453 spirv,
1454 ve,
1455 wasm,
1456 x86,
1457 xcore,
1458 xtensa,
1459 z80,
1460 spork8,
1461 };
1462
1463 pub inline fn family(arch: Arch) Family {
1464 return switch (arch) {
1465 .aarch64, .aarch64_be => .aarch64,
1466 .alpha => .alpha,
1467 .amdgcn => .amdgcn,
1468 .arc, .arceb => .arc,
1469 .arm, .armeb, .thumb, .thumbeb => .arm,
1470 .avr => .avr,
1471 .bpfeb, .bpfel => .bpf,
1472 .csky => .csky,
1473 .ez80 => .z80,
1474 .hexagon => .hexagon,
1475 .hppa, .hppa64 => .hppa,
1476 .kalimba => .kalimba,
1477 .kvx => .kvx,
1478 .lanai => .lanai,
1479 .loongarch32, .loongarch64 => .loongarch,
1480 .m68k => .m68k,
1481 .m88k => .m88k,
1482 .microblaze, .microblazeel => .microblaze,
1483 .mips, .mipsel, .mips64, .mips64el => .mips,
1484 .msp430 => .msp430,
1485 .or1k => .or1k,
1486 .nvptx, .nvptx64 => .nvptx,
1487 .powerpc, .powerpcle, .powerpc64, .powerpc64le => .powerpc,
1488 .propeller => .propeller,
1489 .riscv32, .riscv32be, .riscv64, .riscv64be => .riscv,
1490 .s390x => .s390x,
1491 .sh, .sheb => .sh,
1492 .sparc, .sparc64 => .sparc,
1493 .spirv32, .spirv64 => .spirv,
1494 .ve => .ve,
1495 .wasm32, .wasm64 => .wasm,
1496 .x86_16, .x86, .x86_64 => .x86,
1497 .xcore => .xcore,
1498 .xtensa, .xtensaeb => .xtensa,
1499 .spork8 => .spork8,
1500 };
1501 }
1502
1503 pub inline fn isX86(arch: Arch) bool {
1504 return switch (arch) {
1505 .x86_16, .x86, .x86_64 => true,
1506 else => false,
1507 };
1508 }
1509
1510 /// Note that this includes Thumb.
1511 pub inline fn isArm(arch: Arch) bool {
1512 return switch (arch) {
1513 .arm, .armeb => true,
1514 else => arch.isThumb(),
1515 };
1516 }
1517
1518 pub inline fn isThumb(arch: Arch) bool {
1519 return switch (arch) {
1520 .thumb, .thumbeb => true,
1521 else => false,
1522 };
1523 }
1524
1525 /// Deprecated; to be removed in 0.18.0. Use `isAarch64` instead.
1526 pub const isAARCH64 = isAarch64;
1527
1528 pub inline fn isAarch64(arch: Arch) bool {
1529 return switch (arch) {
1530 .aarch64, .aarch64_be => true,
1531 else => false,
1532 };
1533 }
1534
1535 pub inline fn isArc(arch: Arch) bool {
1536 return switch (arch) {
1537 .arc, .arceb => true,
1538 else => false,
1539 };
1540 }
1541
1542 pub inline fn isHppa(arch: Arch) bool {
1543 return switch (arch) {
1544 .hppa, .hppa64 => true,
1545 else => false,
1546 };
1547 }
1548
1549 pub inline fn isWasm(arch: Arch) bool {
1550 return switch (arch) {
1551 .wasm32, .wasm64 => true,
1552 else => false,
1553 };
1554 }
1555
1556 /// Deprecated; to be removed in 0.18.0. Use `isLoongarch` instead.
1557 pub const isLoongArch = isLoongarch;
1558
1559 pub inline fn isLoongarch(arch: Arch) bool {
1560 return switch (arch) {
1561 .loongarch32, .loongarch64 => true,
1562 else => false,
1563 };
1564 }
1565
1566 /// Deprecated; to be removed in 0.18.0. Use `isRiscv` instead.
1567 pub const isRISCV = isRiscv;
1568
1569 pub inline fn isRiscv(arch: Arch) bool {
1570 return arch.isRiscv32() or arch.isRiscv64();
1571 }
1572
1573 pub inline fn isRiscv32(arch: Arch) bool {
1574 return switch (arch) {
1575 .riscv32, .riscv32be => true,
1576 else => false,
1577 };
1578 }
1579
1580 pub inline fn isRiscv64(arch: Arch) bool {
1581 return switch (arch) {
1582 .riscv64, .riscv64be => true,
1583 else => false,
1584 };
1585 }
1586
1587 pub inline fn isMicroblaze(arch: Arch) bool {
1588 return switch (arch) {
1589 .microblaze, .microblazeel => true,
1590 else => false,
1591 };
1592 }
1593
1594 /// Deprecated; to be removed in 0.18.0. Use `isMips` instead.
1595 pub const isMIPS = isMips;
1596
1597 pub inline fn isMips(arch: Arch) bool {
1598 return arch.isMips32() or arch.isMips64();
1599 }
1600
1601 /// Deprecated; to be removed in 0.18.0. Use `isMips32` instead.
1602 pub const isMIPS32 = isMips32;
1603
1604 pub inline fn isMips32(arch: Arch) bool {
1605 return switch (arch) {
1606 .mips, .mipsel => true,
1607 else => false,
1608 };
1609 }
1610
1611 /// Deprecated; to be removed in 0.18.0. Use `isMips64` instead.
1612 pub const isMIPS64 = isMips64;
1613
1614 pub inline fn isMips64(arch: Arch) bool {
1615 return switch (arch) {
1616 .mips64, .mips64el => true,
1617 else => false,
1618 };
1619 }
1620
1621 /// Deprecated; to be removed in 0.18.0. Use `isPowerpc` instead.
1622 pub const isPowerPC = isPowerpc;
1623
1624 pub inline fn isPowerpc(arch: Arch) bool {
1625 return arch.isPowerpc32() or arch.isPowerpc64();
1626 }
1627
1628 /// Deprecated; to be removed in 0.18.0. Use `isPowerpc32` instead.
1629 pub const isPowerPC32 = isPowerpc32;
1630
1631 pub inline fn isPowerpc32(arch: Arch) bool {
1632 return switch (arch) {
1633 .powerpc, .powerpcle => true,
1634 else => false,
1635 };
1636 }
1637
1638 /// Deprecated; to be removed in 0.18.0. Use `isPowerpc64` instead.
1639 pub const isPowerPC64 = isPowerpc64;
1640
1641 pub inline fn isPowerpc64(arch: Arch) bool {
1642 return switch (arch) {
1643 .powerpc64, .powerpc64le => true,
1644 else => false,
1645 };
1646 }
1647
1648 /// Deprecated; to be removed in 0.18.0. Use `isSparc` instead.
1649 pub const isSPARC = isSparc;
1650
1651 pub inline fn isSparc(arch: Arch) bool {
1652 return switch (arch) {
1653 .sparc, .sparc64 => true,
1654 else => false,
1655 };
1656 }
1657
1658 /// Deprecated; to be removed in 0.18.0. Use `isSpirv` instead.
1659 pub const isSpirV = isSpirv;
1660
1661 pub inline fn isSpirv(arch: Arch) bool {
1662 return switch (arch) {
1663 .spirv32, .spirv64 => true,
1664 else => false,
1665 };
1666 }
1667
1668 pub inline fn isSh(arch: Arch) bool {
1669 return switch (arch) {
1670 .sh, .sheb => true,
1671 else => false,
1672 };
1673 }
1674
1675 pub inline fn isBpf(arch: Arch) bool {
1676 return switch (arch) {
1677 .bpfel, .bpfeb => true,
1678 else => false,
1679 };
1680 }
1681
1682 pub inline fn isNvptx(arch: Arch) bool {
1683 return switch (arch) {
1684 .nvptx, .nvptx64 => true,
1685 else => false,
1686 };
1687 }
1688
1689 pub inline fn isXtensa(arch: Arch) bool {
1690 return switch (arch) {
1691 .xtensa, .xtensaeb => true,
1692 else => false,
1693 };
1694 }
1695
1696 pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) ?*const Cpu.Model {
1697 for (arch.allCpuModels()) |cpu| {
1698 if (std.mem.eql(u8, cpu_name, cpu.name)) {
1699 return cpu;
1700 }
1701 }
1702 return null;
1703 }
1704
1705 pub fn endian(arch: Arch) std.builtin.Endian {
1706 return switch (arch) {
1707 .aarch64,
1708 .alpha,
1709 .arm,
1710 .arc,
1711 .avr,
1712 .bpfel,
1713 .csky,
1714 .hexagon,
1715 .kalimba,
1716 .kvx,
1717 .loongarch32,
1718 .loongarch64,
1719 .microblazeel,
1720 .mipsel,
1721 .mips64el,
1722 .msp430,
1723 .powerpcle,
1724 .powerpc64le,
1725 .propeller,
1726 .riscv32,
1727 .riscv64,
1728 .sh,
1729 .thumb,
1730 .ve,
1731 .wasm32,
1732 .wasm64,
1733 .x86_16,
1734 .x86,
1735 .x86_64,
1736 .xcore,
1737 .xtensa,
1738 .ez80,
1739 => .little,
1740
1741 .aarch64_be,
1742 .arceb,
1743 .armeb,
1744 .bpfeb,
1745 .hppa,
1746 .hppa64,
1747 .lanai,
1748 .m68k,
1749 .m88k,
1750 .microblaze,
1751 .mips,
1752 .mips64,
1753 .or1k,
1754 .powerpc,
1755 .powerpc64,
1756 .riscv32be,
1757 .riscv64be,
1758 .s390x,
1759 .sheb,
1760 .thumbeb,
1761 .sparc,
1762 .sparc64,
1763 .xtensaeb,
1764 .spork8,
1765 => .big,
1766
1767 // GPU endianness is opaque. For now, assume little endian.
1768 .amdgcn,
1769 .nvptx,
1770 .nvptx64,
1771 .spirv32,
1772 .spirv64,
1773 => .little,
1774 };
1775 }
1776
1777 /// All CPU features Zig is aware of, sorted lexicographically by name.
1778 pub fn allFeaturesList(arch: Arch) []const Cpu.Feature {
1779 return switch (arch.family()) {
1780 inline else => |f| &@field(Target, @tagName(f)).all_features,
1781 };
1782 }
1783
1784 /// All processors Zig is aware of, sorted lexicographically by name.
1785 pub fn allCpuModels(arch: Arch) []const *const Cpu.Model {
1786 return switch (arch.family()) {
1787 inline else => |f| comptime allCpusFromDecls(@field(Target, @tagName(f)).cpu),
1788 };
1789 }
1790
1791 fn allCpusFromDecls(comptime cpus: type) []const *const Cpu.Model {
1792 @setEvalBranchQuota(2000);
1793 const decl_names = @typeInfo(cpus).@"struct".decl_names;
1794 var array: [decl_names.len]*const Cpu.Model = undefined;
1795 for (decl_names, 0..) |decl_name, i| {
1796 array[i] = &@field(cpus, decl_name);
1797 }
1798 const finalized = array;
1799 return &finalized;
1800 }
1801
1802 /// 0c spim little-endian MIPS 3000 family
1803 /// 1c 68000 Motorola MC68000
1804 /// 2c 68020 Motorola MC68020
1805 /// 5c arm little-endian ARM
1806 /// 6c amd64 AMD64 and compatibles (e.g., Intel EM64T)
1807 /// 7c arm64 ARM64 (ARMv8)
1808 /// 8c 386 Intel x86, i486, Pentium, etc.
1809 /// kc sparc Sun SPARC
1810 /// qc power Power PC
1811 /// vc mips big-endian MIPS 3000 family
1812 pub fn plan9Ext(arch: Cpu.Arch) [:0]const u8 {
1813 return switch (arch) {
1814 .arm => ".5",
1815 .x86_64 => ".6",
1816 .aarch64 => ".7",
1817 .x86 => ".8",
1818 .sparc => ".k",
1819 .powerpc, .powerpcle => ".q",
1820 .mips, .mipsel => ".v",
1821 // ISAs without designated characters get 'X' for lack of a better option.
1822 else => ".X",
1823 };
1824 }
1825
1826 /// Returns the array of `Arch` to which a specific `std.builtin.CallingConvention` applies.
1827 /// Asserts that `cc` is not `.auto`, `.@"async"`, `.naked`, or `.@"inline"`.
1828 pub fn fromCallingConvention(cc: std.builtin.CallingConvention.Tag) []const Arch {
1829 return switch (cc) {
1830 .auto,
1831 .async,
1832 .naked,
1833 .@"inline",
1834 => unreachable,
1835
1836 .x86_64_sysv,
1837 .x86_64_x32,
1838 .x86_64_win,
1839 .x86_64_regcall_v3_sysv,
1840 .x86_64_regcall_v4_win,
1841 .x86_64_vectorcall,
1842 .x86_64_interrupt,
1843 .x86_64_preserve_none,
1844 => &.{.x86_64},
1845
1846 .x86_sysv,
1847 .x86_win,
1848 .x86_mingw,
1849 .x86_stdcall,
1850 .x86_fastcall,
1851 .x86_thiscall,
1852 .x86_thiscall_mingw,
1853 .x86_regcall_v3,
1854 .x86_regcall_v4_win,
1855 .x86_vectorcall,
1856 .x86_interrupt,
1857 => &.{.x86},
1858
1859 .x86_16_cdecl,
1860 .x86_16_stdcall,
1861 .x86_16_regparmcall,
1862 .x86_16_interrupt,
1863 => &.{.x86_16},
1864
1865 .aarch64_aapcs,
1866 .aarch64_aapcs_darwin,
1867 .aarch64_aapcs_win,
1868 .aarch64_vfabi,
1869 .aarch64_vfabi_sve,
1870 .aarch64_preserve_none,
1871 => &.{ .aarch64, .aarch64_be },
1872
1873 .alpha_osf,
1874 => &.{.alpha},
1875
1876 .arm_aapcs,
1877 .arm_aapcs_vfp,
1878 .arm_interrupt,
1879 => &.{ .arm, .armeb, .thumb, .thumbeb },
1880
1881 .mips64_n64,
1882 .mips64_n32,
1883 .mips64_interrupt,
1884 => &.{ .mips64, .mips64el },
1885
1886 .mips_o32,
1887 .mips_interrupt,
1888 => &.{ .mips, .mipsel },
1889
1890 .riscv64_lp64,
1891 .riscv64_lp64_v,
1892 .riscv64_interrupt,
1893 => &.{ .riscv64, .riscv64be },
1894
1895 .riscv32_ilp32,
1896 .riscv32_ilp32_v,
1897 .riscv32_interrupt,
1898 => &.{ .riscv32, .riscv32be },
1899
1900 .sparc64_sysv,
1901 => &.{.sparc64},
1902
1903 .sparc_sysv,
1904 => &.{.sparc},
1905
1906 .powerpc64_elf,
1907 .powerpc64_elf_altivec,
1908 .powerpc64_elf_v2,
1909 => &.{ .powerpc64, .powerpc64le },
1910
1911 .powerpc_sysv,
1912 .powerpc_sysv_altivec,
1913 .powerpc_aix,
1914 .powerpc_aix_altivec,
1915 => &.{ .powerpc, .powerpcle },
1916
1917 .wasm_mvp,
1918 => &.{ .wasm64, .wasm32 },
1919
1920 .arc_sysv,
1921 .arc_interrupt,
1922 => &.{ .arc, .arceb },
1923
1924 .avr_gnu,
1925 .avr_builtin,
1926 .avr_signal,
1927 .avr_interrupt,
1928 => &.{.avr},
1929
1930 .bpf_std,
1931 => &.{ .bpfel, .bpfeb },
1932
1933 .csky_sysv,
1934 .csky_interrupt,
1935 => &.{.csky},
1936
1937 .hexagon_sysv,
1938 .hexagon_sysv_hvx,
1939 => &.{.hexagon},
1940
1941 .hppa_elf,
1942 => &.{.hppa},
1943
1944 .hppa64_elf,
1945 => &.{.hppa64},
1946
1947 .kvx_lp64,
1948 .kvx_ilp32,
1949 => &.{.kvx},
1950
1951 .lanai_sysv,
1952 => &.{.lanai},
1953
1954 .loongarch64_lp64,
1955 => &.{.loongarch64},
1956
1957 .loongarch32_ilp32,
1958 => &.{.loongarch32},
1959
1960 .m68k_sysv,
1961 .m68k_gnu,
1962 .m68k_rtd,
1963 .m68k_interrupt,
1964 => &.{.m68k},
1965
1966 .m88k_sysv,
1967 => &.{.m88k},
1968
1969 .microblaze_std,
1970 .microblaze_interrupt,
1971 => &.{ .microblaze, .microblazeel },
1972
1973 .msp430_eabi,
1974 .msp430_interrupt,
1975 => &.{.msp430},
1976
1977 .or1k_sysv,
1978 => &.{.or1k},
1979
1980 .propeller_sysv,
1981 => &.{.propeller},
1982
1983 .s390x_sysv,
1984 .s390x_sysv_vx,
1985 => &.{.s390x},
1986
1987 .sh_gnu,
1988 .sh_renesas,
1989 .sh_interrupt,
1990 => &.{ .sh, .sheb },
1991
1992 .ve_sysv,
1993 => &.{.ve},
1994
1995 .xcore_xs1,
1996 .xcore_xs2,
1997 => &.{.xcore},
1998
1999 .xtensa_call0,
2000 .xtensa_windowed,
2001 => &.{ .xtensa, .xtensaeb },
2002
2003 .amdgcn_device,
2004 .amdgcn_kernel,
2005 .amdgcn_cs,
2006 => &.{.amdgcn},
2007
2008 .nvptx_device,
2009 .nvptx_kernel,
2010 => &.{ .nvptx, .nvptx64 },
2011
2012 .spirv_device,
2013 .spirv_kernel,
2014 .spirv_fragment,
2015 .spirv_vertex,
2016 .spirv_task,
2017 .spirv_mesh,
2018 => &.{ .spirv32, .spirv64 },
2019
2020 .ez80_cet,
2021 .ez80_tiflags,
2022 => &.{.ez80},
2023
2024 .spork8,
2025 => &.{.spork8},
2026 };
2027 }
2028 };
2029
2030 pub const Model = struct {
2031 name: []const u8,
2032 llvm_name: ?[:0]const u8,
2033 features: Feature.Set,
2034
2035 pub fn toCpu(model: *const Model, arch: Arch) Cpu {
2036 var features = model.features;
2037 features.populateDependencies(arch.allFeaturesList());
2038 return .{
2039 .arch = arch,
2040 .model = model,
2041 .features = features,
2042 };
2043 }
2044
2045 /// Returns the most bare-bones CPU model that is valid for `arch`. Note that this function
2046 /// can return CPU models that are understood by LLVM, but *not* understood by Clang. If
2047 /// Clang compatibility is important, consider using `baseline` instead.
2048 pub fn generic(arch: Arch) *const Model {
2049 return switch (arch) {
2050 .alpha => &alpha.cpu.ev4,
2051 .amdgcn => &amdgcn.cpu.gfx600,
2052 .avr => &avr.cpu.avr1,
2053 .hppa => &hppa.cpu.ts_1,
2054 .hppa64 => &hppa.cpu.pa_8000,
2055 .kvx => &kvx.cpu.coolidge_v1,
2056 .loongarch32 => &loongarch.cpu.generic_la32,
2057 .loongarch64 => &loongarch.cpu.generic_la64,
2058 .mips, .mipsel => &mips.cpu.mips32,
2059 .mips64, .mips64el => &mips.cpu.mips64,
2060 .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
2061 .powerpc, .powerpcle => &powerpc.cpu.ppc,
2062 .powerpc64, .powerpc64le => &powerpc.cpu.ppc64,
2063 .propeller => &propeller.cpu.p1,
2064 .riscv32, .riscv32be => &riscv.cpu.generic_rv32,
2065 .riscv64, .riscv64be => &riscv.cpu.generic_rv64,
2066 .sparc64 => &sparc.cpu.v9, // SPARC can only be 64-bit from v9 and up.
2067 .wasm32, .wasm64 => &wasm.cpu.mvp,
2068 .x86_16 => &x86.cpu.i86,
2069 .x86 => &x86.cpu.i386,
2070 .x86_64 => &x86.cpu.x86_64,
2071 inline else => |a| &@field(Target, @tagName(a.family())).cpu.generic,
2072 };
2073 }
2074
2075 /// Returns a conservative CPU model for `arch` that is expected to be compatible with the
2076 /// vast majority of hardware available. This function is guaranteed to return CPU models
2077 /// that are understood by both LLVM and Clang, unlike `generic`.
2078 ///
2079 /// For certain `os` values, this function will additionally bump the baseline higher than
2080 /// the baseline would be for `arch` in isolation; for example, for `aarch64-macos`, the
2081 /// baseline is considered to be `apple_m1`. To avoid this behavior entirely, pass
2082 /// `Os.Tag.freestanding`.
2083 pub fn baseline(arch: Arch, os: Os) *const Model {
2084 return switch (arch) {
2085 .alpha => &alpha.cpu.ev6,
2086 .amdgcn => &amdgcn.cpu.gfx906,
2087 .arm => switch (os.tag) {
2088 .@"3ds" => &arm.cpu.mpcore,
2089 .vita => &arm.cpu.cortex_a9,
2090 .gba => &arm.cpu.arm7tdmi,
2091 else => &arm.cpu.baseline,
2092 },
2093 .thumb => switch (os.tag) {
2094 .vita => &arm.cpu.cortex_a9,
2095 .gba => &arm.cpu.arm7tdmi,
2096 else => &arm.cpu.baseline,
2097 },
2098 .armeb, .thumbeb => &arm.cpu.baseline,
2099 .aarch64 => switch (os.tag) {
2100 .haiku => &aarch64.cpu.cortex_a55,
2101 .driverkit, .maccatalyst, .macos => &aarch64.cpu.apple_m1,
2102 .ios, .tvos => &aarch64.cpu.apple_a7,
2103 .visionos => &aarch64.cpu.apple_m2,
2104 .watchos => &aarch64.cpu.apple_s4,
2105 .@"switch" => &aarch64.cpu.cortex_a57,
2106 else => generic(arch),
2107 },
2108 .avr => &avr.cpu.avr2,
2109 .bpfel, .bpfeb => &bpf.cpu.v3,
2110 .csky => &csky.cpu.ck810, // gcc/clang do not have a generic csky model.
2111 .hexagon => &hexagon.cpu.hexagonv68, // gcc/clang do not have a generic hexagon model.
2112 .hppa => &hppa.cpu.pa_7300lc,
2113 .kvx => &kvx.cpu.coolidge_v2,
2114 .lanai => &lanai.cpu.v11, // clang does not have a generic lanai model.
2115 .loongarch32 => &loongarch.cpu.la32v1_0,
2116 .loongarch64 => &loongarch.cpu.la64v1_0,
2117 .m68k => &m68k.cpu.M68030,
2118 .mips => &mips.cpu.mips32r2,
2119 .mipsel => switch (os.tag) {
2120 .psx => &mips.cpu.r3000a,
2121 .psp => &mips.cpu.allegrex,
2122 else => &mips.cpu.mips32r2,
2123 },
2124 .mips64 => switch (os.tag) {
2125 .openbsd => &mips.cpu.octeon,
2126 else => &mips.cpu.mips64r2,
2127 },
2128 .mips64el => &mips.cpu.mips64r2,
2129 .msp430 => &msp430.cpu.msp430,
2130 .nvptx, .nvptx64 => &nvptx.cpu.sm_52,
2131 .powerpc => switch (os.tag) {
2132 .openbsd, .wiiu => &powerpc.cpu.@"750",
2133 else => generic(arch),
2134 },
2135 .powerpc64 => switch (os.tag) {
2136 .linux, .freebsd => &powerpc.cpu.pwr8,
2137 .openbsd => &powerpc.cpu.pwr9,
2138 else => generic(arch),
2139 },
2140 .powerpc64le => &powerpc.cpu.ppc64le,
2141 .riscv32, .riscv32be => &riscv.cpu.baseline_rv32,
2142 .riscv64, .riscv64be => &riscv.cpu.baseline_rv64,
2143 .s390x => &s390x.cpu.arch11,
2144 .sparc => switch (os.tag) {
2145 .linux => &sparc.cpu.v9, // glibc does not work with 'plain' v8.
2146 else => generic(arch),
2147 },
2148 .sparc64 => &sparc.cpu.ultrasparc,
2149 .x86 => &x86.cpu.pentium4,
2150 .x86_64 => switch (os.tag) {
2151 .driverkit, .maccatalyst => &x86.cpu.nehalem,
2152 .macos => &x86.cpu.core2,
2153 .ps4 => &x86.cpu.btver2,
2154 .ps5 => &x86.cpu.znver2,
2155 else => generic(arch),
2156 },
2157 .xcore => &xcore.cpu.xs1b_generic,
2158 .xtensa => &xtensa.cpu.esp32,
2159 .wasm32, .wasm64 => &wasm.cpu.lime1,
2160
2161 else => generic(arch),
2162 };
2163 }
2164 };
2165
2166 /// The "default" set of CPU features for cross-compiling. A conservative set
2167 /// of features that is expected to be supported on most available hardware.
2168 pub fn baseline(arch: Arch, os: Os) Cpu {
2169 return Model.baseline(arch, os).toCpu(arch);
2170 }
2171
2172 /// Returns true if `feature` is enabled.
2173 pub fn has(cpu: Cpu, comptime family: Arch.Family, feature: @field(Target, @tagName(family)).Feature) bool {
2174 if (family != cpu.arch.family()) return false;
2175 return cpu.features.isEnabled(@backingInt(feature));
2176 }
2177
2178 /// Returns true if any feature in `features` is enabled.
2179 pub fn hasAny(cpu: Cpu, comptime family: Arch.Family, features: []const @field(Target, @tagName(family)).Feature) bool {
2180 if (family != cpu.arch.family()) return false;
2181 for (features) |feature| {
2182 if (cpu.features.isEnabled(@backingInt(feature))) return true;
2183 }
2184 return false;
2185 }
2186
2187 /// Returns true if all features in `features` are enabled.
2188 pub fn hasAll(cpu: Cpu, comptime family: Arch.Family, features: []const @field(Target, @tagName(family)).Feature) bool {
2189 if (family != cpu.arch.family()) return false;
2190 for (features) |feature| {
2191 if (!cpu.features.isEnabled(@backingInt(feature))) return false;
2192 }
2193 return true;
2194 }
2195};
2196
2197pub fn zigTriple(target: *const Target, allocator: Allocator) Allocator.Error![]u8 {
2198 return Query.fromTarget(target).zigTriple(allocator);
2199}
2200
2201/// Deprecated; to be removed in 0.18.0. Use `std.zig.target.hurdTupleSimple` instead.
2202pub fn hurdTupleSimple(allocator: Allocator, arch: Cpu.Arch, abi: Abi) ![]u8 {
2203 return std.fmt.allocPrint(allocator, "{s}-{s}", .{ @tagName(arch), @tagName(abi) });
2204}
2205
2206/// Deprecated; to be removed in 0.18.0. Use `std.zig.target.hurdTuple` instead.
2207pub fn hurdTuple(target: *const Target, allocator: Allocator) ![]u8 {
2208 return hurdTupleSimple(allocator, target.cpu.arch, target.abi);
2209}
2210
2211/// Deprecated; to be removed in 0.18.0. Use `std.zig.target.linuxTripleSimple` instead.
2212pub fn linuxTripleSimple(allocator: Allocator, arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![]u8 {
2213 return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ @tagName(arch), @tagName(os_tag), @tagName(abi) });
2214}
2215
2216/// Deprecated; to be removed in 0.18.0. Use `std.zig.target.linuxTriple` instead.
2217pub fn linuxTriple(target: *const Target, allocator: Allocator) ![]u8 {
2218 return linuxTripleSimple(allocator, target.cpu.arch, target.os.tag, target.abi);
2219}
2220
2221pub fn exeFileExt(target: *const Target) [:0]const u8 {
2222 return target.os.tag.exeFileExt(target.cpu.arch);
2223}
2224
2225pub fn staticLibSuffix(target: *const Target) [:0]const u8 {
2226 return target.os.tag.staticLibSuffix(target.abi);
2227}
2228
2229pub fn dynamicLibSuffix(target: *const Target) [:0]const u8 {
2230 return target.os.tag.dynamicLibSuffix();
2231}
2232
2233pub fn libPrefix(target: *const Target) [:0]const u8 {
2234 return target.os.tag.libPrefix(target.abi);
2235}
2236
2237pub inline fn isMinGW(target: *const Target) bool {
2238 return target.os.tag == .windows and target.abi.isGnu();
2239}
2240
2241pub inline fn isGnuLibC(target: *const Target) bool {
2242 return switch (target.os.tag) {
2243 .hurd, .linux => target.abi.isGnu(),
2244 else => false,
2245 };
2246}
2247
2248pub inline fn isMuslLibC(target: *const Target) bool {
2249 return target.os.tag == .linux and target.abi.isMusl();
2250}
2251
2252pub inline fn isBionicLibC(target: *const Target) bool {
2253 return target.os.tag == .linux and target.abi.isAndroid();
2254}
2255
2256pub inline fn isDarwinLibC(target: *const Target) bool {
2257 return switch (target.abi) {
2258 .none, .simulator => target.os.tag.isDarwin(),
2259 else => false,
2260 };
2261}
2262
2263pub inline fn isFreeBSDLibC(target: *const Target) bool {
2264 return switch (target.abi) {
2265 .none, .eabihf => target.os.tag == .freebsd,
2266 else => false,
2267 };
2268}
2269
2270pub inline fn isNetBSDLibC(target: *const Target) bool {
2271 return switch (target.abi) {
2272 .none, .eabi, .eabihf => target.os.tag == .netbsd,
2273 else => false,
2274 };
2275}
2276
2277pub inline fn isOpenBSDLibC(target: *const Target) bool {
2278 return switch (target.abi) {
2279 .none, .eabi, .eabihf => target.os.tag == .openbsd,
2280 else => false,
2281 };
2282}
2283
2284pub inline fn isWasiLibC(target: *const Target) bool {
2285 return target.os.tag == .wasi and target.abi.isMusl();
2286}
2287
2288/// Does this target require linking libc? This may be the case if the target has an unstable
2289/// syscall interface, for example.
2290pub fn requiresLibC(target: *const Target) bool {
2291 return switch (target.os.tag) {
2292 .illumos,
2293 .driverkit,
2294 .ios,
2295 .maccatalyst,
2296 .macos,
2297 .tvos,
2298 .watchos,
2299 .visionos,
2300 .dragonfly,
2301 .haiku,
2302 .serenity,
2303 .emscripten,
2304 => true,
2305
2306 // Android API levels prior to 29 did not have native TLS support. For these API levels, TLS
2307 // is implemented through calls to `__emutls_get_address`. We provide this function in
2308 // compiler-rt, but it's implemented by way of `pthread_key_create` et al, so linking libc
2309 // is required.
2310 .linux => target.abi.isAndroid() and target.os.version_range.linux.android < 29,
2311
2312 .windows,
2313 .freebsd,
2314 .netbsd,
2315 .openbsd,
2316 .freestanding,
2317 .fuchsia,
2318 .managarm,
2319 .rtems,
2320 .cuda,
2321 .nvcl,
2322 .amdhsa,
2323 .psx,
2324 .ps3,
2325 .ps4,
2326 .ps5,
2327 .gba,
2328 .psp,
2329 .vita,
2330 .mesa3d,
2331 .contiki,
2332 .amdpal,
2333 .hermit,
2334 .hurd,
2335 .wasi,
2336 .uefi,
2337 .opencl,
2338 .opengl,
2339 .vulkan,
2340 .plan9,
2341 .other,
2342 .@"3ds",
2343 .wiiu,
2344 .@"switch",
2345 .tios,
2346 .ashetos,
2347 => false,
2348 };
2349}
2350
2351/// The places where a user can specify an address space attribute
2352pub const AddressSpaceContext = enum {
2353 /// A function is specified to be placed in a certain address space.
2354 function,
2355 /// A (global) variable is specified to be placed in a certain address space. In contrast to
2356 /// `.constant`, these values (and thus the address space they will be placed in) are required
2357 /// to be mutable.
2358 variable,
2359 /// A (global) constant value is specified to be placed in a certain address space. In contrast
2360 /// to `.variable`, values placed in this address space are not required to be mutable.
2361 constant,
2362 /// A pointer is ascripted to point into a certain address space.
2363 pointer,
2364};
2365
2366/// Returns whether this target supports `address_space`. If `context` is `null`, this
2367/// function simply answers the general question of whether the target has any concept
2368/// of `address_space`; if non-`null`, the function additionally checks whether
2369/// `address_space` is valid in that context.
2370pub fn supportsAddressSpace(
2371 target: Target,
2372 address_space: std.builtin.AddressSpace,
2373 context: ?AddressSpaceContext,
2374) bool {
2375 const arch = target.cpu.arch;
2376
2377 const is_nvptx = arch.isNvptx();
2378 const is_spirv = arch.isSpirV();
2379 const is_gpu = is_nvptx or is_spirv or arch == .amdgcn;
2380
2381 return switch (address_space) {
2382 .generic => true,
2383 .fs, .gs, .ss => (arch == .x86_64 or arch == .x86 or arch == .x86_16) and (context == null or context == .pointer),
2384 // Technically x86 can use segmentation...
2385 .far => (arch == .x86_16),
2386
2387 .flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr, // TODO this should also check how many flash banks the cpu has
2388 .cog, .hub => arch == .propeller,
2389 .lut => arch == .propeller and std.Target.propeller.featureSetHas(target.cpu.features, .p2),
2390
2391 .global, .local, .shared => is_gpu,
2392 .constant => (is_gpu and (context == null or context == .constant)) or
2393 (is_spirv and (context == null or context == .constant or context == .pointer)),
2394 .param => is_nvptx,
2395 .input, .output, .uniform, .push_constant, .storage_buffer => is_spirv,
2396 .physical_storage_buffer => arch == .spirv64,
2397 .externref, .funcref => target.cpu.has(.wasm, .reference_types),
2398 };
2399}
2400
2401pub const DynamicLinker = struct {
2402 /// Contains the memory used to store the dynamic linker path. This field
2403 /// should not be used directly. See `get` and `set`. This field exists so
2404 /// that this API requires no allocator.
2405 buffer: [255]u8,
2406
2407 /// Used to construct the dynamic linker path. This field should not be used
2408 /// directly. See `get` and `set`.
2409 len: u8,
2410
2411 pub const none: DynamicLinker = .{ .buffer = undefined, .len = 0 };
2412
2413 /// Asserts that the length is less than or equal to 255 bytes.
2414 pub fn init(maybe_path: ?[]const u8) DynamicLinker {
2415 var dl: DynamicLinker = undefined;
2416 dl.set(maybe_path);
2417 return dl;
2418 }
2419
2420 pub fn initFmt(comptime fmt_str: []const u8, args: anytype) !DynamicLinker {
2421 var dl: DynamicLinker = undefined;
2422 try dl.setFmt(fmt_str, args);
2423 return dl;
2424 }
2425
2426 /// The returned memory has the same lifetime as the `DynamicLinker`.
2427 pub fn get(dl: *const DynamicLinker) ?[]const u8 {
2428 return if (dl.len > 0) dl.buffer[0..dl.len] else null;
2429 }
2430
2431 /// Asserts that the length is less than or equal to 255 bytes.
2432 pub fn set(dl: *DynamicLinker, maybe_path: ?[]const u8) void {
2433 const path = maybe_path orelse "";
2434 @memcpy(dl.buffer[0..path.len], path);
2435 dl.len = @intCast(path.len);
2436 }
2437
2438 /// Asserts that the length is less than or equal to 255 bytes.
2439 pub fn setFmt(dl: *DynamicLinker, comptime fmt_str: []const u8, args: anytype) !void {
2440 dl.len = @intCast((try std.mem.print(&dl.buffer, fmt_str, args)).len);
2441 }
2442
2443 pub fn eql(lhs: DynamicLinker, rhs: DynamicLinker) bool {
2444 return std.mem.eql(u8, lhs.buffer[0..lhs.len], rhs.buffer[0..rhs.len]);
2445 }
2446
2447 pub const Kind = enum {
2448 /// No dynamic linker.
2449 none,
2450 /// Dynamic linker path is determined by the arch/OS components.
2451 arch_os,
2452 /// Dynamic linker path is determined by the arch/OS/ABI components.
2453 arch_os_abi,
2454 };
2455
2456 pub fn kind(os: Os.Tag) Kind {
2457 return switch (os) {
2458 .fuchsia,
2459
2460 .haiku,
2461 .illumos,
2462 .serenity,
2463
2464 .dragonfly,
2465 .freebsd,
2466 .netbsd,
2467 .openbsd,
2468
2469 .driverkit,
2470 .ios,
2471 .maccatalyst,
2472 .macos,
2473 .tvos,
2474 .visionos,
2475 .watchos,
2476 => .arch_os,
2477 .hurd,
2478 .linux,
2479 => .arch_os_abi,
2480 .freestanding,
2481 .other,
2482
2483 .contiki,
2484 .hermit,
2485 .managarm, // Needs to be double-checked.
2486
2487 .plan9,
2488 .rtems,
2489
2490 .uefi,
2491 .windows,
2492
2493 .@"3ds",
2494 .wiiu,
2495 .@"switch",
2496 .gba,
2497
2498 .emscripten,
2499 .wasi,
2500
2501 .amdhsa,
2502 .amdpal,
2503 .cuda,
2504 .mesa3d,
2505 .nvcl,
2506 .opencl,
2507 .opengl,
2508 .vulkan,
2509
2510 .psx,
2511 .ps3,
2512 .ps4,
2513 .ps5,
2514 .psp,
2515 .vita,
2516
2517 .tios,
2518 .ashetos,
2519 => .none,
2520 };
2521 }
2522
2523 /// The strictness of this function depends on the value of `kind(os.tag)`:
2524 ///
2525 /// * `.none`: Ignores all arguments and just returns `none`.
2526 /// * `.arch_os`: Ignores `abi` and returns the dynamic linker matching `cpu` and `os`.
2527 /// * `.arch_os_abi`: Returns the dynamic linker matching `cpu`, `os`, and `abi`.
2528 ///
2529 /// In the case of `.arch_os` in particular, callers should be aware that a valid dynamic linker
2530 /// being returned only means that the `cpu` + `os` combination represents a platform that
2531 /// actually exists and which has an established dynamic linker path that does not change with
2532 /// the ABI; it does not necessarily mean that `abi` makes any sense at all for that platform.
2533 /// The responsibility for determining whether `abi` is valid in this case rests with the
2534 /// caller. `Abi.default()` can be used to pick a best-effort default ABI for such platforms.
2535 pub fn standard(cpu: Cpu, os: Os, abi: Abi) DynamicLinker {
2536 return switch (os.tag) {
2537 .fuchsia => switch (cpu.arch) {
2538 .arm,
2539 .aarch64,
2540 .riscv64,
2541 .thumb,
2542 .x86_64,
2543 => init("ld.so.1"), // Fuchsia is unusual in that `DT_INTERP` is just a basename.
2544 else => none,
2545 },
2546
2547 .haiku => switch (cpu.arch) {
2548 .arm,
2549 .aarch64,
2550 .riscv64,
2551 .x86,
2552 .x86_64,
2553 => init("/system/runtime_loader"),
2554 else => none,
2555 },
2556
2557 .hurd => switch (cpu.arch) {
2558 .aarch64,
2559 .aarch64_be,
2560 => |arch| if (abi == .gnu) initFmt("/lib/ld-{s}.so.1", .{@tagName(arch)}) else none,
2561
2562 .x86 => if (abi == .gnu) init("/lib/ld.so.1") else none,
2563 .x86_64 => initFmt("/lib/ld-{s}.so.1", .{switch (abi) {
2564 .gnu => "x86-64",
2565 .gnux32 => "x32",
2566 else => return none,
2567 }}),
2568
2569 else => none,
2570 },
2571
2572 .illumos,
2573 => switch (cpu.arch) {
2574 .x86,
2575 .x86_64,
2576 => initFmt("/lib/{s}ld.so.1", .{if (ptrBitWidth_cpu_abi(cpu, .none) == 64) "64/" else ""}),
2577 else => none,
2578 },
2579
2580 .linux => if (abi.isAndroid())
2581 switch (cpu.arch) {
2582 .arm => if (abi == .androideabi) init("/system/bin/linker") else none,
2583
2584 .aarch64,
2585 .riscv64,
2586 .x86,
2587 .x86_64,
2588 => if (abi == .android) initFmt("/system/bin/linker{s}", .{
2589 if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64" else "",
2590 }) else none,
2591
2592 else => none,
2593 }
2594 else if (abi.isMusl())
2595 switch (cpu.arch) {
2596 .arm,
2597 .armeb,
2598 .thumb,
2599 .thumbeb,
2600 => |arch| initFmt("/lib/ld-musl-arm{s}{s}.so.1", .{
2601 if (arch == .armeb or arch == .thumbeb) "eb" else "",
2602 switch (abi) {
2603 .musleabi => "",
2604 .musleabihf => "hf",
2605 else => return none,
2606 },
2607 }),
2608
2609 .loongarch32,
2610 .loongarch64,
2611 => |arch| initFmt("/lib/ld-musl-{s}{s}.so.1", .{
2612 @tagName(arch),
2613 switch (abi) {
2614 .musl => "",
2615 .muslf32 => "-sp",
2616 .muslsf => "-sf",
2617 else => return none,
2618 },
2619 }),
2620
2621 .aarch64,
2622 .aarch64_be,
2623 .hexagon,
2624 .kvx,
2625 .m68k,
2626 .microblaze,
2627 .microblazeel,
2628 .or1k,
2629 .powerpc64,
2630 .powerpc64le,
2631 .s390x,
2632 => |arch| if (abi == .musl) initFmt("/lib/ld-musl-{s}.so.1", .{@tagName(arch)}) else none,
2633
2634 .mips,
2635 .mipsel,
2636 => |arch| initFmt("/lib/ld-musl-mips{s}{s}{s}.so.1", .{
2637 if (cpu.has(.mips, .mips32r6)) "r6" else "",
2638 if (arch == .mipsel) "el" else "",
2639 switch (abi) {
2640 .musleabi => "-sf",
2641 .musleabihf => "",
2642 else => return none,
2643 },
2644 }),
2645
2646 .mips64,
2647 .mips64el,
2648 => |arch| initFmt("/lib/ld-musl-mips{s}{s}{s}.so.1", .{
2649 switch (abi) {
2650 .muslabi64 => "64",
2651 .muslabin32 => "n32",
2652 else => return none,
2653 },
2654 if (cpu.has(.mips, .mips64r6)) "r6" else "",
2655 if (arch == .mips64el) "el" else "",
2656 }),
2657
2658 .powerpc => initFmt("/lib/ld-musl-powerpc{s}.so.1", .{switch (abi) {
2659 .musleabi => "-sf",
2660 .musleabihf => "",
2661 else => return none,
2662 }}),
2663
2664 .sh,
2665 .sheb,
2666 => |arch| initFmt("/lib/ld-musl-{t}{s}.so.1", .{
2667 arch,
2668 switch (abi) {
2669 .musleabi => "-nofpu",
2670 .musleabihf => "",
2671 else => return none,
2672 },
2673 }),
2674
2675 .riscv32,
2676 .riscv64,
2677 => |arch| if (abi == .musl) initFmt("/lib/ld-musl-{s}{s}.so.1", .{
2678 @tagName(arch),
2679 if (cpu.has(.riscv, .d))
2680 ""
2681 else if (cpu.has(.riscv, .f))
2682 "-sp"
2683 else
2684 "-sf",
2685 }) else none,
2686
2687 .x86 => if (abi == .musl) init("/lib/ld-musl-i386.so.1") else none,
2688
2689 .x86_64 => initFmt("/lib/ld-musl-{s}.so.1", .{switch (abi) {
2690 .musl => "x86_64",
2691 .muslx32 => "x32",
2692 else => return none,
2693 }}),
2694
2695 else => none,
2696 }
2697 else if (abi.isGnu())
2698 switch (cpu.arch) {
2699 .arc,
2700 .arceb,
2701 => |arch| if (abi == .gnu) initFmt("/lib/ld-linux-{t}.so.2", .{arch}) else none,
2702
2703 .arm,
2704 .armeb,
2705 => initFmt("/lib/ld-linux{s}.so.3", .{switch (abi) {
2706 .gnueabi => "",
2707 .gnueabihf => "-armhf",
2708 else => return none,
2709 }}),
2710
2711 .aarch64,
2712 .aarch64_be,
2713 .or1k,
2714 => |arch| if (abi == .gnu) initFmt("/lib/ld-linux-{s}.so.1", .{@tagName(arch)}) else none,
2715
2716 .csky => initFmt("/lib/ld-linux-cskyv2{s}.so.1", .{switch (abi) {
2717 .gnueabi => "",
2718 .gnueabihf => "-hf",
2719 else => return none,
2720 }}),
2721
2722 .loongarch32,
2723 .loongarch64,
2724 => |arch| initFmt("/lib{s}/ld-linux-{s}{s}.so.1", .{
2725 switch (arch) {
2726 .loongarch32 => "32",
2727 .loongarch64 => "64",
2728 else => unreachable,
2729 },
2730 switch (arch) {
2731 .loongarch32 => "loongarch-ilp32",
2732 .loongarch64 => "loongarch-lp64",
2733 else => unreachable,
2734 },
2735 switch (abi) {
2736 .gnu => "d",
2737 .gnuf32 => "f",
2738 .gnusf => "s",
2739 else => return none,
2740 },
2741 }),
2742
2743 .hppa,
2744 .m68k,
2745 .microblaze,
2746 .microblazeel,
2747 .xtensa,
2748 .xtensaeb,
2749 => if (abi == .gnu) init("/lib/ld.so.1") else none,
2750
2751 .mips,
2752 .mipsel,
2753 => switch (abi) {
2754 .gnueabi,
2755 .gnueabihf,
2756 => initFmt("/lib/ld{s}.so.1", .{
2757 if (cpu.has(.mips, .nan2008)) "-linux-mipsn8" else "",
2758 }),
2759 else => none,
2760 },
2761
2762 .mips64,
2763 .mips64el,
2764 => initFmt("/lib{s}/ld{s}.so.1", .{
2765 switch (abi) {
2766 .gnuabi64 => "64",
2767 .gnuabin32 => "32",
2768 else => return none,
2769 },
2770 if (cpu.has(.mips, .nan2008)) "-linux-mipsn8" else "",
2771 }),
2772
2773 .powerpc => switch (abi) {
2774 .gnueabi,
2775 .gnueabihf,
2776 => init("/lib/ld.so.1"),
2777 else => none,
2778 },
2779
2780 .powerpc64 => if (abi == .gnu) init("/lib64/ld64.so.1") else none,
2781 .powerpc64le => if (abi == .gnu) init("/lib64/ld64.so.2") else none,
2782
2783 .riscv32,
2784 .riscv64,
2785 => |arch| if (abi == .gnu) initFmt("/lib/ld-linux-{s}{s}.so.1", .{
2786 switch (arch) {
2787 .riscv32 => "riscv32-ilp32",
2788 .riscv64 => "riscv64-lp64",
2789 else => unreachable,
2790 },
2791 if (cpu.has(.riscv, .d))
2792 "d"
2793 else if (cpu.has(.riscv, .f))
2794 "f"
2795 else
2796 "",
2797 }) else none,
2798
2799 .s390x => if (abi == .gnu) init("/lib/ld64.so.1") else none,
2800
2801 .sh,
2802 .sheb,
2803 => switch (abi) {
2804 .gnueabi,
2805 .gnueabihf,
2806 => init("/lib/ld-linux.so.2"),
2807 else => none,
2808 },
2809
2810 .alpha,
2811 .sparc,
2812 .x86,
2813 => if (abi == .gnu) init("/lib/ld-linux.so.2") else none,
2814
2815 .sparc64 => if (abi == .gnu) init("/lib64/ld-linux.so.2") else none,
2816
2817 .x86_64 => switch (abi) {
2818 .gnu => init("/lib64/ld-linux-x86-64.so.2"),
2819 .gnux32 => init("/libx32/ld-linux-x32.so.2"),
2820 else => none,
2821 },
2822
2823 else => none,
2824 }
2825 else
2826 none, // Not a known Linux libc.
2827
2828 .serenity => switch (cpu.arch) {
2829 .aarch64,
2830 .riscv64,
2831 .x86_64,
2832 => init("/usr/lib/Loader.so"),
2833 else => none,
2834 },
2835
2836 .dragonfly => if (cpu.arch == .x86_64) initFmt("{s}/libexec/ld-elf.so.2", .{
2837 if (os.version_range.semver.isAtLeast(.{ .major = 3, .minor = 8, .patch = 0 }) orelse false)
2838 ""
2839 else
2840 "/usr",
2841 }) else none,
2842
2843 .freebsd => switch (cpu.arch) {
2844 .arm,
2845 .aarch64,
2846 .powerpc,
2847 .powerpc64,
2848 .powerpc64le,
2849 .riscv64,
2850 .x86,
2851 .x86_64,
2852 => initFmt("{s}/libexec/ld-elf.so.1", .{
2853 if (os.version_range.semver.isAtLeast(.{ .major = 6, .minor = 0, .patch = 0 }) orelse false)
2854 ""
2855 else
2856 "/usr",
2857 }),
2858 else => none,
2859 },
2860
2861 .netbsd => switch (cpu.arch) {
2862 .alpha,
2863 .arm,
2864 .armeb,
2865 .aarch64,
2866 .aarch64_be,
2867 .hppa,
2868 .m68k,
2869 .mips,
2870 .mipsel,
2871 .mips64,
2872 .mips64el,
2873 .powerpc,
2874 .riscv32,
2875 .riscv64,
2876 .sh,
2877 .sheb,
2878 .sparc,
2879 .sparc64,
2880 .x86,
2881 .x86_64,
2882 => init("/libexec/ld.elf_so"),
2883 else => none,
2884 },
2885
2886 .openbsd => switch (cpu.arch) {
2887 .alpha,
2888 .arm,
2889 .aarch64,
2890 .hppa,
2891 .m88k,
2892 .mips64,
2893 .mips64el,
2894 .powerpc,
2895 .powerpc64,
2896 .riscv64,
2897 .sh,
2898 .sparc64,
2899 .x86,
2900 .x86_64,
2901 => init("/usr/libexec/ld.so"),
2902 else => none,
2903 },
2904
2905 .driverkit,
2906 .ios,
2907 .maccatalyst,
2908 .macos,
2909 .tvos,
2910 .visionos,
2911 .watchos,
2912 => switch (cpu.arch) {
2913 .aarch64,
2914 .x86_64,
2915 => init("/usr/lib/dyld"),
2916 else => none,
2917 },
2918
2919 // Operating systems in this list have been verified as not having a standard
2920 // dynamic linker path.
2921 .freestanding,
2922 .other,
2923
2924 .contiki,
2925 .hermit,
2926
2927 .plan9,
2928 .rtems,
2929
2930 .uefi,
2931 .windows,
2932
2933 .@"3ds",
2934 .wiiu,
2935 .@"switch",
2936 .gba,
2937
2938 .psx,
2939 .psp,
2940 .vita,
2941
2942 .emscripten,
2943 .wasi,
2944
2945 .amdhsa,
2946 .amdpal,
2947 .cuda,
2948 .mesa3d,
2949 .nvcl,
2950 .opencl,
2951 .opengl,
2952 .vulkan,
2953
2954 .tios,
2955 .ashetos,
2956 => none,
2957
2958 // TODO go over each item in this list and either move it to the above list, or
2959 // implement the standard dynamic linker path code for it.
2960 .managarm,
2961
2962 .ps3,
2963 .ps4,
2964 .ps5,
2965 => none,
2966 } catch unreachable;
2967 }
2968};
2969
2970pub fn standardDynamicLinkerPath(target: *const Target) DynamicLinker {
2971 return DynamicLinker.standard(target.cpu, target.os, target.abi);
2972}
2973
2974pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 {
2975 return ptrBitWidth_arch_abi(cpu.arch, abi);
2976}
2977
2978pub fn ptrBitWidth_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) u16 {
2979 switch (abi) {
2980 .gnux32,
2981 .muslx32,
2982 .x32,
2983 .gnuabin32,
2984 .muslabin32,
2985 .abin32,
2986 .ilp32,
2987 => return 32,
2988 else => {},
2989 }
2990
2991 return switch (cpu_arch) {
2992 .avr,
2993 .msp430,
2994 .x86_16,
2995 .spork8,
2996 => 16,
2997
2998 .ez80,
2999 => 24,
3000
3001 .arc,
3002 .arceb,
3003 .arm,
3004 .armeb,
3005 .csky,
3006 .hexagon,
3007 .hppa,
3008 .kalimba,
3009 .lanai,
3010 .loongarch32,
3011 .m68k,
3012 .m88k,
3013 .microblaze,
3014 .microblazeel,
3015 .mips,
3016 .mipsel,
3017 .nvptx,
3018 .or1k,
3019 .powerpc,
3020 .powerpcle,
3021 .propeller,
3022 .riscv32,
3023 .riscv32be,
3024 .sh,
3025 .sheb,
3026 .sparc,
3027 .spirv32,
3028 .thumb,
3029 .thumbeb,
3030 .wasm32,
3031 .x86,
3032 .xcore,
3033 .xtensa,
3034 .xtensaeb,
3035 => 32,
3036
3037 .aarch64,
3038 .aarch64_be,
3039 .alpha,
3040 .amdgcn,
3041 .bpfeb,
3042 .bpfel,
3043 .hppa64,
3044 .kvx,
3045 .loongarch64,
3046 .mips64,
3047 .mips64el,
3048 .nvptx64,
3049 .powerpc64,
3050 .powerpc64le,
3051 .riscv64,
3052 .riscv64be,
3053 .s390x,
3054 .sparc64,
3055 .spirv64,
3056 .ve,
3057 .wasm64,
3058 .x86_64,
3059 => 64,
3060 };
3061}
3062
3063pub fn ptrBitWidth(target: *const Target) u16 {
3064 return ptrBitWidth_cpu_abi(target.cpu, target.abi);
3065}
3066
3067pub fn stackAlignment(target: *const Target) u16 {
3068 // Overrides for when the stack alignment is not equal to the pointer width.
3069 switch (target.cpu.arch) {
3070 .ez80 => return 1,
3071
3072 .m68k => return 2,
3073
3074 .amdgcn => return 4,
3075
3076 .arm,
3077 .armeb,
3078 .hppa,
3079 .lanai,
3080 .mips,
3081 .mipsel,
3082 .sparc,
3083 .thumb,
3084 .thumbeb,
3085 => return 8,
3086
3087 .aarch64,
3088 .aarch64_be,
3089 .alpha,
3090 .bpfeb,
3091 .bpfel,
3092 .hppa64,
3093 .loongarch32,
3094 .loongarch64,
3095 .mips64,
3096 .mips64el,
3097 .sparc64,
3098 .ve,
3099 .wasm32,
3100 .wasm64,
3101 .x86_64,
3102 => return 16,
3103
3104 // Some of the following prongs should really be testing the ABI, but our current `Abi` enum
3105 // can't handle that level of nuance yet.
3106 .powerpc64,
3107 .powerpc64le,
3108 => if (target.os.tag == .linux) return 16,
3109
3110 .riscv32,
3111 .riscv32be,
3112 .riscv64,
3113 .riscv64be,
3114 => if (!target.cpu.has(.riscv, .e)) return 16,
3115
3116 .x86 => if (target.os.tag != .windows and target.os.tag != .uefi) return 16,
3117
3118 .kvx => return 32,
3119
3120 .spork8 => return 256,
3121
3122 else => {},
3123 }
3124
3125 return @divExact(target.ptrBitWidth(), 8);
3126}
3127
3128pub const StackGrowth = enum {
3129 down,
3130 up,
3131};
3132
3133pub fn stackGrowth(target: *const Target) StackGrowth {
3134 // Strictly speaking, most architectures don't inherently define the stack growth direction; you
3135 // could quite easily argue that it is in fact a property of the ABI. However, that's just not
3136 // really how it plays out in the real world. And besides, we have no mechanism for indicating
3137 // a different stack growth ABI, nor a compelling use case for creating such a mechanism.
3138 return switch (target.cpu.arch) {
3139 .hppa,
3140 .hppa64,
3141 .spork8,
3142 => .up,
3143 else => .down,
3144 };
3145}
3146
3147/// Default signedness of `char` for the native C compiler for this target
3148/// Note that char signedness is implementation-defined and many compilers provide
3149/// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char
3150/// Returns `null` if no C ABI is defined for this target.
3151pub fn cCharSignedness(target: *const Target) ?std.builtin.Signedness {
3152 switch (target.os.tag) {
3153 .opengl => return null,
3154 else => {},
3155 }
3156 if (target.os.tag.isDarwin() or target.os.tag == .windows or target.os.tag == .uefi) return .signed;
3157 return switch (target.cpu.arch) {
3158 .aarch64,
3159 .aarch64_be,
3160 .arm,
3161 .armeb,
3162 .arc,
3163 .arceb,
3164 .csky,
3165 .ez80,
3166 .hexagon,
3167 .msp430,
3168 .powerpc,
3169 .powerpcle,
3170 .powerpc64,
3171 .powerpc64le,
3172 .s390x,
3173 .riscv32,
3174 .riscv32be,
3175 .riscv64,
3176 .riscv64be,
3177 .thumb,
3178 .thumbeb,
3179 .xcore,
3180 .xtensa,
3181 .xtensaeb,
3182 => .unsigned,
3183 else => .signed,
3184 };
3185}
3186
3187pub const CType = enum {
3188 char,
3189 short,
3190 ushort,
3191 int,
3192 uint,
3193 long,
3194 ulong,
3195 longlong,
3196 ulonglong,
3197 float,
3198 double,
3199 longdouble,
3200};
3201
3202/// Returns `null` if no C ABI is defined for this target.
3203pub fn cTypeByteSize(t: *const Target, c_type: CType) ?u16 {
3204 return switch (c_type) {
3205 .char,
3206 .short,
3207 .ushort,
3208 .int,
3209 .uint,
3210 .long,
3211 .ulong,
3212 .longlong,
3213 .ulonglong,
3214 .float,
3215 .double,
3216 => @divExact(cTypeBitSize(t, c_type) orelse return null, 8),
3217
3218 .longdouble => switch (cTypeBitSize(t, c_type) orelse return null) {
3219 64 => 8,
3220 80 => @intCast(std.mem.alignForward(usize, 10, cTypeAlignment(t, c_type).?)),
3221 128 => 16,
3222 else => unreachable,
3223 },
3224 };
3225}
3226
3227/// Returns `null` if no C ABI is defined for this target.
3228pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {
3229 return switch (target.os.tag) {
3230 .freestanding,
3231 .other,
3232 .ashetos,
3233 => switch (target.cpu.arch) {
3234 .msp430,
3235 .x86_16,
3236 => switch (c_type) {
3237 .char => 8,
3238 .short, .ushort, .int, .uint => 16,
3239 .float, .long, .ulong => 32,
3240 .longlong, .ulonglong, .double, .longdouble => 64,
3241 },
3242 .avr => switch (c_type) {
3243 .char => 8,
3244 .short, .ushort, .int, .uint => 16,
3245 .long, .ulong, .float, .double, .longdouble => 32,
3246 .longlong, .ulonglong => 64,
3247 },
3248 // https://github.com/benanderman/spork-8/blob/main/Programming.md
3249 .spork8 => switch (c_type) {
3250 .char => 8,
3251 .short, .ushort, .int, .uint => 16,
3252 .long, .ulong, .float => 32,
3253 .double, .longdouble, .longlong, .ulonglong => 64,
3254 },
3255 .mips64,
3256 .mips64el,
3257 => switch (c_type) {
3258 .char => 8,
3259 .short, .ushort => 16,
3260 .int, .uint, .float => 32,
3261 .long, .ulong => switch (target.abi) {
3262 .abin32 => 32,
3263 else => 64,
3264 },
3265 .longlong, .ulonglong, .double => 64,
3266 .longdouble => 128,
3267 },
3268 .x86_64 => switch (c_type) {
3269 .char => 8,
3270 .short, .ushort => 16,
3271 .int, .uint, .float => 32,
3272 .long, .ulong => switch (target.abi) {
3273 .x32 => 32,
3274 else => 64,
3275 },
3276 .longlong, .ulonglong, .double => 64,
3277 .longdouble => 80,
3278 },
3279 else => switch (c_type) {
3280 .char => 8,
3281 .short, .ushort => 16,
3282 .int, .uint, .float => 32,
3283 .long, .ulong => target.ptrBitWidth(),
3284 .longlong, .ulonglong, .double => 64,
3285 .longdouble => switch (target.cpu.arch) {
3286 .x86 => 80,
3287
3288 .alpha,
3289 .riscv32,
3290 .riscv32be,
3291 .riscv64,
3292 .riscv64be,
3293 .aarch64,
3294 .aarch64_be,
3295 .powerpc,
3296 .powerpcle,
3297 .powerpc64,
3298 .powerpc64le,
3299 .s390x,
3300 .sparc64,
3301 .wasm32,
3302 .wasm64,
3303 .loongarch32,
3304 .loongarch64,
3305 .ve,
3306 => 128,
3307
3308 else => 64,
3309 },
3310 },
3311 },
3312
3313 .fuchsia,
3314 .hermit,
3315
3316 .haiku,
3317 .hurd,
3318 .illumos,
3319 .linux,
3320 .plan9,
3321 .rtems,
3322 .serenity,
3323
3324 .freebsd,
3325 .dragonfly,
3326 .netbsd,
3327 .openbsd,
3328
3329 .wasi,
3330 .emscripten,
3331 => switch (target.cpu.arch) {
3332 .mips64,
3333 .mips64el,
3334 => switch (c_type) {
3335 .char => 8,
3336 .short, .ushort => 16,
3337 .int, .uint, .float => 32,
3338 .long, .ulong => switch (target.abi) {
3339 .gnuabin32, .muslabin32, .abin32 => 32,
3340 else => 64,
3341 },
3342 .longlong, .ulonglong, .double => 64,
3343 .longdouble => 128,
3344 },
3345 .x86_64 => switch (c_type) {
3346 .char => 8,
3347 .short, .ushort => 16,
3348 .int, .uint, .float => 32,
3349 .long, .ulong => switch (target.abi) {
3350 .gnux32, .muslx32, .x32 => 32,
3351 else => 64,
3352 },
3353 .longlong, .ulonglong, .double => 64,
3354 .longdouble => 80,
3355 },
3356 else => switch (c_type) {
3357 .char => 8,
3358 .short, .ushort => 16,
3359 .int, .uint, .float => 32,
3360 .long, .ulong => target.ptrBitWidth(),
3361 .longlong, .ulonglong, .double => 64,
3362 .longdouble => switch (target.cpu.arch) {
3363 .x86 => switch (target.abi) {
3364 .android => 64,
3365 else => 80,
3366 },
3367
3368 .powerpc,
3369 .powerpcle,
3370 => switch (target.abi) {
3371 .musleabi, .musleabihf => 64,
3372 else => switch (target.os.tag) {
3373 .netbsd,
3374 .openbsd,
3375 => 64,
3376 else => 128,
3377 },
3378 },
3379
3380 .powerpc64,
3381 .powerpc64le,
3382 => switch (target.abi) {
3383 .musl => 64,
3384 else => switch (target.os.tag) {
3385 .freebsd,
3386 .openbsd,
3387 => 64,
3388 else => 128,
3389 },
3390 },
3391
3392 .alpha,
3393 .riscv32,
3394 .riscv32be,
3395 .riscv64,
3396 .riscv64be,
3397 .aarch64,
3398 .aarch64_be,
3399 .s390x,
3400 .mips64,
3401 .mips64el,
3402 .sparc64,
3403 .wasm32,
3404 .wasm64,
3405 .loongarch32,
3406 .loongarch64,
3407 .ve,
3408 => 128,
3409
3410 else => 64,
3411 },
3412 },
3413 },
3414
3415 .windows, .uefi => switch (target.cpu.arch) {
3416 .x86 => switch (c_type) {
3417 .char => 8,
3418 .short, .ushort => 16,
3419 .int, .uint, .float => 32,
3420 .long, .ulong => 32,
3421 .longlong, .ulonglong, .double => 64,
3422 .longdouble => switch (target.abi) {
3423 .gnu => 80,
3424 else => 64,
3425 },
3426 },
3427 .x86_64 => switch (c_type) {
3428 .char => 8,
3429 .short, .ushort => 16,
3430 .int, .uint, .float => 32,
3431 .long, .ulong => 32,
3432 .longlong, .ulonglong, .double => 64,
3433 .longdouble => switch (target.abi) {
3434 .gnu => 80,
3435 else => 64,
3436 },
3437 },
3438 else => switch (c_type) {
3439 .char => 8,
3440 .short, .ushort => 16,
3441 .int, .uint, .float => 32,
3442 .long, .ulong => 32,
3443 .longlong, .ulonglong, .double => 64,
3444 .longdouble => 64,
3445 },
3446 },
3447
3448 .driverkit,
3449 .ios,
3450 .maccatalyst,
3451 .macos,
3452 .tvos,
3453 .visionos,
3454 .watchos,
3455 => switch (c_type) {
3456 .char => 8,
3457 .short, .ushort => 16,
3458 .int, .uint, .float => 32,
3459 .long, .ulong => switch (target.cpu.arch) {
3460 .x86_64 => 64,
3461 else => switch (target.abi) {
3462 .ilp32 => 32,
3463 else => 64,
3464 },
3465 },
3466 .longlong, .ulonglong, .double => 64,
3467 .longdouble => switch (target.cpu.arch) {
3468 .x86_64 => 80,
3469 else => 64,
3470 },
3471 },
3472
3473 .nvcl, .cuda => switch (c_type) {
3474 .char => 8,
3475 .short, .ushort => 16,
3476 .int, .uint, .float => 32,
3477 .long, .ulong => switch (target.cpu.arch) {
3478 .nvptx => 32,
3479 .nvptx64 => 64,
3480 else => 64,
3481 },
3482 .longlong, .ulonglong, .double => 64,
3483 .longdouble => 64,
3484 },
3485
3486 .amdhsa, .amdpal, .mesa3d => switch (c_type) {
3487 .char => 8,
3488 .short, .ushort => 16,
3489 .int, .uint, .float => 32,
3490 .long, .ulong, .longlong, .ulonglong, .double => 64,
3491 .longdouble => 128,
3492 },
3493
3494 .opencl, .vulkan => switch (c_type) {
3495 .char => 8,
3496 .short, .ushort => 16,
3497 .int, .uint, .float => 32,
3498 .long, .ulong, .double => 64,
3499 .longlong, .ulonglong => 128,
3500 // Note: The OpenCL specification does not guarantee a particular size for long double,
3501 // but clang uses 128 bits.
3502 .longdouble => 128,
3503 },
3504
3505 .@"3ds" => switch (c_type) {
3506 .char => 8,
3507 .short, .ushort => 16,
3508 .int, .uint, .float, .long, .ulong => 32,
3509 .longlong, .ulonglong, .double, .longdouble => 64,
3510 },
3511
3512 .wiiu => switch (c_type) {
3513 .char => 8,
3514 .short, .ushort => 16,
3515 .int, .uint, .float, .long, .ulong => 32,
3516 .longlong, .ulonglong, .double, .longdouble => 64,
3517 },
3518
3519 .@"switch" => switch (c_type) {
3520 .char => 8,
3521 .short, .ushort => 16,
3522 .int, .uint, .float => 32,
3523 .long, .ulong, .longlong, .ulonglong, .double => 64,
3524 .longdouble => 128,
3525 },
3526
3527 .gba => switch (c_type) {
3528 .char => return 8,
3529 .short, .ushort => return 16,
3530 .int, .uint, .long, .ulong, .float => return 32,
3531 .longlong, .ulonglong, .double, .longdouble => return 64,
3532 },
3533
3534 .psx => switch (c_type) {
3535 .char => 8,
3536 .short, .ushort => 16,
3537 .int, .uint, .long, .ulong, .float => 32,
3538 .longlong, .ulonglong, .double, .longdouble => 64,
3539 },
3540 .ps4, .ps5 => switch (c_type) {
3541 .char => 8,
3542 .short, .ushort => 16,
3543 .int, .uint, .float => 32,
3544 .long, .ulong => 64,
3545 .longlong, .ulonglong, .double => 64,
3546 .longdouble => 80,
3547 },
3548 .psp, .vita => switch (c_type) {
3549 .char => 8,
3550 .short, .ushort => 16,
3551 .int, .uint, .float => 32,
3552 .long, .ulong => 64,
3553 .longlong, .ulonglong, .double, .longdouble => 64,
3554 },
3555 .tios => switch (c_type) {
3556 .char => 8,
3557 .short, .ushort => 16,
3558 .int, .uint => 24,
3559 .long, .ulong, .float, .double => 32,
3560 .longlong, .ulonglong, .longdouble => 64,
3561 },
3562
3563 .opengl => null,
3564
3565 .ps3,
3566 .contiki,
3567 .managarm,
3568 => @panic("specify the C integer and float type sizes for this OS"),
3569 };
3570}
3571
3572/// Returns `null` if no C ABI is defined for this target.
3573pub fn cTypeAlignment(target: *const Target, c_type: CType) ?u16 {
3574 // Overrides for unusual alignments
3575 switch (target.cpu.arch) {
3576 .avr,
3577 .ez80,
3578 .spork8,
3579 => return 1,
3580 .x86 => switch (target.os.tag) {
3581 .windows, .uefi => switch (c_type) {
3582 .longlong, .ulonglong, .double => return 8,
3583 .longdouble => switch (target.abi) {
3584 .gnu => return 4,
3585 else => return 8,
3586 },
3587 else => {},
3588 },
3589 else => {},
3590 },
3591 .m68k => switch (c_type) {
3592 .int, .uint, .long, .ulong => return 2,
3593 else => {},
3594 },
3595 .wasm32, .wasm64 => switch (target.os.tag) {
3596 .emscripten => switch (c_type) {
3597 .longdouble => return 8,
3598 else => {},
3599 },
3600 else => {},
3601 },
3602 else => {},
3603 }
3604
3605 // Next-power-of-two-aligned, up to a maximum.
3606 return @min(
3607 std.math.ceilPowerOfTwoAssert(u16, ((cTypeBitSize(target, c_type) orelse return null) + 7) / 8),
3608 @as(u16, switch (target.cpu.arch) {
3609 .msp430,
3610 .x86_16,
3611 => 2,
3612
3613 .arc,
3614 .arceb,
3615 .csky,
3616 .kalimba,
3617 .microblaze,
3618 .microblazeel,
3619 .or1k,
3620 .propeller,
3621 .sh,
3622 .sheb,
3623 .x86,
3624 .xcore,
3625 .xtensa,
3626 .xtensaeb,
3627 => 4,
3628
3629 .amdgcn,
3630 .arm,
3631 .armeb,
3632 .bpfeb,
3633 .bpfel,
3634 .hexagon,
3635 .hppa,
3636 .lanai,
3637 .m68k,
3638 .m88k,
3639 .mips,
3640 .mipsel,
3641 .nvptx,
3642 .nvptx64,
3643 .s390x,
3644 .sparc,
3645 .thumb,
3646 .thumbeb,
3647 => 8,
3648
3649 .aarch64,
3650 .aarch64_be,
3651 .alpha,
3652 .hppa64,
3653 .kvx,
3654 .loongarch32,
3655 .loongarch64,
3656 .mips64,
3657 .mips64el,
3658 .powerpc,
3659 .powerpcle,
3660 .powerpc64,
3661 .powerpc64le,
3662 .riscv32,
3663 .riscv32be,
3664 .riscv64,
3665 .riscv64be,
3666 .sparc64,
3667 .spirv32,
3668 .spirv64,
3669 .ve,
3670 .wasm32,
3671 .wasm64,
3672 .x86_64,
3673 => 16,
3674
3675 .avr,
3676 .ez80,
3677 .spork8,
3678 => unreachable, // Handled above.
3679 }),
3680 );
3681}
3682
3683pub fn cMaxIntAlignment(target: *const Target) u16 {
3684 return switch (target.cpu.arch) {
3685 .avr,
3686 .ez80,
3687 .spork8,
3688 => 1,
3689
3690 .msp430,
3691 .x86_16,
3692 => 2,
3693
3694 .arc,
3695 .arceb,
3696 .csky,
3697 .kalimba,
3698 .microblaze,
3699 .microblazeel,
3700 .or1k,
3701 .propeller,
3702 .sh,
3703 .sheb,
3704 .xcore,
3705 => 4,
3706
3707 .x86 => switch (target.os.tag) {
3708 else => 4,
3709 .uefi, .windows => 8,
3710 },
3711
3712 .arm,
3713 .armeb,
3714 .hexagon,
3715 .hppa,
3716 .lanai,
3717 .loongarch32,
3718 .m68k,
3719 .m88k,
3720 .mips,
3721 .mipsel,
3722 .powerpc,
3723 .powerpcle,
3724 .riscv32,
3725 .riscv32be,
3726 .s390x,
3727 .sparc,
3728 .thumb,
3729 .thumbeb,
3730 .xtensa,
3731 .xtensaeb,
3732 => 8,
3733
3734 .aarch64,
3735 .aarch64_be,
3736 .alpha,
3737 .amdgcn,
3738 .bpfel,
3739 .bpfeb,
3740 .hppa64,
3741 .kvx,
3742 .loongarch64,
3743 .mips64,
3744 .mips64el,
3745 .nvptx,
3746 .nvptx64,
3747 .powerpc64,
3748 .powerpc64le,
3749 .riscv64,
3750 .riscv64be,
3751 .sparc64,
3752 .spirv32,
3753 .spirv64,
3754 .ve,
3755 .wasm32,
3756 .wasm64,
3757 .x86_64,
3758 => 16,
3759 };
3760}
3761
3762pub fn cCallingConvention(target: *const Target) ?std.builtin.CallingConvention {
3763 return switch (target.cpu.arch) {
3764 .x86_64 => switch (target.os.tag) {
3765 .windows, .uefi => .{ .x86_64_win = .{} },
3766 else => switch (target.abi) {
3767 .gnux32, .muslx32, .x32 => .{ .x86_64_x32 = .{} },
3768 else => .{ .x86_64_sysv = .{} },
3769 },
3770 },
3771 .x86 => switch (target.os.tag) {
3772 .windows, .uefi => if (target.isMinGW()) .{ .x86_mingw = .{} } else .{ .x86_win = .{} },
3773 else => .{ .x86_sysv = .{} },
3774 },
3775 .x86_16 => .{ .x86_16_cdecl = .{} },
3776 .aarch64, .aarch64_be => if (target.os.tag.isDarwin())
3777 .{ .aarch64_aapcs_darwin = .{} }
3778 else switch (target.os.tag) {
3779 .windows => .{ .aarch64_aapcs_win = .{} },
3780 else => .{ .aarch64_aapcs = .{} },
3781 },
3782 .alpha => .{ .alpha_osf = .{} },
3783 .arm, .armeb, .thumb, .thumbeb => switch (target.abi.float()) {
3784 .soft => .{ .arm_aapcs = .{} },
3785 .hard => .{ .arm_aapcs_vfp = .{} },
3786 },
3787 .mips64, .mips64el => switch (target.abi) {
3788 .gnuabin32, .muslabin32, .abin32 => .{ .mips64_n32 = .{} },
3789 else => .{ .mips64_n64 = .{} },
3790 },
3791 .mips, .mipsel => .{ .mips_o32 = .{} },
3792 .riscv64, .riscv64be => .{ .riscv64_lp64 = .{} },
3793 .riscv32, .riscv32be => .{ .riscv32_ilp32 = .{} },
3794 .sparc64 => .{ .sparc64_sysv = .{} },
3795 .sparc => .{ .sparc_sysv = .{} },
3796 .powerpc64 => if (target.os.tag == .ps3 or target.abi.isGnu())
3797 .{ .powerpc64_elf = .{} }
3798 else
3799 .{ .powerpc64_elf_v2 = .{} },
3800 .powerpc64le => .{ .powerpc64_elf_v2 = .{} },
3801 .powerpc, .powerpcle => .{ .powerpc_sysv = .{} },
3802 .wasm32, .wasm64 => .{ .wasm_mvp = .{} },
3803 .arc, .arceb => .{ .arc_sysv = .{} },
3804 .avr => .avr_gnu,
3805 .bpfel, .bpfeb => .{ .bpf_std = .{} },
3806 .csky => .{ .csky_sysv = .{} },
3807 .hexagon => .{ .hexagon_sysv = .{} },
3808 .hppa => .{ .hppa_elf = .{} },
3809 .hppa64 => .{ .hppa64_elf = .{} },
3810 .kalimba => null,
3811 .kvx => switch (target.abi) {
3812 .ilp32 => .{ .kvx_ilp32 = .{} },
3813 else => .{ .kvx_lp64 = .{} },
3814 },
3815 .lanai => .{ .lanai_sysv = .{} },
3816 .loongarch64 => .{ .loongarch64_lp64 = .{} },
3817 .loongarch32 => .{ .loongarch32_ilp32 = .{} },
3818 .m68k => .{ .m68k_gnu = .{} },
3819 .m88k => .{ .m88k_sysv = .{} },
3820 .microblaze, .microblazeel => .{ .microblaze_std = .{} },
3821 .msp430 => .{ .msp430_eabi = .{} },
3822 .or1k => .{ .or1k_sysv = .{} },
3823 .propeller => .{ .propeller_sysv = .{} },
3824 .s390x => .{ .s390x_sysv = .{} },
3825 .sh, .sheb => .{ .sh_gnu = .{} },
3826 .ve => .{ .ve_sysv = .{} },
3827 .xcore => .{ .xcore_xs1 = .{} },
3828 .xtensa, .xtensaeb => .{ .xtensa_call0 = .{} },
3829 .amdgcn => .{ .amdgcn_device = .{} },
3830 .nvptx, .nvptx64 => .nvptx_device,
3831 .spirv32, .spirv64 => .spirv_device,
3832 .ez80 => .ez80_cet,
3833 .spork8 => .spork8,
3834 };
3835}
3836
3837const Target = @This();
3838const std = @import("std.zig");
3839const builtin = @import("builtin");
3840const Allocator = std.mem.Allocator;
3841const assert = std.debug.assert;
3842
3843test {
3844 std.testing.refAllDecls(Cpu.Arch);
3845}