blob e00a1c15 (88743B) - Raw
1 const std = @import("std.zig"); 2 const builtin = @import("builtin"); 3 const mem = std.mem; 4 const Version = std.SemanticVersion; 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 @intFromEnum(self) >= @intFromEnum(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 @intFromEnum(ver) >= @intFromEnum(self.min) and @intFromEnum(ver) <= @intFromEnum(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 (@intFromEnum(self.min) >= @intFromEnum(ver)) return true; 157 if (@intFromEnum(self.max) < @intFromEnum(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 (@intFromEnum(self) >= @intFromEnum(WindowsVersion.nt4) and @intFromEnum(self) <= @intFromEnum(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, "@enumFromInt(Target.Os.WindowsVersion, 0x{X:0>8})", .{@intFromEnum(self)}); 176 } 177 } else if (fmt.len == 0) { 178 if (@intFromEnum(self) >= @intFromEnum(WindowsVersion.nt4) and @intFromEnum(self) <= @intFromEnum(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})", .{@intFromEnum(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, .patch = 0 }, 276 .max = .{ .major = 13, .minor = 1, .patch = 0 }, 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, .patch = 0 }, 284 }, 285 }, 286 .x86_64 => VersionRange{ 287 .semver = .{ 288 .min = .{ .major = 11, .minor = 7, .patch = 1 }, 289 .max = .{ .major = 13, .minor = 3, .patch = 0 }, 290 }, 291 }, 292 else => unreachable, 293 }, 294 .ios => return .{ 295 .semver = .{ 296 .min = .{ .major = 12, .minor = 0, .patch = 0 }, 297 .max = .{ .major = 13, .minor = 4, .patch = 0 }, 298 }, 299 }, 300 .watchos => return .{ 301 .semver = .{ 302 .min = .{ .major = 6, .minor = 0, .patch = 0 }, 303 .max = .{ .major = 6, .minor = 2, .patch = 0 }, 304 }, 305 }, 306 .tvos => return .{ 307 .semver = .{ 308 .min = .{ .major = 13, .minor = 0, .patch = 0 }, 309 .max = .{ .major = 13, .minor = 4, .patch = 0 }, 310 }, 311 }, 312 .netbsd => return .{ 313 .semver = .{ 314 .min = .{ .major = 8, .minor = 0, .patch = 0 }, 315 .max = .{ .major = 10, .minor = 0, .patch = 0 }, 316 }, 317 }, 318 .openbsd => return .{ 319 .semver = .{ 320 .min = .{ .major = 6, .minor = 8, .patch = 0 }, 321 .max = .{ .major = 7, .minor = 2, .patch = 0 }, 322 }, 323 }, 324 .dragonfly => return .{ 325 .semver = .{ 326 .min = .{ .major = 5, .minor = 8, .patch = 0 }, 327 .max = .{ .major = 6, .minor = 4, .patch = 0 }, 328 }, 329 }, 330 .solaris => return .{ 331 .semver = .{ 332 .min = .{ .major = 5, .minor = 11, .patch = 0 }, 333 .max = .{ .major = 5, .minor = 11, .patch = 0 }, 334 }, 335 }, 336 337 .linux => return .{ 338 .linux = .{ 339 .range = .{ 340 .min = .{ .major = 3, .minor = 16, .patch = 0 }, 341 .max = .{ .major = 5, .minor = 10, .patch = 81 }, 342 }, 343 .glibc = .{ .major = 2, .minor = 19, .patch = 0 }, 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 loongarch = @import("target/loongarch.zig"); 463 pub const m68k = @import("target/m68k.zig"); 464 pub const mips = @import("target/mips.zig"); 465 pub const msp430 = @import("target/msp430.zig"); 466 pub const nvptx = @import("target/nvptx.zig"); 467 pub const powerpc = @import("target/powerpc.zig"); 468 pub const riscv = @import("target/riscv.zig"); 469 pub const sparc = @import("target/sparc.zig"); 470 pub const spirv = @import("target/spirv.zig"); 471 pub const s390x = @import("target/s390x.zig"); 472 pub const ve = @import("target/ve.zig"); 473 pub const wasm = @import("target/wasm.zig"); 474 pub const x86 = @import("target/x86.zig"); 475 pub const xtensa = @import("target/xtensa.zig"); 476 477 pub const Abi = enum { 478 none, 479 gnu, 480 gnuabin32, 481 gnuabi64, 482 gnueabi, 483 gnueabihf, 484 gnuf32, 485 gnuf64, 486 gnusf, 487 gnux32, 488 gnuilp32, 489 code16, 490 eabi, 491 eabihf, 492 android, 493 musl, 494 musleabi, 495 musleabihf, 496 muslx32, 497 msvc, 498 itanium, 499 cygnus, 500 coreclr, 501 simulator, 502 macabi, 503 pixel, 504 vertex, 505 geometry, 506 hull, 507 domain, 508 compute, 509 library, 510 raygeneration, 511 intersection, 512 anyhit, 513 closesthit, 514 miss, 515 callable, 516 mesh, 517 amplification, 518 519 pub fn default(arch: Cpu.Arch, target_os: Os) Abi { 520 if (arch.isWasm()) { 521 return .musl; 522 } 523 switch (target_os.tag) { 524 .freestanding, 525 .ananas, 526 .cloudabi, 527 .dragonfly, 528 .lv2, 529 .solaris, 530 .zos, 531 .minix, 532 .rtems, 533 .nacl, 534 .aix, 535 .cuda, 536 .nvcl, 537 .amdhsa, 538 .ps4, 539 .ps5, 540 .elfiamcu, 541 .mesa3d, 542 .contiki, 543 .amdpal, 544 .hermit, 545 .other, 546 => return .eabi, 547 .openbsd, 548 .freebsd, 549 .fuchsia, 550 .kfreebsd, 551 .netbsd, 552 .hurd, 553 .haiku, 554 .windows, 555 => return .gnu, 556 .uefi => return .msvc, 557 .linux, 558 .wasi, 559 .emscripten, 560 => return .musl, 561 .opencl, // TODO: SPIR-V ABIs with Linkage capability 562 .glsl450, 563 .vulkan, 564 .plan9, // TODO specify abi 565 .macos, 566 .ios, 567 .tvos, 568 .watchos, 569 .driverkit, 570 .shadermodel, 571 => return .none, 572 } 573 } 574 575 pub fn isGnu(abi: Abi) bool { 576 return switch (abi) { 577 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true, 578 else => false, 579 }; 580 } 581 582 pub fn isMusl(abi: Abi) bool { 583 return switch (abi) { 584 .musl, .musleabi, .musleabihf => true, 585 else => false, 586 }; 587 } 588 589 pub fn floatAbi(abi: Abi) FloatAbi { 590 return switch (abi) { 591 .gnueabihf, 592 .eabihf, 593 .musleabihf, 594 => .hard, 595 else => .soft, 596 }; 597 } 598 }; 599 600 pub const ObjectFormat = enum { 601 /// Common Object File Format (Windows) 602 coff, 603 /// DirectX Container 604 dxcontainer, 605 /// Executable and Linking Format 606 elf, 607 /// macOS relocatables 608 macho, 609 /// Standard, Portable Intermediate Representation V 610 spirv, 611 /// WebAssembly 612 wasm, 613 /// C source code 614 c, 615 /// Intel IHEX 616 hex, 617 /// Machine code with no metadata. 618 raw, 619 /// Plan 9 from Bell Labs 620 plan9, 621 /// Nvidia PTX format 622 nvptx, 623 624 pub fn fileExt(of: ObjectFormat, cpu_arch: Cpu.Arch) [:0]const u8 { 625 return switch (of) { 626 .coff => ".obj", 627 .elf, .macho, .wasm => ".o", 628 .c => ".c", 629 .spirv => ".spv", 630 .hex => ".ihex", 631 .raw => ".bin", 632 .plan9 => plan9Ext(cpu_arch), 633 .nvptx => ".ptx", 634 .dxcontainer => ".dxil", 635 }; 636 } 637 638 pub fn default(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat { 639 return switch (os_tag) { 640 .windows, .uefi => .coff, 641 .ios, .macos, .watchos, .tvos => .macho, 642 .plan9 => .plan9, 643 else => return switch (cpu_arch) { 644 .wasm32, .wasm64 => .wasm, 645 .spirv32, .spirv64 => .spirv, 646 .nvptx, .nvptx64 => .nvptx, 647 else => .elf, 648 }, 649 }; 650 } 651 }; 652 653 pub const SubSystem = enum { 654 Console, 655 Windows, 656 Posix, 657 Native, 658 EfiApplication, 659 EfiBootServiceDriver, 660 EfiRom, 661 EfiRuntimeDriver, 662 }; 663 664 pub const Cpu = struct { 665 /// Architecture 666 arch: Arch, 667 668 /// The CPU model to target. It has a set of features 669 /// which are overridden with the `features` field. 670 model: *const Model, 671 672 /// An explicit list of the entire CPU feature set. It may differ from the specific CPU model's features. 673 features: Feature.Set, 674 675 pub const Feature = struct { 676 /// The bit index into `Set`. Has a default value of `undefined` because the canonical 677 /// structures are populated via comptime logic. 678 index: Set.Index = undefined, 679 680 /// Has a default value of `undefined` because the canonical 681 /// structures are populated via comptime logic. 682 name: []const u8 = undefined, 683 684 /// If this corresponds to an LLVM-recognized feature, this will be populated; 685 /// otherwise null. 686 llvm_name: ?[:0]const u8, 687 688 /// Human-friendly UTF-8 text. 689 description: []const u8, 690 691 /// Sparse `Set` of features this depends on. 692 dependencies: Set, 693 694 /// A bit set of all the features. 695 pub const Set = struct { 696 ints: [usize_count]usize, 697 698 pub const needed_bit_count = 288; 699 pub const byte_count = (needed_bit_count + 7) / 8; 700 pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize); 701 pub const Index = std.math.Log2Int(std.meta.Int(.unsigned, usize_count * @bitSizeOf(usize))); 702 pub const ShiftInt = std.math.Log2Int(usize); 703 704 pub const empty = Set{ .ints = [1]usize{0} ** usize_count }; 705 706 pub fn isEmpty(set: Set) bool { 707 return for (set.ints) |x| { 708 if (x != 0) break false; 709 } else true; 710 } 711 712 pub fn isEnabled(set: Set, arch_feature_index: Index) bool { 713 const usize_index = arch_feature_index / @bitSizeOf(usize); 714 const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize))); 715 return (set.ints[usize_index] & (@as(usize, 1) << bit_index)) != 0; 716 } 717 718 /// Adds the specified feature but not its dependencies. 719 pub fn addFeature(set: *Set, arch_feature_index: Index) void { 720 const usize_index = arch_feature_index / @bitSizeOf(usize); 721 const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize))); 722 set.ints[usize_index] |= @as(usize, 1) << bit_index; 723 } 724 725 /// Adds the specified feature set but not its dependencies. 726 pub fn addFeatureSet(set: *Set, other_set: Set) void { 727 set.ints = @as(@Vector(usize_count, usize), set.ints) | @as(@Vector(usize_count, usize), other_set.ints); 728 } 729 730 /// Removes the specified feature but not its dependents. 731 pub fn removeFeature(set: *Set, arch_feature_index: Index) void { 732 const usize_index = arch_feature_index / @bitSizeOf(usize); 733 const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize))); 734 set.ints[usize_index] &= ~(@as(usize, 1) << bit_index); 735 } 736 737 /// Removes the specified feature but not its dependents. 738 pub fn removeFeatureSet(set: *Set, other_set: Set) void { 739 set.ints = @as(@Vector(usize_count, usize), set.ints) & ~@as(@Vector(usize_count, usize), other_set.ints); 740 } 741 742 pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void { 743 @setEvalBranchQuota(1000000); 744 745 var old = set.ints; 746 while (true) { 747 for (all_features_list, 0..) |feature, index_usize| { 748 const index = @as(Index, @intCast(index_usize)); 749 if (set.isEnabled(index)) { 750 set.addFeatureSet(feature.dependencies); 751 } 752 } 753 const nothing_changed = mem.eql(usize, &old, &set.ints); 754 if (nothing_changed) return; 755 old = set.ints; 756 } 757 } 758 759 pub fn asBytes(set: *const Set) *const [byte_count]u8 { 760 return @as(*const [byte_count]u8, @ptrCast(&set.ints)); 761 } 762 763 pub fn eql(set: Set, other_set: Set) bool { 764 return mem.eql(usize, &set.ints, &other_set.ints); 765 } 766 767 pub fn isSuperSetOf(set: Set, other_set: Set) bool { 768 const V = @Vector(usize_count, usize); 769 const set_v: V = set.ints; 770 const other_v: V = other_set.ints; 771 return @reduce(.And, (set_v & other_v) == other_v); 772 } 773 }; 774 775 pub fn feature_set_fns(comptime F: type) type { 776 return struct { 777 /// Populates only the feature bits specified. 778 pub fn featureSet(features: []const F) Set { 779 var x = Set.empty; 780 for (features) |feature| { 781 x.addFeature(@intFromEnum(feature)); 782 } 783 return x; 784 } 785 786 /// Returns true if the specified feature is enabled. 787 pub fn featureSetHas(set: Set, feature: F) bool { 788 return set.isEnabled(@intFromEnum(feature)); 789 } 790 791 /// Returns true if any specified feature is enabled. 792 pub fn featureSetHasAny(set: Set, features: anytype) bool { 793 comptime std.debug.assert(std.meta.trait.isIndexable(@TypeOf(features))); 794 inline for (features) |feature| { 795 if (set.isEnabled(@intFromEnum(@as(F, feature)))) return true; 796 } 797 return false; 798 } 799 800 /// Returns true if every specified feature is enabled. 801 pub fn featureSetHasAll(set: Set, features: anytype) bool { 802 comptime std.debug.assert(std.meta.trait.isIndexable(@TypeOf(features))); 803 inline for (features) |feature| { 804 if (!set.isEnabled(@intFromEnum(@as(F, feature)))) return false; 805 } 806 return true; 807 } 808 }; 809 } 810 }; 811 812 pub const Arch = enum { 813 arm, 814 armeb, 815 aarch64, 816 aarch64_be, 817 aarch64_32, 818 arc, 819 avr, 820 bpfel, 821 bpfeb, 822 csky, 823 dxil, 824 hexagon, 825 loongarch32, 826 loongarch64, 827 m68k, 828 mips, 829 mipsel, 830 mips64, 831 mips64el, 832 msp430, 833 powerpc, 834 powerpcle, 835 powerpc64, 836 powerpc64le, 837 r600, 838 amdgcn, 839 riscv32, 840 riscv64, 841 sparc, 842 sparc64, 843 sparcel, 844 s390x, 845 tce, 846 tcele, 847 thumb, 848 thumbeb, 849 x86, 850 x86_64, 851 xcore, 852 xtensa, 853 nvptx, 854 nvptx64, 855 le32, 856 le64, 857 amdil, 858 amdil64, 859 hsail, 860 hsail64, 861 spir, 862 spir64, 863 spirv32, 864 spirv64, 865 kalimba, 866 shave, 867 lanai, 868 wasm32, 869 wasm64, 870 renderscript32, 871 renderscript64, 872 ve, 873 // Stage1 currently assumes that architectures above this comment 874 // map one-to-one with the ZigLLVM_ArchType enum. 875 spu_2, 876 877 pub fn isX86(arch: Arch) bool { 878 return switch (arch) { 879 .x86, .x86_64 => true, 880 else => false, 881 }; 882 } 883 884 pub fn isARM(arch: Arch) bool { 885 return switch (arch) { 886 .arm, .armeb => true, 887 else => false, 888 }; 889 } 890 891 pub fn isAARCH64(arch: Arch) bool { 892 return switch (arch) { 893 .aarch64, .aarch64_be, .aarch64_32 => true, 894 else => false, 895 }; 896 } 897 898 pub fn isThumb(arch: Arch) bool { 899 return switch (arch) { 900 .thumb, .thumbeb => true, 901 else => false, 902 }; 903 } 904 905 pub fn isWasm(arch: Arch) bool { 906 return switch (arch) { 907 .wasm32, .wasm64 => true, 908 else => false, 909 }; 910 } 911 912 pub fn isRISCV(arch: Arch) bool { 913 return switch (arch) { 914 .riscv32, .riscv64 => true, 915 else => false, 916 }; 917 } 918 919 pub fn isMIPS(arch: Arch) bool { 920 return switch (arch) { 921 .mips, .mipsel, .mips64, .mips64el => true, 922 else => false, 923 }; 924 } 925 926 pub fn isPPC(arch: Arch) bool { 927 return switch (arch) { 928 .powerpc, .powerpcle => true, 929 else => false, 930 }; 931 } 932 933 pub fn isPPC64(arch: Arch) bool { 934 return switch (arch) { 935 .powerpc64, .powerpc64le => true, 936 else => false, 937 }; 938 } 939 940 pub fn isSPARC(arch: Arch) bool { 941 return switch (arch) { 942 .sparc, .sparcel, .sparc64 => true, 943 else => false, 944 }; 945 } 946 947 pub fn isSpirV(arch: Arch) bool { 948 return switch (arch) { 949 .spirv32, .spirv64 => true, 950 else => false, 951 }; 952 } 953 954 pub fn isBpf(arch: Arch) bool { 955 return switch (arch) { 956 .bpfel, .bpfeb => true, 957 else => false, 958 }; 959 } 960 961 pub fn isNvptx(arch: Arch) bool { 962 return switch (arch) { 963 .nvptx, .nvptx64 => true, 964 else => false, 965 }; 966 } 967 968 pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model { 969 for (arch.allCpuModels()) |cpu| { 970 if (mem.eql(u8, cpu_name, cpu.name)) { 971 return cpu; 972 } 973 } 974 return error.UnknownCpuModel; 975 } 976 977 pub fn toElfMachine(arch: Arch) std.elf.EM { 978 return switch (arch) { 979 .avr => .AVR, 980 .msp430 => .MSP430, 981 .arc => .ARC, 982 .arm => .ARM, 983 .armeb => .ARM, 984 .hexagon => .HEXAGON, 985 .dxil => .NONE, 986 .m68k => .@"68K", 987 .le32 => .NONE, 988 .mips => .MIPS, 989 .mipsel => .MIPS_RS3_LE, 990 .powerpc, .powerpcle => .PPC, 991 .r600 => .NONE, 992 .riscv32 => .RISCV, 993 .sparc => .SPARC, 994 .sparcel => .SPARC, 995 .tce => .NONE, 996 .tcele => .NONE, 997 .thumb => .ARM, 998 .thumbeb => .ARM, 999 .x86 => .@"386", 1000 .xcore => .XCORE, 1001 .xtensa => .XTENSA, 1002 .nvptx => .NONE, 1003 .amdil => .NONE, 1004 .hsail => .NONE, 1005 .spir => .NONE, 1006 .kalimba => .CSR_KALIMBA, 1007 .shave => .NONE, 1008 .lanai => .LANAI, 1009 .wasm32 => .NONE, 1010 .renderscript32 => .NONE, 1011 .aarch64_32 => .AARCH64, 1012 .aarch64 => .AARCH64, 1013 .aarch64_be => .AARCH64, 1014 .mips64 => .MIPS, 1015 .mips64el => .MIPS_RS3_LE, 1016 .powerpc64 => .PPC64, 1017 .powerpc64le => .PPC64, 1018 .riscv64 => .RISCV, 1019 .x86_64 => .X86_64, 1020 .nvptx64 => .NONE, 1021 .le64 => .NONE, 1022 .amdil64 => .NONE, 1023 .hsail64 => .NONE, 1024 .spir64 => .NONE, 1025 .wasm64 => .NONE, 1026 .renderscript64 => .NONE, 1027 .amdgcn => .AMDGPU, 1028 .bpfel => .BPF, 1029 .bpfeb => .BPF, 1030 .csky => .CSKY, 1031 .sparc64 => .SPARCV9, 1032 .s390x => .S390, 1033 .ve => .NONE, 1034 .spu_2 => .SPU_2, 1035 .spirv32 => .NONE, 1036 .spirv64 => .NONE, 1037 .loongarch32 => .NONE, 1038 .loongarch64 => .NONE, 1039 }; 1040 } 1041 1042 pub fn toCoffMachine(arch: Arch) std.coff.MachineType { 1043 return switch (arch) { 1044 .avr => .Unknown, 1045 .msp430 => .Unknown, 1046 .arc => .Unknown, 1047 .arm => .ARM, 1048 .armeb => .Unknown, 1049 .dxil => .Unknown, 1050 .hexagon => .Unknown, 1051 .m68k => .Unknown, 1052 .le32 => .Unknown, 1053 .mips => .Unknown, 1054 .mipsel => .Unknown, 1055 .powerpc, .powerpcle => .POWERPC, 1056 .r600 => .Unknown, 1057 .riscv32 => .RISCV32, 1058 .sparc => .Unknown, 1059 .sparcel => .Unknown, 1060 .tce => .Unknown, 1061 .tcele => .Unknown, 1062 .thumb => .Thumb, 1063 .thumbeb => .Thumb, 1064 .x86 => .I386, 1065 .xcore => .Unknown, 1066 .xtensa => .Unknown, 1067 .nvptx => .Unknown, 1068 .amdil => .Unknown, 1069 .hsail => .Unknown, 1070 .spir => .Unknown, 1071 .kalimba => .Unknown, 1072 .shave => .Unknown, 1073 .lanai => .Unknown, 1074 .wasm32 => .Unknown, 1075 .renderscript32 => .Unknown, 1076 .aarch64_32 => .ARM64, 1077 .aarch64 => .ARM64, 1078 .aarch64_be => .ARM64, 1079 .mips64 => .Unknown, 1080 .mips64el => .Unknown, 1081 .powerpc64 => .Unknown, 1082 .powerpc64le => .Unknown, 1083 .riscv64 => .RISCV64, 1084 .x86_64 => .X64, 1085 .nvptx64 => .Unknown, 1086 .le64 => .Unknown, 1087 .amdil64 => .Unknown, 1088 .hsail64 => .Unknown, 1089 .spir64 => .Unknown, 1090 .wasm64 => .Unknown, 1091 .renderscript64 => .Unknown, 1092 .amdgcn => .Unknown, 1093 .bpfel => .Unknown, 1094 .bpfeb => .Unknown, 1095 .csky => .Unknown, 1096 .sparc64 => .Unknown, 1097 .s390x => .Unknown, 1098 .ve => .Unknown, 1099 .spu_2 => .Unknown, 1100 .spirv32 => .Unknown, 1101 .spirv64 => .Unknown, 1102 .loongarch32 => .Unknown, 1103 .loongarch64 => .Unknown, 1104 }; 1105 } 1106 1107 pub fn endian(arch: Arch) std.builtin.Endian { 1108 return switch (arch) { 1109 .avr, 1110 .arm, 1111 .aarch64_32, 1112 .aarch64, 1113 .amdgcn, 1114 .amdil, 1115 .amdil64, 1116 .bpfel, 1117 .csky, 1118 .xtensa, 1119 .hexagon, 1120 .hsail, 1121 .hsail64, 1122 .kalimba, 1123 .le32, 1124 .le64, 1125 .mipsel, 1126 .mips64el, 1127 .msp430, 1128 .nvptx, 1129 .nvptx64, 1130 .sparcel, 1131 .tcele, 1132 .powerpcle, 1133 .powerpc64le, 1134 .r600, 1135 .riscv32, 1136 .riscv64, 1137 .x86, 1138 .x86_64, 1139 .wasm32, 1140 .wasm64, 1141 .xcore, 1142 .thumb, 1143 .spir, 1144 .spir64, 1145 .renderscript32, 1146 .renderscript64, 1147 .shave, 1148 .ve, 1149 .spu_2, 1150 // GPU bitness is opaque. For now, assume little endian. 1151 .spirv32, 1152 .spirv64, 1153 .dxil, 1154 .loongarch32, 1155 .loongarch64, 1156 => .Little, 1157 1158 .arc, 1159 .armeb, 1160 .aarch64_be, 1161 .bpfeb, 1162 .m68k, 1163 .mips, 1164 .mips64, 1165 .powerpc, 1166 .powerpc64, 1167 .thumbeb, 1168 .sparc, 1169 .sparc64, 1170 .tce, 1171 .lanai, 1172 .s390x, 1173 => .Big, 1174 }; 1175 } 1176 1177 /// Returns whether this architecture supports the address space 1178 pub fn supportsAddressSpace(arch: Arch, address_space: std.builtin.AddressSpace) bool { 1179 const is_nvptx = arch == .nvptx or arch == .nvptx64; 1180 const is_spirv = arch == .spirv32 or arch == .spirv64; 1181 const is_gpu = is_nvptx or is_spirv or arch == .amdgcn; 1182 return switch (address_space) { 1183 .generic => true, 1184 .fs, .gs, .ss => arch == .x86_64 or arch == .x86, 1185 .global, .constant, .local, .shared => is_gpu, 1186 .param => is_nvptx, 1187 // TODO this should also check how many flash banks the cpu has 1188 .flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr, 1189 }; 1190 } 1191 1192 /// Returns a name that matches the lib/std/target/* source file name. 1193 pub fn genericName(arch: Arch) []const u8 { 1194 return switch (arch) { 1195 .arm, .armeb, .thumb, .thumbeb => "arm", 1196 .aarch64, .aarch64_be, .aarch64_32 => "aarch64", 1197 .bpfel, .bpfeb => "bpf", 1198 .loongarch32, .loongarch64 => "loongarch", 1199 .mips, .mipsel, .mips64, .mips64el => "mips", 1200 .powerpc, .powerpcle, .powerpc64, .powerpc64le => "powerpc", 1201 .amdgcn => "amdgpu", 1202 .riscv32, .riscv64 => "riscv", 1203 .sparc, .sparc64, .sparcel => "sparc", 1204 .s390x => "s390x", 1205 .x86, .x86_64 => "x86", 1206 .nvptx, .nvptx64 => "nvptx", 1207 .wasm32, .wasm64 => "wasm", 1208 .spirv32, .spirv64 => "spirv", 1209 else => @tagName(arch), 1210 }; 1211 } 1212 1213 /// All CPU features Zig is aware of, sorted lexicographically by name. 1214 pub fn allFeaturesList(arch: Arch) []const Cpu.Feature { 1215 return switch (arch) { 1216 .arm, .armeb, .thumb, .thumbeb => &arm.all_features, 1217 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.all_features, 1218 .arc => &arc.all_features, 1219 .avr => &avr.all_features, 1220 .bpfel, .bpfeb => &bpf.all_features, 1221 .csky => &csky.all_features, 1222 .hexagon => &hexagon.all_features, 1223 .loongarch32, .loongarch64 => &loongarch.all_features, 1224 .m68k => &m68k.all_features, 1225 .mips, .mipsel, .mips64, .mips64el => &mips.all_features, 1226 .msp430 => &msp430.all_features, 1227 .powerpc, .powerpcle, .powerpc64, .powerpc64le => &powerpc.all_features, 1228 .amdgcn => &amdgpu.all_features, 1229 .riscv32, .riscv64 => &riscv.all_features, 1230 .sparc, .sparc64, .sparcel => &sparc.all_features, 1231 .spirv32, .spirv64 => &spirv.all_features, 1232 .s390x => &s390x.all_features, 1233 .x86, .x86_64 => &x86.all_features, 1234 .xtensa => &xtensa.all_features, 1235 .nvptx, .nvptx64 => &nvptx.all_features, 1236 .ve => &ve.all_features, 1237 .wasm32, .wasm64 => &wasm.all_features, 1238 1239 else => &[0]Cpu.Feature{}, 1240 }; 1241 } 1242 1243 /// All processors Zig is aware of, sorted lexicographically by name. 1244 pub fn allCpuModels(arch: Arch) []const *const Cpu.Model { 1245 return switch (arch) { 1246 .arc => comptime allCpusFromDecls(arc.cpu), 1247 .arm, .armeb, .thumb, .thumbeb => comptime allCpusFromDecls(arm.cpu), 1248 .aarch64, .aarch64_be, .aarch64_32 => comptime allCpusFromDecls(aarch64.cpu), 1249 .avr => comptime allCpusFromDecls(avr.cpu), 1250 .bpfel, .bpfeb => comptime allCpusFromDecls(bpf.cpu), 1251 .csky => comptime allCpusFromDecls(csky.cpu), 1252 .hexagon => comptime allCpusFromDecls(hexagon.cpu), 1253 .loongarch32, .loongarch64 => comptime allCpusFromDecls(loongarch.cpu), 1254 .m68k => comptime allCpusFromDecls(m68k.cpu), 1255 .mips, .mipsel, .mips64, .mips64el => comptime allCpusFromDecls(mips.cpu), 1256 .msp430 => comptime allCpusFromDecls(msp430.cpu), 1257 .powerpc, .powerpcle, .powerpc64, .powerpc64le => comptime allCpusFromDecls(powerpc.cpu), 1258 .amdgcn => comptime allCpusFromDecls(amdgpu.cpu), 1259 .riscv32, .riscv64 => comptime allCpusFromDecls(riscv.cpu), 1260 .sparc, .sparc64, .sparcel => comptime allCpusFromDecls(sparc.cpu), 1261 .spirv32, .spirv64 => comptime allCpusFromDecls(spirv.cpu), 1262 .s390x => comptime allCpusFromDecls(s390x.cpu), 1263 .x86, .x86_64 => comptime allCpusFromDecls(x86.cpu), 1264 .xtensa => comptime allCpusFromDecls(xtensa.cpu), 1265 .nvptx, .nvptx64 => comptime allCpusFromDecls(nvptx.cpu), 1266 .ve => comptime allCpusFromDecls(ve.cpu), 1267 .wasm32, .wasm64 => comptime allCpusFromDecls(wasm.cpu), 1268 1269 else => &[0]*const Model{}, 1270 }; 1271 } 1272 1273 fn allCpusFromDecls(comptime cpus: type) []const *const Cpu.Model { 1274 const decls = @typeInfo(cpus).Struct.decls; 1275 var array: [decls.len]*const Cpu.Model = undefined; 1276 for (decls, 0..) |decl, i| { 1277 array[i] = &@field(cpus, decl.name); 1278 } 1279 return &array; 1280 } 1281 }; 1282 1283 pub const Model = struct { 1284 name: []const u8, 1285 llvm_name: ?[:0]const u8, 1286 features: Feature.Set, 1287 1288 pub fn toCpu(model: *const Model, arch: Arch) Cpu { 1289 var features = model.features; 1290 features.populateDependencies(arch.allFeaturesList()); 1291 return .{ 1292 .arch = arch, 1293 .model = model, 1294 .features = features, 1295 }; 1296 } 1297 1298 pub fn generic(arch: Arch) *const Model { 1299 const S = struct { 1300 const generic_model = Model{ 1301 .name = "generic", 1302 .llvm_name = null, 1303 .features = Cpu.Feature.Set.empty, 1304 }; 1305 }; 1306 return switch (arch) { 1307 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic, 1308 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic, 1309 .avr => &avr.cpu.avr2, 1310 .bpfel, .bpfeb => &bpf.cpu.generic, 1311 .hexagon => &hexagon.cpu.generic, 1312 .loongarch32 => &loongarch.cpu.generic_la32, 1313 .loongarch64 => &loongarch.cpu.generic_la64, 1314 .m68k => &m68k.cpu.generic, 1315 .mips, .mipsel => &mips.cpu.mips32, 1316 .mips64, .mips64el => &mips.cpu.mips64, 1317 .msp430 => &msp430.cpu.generic, 1318 .powerpc => &powerpc.cpu.ppc, 1319 .powerpcle => &powerpc.cpu.ppc, 1320 .powerpc64 => &powerpc.cpu.ppc64, 1321 .powerpc64le => &powerpc.cpu.ppc64le, 1322 .amdgcn => &amdgpu.cpu.generic, 1323 .riscv32 => &riscv.cpu.generic_rv32, 1324 .riscv64 => &riscv.cpu.generic_rv64, 1325 .spirv32, .spirv64 => &spirv.cpu.generic, 1326 .sparc, .sparcel => &sparc.cpu.generic, 1327 .sparc64 => &sparc.cpu.v9, // 64-bit SPARC needs v9 as the baseline 1328 .s390x => &s390x.cpu.generic, 1329 .x86 => &x86.cpu.i386, 1330 .x86_64 => &x86.cpu.x86_64, 1331 .nvptx, .nvptx64 => &nvptx.cpu.sm_20, 1332 .ve => &ve.cpu.generic, 1333 .wasm32, .wasm64 => &wasm.cpu.generic, 1334 1335 else => &S.generic_model, 1336 }; 1337 } 1338 1339 pub fn baseline(arch: Arch) *const Model { 1340 return switch (arch) { 1341 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline, 1342 .riscv32 => &riscv.cpu.baseline_rv32, 1343 .riscv64 => &riscv.cpu.baseline_rv64, 1344 .x86 => &x86.cpu.pentium4, 1345 .nvptx, .nvptx64 => &nvptx.cpu.sm_20, 1346 .sparc, .sparcel => &sparc.cpu.v8, 1347 1348 else => generic(arch), 1349 }; 1350 } 1351 }; 1352 1353 /// The "default" set of CPU features for cross-compiling. A conservative set 1354 /// of features that is expected to be supported on most available hardware. 1355 pub fn baseline(arch: Arch) Cpu { 1356 return Model.baseline(arch).toCpu(arch); 1357 } 1358 }; 1359 1360 pub fn zigTriple(self: Target, allocator: mem.Allocator) ![]u8 { 1361 return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator); 1362 } 1363 1364 pub fn linuxTripleSimple(allocator: mem.Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![]u8 { 1365 return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) }); 1366 } 1367 1368 pub fn linuxTriple(self: Target, allocator: mem.Allocator) ![]u8 { 1369 return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi); 1370 } 1371 1372 pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 { 1373 return switch (os_tag) { 1374 .windows => ".exe", 1375 .uefi => ".efi", 1376 .plan9 => plan9Ext(cpu_arch), 1377 else => switch (cpu_arch) { 1378 .wasm32, .wasm64 => ".wasm", 1379 else => "", 1380 }, 1381 }; 1382 } 1383 1384 pub fn exeFileExt(self: Target) [:0]const u8 { 1385 return exeFileExtSimple(self.cpu.arch, self.os.tag); 1386 } 1387 1388 pub fn staticLibSuffix_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 { 1389 if (abi == .msvc) { 1390 return ".lib"; 1391 } 1392 switch (os_tag) { 1393 .windows, .uefi => return ".lib", 1394 else => return ".a", 1395 } 1396 } 1397 1398 pub fn staticLibSuffix(self: Target) [:0]const u8 { 1399 return staticLibSuffix_os_abi(self.os.tag, self.abi); 1400 } 1401 1402 pub fn dynamicLibSuffix(self: Target) [:0]const u8 { 1403 return self.os.tag.dynamicLibSuffix(); 1404 } 1405 1406 pub fn libPrefix_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 { 1407 if (abi == .msvc) { 1408 return ""; 1409 } 1410 switch (os_tag) { 1411 .windows, .uefi => return "", 1412 else => return "lib", 1413 } 1414 } 1415 1416 pub fn libPrefix(self: Target) [:0]const u8 { 1417 return libPrefix_os_abi(self.os.tag, self.abi); 1418 } 1419 1420 pub fn isMinGW(self: Target) bool { 1421 return self.os.tag == .windows and self.isGnu(); 1422 } 1423 1424 pub fn isGnu(self: Target) bool { 1425 return self.abi.isGnu(); 1426 } 1427 1428 pub fn isMusl(self: Target) bool { 1429 return self.abi.isMusl(); 1430 } 1431 1432 pub fn isAndroid(self: Target) bool { 1433 return self.abi == .android; 1434 } 1435 1436 pub fn isWasm(self: Target) bool { 1437 return self.cpu.arch.isWasm(); 1438 } 1439 1440 pub fn isDarwin(self: Target) bool { 1441 return self.os.tag.isDarwin(); 1442 } 1443 1444 pub fn isBSD(self: Target) bool { 1445 return self.os.tag.isBSD(); 1446 } 1447 1448 pub fn isBpfFreestanding(self: Target) bool { 1449 return self.cpu.arch.isBpf() and self.os.tag == .freestanding; 1450 } 1451 1452 pub fn isGnuLibC_os_tag_abi(os_tag: Os.Tag, abi: Abi) bool { 1453 return os_tag == .linux and abi.isGnu(); 1454 } 1455 1456 pub fn isGnuLibC(self: Target) bool { 1457 return isGnuLibC_os_tag_abi(self.os.tag, self.abi); 1458 } 1459 1460 pub fn supportsNewStackCall(self: Target) bool { 1461 return !self.cpu.arch.isWasm(); 1462 } 1463 1464 pub fn isSpirV(self: Target) bool { 1465 return self.cpu.arch.isSpirV(); 1466 } 1467 1468 pub const FloatAbi = enum { 1469 hard, 1470 soft, 1471 soft_fp, 1472 }; 1473 1474 pub fn getFloatAbi(self: Target) FloatAbi { 1475 return self.abi.floatAbi(); 1476 } 1477 1478 pub fn hasDynamicLinker(self: Target) bool { 1479 if (self.cpu.arch.isWasm()) { 1480 return false; 1481 } 1482 switch (self.os.tag) { 1483 .freestanding, 1484 .ios, 1485 .tvos, 1486 .watchos, 1487 .macos, 1488 .uefi, 1489 .windows, 1490 .emscripten, 1491 .opencl, 1492 .glsl450, 1493 .vulkan, 1494 .plan9, 1495 .other, 1496 => return false, 1497 else => return true, 1498 } 1499 } 1500 1501 pub const DynamicLinker = struct { 1502 /// Contains the memory used to store the dynamic linker path. This field should 1503 /// not be used directly. See `get` and `set`. This field exists so that this API requires no allocator. 1504 buffer: [255]u8 = undefined, 1505 1506 /// Used to construct the dynamic linker path. This field should not be used 1507 /// directly. See `get` and `set`. 1508 max_byte: ?u8 = null, 1509 1510 /// Asserts that the length is less than or equal to 255 bytes. 1511 pub fn init(dl_or_null: ?[]const u8) DynamicLinker { 1512 var result: DynamicLinker = undefined; 1513 result.set(dl_or_null); 1514 return result; 1515 } 1516 1517 /// The returned memory has the same lifetime as the `DynamicLinker`. 1518 pub fn get(self: *const DynamicLinker) ?[]const u8 { 1519 const m: usize = self.max_byte orelse return null; 1520 return self.buffer[0 .. m + 1]; 1521 } 1522 1523 /// Asserts that the length is less than or equal to 255 bytes. 1524 pub fn set(self: *DynamicLinker, dl_or_null: ?[]const u8) void { 1525 if (dl_or_null) |dl| { 1526 @memcpy(self.buffer[0..dl.len], dl); 1527 self.max_byte = @as(u8, @intCast(dl.len - 1)); 1528 } else { 1529 self.max_byte = null; 1530 } 1531 } 1532 }; 1533 1534 pub fn standardDynamicLinkerPath(self: Target) DynamicLinker { 1535 var result: DynamicLinker = .{}; 1536 const S = struct { 1537 fn print(r: *DynamicLinker, comptime fmt: []const u8, args: anytype) DynamicLinker { 1538 r.max_byte = @as(u8, @intCast((std.fmt.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1)); 1539 return r.*; 1540 } 1541 fn copy(r: *DynamicLinker, s: []const u8) DynamicLinker { 1542 @memcpy(r.buffer[0..s.len], s); 1543 r.max_byte = @as(u8, @intCast(s.len - 1)); 1544 return r.*; 1545 } 1546 }; 1547 const print = S.print; 1548 const copy = S.copy; 1549 1550 if (self.abi == .android) { 1551 const suffix = if (self.ptrBitWidth() == 64) "64" else ""; 1552 return print(&result, "/system/bin/linker{s}", .{suffix}); 1553 } 1554 1555 if (self.abi.isMusl()) { 1556 const is_arm = switch (self.cpu.arch) { 1557 .arm, .armeb, .thumb, .thumbeb => true, 1558 else => false, 1559 }; 1560 const arch_part = switch (self.cpu.arch) { 1561 .arm, .thumb => "arm", 1562 .armeb, .thumbeb => "armeb", 1563 else => |arch| @tagName(arch), 1564 }; 1565 const arch_suffix = if (is_arm and self.abi.floatAbi() == .hard) "hf" else ""; 1566 return print(&result, "/lib/ld-musl-{s}{s}.so.1", .{ arch_part, arch_suffix }); 1567 } 1568 1569 switch (self.os.tag) { 1570 .freebsd => return copy(&result, "/libexec/ld-elf.so.1"), 1571 .netbsd => return copy(&result, "/libexec/ld.elf_so"), 1572 .openbsd => return copy(&result, "/usr/libexec/ld.so"), 1573 .dragonfly => return copy(&result, "/libexec/ld-elf.so.2"), 1574 .solaris => return copy(&result, "/lib/64/ld.so.1"), 1575 .linux => switch (self.cpu.arch) { 1576 .x86, 1577 .sparc, 1578 .sparcel, 1579 => return copy(&result, "/lib/ld-linux.so.2"), 1580 1581 .aarch64 => return copy(&result, "/lib/ld-linux-aarch64.so.1"), 1582 .aarch64_be => return copy(&result, "/lib/ld-linux-aarch64_be.so.1"), 1583 .aarch64_32 => return copy(&result, "/lib/ld-linux-aarch64_32.so.1"), 1584 1585 .arm, 1586 .armeb, 1587 .thumb, 1588 .thumbeb, 1589 => return copy(&result, switch (self.abi.floatAbi()) { 1590 .hard => "/lib/ld-linux-armhf.so.3", 1591 else => "/lib/ld-linux.so.3", 1592 }), 1593 1594 .mips, 1595 .mipsel, 1596 .mips64, 1597 .mips64el, 1598 => { 1599 const lib_suffix = switch (self.abi) { 1600 .gnuabin32, .gnux32 => "32", 1601 .gnuabi64 => "64", 1602 else => "", 1603 }; 1604 const is_nan_2008 = mips.featureSetHas(self.cpu.features, .nan2008); 1605 const loader = if (is_nan_2008) "ld-linux-mipsn8.so.1" else "ld.so.1"; 1606 return print(&result, "/lib{s}/{s}", .{ lib_suffix, loader }); 1607 }, 1608 1609 .powerpc, .powerpcle => return copy(&result, "/lib/ld.so.1"), 1610 .powerpc64, .powerpc64le => return copy(&result, "/lib64/ld64.so.2"), 1611 .s390x => return copy(&result, "/lib64/ld64.so.1"), 1612 .sparc64 => return copy(&result, "/lib64/ld-linux.so.2"), 1613 .x86_64 => return copy(&result, switch (self.abi) { 1614 .gnux32 => "/libx32/ld-linux-x32.so.2", 1615 else => "/lib64/ld-linux-x86-64.so.2", 1616 }), 1617 1618 .riscv32 => return copy(&result, "/lib/ld-linux-riscv32-ilp32.so.1"), 1619 .riscv64 => return copy(&result, "/lib/ld-linux-riscv64-lp64.so.1"), 1620 1621 // Architectures in this list have been verified as not having a standard 1622 // dynamic linker path. 1623 .wasm32, 1624 .wasm64, 1625 .bpfel, 1626 .bpfeb, 1627 .nvptx, 1628 .nvptx64, 1629 .spu_2, 1630 .avr, 1631 .spirv32, 1632 .spirv64, 1633 => return result, 1634 1635 // TODO go over each item in this list and either move it to the above list, or 1636 // implement the standard dynamic linker path code for it. 1637 .arc, 1638 .csky, 1639 .hexagon, 1640 .m68k, 1641 .msp430, 1642 .r600, 1643 .amdgcn, 1644 .tce, 1645 .tcele, 1646 .xcore, 1647 .le32, 1648 .le64, 1649 .amdil, 1650 .amdil64, 1651 .hsail, 1652 .hsail64, 1653 .spir, 1654 .spir64, 1655 .kalimba, 1656 .shave, 1657 .lanai, 1658 .renderscript32, 1659 .renderscript64, 1660 .ve, 1661 .dxil, 1662 .loongarch32, 1663 .loongarch64, 1664 .xtensa, 1665 => return result, 1666 }, 1667 1668 .ios, 1669 .tvos, 1670 .watchos, 1671 .macos, 1672 => return copy(&result, "/usr/lib/dyld"), 1673 1674 // Operating systems in this list have been verified as not having a standard 1675 // dynamic linker path. 1676 .freestanding, 1677 .uefi, 1678 .windows, 1679 .emscripten, 1680 .wasi, 1681 .opencl, 1682 .glsl450, 1683 .vulkan, 1684 .other, 1685 .plan9, 1686 => return result, 1687 1688 // TODO revisit when multi-arch for Haiku is available 1689 .haiku => return copy(&result, "/system/runtime_loader"), 1690 1691 // TODO go over each item in this list and either move it to the above list, or 1692 // implement the standard dynamic linker path code for it. 1693 .ananas, 1694 .cloudabi, 1695 .fuchsia, 1696 .kfreebsd, 1697 .lv2, 1698 .zos, 1699 .minix, 1700 .rtems, 1701 .nacl, 1702 .aix, 1703 .cuda, 1704 .nvcl, 1705 .amdhsa, 1706 .ps4, 1707 .ps5, 1708 .elfiamcu, 1709 .mesa3d, 1710 .contiki, 1711 .amdpal, 1712 .hermit, 1713 .hurd, 1714 .driverkit, 1715 .shadermodel, 1716 => return result, 1717 } 1718 } 1719 1720 /// 0c spim little-endian MIPS 3000 family 1721 /// 1c 68000 Motorola MC68000 1722 /// 2c 68020 Motorola MC68020 1723 /// 5c arm little-endian ARM 1724 /// 6c amd64 AMD64 and compatibles (e.g., Intel EM64T) 1725 /// 7c arm64 ARM64 (ARMv8) 1726 /// 8c 386 Intel x86, i486, Pentium, etc. 1727 /// kc sparc Sun SPARC 1728 /// qc power Power PC 1729 /// vc mips big-endian MIPS 3000 family 1730 pub fn plan9Ext(cpu_arch: Cpu.Arch) [:0]const u8 { 1731 return switch (cpu_arch) { 1732 .arm => ".5", 1733 .x86_64 => ".6", 1734 .aarch64 => ".7", 1735 .x86 => ".8", 1736 .sparc => ".k", 1737 .powerpc, .powerpcle => ".q", 1738 .mips, .mipsel => ".v", 1739 // ISAs without designated characters get 'X' for lack of a better option. 1740 else => ".X", 1741 }; 1742 } 1743 1744 pub inline fn maxIntAlignment(target: Target) u16 { 1745 return switch (target.cpu.arch) { 1746 .avr => 1, 1747 .msp430 => 2, 1748 .xcore => 4, 1749 1750 .arm, 1751 .armeb, 1752 .thumb, 1753 .thumbeb, 1754 .hexagon, 1755 .mips, 1756 .mipsel, 1757 .powerpc, 1758 .powerpcle, 1759 .r600, 1760 .amdgcn, 1761 .riscv32, 1762 .sparc, 1763 .sparcel, 1764 .s390x, 1765 .lanai, 1766 .wasm32, 1767 .wasm64, 1768 => 8, 1769 1770 .x86 => if (target.ofmt == .c) 16 else return switch (target.os.tag) { 1771 .windows, .uefi => 8, 1772 else => 4, 1773 }, 1774 1775 // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16 1776 // is a relevant number in three cases: 1777 // 1. Different machine code instruction when loading into SIMD register. 1778 // 2. The C ABI wants 16 for extern structs. 1779 // 3. 16-byte cmpxchg needs 16-byte alignment. 1780 // Same logic for powerpc64, mips64, sparc64. 1781 .x86_64, 1782 .powerpc64, 1783 .powerpc64le, 1784 .mips64, 1785 .mips64el, 1786 .sparc64, 1787 => return switch (target.ofmt) { 1788 .c => 16, 1789 else => 8, 1790 }, 1791 1792 // Even LLVMABIAlignmentOfType(i128) agrees on these targets. 1793 .aarch64, 1794 .aarch64_be, 1795 .aarch64_32, 1796 .riscv64, 1797 .bpfel, 1798 .bpfeb, 1799 .nvptx, 1800 .nvptx64, 1801 => 16, 1802 1803 // Below this comment are unverified but based on the fact that C requires 1804 // int128_t to be 16 bytes aligned, it's a safe default. 1805 .spu_2, 1806 .csky, 1807 .arc, 1808 .m68k, 1809 .tce, 1810 .tcele, 1811 .le32, 1812 .amdil, 1813 .hsail, 1814 .spir, 1815 .kalimba, 1816 .renderscript32, 1817 .spirv32, 1818 .shave, 1819 .le64, 1820 .amdil64, 1821 .hsail64, 1822 .spir64, 1823 .renderscript64, 1824 .ve, 1825 .spirv64, 1826 .dxil, 1827 .loongarch32, 1828 .loongarch64, 1829 .xtensa, 1830 => 16, 1831 }; 1832 } 1833 1834 pub fn ptrBitWidth(target: Target) u16 { 1835 switch (target.abi) { 1836 .gnux32, .muslx32, .gnuabin32, .gnuilp32 => return 32, 1837 .gnuabi64 => return 64, 1838 else => {}, 1839 } 1840 switch (target.cpu.arch) { 1841 .avr, 1842 .msp430, 1843 .spu_2, 1844 => return 16, 1845 1846 .arc, 1847 .arm, 1848 .armeb, 1849 .csky, 1850 .hexagon, 1851 .m68k, 1852 .le32, 1853 .mips, 1854 .mipsel, 1855 .powerpc, 1856 .powerpcle, 1857 .r600, 1858 .riscv32, 1859 .sparcel, 1860 .tce, 1861 .tcele, 1862 .thumb, 1863 .thumbeb, 1864 .x86, 1865 .xcore, 1866 .nvptx, 1867 .amdil, 1868 .hsail, 1869 .spir, 1870 .kalimba, 1871 .shave, 1872 .lanai, 1873 .wasm32, 1874 .renderscript32, 1875 .aarch64_32, 1876 .spirv32, 1877 .loongarch32, 1878 .dxil, 1879 .xtensa, 1880 => return 32, 1881 1882 .aarch64, 1883 .aarch64_be, 1884 .mips64, 1885 .mips64el, 1886 .powerpc64, 1887 .powerpc64le, 1888 .riscv64, 1889 .x86_64, 1890 .nvptx64, 1891 .le64, 1892 .amdil64, 1893 .hsail64, 1894 .spir64, 1895 .wasm64, 1896 .renderscript64, 1897 .amdgcn, 1898 .bpfel, 1899 .bpfeb, 1900 .sparc64, 1901 .s390x, 1902 .ve, 1903 .spirv64, 1904 .loongarch64, 1905 => return 64, 1906 1907 .sparc => return if (std.Target.sparc.featureSetHas(target.cpu.features, .v9)) 64 else 32, 1908 } 1909 } 1910 1911 pub fn stackAlignment(target: Target) u16 { 1912 return switch (target.cpu.arch) { 1913 .amdgcn => 4, 1914 .x86 => switch (target.os.tag) { 1915 .windows => 4, 1916 else => 16, 1917 }, 1918 .arm, 1919 .armeb, 1920 .thumb, 1921 .thumbeb, 1922 .mips, 1923 .mipsel, 1924 .sparc, 1925 .sparcel, 1926 => 8, 1927 .aarch64, 1928 .aarch64_be, 1929 .aarch64_32, 1930 .bpfeb, 1931 .bpfel, 1932 .mips64, 1933 .mips64el, 1934 .powerpc64, 1935 .powerpc64le, 1936 .riscv32, 1937 .riscv64, 1938 .sparc64, 1939 .x86_64, 1940 .ve, 1941 .wasm32, 1942 .wasm64, 1943 => 16, 1944 else => @divExact(target.ptrBitWidth(), 8), 1945 }; 1946 } 1947 1948 /// Default signedness of `char` for the native C compiler for this target 1949 /// Note that char signedness is implementation-defined and many compilers provide 1950 /// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char 1951 pub fn charSignedness(target: Target) std.builtin.Signedness { 1952 switch (target.cpu.arch) { 1953 .aarch64, 1954 .aarch64_32, 1955 .aarch64_be, 1956 .arm, 1957 .armeb, 1958 .thumb, 1959 .thumbeb, 1960 => return if (target.os.tag.isDarwin() or target.os.tag == .windows) .signed else .unsigned, 1961 .powerpc, .powerpc64 => return if (target.os.tag.isDarwin()) .signed else .unsigned, 1962 .powerpc64le, 1963 .s390x, 1964 .xcore, 1965 .arc, 1966 .msp430, 1967 .riscv32, 1968 .riscv64, 1969 => return .unsigned, 1970 else => return .signed, 1971 } 1972 } 1973 1974 pub const CType = enum { 1975 char, 1976 short, 1977 ushort, 1978 int, 1979 uint, 1980 long, 1981 ulong, 1982 longlong, 1983 ulonglong, 1984 float, 1985 double, 1986 longdouble, 1987 }; 1988 1989 pub fn c_type_byte_size(t: Target, c_type: CType) u16 { 1990 return switch (c_type) { 1991 .char, 1992 .short, 1993 .ushort, 1994 .int, 1995 .uint, 1996 .long, 1997 .ulong, 1998 .longlong, 1999 .ulonglong, 2000 .float, 2001 .double, 2002 => @divExact(c_type_bit_size(t, c_type), 8), 2003 2004 .longdouble => switch (c_type_bit_size(t, c_type)) { 2005 16 => 2, 2006 32 => 4, 2007 64 => 8, 2008 80 => @as(u16, @intCast(mem.alignForward(usize, 10, c_type_alignment(t, .longdouble)))), 2009 128 => 16, 2010 else => unreachable, 2011 }, 2012 }; 2013 } 2014 2015 pub fn c_type_bit_size(target: Target, c_type: CType) u16 { 2016 switch (target.os.tag) { 2017 .freestanding, .other => switch (target.cpu.arch) { 2018 .msp430 => switch (c_type) { 2019 .char => return 8, 2020 .short, .ushort, .int, .uint => return 16, 2021 .float, .long, .ulong => return 32, 2022 .longlong, .ulonglong, .double, .longdouble => return 64, 2023 }, 2024 .avr => switch (c_type) { 2025 .char => return 8, 2026 .short, .ushort, .int, .uint => return 16, 2027 .long, .ulong, .float, .double, .longdouble => return 32, 2028 .longlong, .ulonglong => return 64, 2029 }, 2030 .tce, .tcele => switch (c_type) { 2031 .char => return 8, 2032 .short, .ushort => return 16, 2033 .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32, 2034 .float, .double, .longdouble => return 32, 2035 }, 2036 .mips64, .mips64el => switch (c_type) { 2037 .char => return 8, 2038 .short, .ushort => return 16, 2039 .int, .uint, .float => return 32, 2040 .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32, 2041 .longlong, .ulonglong, .double => return 64, 2042 .longdouble => return 128, 2043 }, 2044 .x86_64 => switch (c_type) { 2045 .char => return 8, 2046 .short, .ushort => return 16, 2047 .int, .uint, .float => return 32, 2048 .long, .ulong => switch (target.abi) { 2049 .gnux32, .muslx32 => return 32, 2050 else => return 64, 2051 }, 2052 .longlong, .ulonglong, .double => return 64, 2053 .longdouble => return 80, 2054 }, 2055 else => switch (c_type) { 2056 .char => return 8, 2057 .short, .ushort => return 16, 2058 .int, .uint, .float => return 32, 2059 .long, .ulong => return target.ptrBitWidth(), 2060 .longlong, .ulonglong, .double => return 64, 2061 .longdouble => switch (target.cpu.arch) { 2062 .x86 => switch (target.abi) { 2063 .android => return 64, 2064 else => return 80, 2065 }, 2066 2067 .powerpc, 2068 .powerpcle, 2069 .powerpc64, 2070 .powerpc64le, 2071 => switch (target.abi) { 2072 .musl, 2073 .musleabi, 2074 .musleabihf, 2075 .muslx32, 2076 => return 64, 2077 else => return 128, 2078 }, 2079 2080 .riscv32, 2081 .riscv64, 2082 .aarch64, 2083 .aarch64_be, 2084 .aarch64_32, 2085 .s390x, 2086 .sparc, 2087 .sparc64, 2088 .sparcel, 2089 .wasm32, 2090 .wasm64, 2091 => return 128, 2092 2093 else => return 64, 2094 }, 2095 }, 2096 }, 2097 2098 .linux, 2099 .freebsd, 2100 .netbsd, 2101 .dragonfly, 2102 .openbsd, 2103 .wasi, 2104 .emscripten, 2105 .plan9, 2106 .solaris, 2107 .haiku, 2108 .ananas, 2109 .fuchsia, 2110 .minix, 2111 => switch (target.cpu.arch) { 2112 .msp430 => switch (c_type) { 2113 .char => return 8, 2114 .short, .ushort, .int, .uint => return 16, 2115 .long, .ulong, .float => return 32, 2116 .longlong, .ulonglong, .double, .longdouble => return 64, 2117 }, 2118 .avr => switch (c_type) { 2119 .char => return 8, 2120 .short, .ushort, .int, .uint => return 16, 2121 .long, .ulong, .float, .double, .longdouble => return 32, 2122 .longlong, .ulonglong => return 64, 2123 }, 2124 .tce, .tcele => switch (c_type) { 2125 .char => return 8, 2126 .short, .ushort => return 16, 2127 .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32, 2128 .float, .double, .longdouble => return 32, 2129 }, 2130 .mips64, .mips64el => switch (c_type) { 2131 .char => return 8, 2132 .short, .ushort => return 16, 2133 .int, .uint, .float => return 32, 2134 .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32, 2135 .longlong, .ulonglong, .double => return 64, 2136 .longdouble => if (target.os.tag == .freebsd) return 64 else return 128, 2137 }, 2138 .x86_64 => switch (c_type) { 2139 .char => return 8, 2140 .short, .ushort => return 16, 2141 .int, .uint, .float => return 32, 2142 .long, .ulong => switch (target.abi) { 2143 .gnux32, .muslx32 => return 32, 2144 else => return 64, 2145 }, 2146 .longlong, .ulonglong, .double => return 64, 2147 .longdouble => return 80, 2148 }, 2149 else => switch (c_type) { 2150 .char => return 8, 2151 .short, .ushort => return 16, 2152 .int, .uint, .float => return 32, 2153 .long, .ulong => return target.ptrBitWidth(), 2154 .longlong, .ulonglong, .double => return 64, 2155 .longdouble => switch (target.cpu.arch) { 2156 .x86 => switch (target.abi) { 2157 .android => return 64, 2158 else => return 80, 2159 }, 2160 2161 .powerpc, 2162 .powerpcle, 2163 => switch (target.abi) { 2164 .musl, 2165 .musleabi, 2166 .musleabihf, 2167 .muslx32, 2168 => return 64, 2169 else => switch (target.os.tag) { 2170 .freebsd, .netbsd, .openbsd => return 64, 2171 else => return 128, 2172 }, 2173 }, 2174 2175 .powerpc64, 2176 .powerpc64le, 2177 => switch (target.abi) { 2178 .musl, 2179 .musleabi, 2180 .musleabihf, 2181 .muslx32, 2182 => return 64, 2183 else => switch (target.os.tag) { 2184 .freebsd, .openbsd => return 64, 2185 else => return 128, 2186 }, 2187 }, 2188 2189 .riscv32, 2190 .riscv64, 2191 .aarch64, 2192 .aarch64_be, 2193 .aarch64_32, 2194 .s390x, 2195 .mips64, 2196 .mips64el, 2197 .sparc, 2198 .sparc64, 2199 .sparcel, 2200 .wasm32, 2201 .wasm64, 2202 => return 128, 2203 2204 else => return 64, 2205 }, 2206 }, 2207 }, 2208 2209 .windows, .uefi => switch (target.cpu.arch) { 2210 .x86 => switch (c_type) { 2211 .char => return 8, 2212 .short, .ushort => return 16, 2213 .int, .uint, .float => return 32, 2214 .long, .ulong => return 32, 2215 .longlong, .ulonglong, .double => return 64, 2216 .longdouble => switch (target.abi) { 2217 .gnu, .gnuilp32, .cygnus => return 80, 2218 else => return 64, 2219 }, 2220 }, 2221 .x86_64 => switch (c_type) { 2222 .char => return 8, 2223 .short, .ushort => return 16, 2224 .int, .uint, .float => return 32, 2225 .long, .ulong => switch (target.abi) { 2226 .cygnus => return 64, 2227 else => return 32, 2228 }, 2229 .longlong, .ulonglong, .double => return 64, 2230 .longdouble => switch (target.abi) { 2231 .gnu, .gnuilp32, .cygnus => return 80, 2232 else => return 64, 2233 }, 2234 }, 2235 else => switch (c_type) { 2236 .char => return 8, 2237 .short, .ushort => return 16, 2238 .int, .uint, .float => return 32, 2239 .long, .ulong => return 32, 2240 .longlong, .ulonglong, .double => return 64, 2241 .longdouble => return 64, 2242 }, 2243 }, 2244 2245 .macos, .ios, .tvos, .watchos => switch (c_type) { 2246 .char => return 8, 2247 .short, .ushort => return 16, 2248 .int, .uint, .float => return 32, 2249 .long, .ulong => switch (target.cpu.arch) { 2250 .x86, .arm, .aarch64_32 => return 32, 2251 .x86_64 => switch (target.abi) { 2252 .gnux32, .muslx32 => return 32, 2253 else => return 64, 2254 }, 2255 else => return 64, 2256 }, 2257 .longlong, .ulonglong, .double => return 64, 2258 .longdouble => switch (target.cpu.arch) { 2259 .x86 => switch (target.abi) { 2260 .android => return 64, 2261 else => return 80, 2262 }, 2263 .x86_64 => return 80, 2264 else => return 64, 2265 }, 2266 }, 2267 2268 .nvcl, .cuda => switch (c_type) { 2269 .char => return 8, 2270 .short, .ushort => return 16, 2271 .int, .uint, .float => return 32, 2272 .long, .ulong => switch (target.cpu.arch) { 2273 .nvptx => return 32, 2274 .nvptx64 => return 64, 2275 else => return 64, 2276 }, 2277 .longlong, .ulonglong, .double => return 64, 2278 .longdouble => return 64, 2279 }, 2280 2281 .amdhsa, .amdpal => switch (c_type) { 2282 .char => return 8, 2283 .short, .ushort => return 16, 2284 .int, .uint, .float => return 32, 2285 .long, .ulong, .longlong, .ulonglong, .double => return 64, 2286 .longdouble => return 128, 2287 }, 2288 2289 .opencl => switch (c_type) { 2290 .char => return 8, 2291 .short, .ushort => return 16, 2292 .int, .uint, .float => return 32, 2293 .long, .ulong, .double => return 64, 2294 .longlong, .ulonglong => return 128, 2295 // Note: The OpenCL specification does not guarantee a particular size for long double, 2296 // but clang uses 128 bits. 2297 .longdouble => return 128, 2298 }, 2299 2300 .ps4, .ps5 => switch (c_type) { 2301 .char => return 8, 2302 .short, .ushort => return 16, 2303 .int, .uint, .float => return 32, 2304 .long, .ulong => return 64, 2305 .longlong, .ulonglong, .double => return 64, 2306 .longdouble => return 80, 2307 }, 2308 2309 .cloudabi, 2310 .kfreebsd, 2311 .lv2, 2312 .zos, 2313 .rtems, 2314 .nacl, 2315 .aix, 2316 .elfiamcu, 2317 .mesa3d, 2318 .contiki, 2319 .hermit, 2320 .hurd, 2321 .glsl450, 2322 .vulkan, 2323 .driverkit, 2324 .shadermodel, 2325 => @panic("TODO specify the C integer and float type sizes for this OS"), 2326 } 2327 } 2328 2329 pub fn c_type_alignment(target: Target, c_type: CType) u16 { 2330 // Overrides for unusual alignments 2331 switch (target.cpu.arch) { 2332 .avr => return 1, 2333 .x86 => switch (target.os.tag) { 2334 .windows, .uefi => switch (c_type) { 2335 .longlong, .ulonglong, .double => return 8, 2336 .longdouble => switch (target.abi) { 2337 .gnu, .gnuilp32, .cygnus => return 4, 2338 else => return 8, 2339 }, 2340 else => {}, 2341 }, 2342 else => {}, 2343 }, 2344 else => {}, 2345 } 2346 2347 // Next-power-of-two-aligned, up to a maximum. 2348 return @min( 2349 std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8), 2350 switch (target.cpu.arch) { 2351 .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) { 2352 .netbsd => switch (target.abi) { 2353 .gnueabi, 2354 .gnueabihf, 2355 .eabi, 2356 .eabihf, 2357 .android, 2358 .musleabi, 2359 .musleabihf, 2360 => 8, 2361 2362 else => @as(u16, 4), 2363 }, 2364 .ios, .tvos, .watchos => 4, 2365 else => 8, 2366 }, 2367 2368 .msp430, 2369 .avr, 2370 => 2, 2371 2372 .arc, 2373 .csky, 2374 .x86, 2375 .xcore, 2376 .dxil, 2377 .loongarch32, 2378 .tce, 2379 .tcele, 2380 .le32, 2381 .amdil, 2382 .hsail, 2383 .spir, 2384 .spirv32, 2385 .kalimba, 2386 .shave, 2387 .renderscript32, 2388 .ve, 2389 .spu_2, 2390 .xtensa, 2391 => 4, 2392 2393 .aarch64_32, 2394 .amdgcn, 2395 .amdil64, 2396 .bpfel, 2397 .bpfeb, 2398 .hexagon, 2399 .hsail64, 2400 .loongarch64, 2401 .m68k, 2402 .mips, 2403 .mipsel, 2404 .sparc, 2405 .sparcel, 2406 .sparc64, 2407 .lanai, 2408 .le64, 2409 .nvptx, 2410 .nvptx64, 2411 .r600, 2412 .s390x, 2413 .spir64, 2414 .spirv64, 2415 .renderscript64, 2416 => 8, 2417 2418 .aarch64, 2419 .aarch64_be, 2420 .mips64, 2421 .mips64el, 2422 .powerpc, 2423 .powerpcle, 2424 .powerpc64, 2425 .powerpc64le, 2426 .riscv32, 2427 .riscv64, 2428 .x86_64, 2429 .wasm32, 2430 .wasm64, 2431 => 16, 2432 }, 2433 ); 2434 } 2435 2436 pub fn c_type_preferred_alignment(target: Target, c_type: CType) u16 { 2437 // Overrides for unusual alignments 2438 switch (target.cpu.arch) { 2439 .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) { 2440 .netbsd => switch (target.abi) { 2441 .gnueabi, 2442 .gnueabihf, 2443 .eabi, 2444 .eabihf, 2445 .android, 2446 .musleabi, 2447 .musleabihf, 2448 => {}, 2449 2450 else => switch (c_type) { 2451 .longdouble => return 4, 2452 else => {}, 2453 }, 2454 }, 2455 .ios, .tvos, .watchos => switch (c_type) { 2456 .longdouble => return 4, 2457 else => {}, 2458 }, 2459 else => {}, 2460 }, 2461 .arc => switch (c_type) { 2462 .longdouble => return 4, 2463 else => {}, 2464 }, 2465 .avr => switch (c_type) { 2466 .char, .int, .uint, .long, .ulong, .float, .longdouble => return 1, 2467 .short, .ushort => return 2, 2468 .double => return 4, 2469 .longlong, .ulonglong => return 8, 2470 }, 2471 .x86 => switch (target.os.tag) { 2472 .windows, .uefi => switch (c_type) { 2473 .longdouble => switch (target.abi) { 2474 .gnu, .gnuilp32, .cygnus => return 4, 2475 else => return 8, 2476 }, 2477 else => {}, 2478 }, 2479 else => switch (c_type) { 2480 .longdouble => return 4, 2481 else => {}, 2482 }, 2483 }, 2484 else => {}, 2485 } 2486 2487 // Next-power-of-two-aligned, up to a maximum. 2488 return @min( 2489 std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8), 2490 switch (target.cpu.arch) { 2491 .msp430 => @as(u16, 2), 2492 2493 .csky, 2494 .xcore, 2495 .dxil, 2496 .loongarch32, 2497 .tce, 2498 .tcele, 2499 .le32, 2500 .amdil, 2501 .hsail, 2502 .spir, 2503 .spirv32, 2504 .kalimba, 2505 .shave, 2506 .renderscript32, 2507 .ve, 2508 .spu_2, 2509 .xtensa, 2510 => 4, 2511 2512 .arc, 2513 .arm, 2514 .armeb, 2515 .avr, 2516 .thumb, 2517 .thumbeb, 2518 .aarch64_32, 2519 .amdgcn, 2520 .amdil64, 2521 .bpfel, 2522 .bpfeb, 2523 .hexagon, 2524 .hsail64, 2525 .x86, 2526 .loongarch64, 2527 .m68k, 2528 .mips, 2529 .mipsel, 2530 .sparc, 2531 .sparcel, 2532 .sparc64, 2533 .lanai, 2534 .le64, 2535 .nvptx, 2536 .nvptx64, 2537 .r600, 2538 .s390x, 2539 .spir64, 2540 .spirv64, 2541 .renderscript64, 2542 => 8, 2543 2544 .aarch64, 2545 .aarch64_be, 2546 .mips64, 2547 .mips64el, 2548 .powerpc, 2549 .powerpcle, 2550 .powerpc64, 2551 .powerpc64le, 2552 .riscv32, 2553 .riscv64, 2554 .x86_64, 2555 .wasm32, 2556 .wasm64, 2557 => 16, 2558 }, 2559 ); 2560 } 2561 }; 2562 2563 test { 2564 std.testing.refAllDecls(Target.Cpu.Arch); 2565 }