blob 9391d590 (84104B) - Raw
1 const std = @import("std.zig"); 2 const builtin = @import("builtin"); 3 const mem = std.mem; 4 const Version = std.builtin.Version; 5 6 /// TODO Nearly all the functions in this namespace would be 7 /// better off if https://github.com/ziglang/zig/issues/425 8 /// was solved. 9 pub const Target = struct { 10 cpu: Cpu, 11 os: Os, 12 abi: Abi, 13 ofmt: ObjectFormat, 14 15 pub const Os = struct { 16 tag: Tag, 17 version_range: VersionRange, 18 19 pub const Tag = enum { 20 freestanding, 21 ananas, 22 cloudabi, 23 dragonfly, 24 freebsd, 25 fuchsia, 26 ios, 27 kfreebsd, 28 linux, 29 lv2, 30 macos, 31 netbsd, 32 openbsd, 33 solaris, 34 windows, 35 zos, 36 haiku, 37 minix, 38 rtems, 39 nacl, 40 aix, 41 cuda, 42 nvcl, 43 amdhsa, 44 ps4, 45 ps5, 46 elfiamcu, 47 tvos, 48 watchos, 49 driverkit, 50 mesa3d, 51 contiki, 52 amdpal, 53 hermit, 54 hurd, 55 wasi, 56 emscripten, 57 shadermodel, 58 uefi, 59 opencl, 60 glsl450, 61 vulkan, 62 plan9, 63 other, 64 65 pub fn isDarwin(tag: Tag) bool { 66 return switch (tag) { 67 .ios, .macos, .watchos, .tvos => true, 68 else => false, 69 }; 70 } 71 72 pub fn isBSD(tag: Tag) bool { 73 return tag.isDarwin() or switch (tag) { 74 .kfreebsd, .freebsd, .openbsd, .netbsd, .dragonfly => true, 75 else => false, 76 }; 77 } 78 79 pub fn dynamicLibSuffix(tag: Tag) [:0]const u8 { 80 if (tag.isDarwin()) { 81 return ".dylib"; 82 } 83 switch (tag) { 84 .windows => return ".dll", 85 else => return ".so", 86 } 87 } 88 89 pub fn defaultVersionRange(tag: Tag, arch: Cpu.Arch) Os { 90 return .{ 91 .tag = tag, 92 .version_range = VersionRange.default(tag, arch), 93 }; 94 } 95 }; 96 97 /// Based on NTDDI version constants from 98 /// https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt 99 pub const WindowsVersion = enum(u32) { 100 nt4 = 0x04000000, 101 win2k = 0x05000000, 102 xp = 0x05010000, 103 ws2003 = 0x05020000, 104 vista = 0x06000000, 105 win7 = 0x06010000, 106 win8 = 0x06020000, 107 win8_1 = 0x06030000, 108 win10 = 0x0A000000, //aka win10_th1 109 win10_th2 = 0x0A000001, 110 win10_rs1 = 0x0A000002, 111 win10_rs2 = 0x0A000003, 112 win10_rs3 = 0x0A000004, 113 win10_rs4 = 0x0A000005, 114 win10_rs5 = 0x0A000006, 115 win10_19h1 = 0x0A000007, 116 win10_vb = 0x0A000008, //aka win10_19h2 117 win10_mn = 0x0A000009, //aka win10_20h1 118 win10_fe = 0x0A00000A, //aka win10_20h2 119 _, 120 121 /// Latest Windows version that the Zig Standard Library is aware of 122 pub const latest = WindowsVersion.win10_fe; 123 124 /// Compared against build numbers reported by the runtime to distinguish win10 versions, 125 /// where 0x0A000000 + index corresponds to the WindowsVersion u32 value. 126 pub const known_win10_build_numbers = [_]u32{ 127 10240, //win10 aka win10_th1 128 10586, //win10_th2 129 14393, //win10_rs1 130 15063, //win10_rs2 131 16299, //win10_rs3 132 17134, //win10_rs4 133 17763, //win10_rs5 134 18362, //win10_19h1 135 18363, //win10_vb aka win10_19h2 136 19041, //win10_mn aka win10_20h1 137 19042, //win10_fe aka win10_20h2 138 }; 139 140 /// Returns whether the first version `self` is newer (greater) than or equal to the second version `ver`. 141 pub fn isAtLeast(self: WindowsVersion, ver: WindowsVersion) bool { 142 return @enumToInt(self) >= @enumToInt(ver); 143 } 144 145 pub const Range = struct { 146 min: WindowsVersion, 147 max: WindowsVersion, 148 149 pub fn includesVersion(self: Range, ver: WindowsVersion) bool { 150 return @enumToInt(ver) >= @enumToInt(self.min) and @enumToInt(ver) <= @enumToInt(self.max); 151 } 152 153 /// Checks if system is guaranteed to be at least `version` or older than `version`. 154 /// Returns `null` if a runtime check is required. 155 pub fn isAtLeast(self: Range, ver: WindowsVersion) ?bool { 156 if (@enumToInt(self.min) >= @enumToInt(ver)) return true; 157 if (@enumToInt(self.max) < @enumToInt(ver)) return false; 158 return null; 159 } 160 }; 161 162 /// This function is defined to serialize a Zig source code representation of this 163 /// type, that, when parsed, will deserialize into the same data. 164 pub fn format( 165 self: WindowsVersion, 166 comptime fmt: []const u8, 167 _: std.fmt.FormatOptions, 168 out_stream: anytype, 169 ) !void { 170 if (comptime std.mem.eql(u8, fmt, "s")) { 171 if (@enumToInt(self) >= @enumToInt(WindowsVersion.nt4) and @enumToInt(self) <= @enumToInt(WindowsVersion.latest)) { 172 try std.fmt.format(out_stream, ".{s}", .{@tagName(self)}); 173 } else { 174 // TODO this code path breaks zig triples, but it is used in `builtin` 175 try std.fmt.format(out_stream, "@intToEnum(Target.Os.WindowsVersion, 0x{X:0>8})", .{@enumToInt(self)}); 176 } 177 } else if (fmt.len == 0) { 178 if (@enumToInt(self) >= @enumToInt(WindowsVersion.nt4) and @enumToInt(self) <= @enumToInt(WindowsVersion.latest)) { 179 try std.fmt.format(out_stream, "WindowsVersion.{s}", .{@tagName(self)}); 180 } else { 181 try std.fmt.format(out_stream, "WindowsVersion(0x{X:0>8})", .{@enumToInt(self)}); 182 } 183 } else { 184 std.fmt.invalidFmtError(fmt, self); 185 } 186 } 187 }; 188 189 pub const LinuxVersionRange = struct { 190 range: Version.Range, 191 glibc: Version, 192 193 pub fn includesVersion(self: LinuxVersionRange, ver: Version) bool { 194 return self.range.includesVersion(ver); 195 } 196 197 /// Checks if system is guaranteed to be at least `version` or older than `version`. 198 /// Returns `null` if a runtime check is required. 199 pub fn isAtLeast(self: LinuxVersionRange, ver: Version) ?bool { 200 return self.range.isAtLeast(ver); 201 } 202 }; 203 204 /// The version ranges here represent the minimum OS version to be supported 205 /// and the maximum OS version to be supported. The default values represent 206 /// the range that the Zig Standard Library bases its abstractions on. 207 /// 208 /// The minimum version of the range is the main setting to tweak for a target. 209 /// Usually, the maximum target OS version will remain the default, which is 210 /// the latest released version of the OS. 211 /// 212 /// To test at compile time if the target is guaranteed to support a given OS feature, 213 /// one should check that the minimum version of the range is greater than or equal to 214 /// the version the feature was introduced in. 215 /// 216 /// To test at compile time if the target certainly will not support a given OS feature, 217 /// one should check that the maximum version of the range is less than the version the 218 /// feature was introduced in. 219 /// 220 /// If neither of these cases apply, a runtime check should be used to determine if the 221 /// target supports a given OS feature. 222 /// 223 /// Binaries built with a given maximum version will continue to function on newer 224 /// operating system versions. However, such a binary may not take full advantage of the 225 /// newer operating system APIs. 226 /// 227 /// See `Os.isAtLeast`. 228 pub const VersionRange = union { 229 none: void, 230 semver: Version.Range, 231 linux: LinuxVersionRange, 232 windows: WindowsVersion.Range, 233 234 /// The default `VersionRange` represents the range that the Zig Standard Library 235 /// bases its abstractions on. 236 pub fn default(tag: Tag, arch: Cpu.Arch) VersionRange { 237 switch (tag) { 238 .freestanding, 239 .ananas, 240 .cloudabi, 241 .fuchsia, 242 .kfreebsd, 243 .lv2, 244 .zos, 245 .haiku, 246 .minix, 247 .rtems, 248 .nacl, 249 .aix, 250 .cuda, 251 .nvcl, 252 .amdhsa, 253 .ps4, 254 .ps5, 255 .elfiamcu, 256 .mesa3d, 257 .contiki, 258 .amdpal, 259 .hermit, 260 .hurd, 261 .wasi, 262 .emscripten, 263 .driverkit, 264 .shadermodel, 265 .uefi, 266 .opencl, // TODO: OpenCL versions 267 .glsl450, // TODO: GLSL versions 268 .vulkan, 269 .plan9, 270 .other, 271 => return .{ .none = {} }, 272 273 .freebsd => return .{ 274 .semver = Version.Range{ 275 .min = .{ .major = 12, .minor = 0 }, 276 .max = .{ .major = 13, .minor = 1 }, 277 }, 278 }, 279 .macos => return switch (arch) { 280 .aarch64 => VersionRange{ 281 .semver = .{ 282 .min = .{ .major = 11, .minor = 7, .patch = 1 }, 283 .max = .{ .major = 13, .minor = 3 }, 284 }, 285 }, 286 .x86_64 => VersionRange{ 287 .semver = .{ 288 .min = .{ .major = 11, .minor = 7, .patch = 1 }, 289 .max = .{ .major = 13, .minor = 3 }, 290 }, 291 }, 292 else => unreachable, 293 }, 294 .ios => return .{ 295 .semver = .{ 296 .min = .{ .major = 12, .minor = 0 }, 297 .max = .{ .major = 13, .minor = 4, .patch = 0 }, 298 }, 299 }, 300 .watchos => return .{ 301 .semver = .{ 302 .min = .{ .major = 6, .minor = 0 }, 303 .max = .{ .major = 6, .minor = 2, .patch = 0 }, 304 }, 305 }, 306 .tvos => return .{ 307 .semver = .{ 308 .min = .{ .major = 13, .minor = 0 }, 309 .max = .{ .major = 13, .minor = 4, .patch = 0 }, 310 }, 311 }, 312 .netbsd => return .{ 313 .semver = .{ 314 .min = .{ .major = 8, .minor = 0 }, 315 .max = .{ .major = 10, .minor = 0 }, 316 }, 317 }, 318 .openbsd => return .{ 319 .semver = .{ 320 .min = .{ .major = 6, .minor = 8 }, 321 .max = .{ .major = 7, .minor = 2 }, 322 }, 323 }, 324 .dragonfly => return .{ 325 .semver = .{ 326 .min = .{ .major = 5, .minor = 8 }, 327 .max = .{ .major = 6, .minor = 4 }, 328 }, 329 }, 330 .solaris => return .{ 331 .semver = .{ 332 .min = .{ .major = 5, .minor = 11 }, 333 .max = .{ .major = 5, .minor = 11 }, 334 }, 335 }, 336 337 .linux => return .{ 338 .linux = .{ 339 .range = .{ 340 .min = .{ .major = 3, .minor = 16 }, 341 .max = .{ .major = 5, .minor = 10, .patch = 81 }, 342 }, 343 .glibc = .{ .major = 2, .minor = 19 }, 344 }, 345 }, 346 347 .windows => return .{ 348 .windows = .{ 349 .min = .win8_1, 350 .max = WindowsVersion.latest, 351 }, 352 }, 353 } 354 } 355 }; 356 357 pub const TaggedVersionRange = union(enum) { 358 none: void, 359 semver: Version.Range, 360 linux: LinuxVersionRange, 361 windows: WindowsVersion.Range, 362 }; 363 364 /// Provides a tagged union. `Target` does not store the tag because it is 365 /// redundant with the OS tag; this function abstracts that part away. 366 pub fn getVersionRange(self: Os) TaggedVersionRange { 367 switch (self.tag) { 368 .linux => return TaggedVersionRange{ .linux = self.version_range.linux }, 369 .windows => return TaggedVersionRange{ .windows = self.version_range.windows }, 370 371 .freebsd, 372 .macos, 373 .ios, 374 .tvos, 375 .watchos, 376 .netbsd, 377 .openbsd, 378 .dragonfly, 379 .solaris, 380 => return TaggedVersionRange{ .semver = self.version_range.semver }, 381 382 else => return .none, 383 } 384 } 385 386 /// Checks if system is guaranteed to be at least `version` or older than `version`. 387 /// Returns `null` if a runtime check is required. 388 pub fn isAtLeast(self: Os, comptime tag: Tag, version: anytype) ?bool { 389 if (self.tag != tag) return false; 390 391 return switch (tag) { 392 .linux => self.version_range.linux.isAtLeast(version), 393 .windows => self.version_range.windows.isAtLeast(version), 394 else => self.version_range.semver.isAtLeast(version), 395 }; 396 } 397 398 /// On Darwin, we always link libSystem which contains libc. 399 /// Similarly on FreeBSD and NetBSD we always link system libc 400 /// since this is the stable syscall interface. 401 pub fn requiresLibC(os: Os) bool { 402 return switch (os.tag) { 403 .freebsd, 404 .netbsd, 405 .macos, 406 .ios, 407 .tvos, 408 .watchos, 409 .dragonfly, 410 .openbsd, 411 .haiku, 412 .solaris, 413 => true, 414 415 .linux, 416 .windows, 417 .freestanding, 418 .ananas, 419 .cloudabi, 420 .fuchsia, 421 .kfreebsd, 422 .lv2, 423 .zos, 424 .minix, 425 .rtems, 426 .nacl, 427 .aix, 428 .cuda, 429 .nvcl, 430 .amdhsa, 431 .ps4, 432 .ps5, 433 .elfiamcu, 434 .mesa3d, 435 .contiki, 436 .amdpal, 437 .hermit, 438 .hurd, 439 .wasi, 440 .emscripten, 441 .driverkit, 442 .shadermodel, 443 .uefi, 444 .opencl, 445 .glsl450, 446 .vulkan, 447 .plan9, 448 .other, 449 => false, 450 }; 451 } 452 }; 453 454 pub const aarch64 = @import("target/aarch64.zig"); 455 pub const arc = @import("target/arc.zig"); 456 pub const amdgpu = @import("target/amdgpu.zig"); 457 pub const arm = @import("target/arm.zig"); 458 pub const avr = @import("target/avr.zig"); 459 pub const bpf = @import("target/bpf.zig"); 460 pub const csky = @import("target/csky.zig"); 461 pub const hexagon = @import("target/hexagon.zig"); 462 pub const m68k = @import("target/m68k.zig"); 463 pub const mips = @import("target/mips.zig"); 464 pub const msp430 = @import("target/msp430.zig"); 465 pub const nvptx = @import("target/nvptx.zig"); 466 pub const powerpc = @import("target/powerpc.zig"); 467 pub const riscv = @import("target/riscv.zig"); 468 pub const sparc = @import("target/sparc.zig"); 469 pub const spirv = @import("target/spirv.zig"); 470 pub const s390x = @import("target/s390x.zig"); 471 pub const ve = @import("target/ve.zig"); 472 pub const wasm = @import("target/wasm.zig"); 473 pub const x86 = @import("target/x86.zig"); 474 475 pub const Abi = enum { 476 none, 477 gnu, 478 gnuabin32, 479 gnuabi64, 480 gnueabi, 481 gnueabihf, 482 gnux32, 483 gnuilp32, 484 code16, 485 eabi, 486 eabihf, 487 android, 488 musl, 489 musleabi, 490 musleabihf, 491 muslx32, 492 msvc, 493 itanium, 494 cygnus, 495 coreclr, 496 simulator, 497 macabi, 498 pixel, 499 vertex, 500 geometry, 501 hull, 502 domain, 503 compute, 504 library, 505 raygeneration, 506 intersection, 507 anyhit, 508 closesthit, 509 miss, 510 callable, 511 mesh, 512 amplification, 513 514 pub fn default(arch: Cpu.Arch, target_os: Os) Abi { 515 if (arch.isWasm()) { 516 return .musl; 517 } 518 switch (target_os.tag) { 519 .freestanding, 520 .ananas, 521 .cloudabi, 522 .dragonfly, 523 .lv2, 524 .solaris, 525 .zos, 526 .minix, 527 .rtems, 528 .nacl, 529 .aix, 530 .cuda, 531 .nvcl, 532 .amdhsa, 533 .ps4, 534 .ps5, 535 .elfiamcu, 536 .mesa3d, 537 .contiki, 538 .amdpal, 539 .hermit, 540 .other, 541 => return .eabi, 542 .openbsd, 543 .freebsd, 544 .fuchsia, 545 .kfreebsd, 546 .netbsd, 547 .hurd, 548 .haiku, 549 .windows, 550 => return .gnu, 551 .uefi => return .msvc, 552 .linux, 553 .wasi, 554 .emscripten, 555 => return .musl, 556 .opencl, // TODO: SPIR-V ABIs with Linkage capability 557 .glsl450, 558 .vulkan, 559 .plan9, // TODO specify abi 560 .macos, 561 .ios, 562 .tvos, 563 .watchos, 564 .driverkit, 565 .shadermodel, 566 => return .none, 567 } 568 } 569 570 pub fn isGnu(abi: Abi) bool { 571 return switch (abi) { 572 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true, 573 else => false, 574 }; 575 } 576 577 pub fn isMusl(abi: Abi) bool { 578 return switch (abi) { 579 .musl, .musleabi, .musleabihf => true, 580 else => false, 581 }; 582 } 583 584 pub fn floatAbi(abi: Abi) FloatAbi { 585 return switch (abi) { 586 .gnueabihf, 587 .eabihf, 588 .musleabihf, 589 => .hard, 590 else => .soft, 591 }; 592 } 593 }; 594 595 pub const ObjectFormat = enum { 596 /// Common Object File Format (Windows) 597 coff, 598 /// DirectX Container 599 dxcontainer, 600 /// Executable and Linking Format 601 elf, 602 /// macOS relocatables 603 macho, 604 /// Standard, Portable Intermediate Representation V 605 spirv, 606 /// WebAssembly 607 wasm, 608 /// C source code 609 c, 610 /// Intel IHEX 611 hex, 612 /// Machine code with no metadata. 613 raw, 614 /// Plan 9 from Bell Labs 615 plan9, 616 /// Nvidia PTX format 617 nvptx, 618 619 pub fn fileExt(of: ObjectFormat, cpu_arch: Cpu.Arch) [:0]const u8 { 620 return switch (of) { 621 .coff => ".obj", 622 .elf, .macho, .wasm => ".o", 623 .c => ".c", 624 .spirv => ".spv", 625 .hex => ".ihex", 626 .raw => ".bin", 627 .plan9 => plan9Ext(cpu_arch), 628 .nvptx => ".ptx", 629 .dxcontainer => ".dxil", 630 }; 631 } 632 633 pub fn default(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat { 634 return switch (os_tag) { 635 .windows, .uefi => .coff, 636 .ios, .macos, .watchos, .tvos => .macho, 637 .plan9 => .plan9, 638 else => return switch (cpu_arch) { 639 .wasm32, .wasm64 => .wasm, 640 .spirv32, .spirv64 => .spirv, 641 .nvptx, .nvptx64 => .nvptx, 642 else => .elf, 643 }, 644 }; 645 } 646 }; 647 648 pub const SubSystem = enum { 649 Console, 650 Windows, 651 Posix, 652 Native, 653 EfiApplication, 654 EfiBootServiceDriver, 655 EfiRom, 656 EfiRuntimeDriver, 657 }; 658 659 pub const Cpu = struct { 660 /// Architecture 661 arch: Arch, 662 663 /// The CPU model to target. It has a set of features 664 /// which are overridden with the `features` field. 665 model: *const Model, 666 667 /// An explicit list of the entire CPU feature set. It may differ from the specific CPU model's features. 668 features: Feature.Set, 669 670 pub const Feature = struct { 671 /// The bit index into `Set`. Has a default value of `undefined` because the canonical 672 /// structures are populated via comptime logic. 673 index: Set.Index = undefined, 674 675 /// Has a default value of `undefined` because the canonical 676 /// structures are populated via comptime logic. 677 name: []const u8 = undefined, 678 679 /// If this corresponds to an LLVM-recognized feature, this will be populated; 680 /// otherwise null. 681 llvm_name: ?[:0]const u8, 682 683 /// Human-friendly UTF-8 text. 684 description: []const u8, 685 686 /// Sparse `Set` of features this depends on. 687 dependencies: Set, 688 689 /// A bit set of all the features. 690 pub const Set = struct { 691 ints: [usize_count]usize, 692 693 pub const needed_bit_count = 288; 694 pub const byte_count = (needed_bit_count + 7) / 8; 695 pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize); 696 pub const Index = std.math.Log2Int(std.meta.Int(.unsigned, usize_count * @bitSizeOf(usize))); 697 pub const ShiftInt = std.math.Log2Int(usize); 698 699 pub const empty = Set{ .ints = [1]usize{0} ** usize_count }; 700 701 pub fn isEmpty(set: Set) bool { 702 return for (set.ints) |x| { 703 if (x != 0) break false; 704 } else true; 705 } 706 707 pub fn isEnabled(set: Set, arch_feature_index: Index) bool { 708 const usize_index = arch_feature_index / @bitSizeOf(usize); 709 const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize)); 710 return (set.ints[usize_index] & (@as(usize, 1) << bit_index)) != 0; 711 } 712 713 /// Adds the specified feature but not its dependencies. 714 pub fn addFeature(set: *Set, arch_feature_index: Index) void { 715 const usize_index = arch_feature_index / @bitSizeOf(usize); 716 const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize)); 717 set.ints[usize_index] |= @as(usize, 1) << bit_index; 718 } 719 720 /// Adds the specified feature set but not its dependencies. 721 pub fn addFeatureSet(set: *Set, other_set: Set) void { 722 set.ints = @as(@Vector(usize_count, usize), set.ints) | @as(@Vector(usize_count, usize), other_set.ints); 723 } 724 725 /// Removes the specified feature but not its dependents. 726 pub fn removeFeature(set: *Set, arch_feature_index: Index) void { 727 const usize_index = arch_feature_index / @bitSizeOf(usize); 728 const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize)); 729 set.ints[usize_index] &= ~(@as(usize, 1) << bit_index); 730 } 731 732 /// Removes the specified feature but not its dependents. 733 pub fn removeFeatureSet(set: *Set, other_set: Set) void { 734 set.ints = @as(@Vector(usize_count, usize), set.ints) & ~@as(@Vector(usize_count, usize), other_set.ints); 735 } 736 737 pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void { 738 @setEvalBranchQuota(1000000); 739 740 var old = set.ints; 741 while (true) { 742 for (all_features_list, 0..) |feature, index_usize| { 743 const index = @intCast(Index, index_usize); 744 if (set.isEnabled(index)) { 745 set.addFeatureSet(feature.dependencies); 746 } 747 } 748 const nothing_changed = mem.eql(usize, &old, &set.ints); 749 if (nothing_changed) return; 750 old = set.ints; 751 } 752 } 753 754 pub fn asBytes(set: *const Set) *const [byte_count]u8 { 755 return @ptrCast(*const [byte_count]u8, &set.ints); 756 } 757 758 pub fn eql(set: Set, other_set: Set) bool { 759 return mem.eql(usize, &set.ints, &other_set.ints); 760 } 761 762 pub fn isSuperSetOf(set: Set, other_set: Set) bool { 763 const V = @Vector(usize_count, usize); 764 const set_v: V = set.ints; 765 const other_v: V = other_set.ints; 766 return @reduce(.And, (set_v & other_v) == other_v); 767 } 768 }; 769 770 pub fn feature_set_fns(comptime F: type) type { 771 return struct { 772 /// Populates only the feature bits specified. 773 pub fn featureSet(features: []const F) Set { 774 var x = Set.empty; 775 for (features) |feature| { 776 x.addFeature(@enumToInt(feature)); 777 } 778 return x; 779 } 780 781 /// Returns true if the specified feature is enabled. 782 pub fn featureSetHas(set: Set, feature: F) bool { 783 return set.isEnabled(@enumToInt(feature)); 784 } 785 786 /// Returns true if any specified feature is enabled. 787 pub fn featureSetHasAny(set: Set, features: anytype) bool { 788 comptime std.debug.assert(std.meta.trait.isIndexable(@TypeOf(features))); 789 inline for (features) |feature| { 790 if (set.isEnabled(@enumToInt(@as(F, feature)))) return true; 791 } 792 return false; 793 } 794 795 /// Returns true if every specified feature is enabled. 796 pub fn featureSetHasAll(set: Set, features: anytype) bool { 797 comptime std.debug.assert(std.meta.trait.isIndexable(@TypeOf(features))); 798 inline for (features) |feature| { 799 if (!set.isEnabled(@enumToInt(@as(F, feature)))) return false; 800 } 801 return true; 802 } 803 }; 804 } 805 }; 806 807 pub const Arch = enum { 808 arm, 809 armeb, 810 aarch64, 811 aarch64_be, 812 aarch64_32, 813 arc, 814 avr, 815 bpfel, 816 bpfeb, 817 csky, 818 dxil, 819 hexagon, 820 loongarch32, 821 loongarch64, 822 m68k, 823 mips, 824 mipsel, 825 mips64, 826 mips64el, 827 msp430, 828 powerpc, 829 powerpcle, 830 powerpc64, 831 powerpc64le, 832 r600, 833 amdgcn, 834 riscv32, 835 riscv64, 836 sparc, 837 sparc64, 838 sparcel, 839 s390x, 840 tce, 841 tcele, 842 thumb, 843 thumbeb, 844 x86, 845 x86_64, 846 xcore, 847 nvptx, 848 nvptx64, 849 le32, 850 le64, 851 amdil, 852 amdil64, 853 hsail, 854 hsail64, 855 spir, 856 spir64, 857 spirv32, 858 spirv64, 859 kalimba, 860 shave, 861 lanai, 862 wasm32, 863 wasm64, 864 renderscript32, 865 renderscript64, 866 ve, 867 // Stage1 currently assumes that architectures above this comment 868 // map one-to-one with the ZigLLVM_ArchType enum. 869 spu_2, 870 871 pub fn isX86(arch: Arch) bool { 872 return switch (arch) { 873 .x86, .x86_64 => true, 874 else => false, 875 }; 876 } 877 878 pub fn isARM(arch: Arch) bool { 879 return switch (arch) { 880 .arm, .armeb => true, 881 else => false, 882 }; 883 } 884 885 pub fn isAARCH64(arch: Arch) bool { 886 return switch (arch) { 887 .aarch64, .aarch64_be, .aarch64_32 => true, 888 else => false, 889 }; 890 } 891 892 pub fn isThumb(arch: Arch) bool { 893 return switch (arch) { 894 .thumb, .thumbeb => true, 895 else => false, 896 }; 897 } 898 899 pub fn isWasm(arch: Arch) bool { 900 return switch (arch) { 901 .wasm32, .wasm64 => true, 902 else => false, 903 }; 904 } 905 906 pub fn isRISCV(arch: Arch) bool { 907 return switch (arch) { 908 .riscv32, .riscv64 => true, 909 else => false, 910 }; 911 } 912 913 pub fn isMIPS(arch: Arch) bool { 914 return switch (arch) { 915 .mips, .mipsel, .mips64, .mips64el => true, 916 else => false, 917 }; 918 } 919 920 pub fn isPPC(arch: Arch) bool { 921 return switch (arch) { 922 .powerpc, .powerpcle => true, 923 else => false, 924 }; 925 } 926 927 pub fn isPPC64(arch: Arch) bool { 928 return switch (arch) { 929 .powerpc64, .powerpc64le => true, 930 else => false, 931 }; 932 } 933 934 pub fn isSPARC(arch: Arch) bool { 935 return switch (arch) { 936 .sparc, .sparcel, .sparc64 => true, 937 else => false, 938 }; 939 } 940 941 pub fn isSPIRV(arch: Arch) bool { 942 return switch (arch) { 943 .spirv32, .spirv64 => true, 944 else => false, 945 }; 946 } 947 948 pub fn isBpf(arch: Arch) bool { 949 return switch (arch) { 950 .bpfel, .bpfeb => true, 951 else => false, 952 }; 953 } 954 955 pub fn isNvptx(arch: Arch) bool { 956 return switch (arch) { 957 .nvptx, .nvptx64 => true, 958 else => false, 959 }; 960 } 961 962 pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model { 963 for (arch.allCpuModels()) |cpu| { 964 if (mem.eql(u8, cpu_name, cpu.name)) { 965 return cpu; 966 } 967 } 968 return error.UnknownCpuModel; 969 } 970 971 pub fn toElfMachine(arch: Arch) std.elf.EM { 972 return switch (arch) { 973 .avr => .AVR, 974 .msp430 => .MSP430, 975 .arc => .ARC, 976 .arm => .ARM, 977 .armeb => .ARM, 978 .hexagon => .HEXAGON, 979 .dxil => .NONE, 980 .m68k => .@"68K", 981 .le32 => .NONE, 982 .mips => .MIPS, 983 .mipsel => .MIPS_RS3_LE, 984 .powerpc, .powerpcle => .PPC, 985 .r600 => .NONE, 986 .riscv32 => .RISCV, 987 .sparc => .SPARC, 988 .sparcel => .SPARC, 989 .tce => .NONE, 990 .tcele => .NONE, 991 .thumb => .ARM, 992 .thumbeb => .ARM, 993 .x86 => .@"386", 994 .xcore => .XCORE, 995 .nvptx => .NONE, 996 .amdil => .NONE, 997 .hsail => .NONE, 998 .spir => .NONE, 999 .kalimba => .CSR_KALIMBA, 1000 .shave => .NONE, 1001 .lanai => .LANAI, 1002 .wasm32 => .NONE, 1003 .renderscript32 => .NONE, 1004 .aarch64_32 => .AARCH64, 1005 .aarch64 => .AARCH64, 1006 .aarch64_be => .AARCH64, 1007 .mips64 => .MIPS, 1008 .mips64el => .MIPS_RS3_LE, 1009 .powerpc64 => .PPC64, 1010 .powerpc64le => .PPC64, 1011 .riscv64 => .RISCV, 1012 .x86_64 => .X86_64, 1013 .nvptx64 => .NONE, 1014 .le64 => .NONE, 1015 .amdil64 => .NONE, 1016 .hsail64 => .NONE, 1017 .spir64 => .NONE, 1018 .wasm64 => .NONE, 1019 .renderscript64 => .NONE, 1020 .amdgcn => .NONE, 1021 .bpfel => .BPF, 1022 .bpfeb => .BPF, 1023 .csky => .CSKY, 1024 .sparc64 => .SPARCV9, 1025 .s390x => .S390, 1026 .ve => .NONE, 1027 .spu_2 => .SPU_2, 1028 .spirv32 => .NONE, 1029 .spirv64 => .NONE, 1030 .loongarch32 => .NONE, 1031 .loongarch64 => .NONE, 1032 }; 1033 } 1034 1035 pub fn toCoffMachine(arch: Arch) std.coff.MachineType { 1036 return switch (arch) { 1037 .avr => .Unknown, 1038 .msp430 => .Unknown, 1039 .arc => .Unknown, 1040 .arm => .ARM, 1041 .armeb => .Unknown, 1042 .dxil => .Unknown, 1043 .hexagon => .Unknown, 1044 .m68k => .Unknown, 1045 .le32 => .Unknown, 1046 .mips => .Unknown, 1047 .mipsel => .Unknown, 1048 .powerpc, .powerpcle => .POWERPC, 1049 .r600 => .Unknown, 1050 .riscv32 => .RISCV32, 1051 .sparc => .Unknown, 1052 .sparcel => .Unknown, 1053 .tce => .Unknown, 1054 .tcele => .Unknown, 1055 .thumb => .Thumb, 1056 .thumbeb => .Thumb, 1057 .x86 => .I386, 1058 .xcore => .Unknown, 1059 .nvptx => .Unknown, 1060 .amdil => .Unknown, 1061 .hsail => .Unknown, 1062 .spir => .Unknown, 1063 .kalimba => .Unknown, 1064 .shave => .Unknown, 1065 .lanai => .Unknown, 1066 .wasm32 => .Unknown, 1067 .renderscript32 => .Unknown, 1068 .aarch64_32 => .ARM64, 1069 .aarch64 => .ARM64, 1070 .aarch64_be => .Unknown, 1071 .mips64 => .Unknown, 1072 .mips64el => .Unknown, 1073 .powerpc64 => .Unknown, 1074 .powerpc64le => .Unknown, 1075 .riscv64 => .RISCV64, 1076 .x86_64 => .X64, 1077 .nvptx64 => .Unknown, 1078 .le64 => .Unknown, 1079 .amdil64 => .Unknown, 1080 .hsail64 => .Unknown, 1081 .spir64 => .Unknown, 1082 .wasm64 => .Unknown, 1083 .renderscript64 => .Unknown, 1084 .amdgcn => .Unknown, 1085 .bpfel => .Unknown, 1086 .bpfeb => .Unknown, 1087 .csky => .Unknown, 1088 .sparc64 => .Unknown, 1089 .s390x => .Unknown, 1090 .ve => .Unknown, 1091 .spu_2 => .Unknown, 1092 .spirv32 => .Unknown, 1093 .spirv64 => .Unknown, 1094 .loongarch32 => .Unknown, 1095 .loongarch64 => .Unknown, 1096 }; 1097 } 1098 1099 pub fn endian(arch: Arch) std.builtin.Endian { 1100 return switch (arch) { 1101 .avr, 1102 .arm, 1103 .aarch64_32, 1104 .aarch64, 1105 .amdgcn, 1106 .amdil, 1107 .amdil64, 1108 .bpfel, 1109 .csky, 1110 .hexagon, 1111 .hsail, 1112 .hsail64, 1113 .kalimba, 1114 .le32, 1115 .le64, 1116 .mipsel, 1117 .mips64el, 1118 .msp430, 1119 .nvptx, 1120 .nvptx64, 1121 .sparcel, 1122 .tcele, 1123 .powerpcle, 1124 .powerpc64le, 1125 .r600, 1126 .riscv32, 1127 .riscv64, 1128 .x86, 1129 .x86_64, 1130 .wasm32, 1131 .wasm64, 1132 .xcore, 1133 .thumb, 1134 .spir, 1135 .spir64, 1136 .renderscript32, 1137 .renderscript64, 1138 .shave, 1139 .ve, 1140 .spu_2, 1141 // GPU bitness is opaque. For now, assume little endian. 1142 .spirv32, 1143 .spirv64, 1144 .dxil, 1145 .loongarch32, 1146 .loongarch64, 1147 => .Little, 1148 1149 .arc, 1150 .armeb, 1151 .aarch64_be, 1152 .bpfeb, 1153 .m68k, 1154 .mips, 1155 .mips64, 1156 .powerpc, 1157 .powerpc64, 1158 .thumbeb, 1159 .sparc, 1160 .sparc64, 1161 .tce, 1162 .lanai, 1163 .s390x, 1164 => .Big, 1165 }; 1166 } 1167 1168 /// Returns whether this architecture supports the address space 1169 pub fn supportsAddressSpace(arch: Arch, address_space: std.builtin.AddressSpace) bool { 1170 const is_nvptx = arch == .nvptx or arch == .nvptx64; 1171 const is_spirv = arch == .spirv32 or arch == .spirv64; 1172 const is_gpu = is_nvptx or is_spirv or arch == .amdgcn; 1173 return switch (address_space) { 1174 .generic => true, 1175 .fs, .gs, .ss => arch == .x86_64 or arch == .x86, 1176 .global, .constant, .local, .shared => is_gpu, 1177 .param => is_nvptx, 1178 // TODO this should also check how many flash banks the cpu has 1179 .flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr, 1180 }; 1181 } 1182 1183 pub fn ptrBitWidth(arch: Arch) u16 { 1184 switch (arch) { 1185 .avr, 1186 .msp430, 1187 .spu_2, 1188 => return 16, 1189 1190 .arc, 1191 .arm, 1192 .armeb, 1193 .csky, 1194 .hexagon, 1195 .m68k, 1196 .le32, 1197 .mips, 1198 .mipsel, 1199 .powerpc, 1200 .powerpcle, 1201 .r600, 1202 .riscv32, 1203 .sparc, 1204 .sparcel, 1205 .tce, 1206 .tcele, 1207 .thumb, 1208 .thumbeb, 1209 .x86, 1210 .xcore, 1211 .nvptx, 1212 .amdil, 1213 .hsail, 1214 .spir, 1215 .kalimba, 1216 .shave, 1217 .lanai, 1218 .wasm32, 1219 .renderscript32, 1220 .aarch64_32, 1221 .spirv32, 1222 .loongarch32, 1223 .dxil, 1224 => return 32, 1225 1226 .aarch64, 1227 .aarch64_be, 1228 .mips64, 1229 .mips64el, 1230 .powerpc64, 1231 .powerpc64le, 1232 .riscv64, 1233 .x86_64, 1234 .nvptx64, 1235 .le64, 1236 .amdil64, 1237 .hsail64, 1238 .spir64, 1239 .wasm64, 1240 .renderscript64, 1241 .amdgcn, 1242 .bpfel, 1243 .bpfeb, 1244 .sparc64, 1245 .s390x, 1246 .ve, 1247 .spirv64, 1248 .loongarch64, 1249 => return 64, 1250 } 1251 } 1252 1253 /// Returns a name that matches the lib/std/target/* source file name. 1254 pub fn genericName(arch: Arch) []const u8 { 1255 return switch (arch) { 1256 .arm, .armeb, .thumb, .thumbeb => "arm", 1257 .aarch64, .aarch64_be, .aarch64_32 => "aarch64", 1258 .bpfel, .bpfeb => "bpf", 1259 .mips, .mipsel, .mips64, .mips64el => "mips", 1260 .powerpc, .powerpcle, .powerpc64, .powerpc64le => "powerpc", 1261 .amdgcn => "amdgpu", 1262 .riscv32, .riscv64 => "riscv", 1263 .sparc, .sparc64, .sparcel => "sparc", 1264 .s390x => "s390x", 1265 .x86, .x86_64 => "x86", 1266 .nvptx, .nvptx64 => "nvptx", 1267 .wasm32, .wasm64 => "wasm", 1268 .spirv32, .spirv64 => "spir-v", 1269 else => @tagName(arch), 1270 }; 1271 } 1272 1273 /// All CPU features Zig is aware of, sorted lexicographically by name. 1274 pub fn allFeaturesList(arch: Arch) []const Cpu.Feature { 1275 return switch (arch) { 1276 .arm, .armeb, .thumb, .thumbeb => &arm.all_features, 1277 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.all_features, 1278 .avr => &avr.all_features, 1279 .bpfel, .bpfeb => &bpf.all_features, 1280 .hexagon => &hexagon.all_features, 1281 .mips, .mipsel, .mips64, .mips64el => &mips.all_features, 1282 .msp430 => &msp430.all_features, 1283 .powerpc, .powerpcle, .powerpc64, .powerpc64le => &powerpc.all_features, 1284 .amdgcn => &amdgpu.all_features, 1285 .riscv32, .riscv64 => &riscv.all_features, 1286 .sparc, .sparc64, .sparcel => &sparc.all_features, 1287 .spirv32, .spirv64 => &spirv.all_features, 1288 .s390x => &s390x.all_features, 1289 .x86, .x86_64 => &x86.all_features, 1290 .nvptx, .nvptx64 => &nvptx.all_features, 1291 .ve => &ve.all_features, 1292 .wasm32, .wasm64 => &wasm.all_features, 1293 1294 else => &[0]Cpu.Feature{}, 1295 }; 1296 } 1297 1298 /// All processors Zig is aware of, sorted lexicographically by name. 1299 pub fn allCpuModels(arch: Arch) []const *const Cpu.Model { 1300 return switch (arch) { 1301 .arm, .armeb, .thumb, .thumbeb => comptime allCpusFromDecls(arm.cpu), 1302 .aarch64, .aarch64_be, .aarch64_32 => comptime allCpusFromDecls(aarch64.cpu), 1303 .avr => comptime allCpusFromDecls(avr.cpu), 1304 .bpfel, .bpfeb => comptime allCpusFromDecls(bpf.cpu), 1305 .hexagon => comptime allCpusFromDecls(hexagon.cpu), 1306 .mips, .mipsel, .mips64, .mips64el => comptime allCpusFromDecls(mips.cpu), 1307 .msp430 => comptime allCpusFromDecls(msp430.cpu), 1308 .powerpc, .powerpcle, .powerpc64, .powerpc64le => comptime allCpusFromDecls(powerpc.cpu), 1309 .amdgcn => comptime allCpusFromDecls(amdgpu.cpu), 1310 .riscv32, .riscv64 => comptime allCpusFromDecls(riscv.cpu), 1311 .sparc, .sparc64, .sparcel => comptime allCpusFromDecls(sparc.cpu), 1312 .s390x => comptime allCpusFromDecls(s390x.cpu), 1313 .x86, .x86_64 => comptime allCpusFromDecls(x86.cpu), 1314 .nvptx, .nvptx64 => comptime allCpusFromDecls(nvptx.cpu), 1315 .ve => comptime allCpusFromDecls(ve.cpu), 1316 .wasm32, .wasm64 => comptime allCpusFromDecls(wasm.cpu), 1317 1318 else => &[0]*const Model{}, 1319 }; 1320 } 1321 1322 fn allCpusFromDecls(comptime cpus: type) []const *const Cpu.Model { 1323 const decls = @typeInfo(cpus).Struct.decls; 1324 var array: [decls.len]*const Cpu.Model = undefined; 1325 for (decls, 0..) |decl, i| { 1326 array[i] = &@field(cpus, decl.name); 1327 } 1328 return &array; 1329 } 1330 }; 1331 1332 pub const Model = struct { 1333 name: []const u8, 1334 llvm_name: ?[:0]const u8, 1335 features: Feature.Set, 1336 1337 pub fn toCpu(model: *const Model, arch: Arch) Cpu { 1338 var features = model.features; 1339 features.populateDependencies(arch.allFeaturesList()); 1340 return .{ 1341 .arch = arch, 1342 .model = model, 1343 .features = features, 1344 }; 1345 } 1346 1347 pub fn generic(arch: Arch) *const Model { 1348 const S = struct { 1349 const generic_model = Model{ 1350 .name = "generic", 1351 .llvm_name = null, 1352 .features = Cpu.Feature.Set.empty, 1353 }; 1354 }; 1355 return switch (arch) { 1356 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic, 1357 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic, 1358 .avr => &avr.cpu.avr2, 1359 .bpfel, .bpfeb => &bpf.cpu.generic, 1360 .hexagon => &hexagon.cpu.generic, 1361 .m68k => &m68k.cpu.generic, 1362 .mips, .mipsel => &mips.cpu.mips32, 1363 .mips64, .mips64el => &mips.cpu.mips64, 1364 .msp430 => &msp430.cpu.generic, 1365 .powerpc => &powerpc.cpu.ppc, 1366 .powerpcle => &powerpc.cpu.ppc, 1367 .powerpc64 => &powerpc.cpu.ppc64, 1368 .powerpc64le => &powerpc.cpu.ppc64le, 1369 .amdgcn => &amdgpu.cpu.generic, 1370 .riscv32 => &riscv.cpu.generic_rv32, 1371 .riscv64 => &riscv.cpu.generic_rv64, 1372 .sparc, .sparcel => &sparc.cpu.generic, 1373 .sparc64 => &sparc.cpu.v9, // 64-bit SPARC needs v9 as the baseline 1374 .s390x => &s390x.cpu.generic, 1375 .x86 => &x86.cpu.i386, 1376 .x86_64 => &x86.cpu.x86_64, 1377 .nvptx, .nvptx64 => &nvptx.cpu.sm_20, 1378 .ve => &ve.cpu.generic, 1379 .wasm32, .wasm64 => &wasm.cpu.generic, 1380 1381 else => &S.generic_model, 1382 }; 1383 } 1384 1385 pub fn baseline(arch: Arch) *const Model { 1386 return switch (arch) { 1387 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline, 1388 .riscv32 => &riscv.cpu.baseline_rv32, 1389 .riscv64 => &riscv.cpu.baseline_rv64, 1390 .x86 => &x86.cpu.pentium4, 1391 .nvptx, .nvptx64 => &nvptx.cpu.sm_20, 1392 .sparc, .sparcel => &sparc.cpu.v8, 1393 1394 else => generic(arch), 1395 }; 1396 } 1397 }; 1398 1399 /// The "default" set of CPU features for cross-compiling. A conservative set 1400 /// of features that is expected to be supported on most available hardware. 1401 pub fn baseline(arch: Arch) Cpu { 1402 return Model.baseline(arch).toCpu(arch); 1403 } 1404 }; 1405 1406 pub const stack_align = 16; 1407 1408 pub fn zigTriple(self: Target, allocator: mem.Allocator) ![]u8 { 1409 return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator); 1410 } 1411 1412 pub fn linuxTripleSimple(allocator: mem.Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![]u8 { 1413 return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) }); 1414 } 1415 1416 pub fn linuxTriple(self: Target, allocator: mem.Allocator) ![]u8 { 1417 return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi); 1418 } 1419 1420 pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 { 1421 return switch (os_tag) { 1422 .windows => ".exe", 1423 .uefi => ".efi", 1424 .plan9 => plan9Ext(cpu_arch), 1425 else => switch (cpu_arch) { 1426 .wasm32, .wasm64 => ".wasm", 1427 else => "", 1428 }, 1429 }; 1430 } 1431 1432 pub fn exeFileExt(self: Target) [:0]const u8 { 1433 return exeFileExtSimple(self.cpu.arch, self.os.tag); 1434 } 1435 1436 pub fn staticLibSuffix_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 { 1437 if (abi == .msvc) { 1438 return ".lib"; 1439 } 1440 switch (os_tag) { 1441 .windows, .uefi => return ".lib", 1442 else => return ".a", 1443 } 1444 } 1445 1446 pub fn staticLibSuffix(self: Target) [:0]const u8 { 1447 return staticLibSuffix_os_abi(self.os.tag, self.abi); 1448 } 1449 1450 pub fn dynamicLibSuffix(self: Target) [:0]const u8 { 1451 return self.os.tag.dynamicLibSuffix(); 1452 } 1453 1454 pub fn libPrefix_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 { 1455 if (abi == .msvc) { 1456 return ""; 1457 } 1458 switch (os_tag) { 1459 .windows, .uefi => return "", 1460 else => return "lib", 1461 } 1462 } 1463 1464 pub fn libPrefix(self: Target) [:0]const u8 { 1465 return libPrefix_os_abi(self.os.tag, self.abi); 1466 } 1467 1468 pub fn isMinGW(self: Target) bool { 1469 return self.os.tag == .windows and self.isGnu(); 1470 } 1471 1472 pub fn isGnu(self: Target) bool { 1473 return self.abi.isGnu(); 1474 } 1475 1476 pub fn isMusl(self: Target) bool { 1477 return self.abi.isMusl(); 1478 } 1479 1480 pub fn isAndroid(self: Target) bool { 1481 return self.abi == .android; 1482 } 1483 1484 pub fn isWasm(self: Target) bool { 1485 return self.cpu.arch.isWasm(); 1486 } 1487 1488 pub fn isDarwin(self: Target) bool { 1489 return self.os.tag.isDarwin(); 1490 } 1491 1492 pub fn isBSD(self: Target) bool { 1493 return self.os.tag.isBSD(); 1494 } 1495 1496 pub fn isBpfFreestanding(self: Target) bool { 1497 return self.cpu.arch.isBpf() and self.os.tag == .freestanding; 1498 } 1499 1500 pub fn isGnuLibC_os_tag_abi(os_tag: Os.Tag, abi: Abi) bool { 1501 return os_tag == .linux and abi.isGnu(); 1502 } 1503 1504 pub fn isGnuLibC(self: Target) bool { 1505 return isGnuLibC_os_tag_abi(self.os.tag, self.abi); 1506 } 1507 1508 pub fn supportsNewStackCall(self: Target) bool { 1509 return !self.cpu.arch.isWasm(); 1510 } 1511 1512 pub const FloatAbi = enum { 1513 hard, 1514 soft, 1515 soft_fp, 1516 }; 1517 1518 pub fn getFloatAbi(self: Target) FloatAbi { 1519 return self.abi.floatAbi(); 1520 } 1521 1522 pub fn hasDynamicLinker(self: Target) bool { 1523 if (self.cpu.arch.isWasm()) { 1524 return false; 1525 } 1526 switch (self.os.tag) { 1527 .freestanding, 1528 .ios, 1529 .tvos, 1530 .watchos, 1531 .macos, 1532 .uefi, 1533 .windows, 1534 .emscripten, 1535 .opencl, 1536 .glsl450, 1537 .vulkan, 1538 .plan9, 1539 .other, 1540 => return false, 1541 else => return true, 1542 } 1543 } 1544 1545 pub const DynamicLinker = struct { 1546 /// Contains the memory used to store the dynamic linker path. This field should 1547 /// not be used directly. See `get` and `set`. This field exists so that this API requires no allocator. 1548 buffer: [255]u8 = undefined, 1549 1550 /// Used to construct the dynamic linker path. This field should not be used 1551 /// directly. See `get` and `set`. 1552 max_byte: ?u8 = null, 1553 1554 /// Asserts that the length is less than or equal to 255 bytes. 1555 pub fn init(dl_or_null: ?[]const u8) DynamicLinker { 1556 var result: DynamicLinker = undefined; 1557 result.set(dl_or_null); 1558 return result; 1559 } 1560 1561 /// The returned memory has the same lifetime as the `DynamicLinker`. 1562 pub fn get(self: *const DynamicLinker) ?[]const u8 { 1563 const m: usize = self.max_byte orelse return null; 1564 return self.buffer[0 .. m + 1]; 1565 } 1566 1567 /// Asserts that the length is less than or equal to 255 bytes. 1568 pub fn set(self: *DynamicLinker, dl_or_null: ?[]const u8) void { 1569 if (dl_or_null) |dl| { 1570 mem.copy(u8, &self.buffer, dl); 1571 self.max_byte = @intCast(u8, dl.len - 1); 1572 } else { 1573 self.max_byte = null; 1574 } 1575 } 1576 }; 1577 1578 pub fn standardDynamicLinkerPath(self: Target) DynamicLinker { 1579 var result: DynamicLinker = .{}; 1580 const S = struct { 1581 fn print(r: *DynamicLinker, comptime fmt: []const u8, args: anytype) DynamicLinker { 1582 r.max_byte = @intCast(u8, (std.fmt.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1); 1583 return r.*; 1584 } 1585 fn copy(r: *DynamicLinker, s: []const u8) DynamicLinker { 1586 mem.copy(u8, &r.buffer, s); 1587 r.max_byte = @intCast(u8, s.len - 1); 1588 return r.*; 1589 } 1590 }; 1591 const print = S.print; 1592 const copy = S.copy; 1593 1594 if (self.abi == .android) { 1595 const suffix = if (self.cpu.arch.ptrBitWidth() == 64) "64" else ""; 1596 return print(&result, "/system/bin/linker{s}", .{suffix}); 1597 } 1598 1599 if (self.abi.isMusl()) { 1600 const is_arm = switch (self.cpu.arch) { 1601 .arm, .armeb, .thumb, .thumbeb => true, 1602 else => false, 1603 }; 1604 const arch_part = switch (self.cpu.arch) { 1605 .arm, .thumb => "arm", 1606 .armeb, .thumbeb => "armeb", 1607 else => |arch| @tagName(arch), 1608 }; 1609 const arch_suffix = if (is_arm and self.abi.floatAbi() == .hard) "hf" else ""; 1610 return print(&result, "/lib/ld-musl-{s}{s}.so.1", .{ arch_part, arch_suffix }); 1611 } 1612 1613 switch (self.os.tag) { 1614 .freebsd => return copy(&result, "/libexec/ld-elf.so.1"), 1615 .netbsd => return copy(&result, "/libexec/ld.elf_so"), 1616 .openbsd => return copy(&result, "/usr/libexec/ld.so"), 1617 .dragonfly => return copy(&result, "/libexec/ld-elf.so.2"), 1618 .solaris => return copy(&result, "/lib/64/ld.so.1"), 1619 .linux => switch (self.cpu.arch) { 1620 .x86, 1621 .sparc, 1622 .sparcel, 1623 => return copy(&result, "/lib/ld-linux.so.2"), 1624 1625 .aarch64 => return copy(&result, "/lib/ld-linux-aarch64.so.1"), 1626 .aarch64_be => return copy(&result, "/lib/ld-linux-aarch64_be.so.1"), 1627 .aarch64_32 => return copy(&result, "/lib/ld-linux-aarch64_32.so.1"), 1628 1629 .arm, 1630 .armeb, 1631 .thumb, 1632 .thumbeb, 1633 => return copy(&result, switch (self.abi.floatAbi()) { 1634 .hard => "/lib/ld-linux-armhf.so.3", 1635 else => "/lib/ld-linux.so.3", 1636 }), 1637 1638 .mips, 1639 .mipsel, 1640 .mips64, 1641 .mips64el, 1642 => { 1643 const lib_suffix = switch (self.abi) { 1644 .gnuabin32, .gnux32 => "32", 1645 .gnuabi64 => "64", 1646 else => "", 1647 }; 1648 const is_nan_2008 = mips.featureSetHas(self.cpu.features, .nan2008); 1649 const loader = if (is_nan_2008) "ld-linux-mipsn8.so.1" else "ld.so.1"; 1650 return print(&result, "/lib{s}/{s}", .{ lib_suffix, loader }); 1651 }, 1652 1653 .powerpc, .powerpcle => return copy(&result, "/lib/ld.so.1"), 1654 .powerpc64, .powerpc64le => return copy(&result, "/lib64/ld64.so.2"), 1655 .s390x => return copy(&result, "/lib64/ld64.so.1"), 1656 .sparc64 => return copy(&result, "/lib64/ld-linux.so.2"), 1657 .x86_64 => return copy(&result, switch (self.abi) { 1658 .gnux32 => "/libx32/ld-linux-x32.so.2", 1659 else => "/lib64/ld-linux-x86-64.so.2", 1660 }), 1661 1662 .riscv32 => return copy(&result, "/lib/ld-linux-riscv32-ilp32.so.1"), 1663 .riscv64 => return copy(&result, "/lib/ld-linux-riscv64-lp64.so.1"), 1664 1665 // Architectures in this list have been verified as not having a standard 1666 // dynamic linker path. 1667 .wasm32, 1668 .wasm64, 1669 .bpfel, 1670 .bpfeb, 1671 .nvptx, 1672 .nvptx64, 1673 .spu_2, 1674 .avr, 1675 .spirv32, 1676 .spirv64, 1677 => return result, 1678 1679 // TODO go over each item in this list and either move it to the above list, or 1680 // implement the standard dynamic linker path code for it. 1681 .arc, 1682 .csky, 1683 .hexagon, 1684 .m68k, 1685 .msp430, 1686 .r600, 1687 .amdgcn, 1688 .tce, 1689 .tcele, 1690 .xcore, 1691 .le32, 1692 .le64, 1693 .amdil, 1694 .amdil64, 1695 .hsail, 1696 .hsail64, 1697 .spir, 1698 .spir64, 1699 .kalimba, 1700 .shave, 1701 .lanai, 1702 .renderscript32, 1703 .renderscript64, 1704 .ve, 1705 .dxil, 1706 .loongarch32, 1707 .loongarch64, 1708 => return result, 1709 }, 1710 1711 .ios, 1712 .tvos, 1713 .watchos, 1714 .macos, 1715 => return copy(&result, "/usr/lib/dyld"), 1716 1717 // Operating systems in this list have been verified as not having a standard 1718 // dynamic linker path. 1719 .freestanding, 1720 .uefi, 1721 .windows, 1722 .emscripten, 1723 .wasi, 1724 .opencl, 1725 .glsl450, 1726 .vulkan, 1727 .other, 1728 .plan9, 1729 => return result, 1730 1731 // TODO revisit when multi-arch for Haiku is available 1732 .haiku => return copy(&result, "/system/runtime_loader"), 1733 1734 // TODO go over each item in this list and either move it to the above list, or 1735 // implement the standard dynamic linker path code for it. 1736 .ananas, 1737 .cloudabi, 1738 .fuchsia, 1739 .kfreebsd, 1740 .lv2, 1741 .zos, 1742 .minix, 1743 .rtems, 1744 .nacl, 1745 .aix, 1746 .cuda, 1747 .nvcl, 1748 .amdhsa, 1749 .ps4, 1750 .ps5, 1751 .elfiamcu, 1752 .mesa3d, 1753 .contiki, 1754 .amdpal, 1755 .hermit, 1756 .hurd, 1757 .driverkit, 1758 .shadermodel, 1759 => return result, 1760 } 1761 } 1762 1763 /// 0c spim little-endian MIPS 3000 family 1764 /// 1c 68000 Motorola MC68000 1765 /// 2c 68020 Motorola MC68020 1766 /// 5c arm little-endian ARM 1767 /// 6c amd64 AMD64 and compatibles (e.g., Intel EM64T) 1768 /// 7c arm64 ARM64 (ARMv8) 1769 /// 8c 386 Intel x86, i486, Pentium, etc. 1770 /// kc sparc Sun SPARC 1771 /// qc power Power PC 1772 /// vc mips big-endian MIPS 3000 family 1773 pub fn plan9Ext(cpu_arch: Cpu.Arch) [:0]const u8 { 1774 return switch (cpu_arch) { 1775 .arm => ".5", 1776 .x86_64 => ".6", 1777 .aarch64 => ".7", 1778 .x86 => ".8", 1779 .sparc => ".k", 1780 .powerpc, .powerpcle => ".q", 1781 .mips, .mipsel => ".v", 1782 // ISAs without designated characters get 'X' for lack of a better option. 1783 else => ".X", 1784 }; 1785 } 1786 1787 pub inline fn maxIntAlignment(target: Target) u16 { 1788 return switch (target.cpu.arch) { 1789 .avr => 1, 1790 .msp430 => 2, 1791 .xcore => 4, 1792 1793 .arm, 1794 .armeb, 1795 .thumb, 1796 .thumbeb, 1797 .hexagon, 1798 .mips, 1799 .mipsel, 1800 .powerpc, 1801 .powerpcle, 1802 .r600, 1803 .amdgcn, 1804 .riscv32, 1805 .sparc, 1806 .sparcel, 1807 .s390x, 1808 .lanai, 1809 .wasm32, 1810 .wasm64, 1811 => 8, 1812 1813 .x86 => if (target.ofmt == .c) 16 else return switch (target.os.tag) { 1814 .windows, .uefi => 8, 1815 else => 4, 1816 }, 1817 1818 // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16 1819 // is a relevant number in three cases: 1820 // 1. Different machine code instruction when loading into SIMD register. 1821 // 2. The C ABI wants 16 for extern structs. 1822 // 3. 16-byte cmpxchg needs 16-byte alignment. 1823 // Same logic for powerpc64, mips64, sparc64. 1824 .x86_64, 1825 .powerpc64, 1826 .powerpc64le, 1827 .mips64, 1828 .mips64el, 1829 .sparc64, 1830 => return switch (target.ofmt) { 1831 .c => 16, 1832 else => 8, 1833 }, 1834 1835 // Even LLVMABIAlignmentOfType(i128) agrees on these targets. 1836 .aarch64, 1837 .aarch64_be, 1838 .aarch64_32, 1839 .riscv64, 1840 .bpfel, 1841 .bpfeb, 1842 .nvptx, 1843 .nvptx64, 1844 => 16, 1845 1846 // Below this comment are unverified but based on the fact that C requires 1847 // int128_t to be 16 bytes aligned, it's a safe default. 1848 .spu_2, 1849 .csky, 1850 .arc, 1851 .m68k, 1852 .tce, 1853 .tcele, 1854 .le32, 1855 .amdil, 1856 .hsail, 1857 .spir, 1858 .kalimba, 1859 .renderscript32, 1860 .spirv32, 1861 .shave, 1862 .le64, 1863 .amdil64, 1864 .hsail64, 1865 .spir64, 1866 .renderscript64, 1867 .ve, 1868 .spirv64, 1869 .dxil, 1870 .loongarch32, 1871 .loongarch64, 1872 => 16, 1873 }; 1874 } 1875 1876 pub const CType = enum { 1877 short, 1878 ushort, 1879 int, 1880 uint, 1881 long, 1882 ulong, 1883 longlong, 1884 ulonglong, 1885 float, 1886 double, 1887 longdouble, 1888 }; 1889 1890 pub fn c_type_byte_size(t: Target, c_type: CType) u16 { 1891 return switch (c_type) { 1892 .short, 1893 .ushort, 1894 .int, 1895 .uint, 1896 .long, 1897 .ulong, 1898 .longlong, 1899 .ulonglong, 1900 => @divExact(c_type_bit_size(t, c_type), 8), 1901 1902 .float => 4, 1903 .double => 8, 1904 1905 .longdouble => switch (c_type_bit_size(t, c_type)) { 1906 16 => 2, 1907 32 => 4, 1908 64 => 8, 1909 80 => @intCast(u16, mem.alignForward(10, c_type_alignment(t, .longdouble))), 1910 128 => 16, 1911 else => unreachable, 1912 }, 1913 }; 1914 } 1915 1916 pub fn c_type_bit_size(target: Target, c_type: CType) u16 { 1917 switch (target.os.tag) { 1918 .freestanding, .other => switch (target.cpu.arch) { 1919 .msp430 => switch (c_type) { 1920 .short, .ushort, .int, .uint => return 16, 1921 .float, .long, .ulong => return 32, 1922 .longlong, .ulonglong, .double, .longdouble => return 64, 1923 }, 1924 .avr => switch (c_type) { 1925 .short, .ushort, .int, .uint => return 16, 1926 .long, .ulong, .float, .double, .longdouble => return 32, 1927 .longlong, .ulonglong => return 64, 1928 }, 1929 .tce, .tcele => switch (c_type) { 1930 .short, .ushort => return 16, 1931 .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32, 1932 .float, .double, .longdouble => return 32, 1933 }, 1934 .mips64, .mips64el => switch (c_type) { 1935 .short, .ushort => return 16, 1936 .int, .uint, .float => return 32, 1937 .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32, 1938 .longlong, .ulonglong, .double => return 64, 1939 .longdouble => return 128, 1940 }, 1941 .x86_64 => switch (c_type) { 1942 .short, .ushort => return 16, 1943 .int, .uint, .float => return 32, 1944 .long, .ulong => switch (target.abi) { 1945 .gnux32, .muslx32 => return 32, 1946 else => return 64, 1947 }, 1948 .longlong, .ulonglong, .double => return 64, 1949 .longdouble => return 80, 1950 }, 1951 else => switch (c_type) { 1952 .short, .ushort => return 16, 1953 .int, .uint, .float => return 32, 1954 .long, .ulong => return target.cpu.arch.ptrBitWidth(), 1955 .longlong, .ulonglong, .double => return 64, 1956 .longdouble => switch (target.cpu.arch) { 1957 .x86 => switch (target.abi) { 1958 .android => return 64, 1959 else => return 80, 1960 }, 1961 1962 .powerpc, 1963 .powerpcle, 1964 .powerpc64, 1965 .powerpc64le, 1966 => switch (target.abi) { 1967 .musl, 1968 .musleabi, 1969 .musleabihf, 1970 .muslx32, 1971 => return 64, 1972 else => return 128, 1973 }, 1974 1975 .riscv32, 1976 .riscv64, 1977 .aarch64, 1978 .aarch64_be, 1979 .aarch64_32, 1980 .s390x, 1981 .sparc, 1982 .sparc64, 1983 .sparcel, 1984 .wasm32, 1985 .wasm64, 1986 => return 128, 1987 1988 else => return 64, 1989 }, 1990 }, 1991 }, 1992 1993 .linux, 1994 .freebsd, 1995 .netbsd, 1996 .dragonfly, 1997 .openbsd, 1998 .wasi, 1999 .emscripten, 2000 .plan9, 2001 .solaris, 2002 .haiku, 2003 .ananas, 2004 .fuchsia, 2005 .minix, 2006 => switch (target.cpu.arch) { 2007 .msp430 => switch (c_type) { 2008 .short, .ushort, .int, .uint => return 16, 2009 .long, .ulong, .float => return 32, 2010 .longlong, .ulonglong, .double, .longdouble => return 64, 2011 }, 2012 .avr => switch (c_type) { 2013 .short, .ushort, .int, .uint => return 16, 2014 .long, .ulong, .float, .double, .longdouble => return 32, 2015 .longlong, .ulonglong => return 64, 2016 }, 2017 .tce, .tcele => switch (c_type) { 2018 .short, .ushort => return 16, 2019 .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32, 2020 .float, .double, .longdouble => return 32, 2021 }, 2022 .mips64, .mips64el => switch (c_type) { 2023 .short, .ushort => return 16, 2024 .int, .uint, .float => return 32, 2025 .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32, 2026 .longlong, .ulonglong, .double => return 64, 2027 .longdouble => if (target.os.tag == .freebsd) return 64 else return 128, 2028 }, 2029 .x86_64 => switch (c_type) { 2030 .short, .ushort => return 16, 2031 .int, .uint, .float => return 32, 2032 .long, .ulong => switch (target.abi) { 2033 .gnux32, .muslx32 => return 32, 2034 else => return 64, 2035 }, 2036 .longlong, .ulonglong, .double => return 64, 2037 .longdouble => return 80, 2038 }, 2039 else => switch (c_type) { 2040 .short, .ushort => return 16, 2041 .int, .uint, .float => return 32, 2042 .long, .ulong => return target.cpu.arch.ptrBitWidth(), 2043 .longlong, .ulonglong, .double => return 64, 2044 .longdouble => switch (target.cpu.arch) { 2045 .x86 => switch (target.abi) { 2046 .android => return 64, 2047 else => return 80, 2048 }, 2049 2050 .powerpc, 2051 .powerpcle, 2052 => switch (target.abi) { 2053 .musl, 2054 .musleabi, 2055 .musleabihf, 2056 .muslx32, 2057 => return 64, 2058 else => switch (target.os.tag) { 2059 .freebsd, .netbsd, .openbsd => return 64, 2060 else => return 128, 2061 }, 2062 }, 2063 2064 .powerpc64, 2065 .powerpc64le, 2066 => switch (target.abi) { 2067 .musl, 2068 .musleabi, 2069 .musleabihf, 2070 .muslx32, 2071 => return 64, 2072 else => switch (target.os.tag) { 2073 .freebsd, .openbsd => return 64, 2074 else => return 128, 2075 }, 2076 }, 2077 2078 .riscv32, 2079 .riscv64, 2080 .aarch64, 2081 .aarch64_be, 2082 .aarch64_32, 2083 .s390x, 2084 .mips64, 2085 .mips64el, 2086 .sparc, 2087 .sparc64, 2088 .sparcel, 2089 .wasm32, 2090 .wasm64, 2091 => return 128, 2092 2093 else => return 64, 2094 }, 2095 }, 2096 }, 2097 2098 .windows, .uefi => switch (target.cpu.arch) { 2099 .x86 => switch (c_type) { 2100 .short, .ushort => return 16, 2101 .int, .uint, .float => return 32, 2102 .long, .ulong => return 32, 2103 .longlong, .ulonglong, .double => return 64, 2104 .longdouble => switch (target.abi) { 2105 .gnu, .gnuilp32, .cygnus => return 80, 2106 else => return 64, 2107 }, 2108 }, 2109 .x86_64 => switch (c_type) { 2110 .short, .ushort => return 16, 2111 .int, .uint, .float => return 32, 2112 .long, .ulong => switch (target.abi) { 2113 .cygnus => return 64, 2114 else => return 32, 2115 }, 2116 .longlong, .ulonglong, .double => return 64, 2117 .longdouble => switch (target.abi) { 2118 .gnu, .gnuilp32, .cygnus => return 80, 2119 else => return 64, 2120 }, 2121 }, 2122 else => switch (c_type) { 2123 .short, .ushort => return 16, 2124 .int, .uint, .float => return 32, 2125 .long, .ulong => return 32, 2126 .longlong, .ulonglong, .double => return 64, 2127 .longdouble => return 64, 2128 }, 2129 }, 2130 2131 .macos, .ios, .tvos, .watchos => switch (c_type) { 2132 .short, .ushort => return 16, 2133 .int, .uint, .float => return 32, 2134 .long, .ulong => switch (target.cpu.arch) { 2135 .x86, .arm, .aarch64_32 => return 32, 2136 .x86_64 => switch (target.abi) { 2137 .gnux32, .muslx32 => return 32, 2138 else => return 64, 2139 }, 2140 else => return 64, 2141 }, 2142 .longlong, .ulonglong, .double => return 64, 2143 .longdouble => switch (target.cpu.arch) { 2144 .x86 => switch (target.abi) { 2145 .android => return 64, 2146 else => return 80, 2147 }, 2148 .x86_64 => return 80, 2149 else => return 64, 2150 }, 2151 }, 2152 2153 .nvcl, .cuda => switch (c_type) { 2154 .short, .ushort => return 16, 2155 .int, .uint, .float => return 32, 2156 .long, .ulong => switch (target.cpu.arch) { 2157 .nvptx => return 32, 2158 .nvptx64 => return 64, 2159 else => return 64, 2160 }, 2161 .longlong, .ulonglong, .double => return 64, 2162 .longdouble => return 64, 2163 }, 2164 2165 .amdhsa, .amdpal => switch (c_type) { 2166 .short, .ushort => return 16, 2167 .int, .uint, .float => return 32, 2168 .long, .ulong, .longlong, .ulonglong, .double => return 64, 2169 .longdouble => return 128, 2170 }, 2171 2172 .cloudabi, 2173 .kfreebsd, 2174 .lv2, 2175 .zos, 2176 .rtems, 2177 .nacl, 2178 .aix, 2179 .ps4, 2180 .ps5, 2181 .elfiamcu, 2182 .mesa3d, 2183 .contiki, 2184 .hermit, 2185 .hurd, 2186 .opencl, 2187 .glsl450, 2188 .vulkan, 2189 .driverkit, 2190 .shadermodel, 2191 => @panic("TODO specify the C integer and float type sizes for this OS"), 2192 } 2193 } 2194 2195 pub fn c_type_alignment(target: Target, c_type: CType) u16 { 2196 // Overrides for unusual alignments 2197 switch (target.cpu.arch) { 2198 .avr => switch (c_type) { 2199 .short, .ushort => return 2, 2200 else => return 1, 2201 }, 2202 .x86 => switch (target.os.tag) { 2203 .windows, .uefi => switch (c_type) { 2204 .longlong, .ulonglong, .double => return 8, 2205 .longdouble => switch (target.abi) { 2206 .gnu, .gnuilp32, .cygnus => return 4, 2207 else => return 8, 2208 }, 2209 else => {}, 2210 }, 2211 else => {}, 2212 }, 2213 else => {}, 2214 } 2215 2216 // Next-power-of-two-aligned, up to a maximum. 2217 return @min( 2218 std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8), 2219 switch (target.cpu.arch) { 2220 .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) { 2221 .netbsd => switch (target.abi) { 2222 .gnueabi, 2223 .gnueabihf, 2224 .eabi, 2225 .eabihf, 2226 .android, 2227 .musleabi, 2228 .musleabihf, 2229 => 8, 2230 2231 else => @as(u16, 4), 2232 }, 2233 .ios, .tvos, .watchos => 4, 2234 else => 8, 2235 }, 2236 2237 .msp430, 2238 .avr, 2239 => 2, 2240 2241 .arc, 2242 .csky, 2243 .x86, 2244 .xcore, 2245 .dxil, 2246 .loongarch32, 2247 .tce, 2248 .tcele, 2249 .le32, 2250 .amdil, 2251 .hsail, 2252 .spir, 2253 .spirv32, 2254 .kalimba, 2255 .shave, 2256 .renderscript32, 2257 .ve, 2258 .spu_2, 2259 => 4, 2260 2261 .aarch64_32, 2262 .amdgcn, 2263 .amdil64, 2264 .bpfel, 2265 .bpfeb, 2266 .hexagon, 2267 .hsail64, 2268 .loongarch64, 2269 .m68k, 2270 .mips, 2271 .mipsel, 2272 .sparc, 2273 .sparcel, 2274 .sparc64, 2275 .lanai, 2276 .le64, 2277 .nvptx, 2278 .nvptx64, 2279 .r600, 2280 .s390x, 2281 .spir64, 2282 .spirv64, 2283 .renderscript64, 2284 => 8, 2285 2286 .aarch64, 2287 .aarch64_be, 2288 .mips64, 2289 .mips64el, 2290 .powerpc, 2291 .powerpcle, 2292 .powerpc64, 2293 .powerpc64le, 2294 .riscv32, 2295 .riscv64, 2296 .x86_64, 2297 .wasm32, 2298 .wasm64, 2299 => 16, 2300 }, 2301 ); 2302 } 2303 2304 pub fn c_type_preferred_alignment(target: Target, c_type: CType) u16 { 2305 // Overrides for unusual alignments 2306 switch (target.cpu.arch) { 2307 .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) { 2308 .netbsd => switch (target.abi) { 2309 .gnueabi, 2310 .gnueabihf, 2311 .eabi, 2312 .eabihf, 2313 .android, 2314 .musleabi, 2315 .musleabihf, 2316 => {}, 2317 2318 else => switch (c_type) { 2319 .longdouble => return 4, 2320 else => {}, 2321 }, 2322 }, 2323 .ios, .tvos, .watchos => switch (c_type) { 2324 .longdouble => return 4, 2325 else => {}, 2326 }, 2327 else => {}, 2328 }, 2329 .arc => switch (c_type) { 2330 .longdouble => return 4, 2331 else => {}, 2332 }, 2333 .avr => switch (c_type) { 2334 .int, .uint, .long, .ulong, .float, .longdouble => return 1, 2335 .short, .ushort => return 2, 2336 .double => return 4, 2337 .longlong, .ulonglong => return 8, 2338 }, 2339 .x86 => switch (target.os.tag) { 2340 .windows, .uefi => switch (c_type) { 2341 .longdouble => switch (target.abi) { 2342 .gnu, .gnuilp32, .cygnus => return 4, 2343 else => return 8, 2344 }, 2345 else => {}, 2346 }, 2347 else => switch (c_type) { 2348 .longdouble => return 4, 2349 else => {}, 2350 }, 2351 }, 2352 else => {}, 2353 } 2354 2355 // Next-power-of-two-aligned, up to a maximum. 2356 return @min( 2357 std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8), 2358 switch (target.cpu.arch) { 2359 .msp430 => @as(u16, 2), 2360 2361 .csky, 2362 .xcore, 2363 .dxil, 2364 .loongarch32, 2365 .tce, 2366 .tcele, 2367 .le32, 2368 .amdil, 2369 .hsail, 2370 .spir, 2371 .spirv32, 2372 .kalimba, 2373 .shave, 2374 .renderscript32, 2375 .ve, 2376 .spu_2, 2377 => 4, 2378 2379 .arc, 2380 .arm, 2381 .armeb, 2382 .avr, 2383 .thumb, 2384 .thumbeb, 2385 .aarch64_32, 2386 .amdgcn, 2387 .amdil64, 2388 .bpfel, 2389 .bpfeb, 2390 .hexagon, 2391 .hsail64, 2392 .x86, 2393 .loongarch64, 2394 .m68k, 2395 .mips, 2396 .mipsel, 2397 .sparc, 2398 .sparcel, 2399 .sparc64, 2400 .lanai, 2401 .le64, 2402 .nvptx, 2403 .nvptx64, 2404 .r600, 2405 .s390x, 2406 .spir64, 2407 .spirv64, 2408 .renderscript64, 2409 => 8, 2410 2411 .aarch64, 2412 .aarch64_be, 2413 .mips64, 2414 .mips64el, 2415 .powerpc, 2416 .powerpcle, 2417 .powerpc64, 2418 .powerpc64le, 2419 .riscv32, 2420 .riscv64, 2421 .x86_64, 2422 .wasm32, 2423 .wasm64, 2424 => 16, 2425 }, 2426 ); 2427 } 2428 }; 2429 2430 test { 2431 std.testing.refAllDecls(Target.Cpu.Arch); 2432 }