1const std = @import("std"); 2const llvm = @import("codegen/llvm/bindings.zig"); 3 4pub const ArchOsAbi = struct { 5 arch: std.Target.Cpu.Arch, 6 os: std.Target.Os.Tag, 7 abi: std.Target.Abi, 8 os_ver: ?std.builtin.Version = null, 9}; 10 11pub const available_libcs = [_]ArchOsAbi{ 12 .{ .arch = .aarch64_be, .os = .linux, .abi = .gnu }, 13 .{ .arch = .aarch64_be, .os = .linux, .abi = .musl }, 14 .{ .arch = .aarch64_be, .os = .windows, .abi = .gnu }, 15 .{ .arch = .aarch64, .os = .linux, .abi = .gnu }, 16 .{ .arch = .aarch64, .os = .linux, .abi = .musl }, 17 .{ .arch = .aarch64, .os = .windows, .abi = .gnu }, 18 .{ .arch = .aarch64, .os = .macos, .abi = .gnu, .os_ver = .{ .major = 11, .minor = 0 } }, 19 .{ .arch = .aarch64, .os = .macos, .abi = .gnu, .os_ver = .{ .major = 12, .minor = 0 } }, 20 .{ .arch = .armeb, .os = .linux, .abi = .gnueabi }, 21 .{ .arch = .armeb, .os = .linux, .abi = .gnueabihf }, 22 .{ .arch = .armeb, .os = .linux, .abi = .musleabi }, 23 .{ .arch = .armeb, .os = .linux, .abi = .musleabihf }, 24 .{ .arch = .armeb, .os = .windows, .abi = .gnu }, 25 .{ .arch = .arm, .os = .linux, .abi = .gnueabi }, 26 .{ .arch = .arm, .os = .linux, .abi = .gnueabihf }, 27 .{ .arch = .arm, .os = .linux, .abi = .musleabi }, 28 .{ .arch = .arm, .os = .linux, .abi = .musleabihf }, 29 .{ .arch = .thumb, .os = .linux, .abi = .gnueabi }, 30 .{ .arch = .thumb, .os = .linux, .abi = .gnueabihf }, 31 .{ .arch = .thumb, .os = .linux, .abi = .musleabi }, 32 .{ .arch = .thumb, .os = .linux, .abi = .musleabihf }, 33 .{ .arch = .arm, .os = .windows, .abi = .gnu }, 34 .{ .arch = .csky, .os = .linux, .abi = .gnueabi }, 35 .{ .arch = .csky, .os = .linux, .abi = .gnueabihf }, 36 .{ .arch = .i386, .os = .linux, .abi = .gnu }, 37 .{ .arch = .i386, .os = .linux, .abi = .musl }, 38 .{ .arch = .i386, .os = .windows, .abi = .gnu }, 39 .{ .arch = .m68k, .os = .linux, .abi = .gnu }, 40 .{ .arch = .m68k, .os = .linux, .abi = .musl }, 41 .{ .arch = .mips64el, .os = .linux, .abi = .gnuabi64 }, 42 .{ .arch = .mips64el, .os = .linux, .abi = .gnuabin32 }, 43 .{ .arch = .mips64el, .os = .linux, .abi = .musl }, 44 .{ .arch = .mips64, .os = .linux, .abi = .gnuabi64 }, 45 .{ .arch = .mips64, .os = .linux, .abi = .gnuabin32 }, 46 .{ .arch = .mips64, .os = .linux, .abi = .musl }, 47 .{ .arch = .mipsel, .os = .linux, .abi = .gnueabi }, 48 .{ .arch = .mipsel, .os = .linux, .abi = .gnueabihf }, 49 .{ .arch = .mipsel, .os = .linux, .abi = .musl }, 50 .{ .arch = .mips, .os = .linux, .abi = .gnueabi }, 51 .{ .arch = .mips, .os = .linux, .abi = .gnueabihf }, 52 .{ .arch = .mips, .os = .linux, .abi = .musl }, 53 .{ .arch = .powerpc64le, .os = .linux, .abi = .gnu }, 54 .{ .arch = .powerpc64le, .os = .linux, .abi = .musl }, 55 .{ .arch = .powerpc64, .os = .linux, .abi = .gnu }, 56 .{ .arch = .powerpc64, .os = .linux, .abi = .musl }, 57 .{ .arch = .powerpc, .os = .linux, .abi = .gnueabi }, 58 .{ .arch = .powerpc, .os = .linux, .abi = .gnueabihf }, 59 .{ .arch = .powerpc, .os = .linux, .abi = .musl }, 60 .{ .arch = .riscv64, .os = .linux, .abi = .gnu }, 61 .{ .arch = .riscv64, .os = .linux, .abi = .musl }, 62 .{ .arch = .s390x, .os = .linux, .abi = .gnu }, 63 .{ .arch = .s390x, .os = .linux, .abi = .musl }, 64 .{ .arch = .sparc, .os = .linux, .abi = .gnu }, 65 .{ .arch = .sparcv9, .os = .linux, .abi = .gnu }, 66 .{ .arch = .wasm32, .os = .freestanding, .abi = .musl }, 67 .{ .arch = .wasm32, .os = .wasi, .abi = .musl }, 68 .{ .arch = .x86_64, .os = .linux, .abi = .gnu }, 69 .{ .arch = .x86_64, .os = .linux, .abi = .gnux32 }, 70 .{ .arch = .x86_64, .os = .linux, .abi = .musl }, 71 .{ .arch = .x86_64, .os = .windows, .abi = .gnu }, 72 .{ .arch = .x86_64, .os = .macos, .abi = .gnu, .os_ver = .{ .major = 10, .minor = 0 } }, 73 .{ .arch = .x86_64, .os = .macos, .abi = .gnu, .os_ver = .{ .major = 11, .minor = 0 } }, 74 .{ .arch = .x86_64, .os = .macos, .abi = .gnu, .os_ver = .{ .major = 12, .minor = 0 } }, 75}; 76 77pub fn libCGenericName(target: std.Target) [:0]const u8 { 78 switch (target.os.tag) { 79 .windows => return "mingw", 80 .macos, .ios, .tvos, .watchos => return "darwin", 81 else => {}, 82 } 83 switch (target.abi) { 84 .gnu, 85 .gnuabin32, 86 .gnuabi64, 87 .gnueabi, 88 .gnueabihf, 89 .gnux32, 90 .gnuilp32, 91 => return "glibc", 92 .musl, 93 .musleabi, 94 .musleabihf, 95 .muslx32, 96 .none, 97 => return "musl", 98 .code16, 99 .eabi, 100 .eabihf, 101 .android, 102 .msvc, 103 .itanium, 104 .cygnus, 105 .coreclr, 106 .simulator, 107 .macabi, 108 => unreachable, 109 } 110} 111 112pub fn osArchName(target: std.Target) [:0]const u8 { 113 return switch (target.os.tag) { 114 .linux => switch (target.cpu.arch) { 115 .arm, .armeb, .thumb, .thumbeb => "arm", 116 .aarch64, .aarch64_be, .aarch64_32 => "arm64", 117 .mips, .mipsel, .mips64, .mips64el => "mips", 118 .powerpc, .powerpcle, .powerpc64, .powerpc64le => "powerpc", 119 .riscv32, .riscv64 => "riscv", 120 .sparc, .sparcel, .sparcv9 => "sparc", 121 .i386, .x86_64 => "x86", 122 else => @tagName(target.cpu.arch), 123 }, 124 else => @tagName(target.cpu.arch), 125 }; 126} 127 128pub fn canBuildLibC(target: std.Target) bool { 129 for (available_libcs) |libc| { 130 if (target.cpu.arch == libc.arch and target.os.tag == libc.os and target.abi == libc.abi) { 131 if (target.os.tag == .macos) { 132 const ver = target.os.version_range.semver; 133 if (ver.min.major != libc.os_ver.?.major) continue; // no match, keep going 134 } 135 return true; 136 } 137 } 138 return false; 139} 140 141pub fn cannotDynamicLink(target: std.Target) bool { 142 return switch (target.os.tag) { 143 .freestanding, .other => true, 144 else => false, 145 }; 146} 147 148/// On Darwin, we always link libSystem which contains libc. 149/// Similarly on FreeBSD and NetBSD we always link system libc 150/// since this is the stable syscall interface. 151pub fn osRequiresLibC(target: std.Target) bool { 152 return target.os.requiresLibC(); 153} 154 155pub fn libcNeedsLibUnwind(target: std.Target) bool { 156 return switch (target.os.tag) { 157 .macos, 158 .ios, 159 .watchos, 160 .tvos, 161 .freestanding, 162 .wasi, // Wasm/WASI currently doesn't offer support for libunwind, so don't link it. 163 => false, 164 165 .windows => target.abi != .msvc, 166 else => true, 167 }; 168} 169 170pub fn requiresPIE(target: std.Target) bool { 171 return target.isAndroid() or target.isDarwin() or target.os.tag == .openbsd; 172} 173 174/// This function returns whether non-pic code is completely invalid on the given target. 175pub fn requiresPIC(target: std.Target, linking_libc: bool) bool { 176 return target.isAndroid() or 177 target.os.tag == .windows or target.os.tag == .uefi or 178 osRequiresLibC(target) or 179 (linking_libc and target.isGnuLibC()); 180} 181 182/// This is not whether the target supports Position Independent Code, but whether the -fPIC 183/// C compiler argument is valid to Clang. 184pub fn supports_fpic(target: std.Target) bool { 185 return target.os.tag != .windows; 186} 187 188pub fn isSingleThreaded(target: std.Target) bool { 189 return target.isWasm(); 190} 191 192/// Valgrind supports more, but Zig does not support them yet. 193pub fn hasValgrindSupport(target: std.Target) bool { 194 switch (target.cpu.arch) { 195 .x86_64 => { 196 return target.os.tag == .linux or target.os.tag == .solaris or 197 (target.os.tag == .windows and target.abi != .msvc); 198 }, 199 else => return false, 200 } 201} 202 203/// The set of targets that LLVM has non-experimental support for. 204/// Used to select between LLVM backend and self-hosted backend when compiling in 205/// release modes. 206pub fn hasLlvmSupport(target: std.Target) bool { 207 return switch (target.cpu.arch) { 208 .arm, 209 .armeb, 210 .aarch64, 211 .aarch64_be, 212 .aarch64_32, 213 .arc, 214 .avr, 215 .bpfel, 216 .bpfeb, 217 .csky, 218 .hexagon, 219 .m68k, 220 .mips, 221 .mipsel, 222 .mips64, 223 .mips64el, 224 .msp430, 225 .powerpc, 226 .powerpcle, 227 .powerpc64, 228 .powerpc64le, 229 .r600, 230 .amdgcn, 231 .riscv32, 232 .riscv64, 233 .sparc, 234 .sparcv9, 235 .sparcel, 236 .s390x, 237 .tce, 238 .tcele, 239 .thumb, 240 .thumbeb, 241 .i386, 242 .x86_64, 243 .xcore, 244 .nvptx, 245 .nvptx64, 246 .le32, 247 .le64, 248 .amdil, 249 .amdil64, 250 .hsail, 251 .hsail64, 252 .spir, 253 .spir64, 254 .kalimba, 255 .shave, 256 .lanai, 257 .wasm32, 258 .wasm64, 259 .renderscript32, 260 .renderscript64, 261 .ve, 262 => true, 263 264 .spu_2, 265 .spirv32, 266 .spirv64, 267 => false, 268 }; 269} 270 271pub fn supportsStackProbing(target: std.Target) bool { 272 return target.os.tag != .windows and target.os.tag != .uefi and 273 (target.cpu.arch == .i386 or target.cpu.arch == .x86_64); 274} 275 276pub fn osToLLVM(os_tag: std.Target.Os.Tag) llvm.OSType { 277 return switch (os_tag) { 278 .freestanding, .other, .opencl, .glsl450, .vulkan, .plan9 => .UnknownOS, 279 .windows, .uefi => .Win32, 280 .ananas => .Ananas, 281 .cloudabi => .CloudABI, 282 .dragonfly => .DragonFly, 283 .freebsd => .FreeBSD, 284 .fuchsia => .Fuchsia, 285 .ios => .IOS, 286 .kfreebsd => .KFreeBSD, 287 .linux => .Linux, 288 .lv2 => .Lv2, 289 .macos => .MacOSX, 290 .netbsd => .NetBSD, 291 .openbsd => .OpenBSD, 292 .solaris => .Solaris, 293 .zos => .ZOS, 294 .haiku => .Haiku, 295 .minix => .Minix, 296 .rtems => .RTEMS, 297 .nacl => .NaCl, 298 .aix => .AIX, 299 .cuda => .CUDA, 300 .nvcl => .NVCL, 301 .amdhsa => .AMDHSA, 302 .ps4 => .PS4, 303 .elfiamcu => .ELFIAMCU, 304 .tvos => .TvOS, 305 .watchos => .WatchOS, 306 .mesa3d => .Mesa3D, 307 .contiki => .Contiki, 308 .amdpal => .AMDPAL, 309 .hermit => .HermitCore, 310 .hurd => .Hurd, 311 .wasi => .WASI, 312 .emscripten => .Emscripten, 313 }; 314} 315 316pub fn archToLLVM(arch_tag: std.Target.Cpu.Arch) llvm.ArchType { 317 return switch (arch_tag) { 318 .arm => .arm, 319 .armeb => .armeb, 320 .aarch64 => .aarch64, 321 .aarch64_be => .aarch64_be, 322 .aarch64_32 => .aarch64_32, 323 .arc => .arc, 324 .avr => .avr, 325 .bpfel => .bpfel, 326 .bpfeb => .bpfeb, 327 .csky => .csky, 328 .hexagon => .hexagon, 329 .m68k => .m68k, 330 .mips => .mips, 331 .mipsel => .mipsel, 332 .mips64 => .mips64, 333 .mips64el => .mips64el, 334 .msp430 => .msp430, 335 .powerpc => .ppc, 336 .powerpcle => .ppcle, 337 .powerpc64 => .ppc64, 338 .powerpc64le => .ppc64le, 339 .r600 => .r600, 340 .amdgcn => .amdgcn, 341 .riscv32 => .riscv32, 342 .riscv64 => .riscv64, 343 .sparc => .sparc, 344 .sparcv9 => .sparcv9, 345 .sparcel => .sparcel, 346 .s390x => .systemz, 347 .tce => .tce, 348 .tcele => .tcele, 349 .thumb => .thumb, 350 .thumbeb => .thumbeb, 351 .i386 => .x86, 352 .x86_64 => .x86_64, 353 .xcore => .xcore, 354 .nvptx => .nvptx, 355 .nvptx64 => .nvptx64, 356 .le32 => .le32, 357 .le64 => .le64, 358 .amdil => .amdil, 359 .amdil64 => .amdil64, 360 .hsail => .hsail, 361 .hsail64 => .hsail64, 362 .spir => .spir, 363 .spir64 => .spir64, 364 .kalimba => .kalimba, 365 .shave => .shave, 366 .lanai => .lanai, 367 .wasm32 => .wasm32, 368 .wasm64 => .wasm64, 369 .renderscript32 => .renderscript32, 370 .renderscript64 => .renderscript64, 371 .ve => .ve, 372 .spu_2, .spirv32, .spirv64 => .UnknownArch, 373 }; 374} 375 376fn eqlIgnoreCase(ignore_case: bool, a: []const u8, b: []const u8) bool { 377 if (ignore_case) { 378 return std.ascii.eqlIgnoreCase(a, b); 379 } else { 380 return std.mem.eql(u8, a, b); 381 } 382} 383 384pub fn is_libc_lib_name(target: std.Target, name: []const u8) bool { 385 const ignore_case = target.os.tag.isDarwin() or target.os.tag == .windows; 386 387 if (eqlIgnoreCase(ignore_case, name, "c")) 388 return true; 389 390 if (target.isMinGW()) { 391 if (eqlIgnoreCase(ignore_case, name, "m")) 392 return true; 393 394 return false; 395 } 396 397 if (target.abi.isGnu() or target.abi.isMusl() or target.os.tag.isDarwin()) { 398 if (eqlIgnoreCase(ignore_case, name, "m")) 399 return true; 400 if (eqlIgnoreCase(ignore_case, name, "rt")) 401 return true; 402 if (eqlIgnoreCase(ignore_case, name, "pthread")) 403 return true; 404 if (eqlIgnoreCase(ignore_case, name, "crypt")) 405 return true; 406 if (eqlIgnoreCase(ignore_case, name, "util")) 407 return true; 408 if (eqlIgnoreCase(ignore_case, name, "xnet")) 409 return true; 410 if (eqlIgnoreCase(ignore_case, name, "resolv")) 411 return true; 412 if (eqlIgnoreCase(ignore_case, name, "dl")) 413 return true; 414 } 415 416 if (target.os.tag.isDarwin() and eqlIgnoreCase(ignore_case, name, "System")) 417 return true; 418 419 return false; 420} 421 422pub fn is_libcpp_lib_name(target: std.Target, name: []const u8) bool { 423 const ignore_case = target.os.tag.isDarwin() or target.os.tag == .windows; 424 425 return eqlIgnoreCase(ignore_case, name, "c++") or 426 eqlIgnoreCase(ignore_case, name, "stdc++") or 427 eqlIgnoreCase(ignore_case, name, "c++abi"); 428} 429 430pub fn hasDebugInfo(target: std.Target) bool { 431 return !target.cpu.arch.isWasm(); 432} 433 434pub fn defaultCompilerRtOptimizeMode(target: std.Target) std.builtin.Mode { 435 if (target.cpu.arch.isWasm() and target.os.tag == .freestanding) { 436 return .ReleaseSmall; 437 } else { 438 return .ReleaseFast; 439 } 440} 441 442pub fn hasRedZone(target: std.Target) bool { 443 return switch (target.cpu.arch) { 444 .x86_64, 445 .i386, 446 .powerpc, 447 .powerpc64, 448 .powerpc64le, 449 .aarch64, 450 .aarch64_be, 451 .aarch64_32, 452 => true, 453 454 else => false, 455 }; 456} 457 458pub fn libcFullLinkFlags(target: std.Target) []const []const u8 { 459 // The linking order of these is significant and should match the order other 460 // c compilers such as gcc or clang use. 461 return switch (target.os.tag) { 462 .netbsd, .openbsd => &[_][]const u8{ 463 "-lm", 464 "-lpthread", 465 "-lc", 466 "-lutil", 467 }, 468 .solaris => &[_][]const u8{ 469 "-lm", 470 "-lsocket", 471 "-lnsl", 472 // Solaris releases after 10 merged the threading libraries into libc. 473 "-lc", 474 }, 475 .haiku => &[_][]const u8{ 476 "-lm", 477 "-lroot", 478 "-lpthread", 479 "-lc", 480 }, 481 else => switch (target.abi) { 482 .android => &[_][]const u8{ 483 "-lm", 484 "-lc", 485 "-ldl", 486 }, 487 else => &[_][]const u8{ 488 "-lm", 489 "-lpthread", 490 "-lc", 491 "-ldl", 492 "-lrt", 493 "-lutil", 494 }, 495 }, 496 }; 497} 498 499pub fn clangMightShellOutForAssembly(target: std.Target) bool { 500 // Clang defaults to using the system assembler over the internal one 501 // when targeting a non-BSD OS. 502 return target.cpu.arch.isSPARC(); 503} 504 505/// Each backend architecture in Clang has a different codepath which may or may not 506/// support an -mcpu flag. 507pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool { 508 return switch (target.cpu.arch) { 509 .arm, .armeb, .thumb, .thumbeb => true, 510 else => false, 511 }; 512} 513 514pub fn needUnwindTables(target: std.Target) bool { 515 return target.os.tag == .windows; 516} 517 518/// TODO this was ported from stage1 but it does not take into account CPU features, 519/// which can affect this value. Audit this! 520pub fn largestAtomicBits(target: std.Target) u32 { 521 return switch (target.cpu.arch) { 522 .avr, 523 .msp430, 524 .spu_2, 525 => 16, 526 527 .arc, 528 .arm, 529 .armeb, 530 .hexagon, 531 .m68k, 532 .le32, 533 .mips, 534 .mipsel, 535 .nvptx, 536 .powerpc, 537 .powerpcle, 538 .r600, 539 .riscv32, 540 .sparc, 541 .sparcel, 542 .tce, 543 .tcele, 544 .thumb, 545 .thumbeb, 546 .i386, 547 .xcore, 548 .amdil, 549 .hsail, 550 .spir, 551 .kalimba, 552 .lanai, 553 .shave, 554 .wasm32, 555 .renderscript32, 556 .csky, 557 .spirv32, 558 => 32, 559 560 .aarch64, 561 .aarch64_be, 562 .aarch64_32, 563 .amdgcn, 564 .bpfel, 565 .bpfeb, 566 .le64, 567 .mips64, 568 .mips64el, 569 .nvptx64, 570 .powerpc64, 571 .powerpc64le, 572 .riscv64, 573 .sparcv9, 574 .s390x, 575 .amdil64, 576 .hsail64, 577 .spir64, 578 .wasm64, 579 .renderscript64, 580 .ve, 581 .spirv64, 582 => 64, 583 584 .x86_64 => 128, 585 }; 586} 587 588pub fn defaultAddressSpace( 589 target: std.Target, 590 context: enum { 591 /// Query the default address space for global constant values. 592 global_constant, 593 /// Query the default address space for global mutable values. 594 global_mutable, 595 /// Query the default address space for function-local values. 596 local, 597 /// Query the default address space for functions themselves. 598 function, 599 }, 600) std.builtin.AddressSpace { 601 _ = target; 602 _ = context; 603 return .generic; 604} 605 606pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 { 607 const have_float = switch (target.abi) { 608 .gnuilp32 => return "ilp32", 609 .gnueabihf, .musleabihf, .eabihf => true, 610 else => false, 611 }; 612 613 switch (target.cpu.arch) { 614 .riscv64 => { 615 const featureSetHas = std.Target.riscv.featureSetHas; 616 if (featureSetHas(target.cpu.features, .d)) { 617 return "lp64d"; 618 } else if (have_float) { 619 return "lp64f"; 620 } else { 621 return "lp64"; 622 } 623 }, 624 .riscv32 => { 625 const featureSetHas = std.Target.riscv.featureSetHas; 626 if (featureSetHas(target.cpu.features, .d)) { 627 return "ilp32d"; 628 } else if (have_float) { 629 return "ilp32f"; 630 } else if (featureSetHas(target.cpu.features, .e)) { 631 return "ilp32e"; 632 } else { 633 return "ilp32"; 634 } 635 }, 636 //TODO add ARM, Mips, and PowerPC 637 else => return null, 638 } 639} 640