╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ target.zig ───────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
195 .coff, 196 .elf, 197 .hex, 198 .macho, 199 .spirv, 200 .raw, 201 .wasm, 202 => {}, 203 } 204 205 return switch (target.cpu.arch) { 206 .arm, 207 .armeb, 208 .aarch64, 209 .aarch64_be, 210 .arc, 211 .avr, 212 .bpfel, 213 .bpfeb, 214 .hexagon, 215 .loongarch32, 216 .loongarch64, 217 .m68k, 218 .mips, 219 .mipsel, 220 .mips64, 221 .mips64el, 222 .msp430, 223 .powerpc, 224 .powerpcle, 225 .powerpc64, 226 .powerpc64le, 227 .amdgcn, 228 .riscv32, 229 .riscv32be, 230 .riscv64, 231 .riscv64be, 232 .sparc, 233 .sparc64, 234 .spirv32, 235 .spirv64, 236 .s390x, 237 .thumb, 238 .thumbeb, 239 .x86, 240 .x86_64, 241 .xcore, 242 .nvptx, 243 .nvptx64, 244 .lanai, 245 .wasm32, 246 .wasm64, 247 .ve, 248 .xtensa, 249 => true, 250 251 // LLVM backend exists but can produce neither assembly nor object files. 252 .csky, 253 => false, 254 255 // Third-party LLVM backend exists. 256 .ez80, 257 => false, 258 259 // No LLVM backend exists. 260 .alpha, 261 .arceb, 262 .hppa, 263 .hppa64, 264 .kalimba, 265 .kvx, 266 .m88k, 267 .microblaze, 268 .microblazeel, 269 .or1k, 270 .propeller, 271 .sh, 272 .sheb, 273 .x86_16, 274 .xtensaeb, 275 .spork8, 276 => false, 277 }; 278 } 279 280 /// The set of targets that Zig supports using LLD to link for. 281 pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool { 282 return switch (ofmt) { 283 .elf, .coff, .wasm => true, 284 else => false, 285 }; 286 } 287 288 /// Returns `true` if `ofmt` has two linker implementations, so `-fnew-linker` is meaningful. 289 pub fn hasNewLinker(ofmt: std.Target.ObjectFormat) bool { 290 return switch (ofmt) { 291 .elf => true, 292 else => false, 293 }; 294 } 295 296 /// The set of targets that our own self-hosted backends have robust support for. 297 /// Used to select between LLVM backend and self-hosted backend when compiling in 298 /// debug mode. A given target should only return true here if it is passing greater 299 /// than or equal to the number of behavior tests as the respective LLVM backend. 300 pub fn selfHostedBackendIsAsRobustAsLlvm(target: *const std.Target) bool { 301 if (comptime builtin.cpu.arch.endian() == .big) return false; // https://github.com/ziglang/zig/issues/25961 302 if (target.cpu.arch.isSpirV()) return true; 303 if (target.cpu.arch == .x86_64 and target.ptrBitWidth() == 64) { 304 if (target.os.tag == .illumos) { 305 // https://github.com/ziglang/zig/issues/25699 306 return false; 307 } 308 // Self-hosted linker needs work: https://github.com/ziglang/zig/issues/24341 309 switch (target.os.tag) { 310 .dragonfly, 311 .freebsd, 312 .netbsd, 313 .openbsd, 314 => return false, 315 else => {}, 316 } 317 return switch (target.ofmt) { 318 .elf => true, 319 .macho => false, // https://codeberg.org/ziglang/zig/issues/35267 320 else => false, 321 }; 322 } 323 return false; 324 } 325 326 pub fn supportsStackProbing(target: *const std.Target, backend: std.lang.CompilerBackend) bool { 327 return switch (backend) { 328 .stage2_aarch64, .stage2_x86_64 => true, 329 .stage2_llvm => target.os.tag != .windows and target.os.tag != .uefi and 330 (target.cpu.arch == .x86 or target.cpu.arch == .x86_64), 331 else => false, 332 }; 333 } 334 335 pub fn supportsStackProtector(target: *const std.Target, backend: std.lang.CompilerBackend) bool { 336 switch (target.os.tag) { 337 .plan9 => return false, 338 else => {}, 339 } 340 switch (target.cpu.arch) { 341 .spirv32, .spirv64 => return false, 342 else => {}, 343 } 344 return switch (backend) { 345 .stage2_llvm => true, 346 else => false, 347 }; 348 } 349 350 pub fn clangSupportsStackProtector(target: *const std.Target) bool { 351 return switch (target.cpu.arch) { 352 .spirv32, .spirv64 => return false, 353 else => true, 354 }; 355 } 356 357 pub fn libcProvidesStackProtector(target: *const std.Target) bool { 358 return !target.isMinGW() and target.os.tag != .wasi and !target.cpu.arch.isSpirV(); 359 } 360 361 /// Returns true if `@returnAddress()` is supported by the target and has a 362 /// reasonably performant implementation for the requested optimization mode. 363 pub fn supportsReturnAddress(target: *const std.Target, optimize: std.lang.Optimize) bool { 364 return switch (target.cpu.arch) { 365 // Emscripten currently implements `emscripten_return_address()` by calling 366 // out into JavaScript and parsing a stack trace, which introduces significant 367 // overhead that we would prefer to avoid in release builds. 368 .wasm32, .wasm64 => target.os.tag == .emscripten and optimize == .debug, 369 .bpfel, .bpfeb => false, 370 .spirv32, .spirv64 => false, 371 else => true, 372 }; 373 } 374 375 pub const CompilerRtClassification = enum { none, only_compiler_rt, only_libunwind, both }; 376 377 pub fn classifyCompilerRtLibName(name: []const u8) CompilerRtClassification { 378 if (std.mem.eql(u8, name, "gcc_s")) { 379 // libgcc_s includes exception handling functions, so if linking this library 380 // is requested, zig needs to instead link libunwind. Otherwise we end up with 381 // the linker unable to find `_Unwind_RaiseException` and other related symbols. 382 return .both; 383 } 384 if (std.mem.eql(u8, name, "compiler_rt") or 385 std.mem.eql(u8, name, "gcc") or 386 std.mem.eql(u8, name, "atomic") or 387 std.mem.eql(u8, name, "ssp")) 388 { 389 return .only_compiler_rt; 390 } 391 if (std.mem.eql(u8, name, "unwind") or 392 std.mem.eql(u8, name, "gcc_eh")) 393 { 394 return .only_libunwind; 395 } 396 return .none; 397 } 398 399 pub fn hasDebugInfo(target: *const std.Target) bool { 400 return switch (target.ofmt) { 401 .raw, .hex => false, 402 else => switch (target.cpu.arch) { 403 // TODO: We should make newer PTX versions depend on older ones so we'd just check `ptx75`. 404 .nvptx, .nvptx64 => target.cpu.hasAny(.nvptx, &.{ 405 .ptx75, 406 .ptx76, 407 .ptx77, 408 .ptx78, 409 .ptx80, 410 .ptx81, 411 .ptx82, 412 .ptx83, 413 .ptx84, 414 .ptx85, 415 .ptx86, 416 .ptx87, 417 .ptx88, 418 .ptx90, 419 }), 420 .bpfel, .bpfeb => false, 421 else => true, 422 }, 423 }; 424 } 425 426 pub fn defaultCompilerRtOptimizeMode(target: *const std.Target) std.lang.Optimize { 427 if (target.cpu.arch.isWasm() and target.os.tag == .freestanding) { 428 return .small; 429 } else { 430 return .fast; 431 } 432 } 433 434 pub fn canBuildLibCompilerRt(target: *const std.Target) enum { no, yes, llvm_only } { 435 switch (target.os.tag) { 436 .plan9 => return .no, 437 else => {}, 438 } 439 switch (target.cpu.arch) { 440 .spirv32, .spirv64 => return .no, 441 .spork8 => return .no, 442 // Remove this once https://github.com/ziglang/zig/issues/23714 is fixed 443 .amdgcn => return .no, 444 else => {}, 445 } 446 return switch (zigBackend(target, false)) { 447 .stage2_aarch64, .stage2_wasm, .stage2_x86_64 => .yes, 448 else => .llvm_only, 449 }; 450 } 451 452 pub fn canBuildLibUbsanRt(target: *const std.Target) enum { no, yes, llvm_only, llvm_lld_only } { 453 switch (target.cpu.arch) { 454 .spork8 => return .no, 455 .spirv32, .spirv64 => return .no, 456 // Remove this once https://github.com/ziglang/zig/issues/23715 is fixed 457 .nvptx, .nvptx64 => return .no, 458 else => {}, 459 } 460 return switch (zigBackend(target, false)) { 461 .stage2_wasm => .yes, 462 .stage2_x86_64 => .yes, 463 else => .llvm_only, 464 }; 465 } 466 467 /// Whether libzigc can fill-in the gaps of an existing libc 468 /// or *is* the libc of the target. 469 pub fn wantsZigC(target: *const std.Target, link_mode: std.lang.LinkMode) bool { 470 return (target.isMuslLibC() and link_mode == .static) or target.isWasiLibC() or target.isMinGW(); 471 } 472 473 pub fn hasRedZone(target: *const std.Target) bool { 474 return switch (target.cpu.arch) { 475 .aarch64, 476 .aarch64_be, 477 .powerpc, 478 .powerpcle, 479 .powerpc64, 480 .powerpc64le, 481 .x86_64, 482 .x86, 483 => true, 484 485 else => false, 486 }; 487 } 488 489 pub fn libcFullLinkFlags(target: *const std.Target) []const []const u8 { 490 // The linking order of these is significant and should match the order other 491 // c compilers such as gcc or clang use. 492 const result: []const []const u8 = switch (target.os.tag) { 493 .dragonfly, .freebsd, .netbsd, .openbsd => &.{ "-lm", "-lpthread", "-lc", "-lutil" }, 494 .illumos => &.{ "-lm", "-lsocket", "-lnsl", "-lc" }, 495 .haiku => &.{ "-lm", "-lroot", "-lpthread", "-lc", "-lnetwork" }, 496 .linux => switch (target.abi) { 497 .android, .androideabi, .ohos, .ohoseabi => &.{ "-lm", "-lc", "-ldl" }, 498 else => &.{ "-lm", "-lpthread", "-lc", "-ldl", "-lrt", "-lutil" }, 499 }, 500 // On SerenityOS libc includes libm, libpthread, libdl, and libssp. 501 .serenity => &.{"-lc"}, 502 else => &.{}, 503 }; 504 return result; 505 } 506 507 pub fn clangMightShellOutForAssembly(target: *const std.Target) bool { 508 // Clang defaults to using the system assembler in some cases. 509 return target.cpu.arch.isNvptx() or target.cpu.arch == .xcore; 510 } 511 512 /// Each backend architecture in Clang has a different codepath which may or may not 513 /// support an -mcpu flag. 514 pub fn clangAssemblerSupportsMcpuArg(target: *const std.Target) bool { 515 return switch (target.cpu.arch) { 516 .arm, .armeb, .thumb, .thumbeb => true, 517 else => false, 518 }; 519 } 520 521 /// Some experimental or poorly-maintained LLVM targets do not properly process CPU models in their 522 /// Clang driver code. For these, we should omit the `-Xclang -target-cpu -Xclang <model>` flags. 523 pub fn clangSupportsTargetCpuArg(target: *const std.Target) bool { 524 return switch (target.cpu.arch) { 525 .arc, 526 .msp430, 527 .ve, 528 .xcore, 529 .xtensa, 530 => false, 531 else => true, 532 }; 533 } 534 535 pub fn clangSupportsFloatAbiArg(target: *const std.Target) bool { 536 return switch (target.cpu.arch) { 537 .arm, 538 .armeb, 539 .thumb, 540 .thumbeb, 541 .csky, 542 .mips, 543 .mipsel, 544 .mips64, 545 .mips64el, 546 .powerpc, 547 .powerpcle, 548 .powerpc64, 549 .powerpc64le, 550 .s390x, 551 .sparc, 552 .sparc64, 553 => true, 554 // We use the target triple for LoongArch. 555 .loongarch32, .loongarch64 => false, 556 else => false, 557 }; 558 } 559 560 pub fn clangSupportsNoImplicitFloatArg(target: *const std.Target) bool { 561 return switch (target.cpu.arch) { 562 .aarch64, 563 .aarch64_be, 564 .arm, 565 .armeb, 566 .thumb, 567 .thumbeb, 568 .riscv32, 569 .riscv32be, 570 .riscv64, 571 .riscv64be, 572 .x86, 573 .x86_64, 574 => true, 575 else => false, 576 }; 577 } 578 579 pub fn defaultUnwindTables(target: *const std.Target, libunwind: bool, libtsan: bool) std.lang.UnwindTables { 580 if (target.os.tag == .windows) { 581 // The old 32-bit x86 variant of SEH doesn't use tables. 582 return if (target.cpu.arch != .x86) .async else .none; 583 } 584 if (target.os.tag.isDarwin()) return .async; 585 if (libunwind) return .async; 586 if (libtsan) return .async; 587 if (std.debug.Dwarf.supportsUnwinding(target)) return .async; 588 return .none; 589 } 590 591 pub fn defaultAddressSpace( 592 target: *const std.Target, 593 context: enum { 594 /// Query the default address space for global constant values. 595 global_constant, 596 /// Query the default address space for global mutable values. 597 global_mutable, 598 /// Query the default address space for function-local values. 599 local, 600 /// Query the default address space for functions themselves. 601 function, 602 }, 603 ) AddressSpace { 604 // The default address space for functions on AVR is .flash to produce 605 // correct fixups into progmem. 606 if (context == .function and target.cpu.arch == .avr) return .flash; 607 if (context == .global_mutable and target.os.tag == .vulkan) return .private; 608 return .generic; 609 } 610 611 /// Returns true if pointers in `from` can be converted to a pointer in `to`. 612 pub fn addrSpaceCastIsValid( 613 target: *const std.Target, 614 from: AddressSpace, 615 to: AddressSpace, 616 ) bool { 617 switch (target.cpu.arch) { 618 .x86_64, .x86 => return target.supportsAddressSpace(from, null) and target.supportsAddressSpace(to, null), 619 .nvptx64, .nvptx, .amdgcn => { 620 const to_generic = target.supportsAddressSpace(from, null) and to == .generic; 621 const from_generic = target.supportsAddressSpace(to, null) and from == .generic; 622 return to_generic or from_generic; 623 }, 624 else => return from == .generic and to == .generic, 625 } 626 } 627 628 /// Returns whether pointer operations (arithmetic, indexing, etc.) should be blocked 629 /// for the given address space on the target architecture. 630 /// 631 /// Under SPIR-V with Vulkan 632 /// (a) all physical pointers (.physical_storage_buffer, .global) always support pointer operations, 633 /// (b) by default logical pointers (.constant, .input, .output, etc.) never support operations 634 /// (c) some logical pointers (.storage_buffer, .shared) do support operations when 635 /// the VariablePointers capability is enabled (which enables OpPtrAccessChain). 636 pub fn shouldBlockPointerOps(target: *const std.Target, as: AddressSpace) bool { 637 if (target.os.tag != .vulkan and target.os.tag != .opengl) return false; 638 639 return switch (as) { 640 // TODO: Vulkan doesn't support pointers in the generic address space, we 641 // should remove this case but this requires a change in defaultAddressSpace(). 642 .generic => true, 643 // For now, all global pointers are represented using StorageBuffer or CrossWorkgroup, 644 // so these are real pointers. 645 // Physical pointers always support operations 646 .global, .physical_storage_buffer => false, 647 // Logical pointers that support operations with VariablePointers capability 648 .shared => !target.cpu.features.isEnabled(@backingInt(std.Target.spirv.Feature.variable_pointers)), 649 .storage_buffer => !target.cpu.features.isEnabled(@backingInt(std.Target.spirv.Feature.variable_pointers)), 650 // Logical pointers that never support operations 651 .constant, 652 .local, 653 .private, 654 .input, 655 .output, 656 .uniform, 657 .push_constant, 658 => true, 659 else => unreachable, 660 }; 661 } 662 663 pub fn isDynamicAMDGCNFeature(target: *const std.Target, feature: std.Target.Cpu.Feature) bool { 664 if (target.cpu.arch != .amdgcn) return false; 665 666 const sramecc_only = &[_]*const std.Target.Cpu.Model{ 667 &std.Target.amdgcn.cpu.gfx1010, 668 &std.Target.amdgcn.cpu.gfx1011, 669 &std.Target.amdgcn.cpu.gfx1012, 670 &std.Target.amdgcn.cpu.gfx1013, 671 }; 672 const xnack_or_sramecc = &[_]*const std.Target.Cpu.Model{ 673 &std.Target.amdgcn.cpu.gfx1030, 674 &std.Target.amdgcn.cpu.gfx1031, 675 &std.Target.amdgcn.cpu.gfx1032, 676 &std.Target.amdgcn.cpu.gfx1033, 677 &std.Target.amdgcn.cpu.gfx1034, 678 &std.Target.amdgcn.cpu.gfx1035, 679 &std.Target.amdgcn.cpu.gfx1036, 680 &std.Target.amdgcn.cpu.gfx1100, 681 &std.Target.amdgcn.cpu.gfx1101, 682 &std.Target.amdgcn.cpu.gfx1102, 683 &std.Target.amdgcn.cpu.gfx1103, 684 &std.Target.amdgcn.cpu.gfx1150, 685 &std.Target.amdgcn.cpu.gfx1151, 686 &std.Target.amdgcn.cpu.gfx1152, 687 &std.Target.amdgcn.cpu.gfx1153, 688 &std.Target.amdgcn.cpu.gfx1200, 689 &std.Target.amdgcn.cpu.gfx1201, 690 }; 691 const feature_tag: std.Target.amdgcn.Feature = @fromBackingInt(@intCast(feature.index)); 692 693 if (feature_tag == .sramecc) { 694 if (std.mem.findScalar( 695 *const std.Target.Cpu.Model, 696 sramecc_only ++ xnack_or_sramecc, 697 target.cpu.model, 698 )) |_| return true; 699 } 700 if (feature_tag == .xnack) { 701 if (std.mem.findScalar( 702 *const std.Target.Cpu.Model, 703 xnack_or_sramecc, 704 target.cpu.model, 705 )) |_| return true; 706 } 707 708 return false; 709 } 710 711 pub fn llvmMachineAbi(target: *const std.Target) ?[:0]const u8 { 712 return switch (target.cpu.arch) { 713 .arm, .armeb, .thumb, .thumbeb => "aapcs", 714 .loongarch64 => switch (target.abi) { 715 .gnusf, .muslsf => "lp64s", 716 .gnuf32, .muslf32 => "lp64f", 717 else => "lp64d", 718 }, 719 .loongarch32 => switch (target.abi) { 720 .gnusf, .muslsf => "ilp32s", 721 .gnuf32, .muslf32 => "ilp32f", 722 else => "ilp32d", 723 }, 724 .mips, .mipsel => "o32", 725 .mips64, .mips64el => switch (target.abi) { 726 .gnuabin32, .muslabin32, .abin32 => "n32", 727 else => "n64", 728 }, 729 .powerpc64 => if (target.os.tag == .ps3) "elfv1" else "elfv2", 730 .powerpc64le => "elfv2", 731 .riscv64, .riscv64be => if (target.cpu.has(.riscv, .e)) 732 "lp64e" 733 else if (target.cpu.has(.riscv, .d)) 734 "lp64d" 735 else if (target.cpu.has(.riscv, .f)) 736 "lp64f" 737 else 738 "lp64", 739 .riscv32, .riscv32be => if (target.cpu.has(.riscv, .e)) 740 "ilp32e" 741 else if (target.cpu.has(.riscv, .d)) 742 "ilp32d" 743 else if (target.cpu.has(.riscv, .f)) 744 "ilp32f" 745 else 746 "ilp32", 747 else => null, 748 }; 749 } 750 751 /// This function returns 1 if function alignment is not observable or settable. Note that this 752 /// value will not necessarily match the backend's default function alignment (e.g. for LLVM). 753 pub fn defaultFunctionAlignment(target: *const std.Target) Alignment { 754 // Overrides of the minimum for performance. 755 return switch (target.cpu.arch) { 756 .csky, 757 .thumb, 758 .thumbeb, 759 .xcore, 760 => .@"4", 761 .aarch64, 762 .aarch64_be, 763 .hexagon, 764 .powerpc, 765 .powerpcle, 766 .powerpc64, 767 .powerpc64le, 768 .s390x, 769 .x86, 770 .x86_64, 771 => .@"16", 772 .loongarch32, 773 .loongarch64, 774 => .@"32", 775 else => minFunctionAlignment(target), 776 }; 777 } 778 779 /// This function returns 1 if function alignment is not observable or settable. 780 pub fn minFunctionAlignment(target: *const std.Target) Alignment { 781 return switch (target.cpu.arch) { 782 .riscv32, 783 .riscv32be, 784 .riscv64, 785 .riscv64be, 786 => if (target.cpu.hasAny(.riscv, &.{ .c, .zca })) .@"2" else .@"4", 787 .thumb, 788 .thumbeb, 789 .csky, 790 .m68k, 791 .msp430, 792 .sh, 793 .sheb, 794 .s390x, 795 .xcore, 796 => .@"2", 797 .aarch64, 798 .aarch64_be, 799 .alpha, 800 .arc, 801 .arceb, 802 .arm, 803 .armeb, 804 .hexagon, 805 .hppa, 806 .hppa64, 807 .lanai, 808 .loongarch32, 809 .loongarch64, 810 .microblaze, 811 .microblazeel, 812 .mips, 813 .mipsel, 814 .powerpc, 815 .powerpcle, 816 .powerpc64, 817 .powerpc64le, 818 .sparc, 819 .sparc64, 820 .xtensa, 821 .xtensaeb, 822 => .@"4", 823 .bpfeb, 824 .bpfel, 825 .kvx, 826 .mips64, 827 .mips64el, 828 => .@"8", 829 .ve, 830 => .@"16", 831 else => .@"1", 832 }; 833 } 834 835 pub fn supportsFunctionAlignment(target: *const std.Target) bool { 836 return switch (target.cpu.arch) { 837 .nvptx, 838 .nvptx64, 839 .spirv32, 840 .spirv64, 841 .wasm32, 842 .wasm64, 843 => false, 844 else => true, 845 }; 846 } 847 848 pub fn functionPointerMask(target: *const std.Target) ?u64 { 849 // 32-bit Arm uses the LSB to mean that the target function contains Thumb code. 850 // MIPS uses the LSB to mean that the target function contains MIPS16/microMIPS code. 851 return if (target.cpu.arch.isArm() or target.cpu.arch.isMIPS32()) 852 ~@as(u32, 1) 853 else if (target.cpu.arch.isMIPS64()) 854 ~@as(u64, 1) 855 else 856 null; 857 } 858 859 pub fn supportsTailCall(target: *const std.Target, backend: std.lang.CompilerBackend) bool { 860 switch (backend) { 861 .stage2_llvm => { 862 dev.check(.llvm_backend); 863 return @import("codegen/llvm.zig").supportsTailCall(target); 864 }, 865 .stage2_c => return true, 866 else => return false, 867 } 868 } 869 870 pub fn supportsThreads(target: *const std.Target, backend: std.lang.CompilerBackend) bool { 871 _ = target; 872 return switch (backend) { 873 .stage2_aarch64 => false, 874 .stage2_loongarch => false, 875 else => true, 876 }; 877 } 878 879 pub fn libcFloatPrefix(float_bits: u16) []const u8 { 880 return switch (float_bits) { 881 16, 80 => "__", 882 32, 64, 128 => "", 883 else => unreachable, 884 }; 885 } 886 887 pub fn libcFloatSuffix(float_bits: u16) []const u8 { 888 return switch (float_bits) { 889 16 => "h", // Non-standard 890 32 => "f", 891 64 => "", 892 80 => "x", // Non-standard 893 128 => "f128", 894 else => unreachable, 895 }; 896 } 897 898 pub fn compilerRtFloatAbbrev(target: *const std.Target, float_bits: u16) []const u8 { 899 return switch (float_bits) { 900 16 => "h", 901 32 => "s", 902 64 => "d", 903 80 => "x", 904 128 => if (target.cpu.arch.isPowerPC()) "k" else "t", 905 else => unreachable, 906 }; 907 } 908 909 pub fn compilerRtIntAbbrev(bits: u16) []const u8 { 910 return switch (bits) { 911 16 => "h", 912 32 => "s", 913 64 => "d", 914 128 => "t", 915 else => unreachable, 916 }; 917 } 918 919 pub fn fnCallConvAllowsZigTypes(cc: std.lang.CallingConvention) bool { 920 return switch (cc) { 921 .auto, .async, .@"inline" => true, 922 // For now we want to authorize PTX kernel to use zig objects, even if 923 // we end up exposing the ABI. The goal is to experiment with more 924 // integrated CPU/GPU code. 925 .nvptx_kernel => true, 926 else => false, 927 }; 928 } 929 930 pub fn zigBackend(target: *const std.Target, use_llvm: bool) std.lang.CompilerBackend { 931 if (use_llvm) return .stage2_llvm; 932 if (target.ofmt == .c) return .stage2_c; 933 return switch (target.cpu.arch) { 934 .aarch64, .aarch64_be => .stage2_aarch64, 935 .arm, .armeb, .thumb, .thumbeb => .stage2_arm, 936 .loongarch32, .loongarch64 => .stage2_loongarch, 937 .powerpc, .powerpcle, .powerpc64, .powerpc64le => .stage2_powerpc, 938 .riscv64 => .stage2_riscv64, 939 .sparc64 => .stage2_sparc64, 940 .spirv32, .spirv64 => .stage2_spirv, 941 .wasm32, .wasm64 => .stage2_wasm, 942 .x86 => .stage2_x86, 943 .x86_64 => .stage2_x86_64, 944 .spork8 => .zsf_spork8, 945 else => .other, 946 }; 947 } 948 949 pub inline fn backendSupportsFeature(backend: std.lang.CompilerBackend, comptime feature: Feature) bool { 950 return switch (feature) { 951 .panic_fn => switch (backend) { 952 .stage2_aarch64, 953 .stage2_c, 954 .stage2_llvm, 955 .stage2_x86_64, 956 .stage2_riscv64, 957 .stage2_wasm, 958 => true, 959 else => false, 960 }, 961 .error_return_trace => switch (backend) { 962 .stage2_llvm, .stage2_x86_64 => true, 963 else => false, 964 }, 965 .is_named_enum_value => switch (backend) { 966 .stage2_llvm, .stage2_x86_64, .stage2_wasm => true, 967 else => false, 968 }, 969 .error_set_has_value => switch (backend) { 970 .stage2_llvm, .stage2_wasm, .stage2_x86_64 => true, 971 else => false, 972 }, 973 .field_reordering => switch (backend) { 974 .stage2_aarch64, .stage2_c, .stage2_llvm, .stage2_loongarch, .stage2_x86_64, .stage2_wasm => true, 975 else => false, 976 }, 977 .separate_thread => switch (backend) { 978 // Supports a separate thread but does not support N separate 979 // threads because they would all just be locking the same mutex to 980 // protect Builder. 981 .stage2_llvm => false, 982 // Please do not make any more exceptions. Backends must support 983 // being run in a separate thread from now on. 984 else => true, 985 }, 986 }; 987 } 988