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