cpu: Cpu,
os: Os,
abi: Abi,
ofmt: ObjectFormat,
dynamic_linker: DynamicLinker = DynamicLinker.none,
pub const Query = @import("Target/Query.zig");
pub const Os = struct {
tag: Tag,
version_range: VersionRange,
pub const Tag = enum {
freestanding,
ananas,
cloudabi,
dragonfly,
freebsd,
fuchsia,
ios,
kfreebsd,
linux,
lv2,
macos,
netbsd,
openbsd,
solaris,
uefi,
windows,
zos,
haiku,
minix,
rtems,
nacl,
aix,
cuda,
nvcl,
amdhsa,
ps4,
ps5,
elfiamcu,
tvos,
watchos,
driverkit,
mesa3d,
contiki,
amdpal,
hermit,
hurd,
wasi,
emscripten,
shadermodel,
liteos,
opencl,
glsl450,
vulkan,
plan9,
illumos,
other,
pub inline fn isDarwin(tag: Tag) bool {
return switch (tag) {
.ios, .macos, .watchos, .tvos => true,
else => false,
};
}
pub inline fn isBSD(tag: Tag) bool {
return tag.isDarwin() or switch (tag) {
.kfreebsd, .freebsd, .openbsd, .netbsd, .dragonfly => true,
else => false,
};
}
pub inline fn isSolarish(tag: Tag) bool {
return tag == .solaris or tag == .illumos;
}
pub fn dynamicLibSuffix(tag: Tag) [:0]const u8 {
if (tag.isDarwin()) {
return ".dylib";
}
switch (tag) {
.windows => return ".dll",
else => return ".so",
}
}
pub fn defaultVersionRange(tag: Tag, arch: Cpu.Arch) Os {
return .{
.tag = tag,
.version_range = VersionRange.default(tag, arch),
};
}
};
pub const WindowsVersion = enum(u32) {
nt4 = 0x04000000,
win2k = 0x05000000,
xp = 0x05010000,
ws2003 = 0x05020000,
vista = 0x06000000,
win7 = 0x06010000,
win8 = 0x06020000,
win8_1 = 0x06030000,
win10 = 0x0A000000,
win10_th2 = 0x0A000001,
win10_rs1 = 0x0A000002,
win10_rs2 = 0x0A000003,
win10_rs3 = 0x0A000004,
win10_rs4 = 0x0A000005,
win10_rs5 = 0x0A000006,
win10_19h1 = 0x0A000007,
win10_vb = 0x0A000008,
win10_mn = 0x0A000009,
win10_fe = 0x0A00000A,
_,
pub const latest = WindowsVersion.win10_fe;
pub const known_win10_build_numbers = [_]u32{
10240,
10586,
14393,
15063,
16299,
17134,
17763,
18362,
18363,
19041,
19042,
};
pub inline fn isAtLeast(self: WindowsVersion, ver: WindowsVersion) bool {
return @intFromEnum(self) >= @intFromEnum(ver);
}
pub const Range = struct {
min: WindowsVersion,
max: WindowsVersion,
pub inline fn includesVersion(self: Range, ver: WindowsVersion) bool {
return @intFromEnum(ver) >= @intFromEnum(self.min) and @intFromEnum(ver) <= @intFromEnum(self.max);
}
pub inline fn isAtLeast(self: Range, ver: WindowsVersion) ?bool {
if (@intFromEnum(self.min) >= @intFromEnum(ver)) return true;
if (@intFromEnum(self.max) < @intFromEnum(ver)) return false;
return null;
}
};
pub fn format(
self: WindowsVersion,
comptime fmt: []const u8,
_: std.fmt.FormatOptions,
out_stream: anytype,
) !void {
if (comptime std.mem.eql(u8, fmt, "s")) {
if (@intFromEnum(self) >= @intFromEnum(WindowsVersion.nt4) and @intFromEnum(self) <= @intFromEnum(WindowsVersion.latest)) {
try std.fmt.format(out_stream, ".{s}", .{@tagName(self)});
} else {
try std.fmt.format(out_stream, "@enumFromInt(Target.Os.WindowsVersion, 0x{X:0>8})", .{@intFromEnum(self)});
}
} else if (fmt.len == 0) {
if (@intFromEnum(self) >= @intFromEnum(WindowsVersion.nt4) and @intFromEnum(self) <= @intFromEnum(WindowsVersion.latest)) {
try std.fmt.format(out_stream, "WindowsVersion.{s}", .{@tagName(self)});
} else {
try std.fmt.format(out_stream, "WindowsVersion(0x{X:0>8})", .{@intFromEnum(self)});
}
} else {
std.fmt.invalidFmtError(fmt, self);
}
}
};
pub const LinuxVersionRange = struct {
range: std.SemanticVersion.Range,
glibc: std.SemanticVersion,
pub inline fn includesVersion(self: LinuxVersionRange, ver: std.SemanticVersion) bool {
return self.range.includesVersion(ver);
}
pub inline fn isAtLeast(self: LinuxVersionRange, ver: std.SemanticVersion) ?bool {
return self.range.isAtLeast(ver);
}
};
pub const VersionRange = union {
none: void,
semver: std.SemanticVersion.Range,
linux: LinuxVersionRange,
windows: WindowsVersion.Range,
pub fn default(tag: Tag, arch: Cpu.Arch) VersionRange {
switch (tag) {
.freestanding,
.ananas,
.cloudabi,
.fuchsia,
.kfreebsd,
.lv2,
.zos,
.haiku,
.minix,
.rtems,
.nacl,
.aix,
.cuda,
.nvcl,
.amdhsa,
.ps4,
.ps5,
.elfiamcu,
.mesa3d,
.contiki,
.amdpal,
.hermit,
.hurd,
.wasi,
.emscripten,
.driverkit,
.shadermodel,
.liteos,
.uefi,
.opencl,
.glsl450,
.vulkan,
.plan9,
.illumos,
.other,
=> return .{ .none = {} },
.freebsd => return .{
.semver = std.SemanticVersion.Range{
.min = .{ .major = 12, .minor = 0, .patch = 0 },
.max = .{ .major = 14, .minor = 0, .patch = 0 },
},
},
.macos => return switch (arch) {
.aarch64 => VersionRange{
.semver = .{
.min = .{ .major = 11, .minor = 7, .patch = 1 },
.max = .{ .major = 14, .minor = 1, .patch = 0 },
},
},
.x86_64 => VersionRange{
.semver = .{
.min = .{ .major = 11, .minor = 7, .patch = 1 },
.max = .{ .major = 14, .minor = 1, .patch = 0 },
},
},
else => unreachable,
},
.ios => return .{
.semver = .{
.min = .{ .major = 12, .minor = 0, .patch = 0 },
.max = .{ .major = 17, .minor = 1, .patch = 0 },
},
},
.watchos => return .{
.semver = .{
.min = .{ .major = 6, .minor = 0, .patch = 0 },
.max = .{ .major = 10, .minor = 1, .patch = 0 },
},
},
.tvos => return .{
.semver = .{
.min = .{ .major = 13, .minor = 0, .patch = 0 },
.max = .{ .major = 17, .minor = 1, .patch = 0 },
},
},
.netbsd => return .{
.semver = .{
.min = .{ .major = 8, .minor = 0, .patch = 0 },
.max = .{ .major = 10, .minor = 0, .patch = 0 },
},
},
.openbsd => return .{
.semver = .{
.min = .{ .major = 6, .minor = 8, .patch = 0 },
.max = .{ .major = 7, .minor = 4, .patch = 0 },
},
},
.dragonfly => return .{
.semver = .{
.min = .{ .major = 5, .minor = 8, .patch = 0 },
.max = .{ .major = 6, .minor = 4, .patch = 0 },
},
},
.solaris => return .{
.semver = .{
.min = .{ .major = 5, .minor = 11, .patch = 0 },
.max = .{ .major = 5, .minor = 11, .patch = 0 },
},
},
.linux => return .{
.linux = .{
.range = .{
.min = .{ .major = 4, .minor = 19, .patch = 0 },
.max = .{ .major = 6, .minor = 5, .patch = 7 },
},
.glibc = .{ .major = 2, .minor = 28, .patch = 0 },
},
},
.windows => return .{
.windows = .{
.min = .win8_1,
.max = WindowsVersion.latest,
},
},
}
}
};
pub const TaggedVersionRange = union(enum) {
none: void,
semver: std.SemanticVersion.Range,
linux: LinuxVersionRange,
windows: WindowsVersion.Range,
};
pub inline fn getVersionRange(self: Os) TaggedVersionRange {
switch (self.tag) {
.linux => return TaggedVersionRange{ .linux = self.version_range.linux },
.windows => return TaggedVersionRange{ .windows = self.version_range.windows },
.freebsd,
.macos,
.ios,
.tvos,
.watchos,
.netbsd,
.openbsd,
.dragonfly,
.solaris,
=> return TaggedVersionRange{ .semver = self.version_range.semver },
else => return .none,
}
}
pub inline fn isAtLeast(self: Os, comptime tag: Tag, version: switch (tag) {
else => std.SemanticVersion,
.windows => WindowsVersion,
}) ?bool {
if (self.tag != tag) return false;
return switch (tag) {
.linux => self.version_range.linux.isAtLeast(version),
.windows => self.version_range.windows.isAtLeast(version),
else => self.version_range.semver.isAtLeast(version),
};
}
pub fn requiresLibC(os: Os) bool {
return switch (os.tag) {
.freebsd,
.netbsd,
.macos,
.ios,
.tvos,
.watchos,
.dragonfly,
.openbsd,
.haiku,
.solaris,
.illumos,
=> true,
.linux,
.windows,
.freestanding,
.ananas,
.cloudabi,
.fuchsia,
.kfreebsd,
.lv2,
.zos,
.minix,
.rtems,
.nacl,
.aix,
.cuda,
.nvcl,
.amdhsa,
.ps4,
.ps5,
.elfiamcu,
.mesa3d,
.contiki,
.amdpal,
.hermit,
.hurd,
.wasi,
.emscripten,
.driverkit,
.shadermodel,
.liteos,
.uefi,
.opencl,
.glsl450,
.vulkan,
.plan9,
.other,
=> false,
};
}
};
pub const aarch64 = @import("Target/aarch64.zig");
pub const arc = @import("Target/arc.zig");
pub const amdgpu = @import("Target/amdgpu.zig");
pub const arm = @import("Target/arm.zig");
pub const avr = @import("Target/avr.zig");
pub const bpf = @import("Target/bpf.zig");
pub const csky = @import("Target/csky.zig");
pub const hexagon = @import("Target/hexagon.zig");
pub const loongarch = @import("Target/loongarch.zig");
pub const m68k = @import("Target/m68k.zig");
pub const mips = @import("Target/mips.zig");
pub const msp430 = @import("Target/msp430.zig");
pub const nvptx = @import("Target/nvptx.zig");
pub const powerpc = @import("Target/powerpc.zig");
pub const riscv = @import("Target/riscv.zig");
pub const sparc = @import("Target/sparc.zig");
pub const spirv = @import("Target/spirv.zig");
pub const s390x = @import("Target/s390x.zig");
pub const ve = @import("Target/ve.zig");
pub const wasm = @import("Target/wasm.zig");
pub const x86 = @import("Target/x86.zig");
pub const xtensa = @import("Target/xtensa.zig");
pub const Abi = enum {
none,
gnu,
gnuabin32,
gnuabi64,
gnueabi,
gnueabihf,
gnuf32,
gnuf64,
gnusf,
gnux32,
gnuilp32,
code16,
eabi,
eabihf,
android,
musl,
musleabi,
musleabihf,
muslx32,
msvc,
itanium,
cygnus,
coreclr,
simulator,
macabi,
pixel,
vertex,
geometry,
hull,
domain,
compute,
library,
raygeneration,
intersection,
anyhit,
closesthit,
miss,
callable,
mesh,
amplification,
pub fn default(arch: Cpu.Arch, target_os: Os) Abi {
if (arch.isWasm()) {
return .musl;
}
switch (target_os.tag) {
.freestanding,
.ananas,
.cloudabi,
.dragonfly,
.lv2,
.zos,
.minix,
.rtems,
.nacl,
.aix,
.cuda,
.nvcl,
.amdhsa,
.ps4,
.ps5,
.elfiamcu,
.mesa3d,
.contiki,
.amdpal,
.hermit,
.other,
=> return .eabi,
.openbsd,
.freebsd,
.fuchsia,
.kfreebsd,
.netbsd,
.hurd,
.haiku,
.windows,
=> return .gnu,
.uefi => return .msvc,
.linux,
.wasi,
.emscripten,
=> return .musl,
.opencl,
.glsl450,
.vulkan,
.plan9,
.macos,
.ios,
.tvos,
.watchos,
.driverkit,
.shadermodel,
.liteos,
.solaris,
.illumos,
=> return .none,
}
}
pub inline fn isGnu(abi: Abi) bool {
return switch (abi) {
.gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true,
else => false,
};
}
pub inline fn isMusl(abi: Abi) bool {
return switch (abi) {
.musl, .musleabi, .musleabihf => true,
else => false,
};
}
pub inline fn floatAbi(abi: Abi) FloatAbi {
return switch (abi) {
.gnueabihf,
.eabihf,
.musleabihf,
=> .hard,
else => .soft,
};
}
};
pub const ObjectFormat = enum {
coff,
dxcontainer,
elf,
macho,
spirv,
wasm,
c,
hex,
raw,
plan9,
nvptx,
pub fn fileExt(of: ObjectFormat, cpu_arch: Cpu.Arch) [:0]const u8 {
return switch (of) {
.coff => ".obj",
.elf, .macho, .wasm => ".o",
.c => ".c",
.spirv => ".spv",
.hex => ".ihex",
.raw => ".bin",
.plan9 => plan9Ext(cpu_arch),
.nvptx => ".ptx",
.dxcontainer => ".dxil",
};
}
pub fn default(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {
return switch (os_tag) {
.windows, .uefi => .coff,
.ios, .macos, .watchos, .tvos => .macho,
.plan9 => .plan9,
else => return switch (cpu_arch) {
.wasm32, .wasm64 => .wasm,
.spirv32, .spirv64 => .spirv,
.nvptx, .nvptx64 => .nvptx,
else => .elf,
},
};
}
};
pub const SubSystem = enum {
Console,
Windows,
Posix,
Native,
EfiApplication,
EfiBootServiceDriver,
EfiRom,
EfiRuntimeDriver,
};
pub const Cpu = struct {
arch: Arch,
model: *const Model,
features: Feature.Set,
pub const Feature = struct {
index: Set.Index = undefined,
name: []const u8 = undefined,
llvm_name: ?[:0]const u8,
description: []const u8,
dependencies: Set,
pub const Set = struct {
ints: [usize_count]usize,
pub const needed_bit_count = 288;
pub const byte_count = (needed_bit_count + 7) / 8;
pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize);
pub const Index = std.math.Log2Int(std.meta.Int(.unsigned, usize_count * @bitSizeOf(usize)));
pub const ShiftInt = std.math.Log2Int(usize);
pub const empty = Set{ .ints = [1]usize{0} ** usize_count };
pub fn isEmpty(set: Set) bool {
return for (set.ints) |x| {
if (x != 0) break false;
} else true;
}
pub fn isEnabled(set: Set, arch_feature_index: Index) bool {
const usize_index = arch_feature_index / @bitSizeOf(usize);
const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize)));
return (set.ints[usize_index] & (@as(usize, 1) << bit_index)) != 0;
}
pub fn addFeature(set: *Set, arch_feature_index: Index) void {
const usize_index = arch_feature_index / @bitSizeOf(usize);
const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize)));
set.ints[usize_index] |= @as(usize, 1) << bit_index;
}
pub fn addFeatureSet(set: *Set, other_set: Set) void {
switch (builtin.zig_backend) {
.stage2_x86_64 => {
for (&set.ints, other_set.ints) |*set_int, other_set_int| set_int.* |= other_set_int;
},
else => {
set.ints = @as(@Vector(usize_count, usize), set.ints) | @as(@Vector(usize_count, usize), other_set.ints);
},
}
}
pub fn removeFeature(set: *Set, arch_feature_index: Index) void {
const usize_index = arch_feature_index / @bitSizeOf(usize);
const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize)));
set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);
}
pub fn removeFeatureSet(set: *Set, other_set: Set) void {
switch (builtin.zig_backend) {
.stage2_x86_64 => {
for (&set.ints, other_set.ints) |*set_int, other_set_int| set_int.* &= ~other_set_int;
},
else => {
set.ints = @as(@Vector(usize_count, usize), set.ints) & ~@as(@Vector(usize_count, usize), other_set.ints);
},
}
}
pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void {
@setEvalBranchQuota(1000000);
var old = set.ints;
while (true) {
for (all_features_list, 0..) |feature, index_usize| {
const index = @as(Index, @intCast(index_usize));
if (set.isEnabled(index)) {
set.addFeatureSet(feature.dependencies);
}
}
const nothing_changed = std.mem.eql(usize, &old, &set.ints);
if (nothing_changed) return;
old = set.ints;
}
}
pub fn asBytes(set: *const Set) *const [byte_count]u8 {
return @as(*const [byte_count]u8, @ptrCast(&set.ints));
}
pub fn eql(set: Set, other_set: Set) bool {
return std.mem.eql(usize, &set.ints, &other_set.ints);
}
pub fn isSuperSetOf(set: Set, other_set: Set) bool {
switch (builtin.zig_backend) {
.stage2_x86_64 => {
var result = true;
for (&set.ints, other_set.ints) |*set_int, other_set_int|
result = result and (set_int.* & other_set_int) == other_set_int;
return result;
},
else => {
const V = @Vector(usize_count, usize);
const set_v: V = set.ints;
const other_v: V = other_set.ints;
return @reduce(.And, (set_v & other_v) == other_v);
},
}
}
};
pub fn feature_set_fns(comptime F: type) type {
return struct {
pub fn featureSet(features: []const F) Set {
var x = Set.empty;
for (features) |feature| {
x.addFeature(@intFromEnum(feature));
}
return x;
}
pub fn featureSetHas(set: Set, feature: F) bool {
return set.isEnabled(@intFromEnum(feature));
}
pub fn featureSetHasAny(set: Set, features: anytype) bool {
inline for (features) |feature| {
if (set.isEnabled(@intFromEnum(@as(F, feature)))) return true;
}
return false;
}
pub fn featureSetHasAll(set: Set, features: anytype) bool {
inline for (features) |feature| {
if (!set.isEnabled(@intFromEnum(@as(F, feature)))) return false;
}
return true;
}
};
}
};
pub const Arch = enum {
arm,
armeb,
aarch64,
aarch64_be,
aarch64_32,
arc,
avr,
bpfel,
bpfeb,
csky,
dxil,
hexagon,
loongarch32,
loongarch64,
m68k,
mips,
mipsel,
mips64,
mips64el,
msp430,
powerpc,
powerpcle,
powerpc64,
powerpc64le,
r600,
amdgcn,
riscv32,
riscv64,
sparc,
sparc64,
sparcel,
s390x,
tce,
tcele,
thumb,
thumbeb,
x86,
x86_64,
xcore,
xtensa,
nvptx,
nvptx64,
le32,
le64,
amdil,
amdil64,
hsail,
hsail64,
spir,
spir64,
spirv32,
spirv64,
kalimba,
shave,
lanai,
wasm32,
wasm64,
renderscript32,
renderscript64,
ve,
spu_2,
pub inline fn isX86(arch: Arch) bool {
return switch (arch) {
.x86, .x86_64 => true,
else => false,
};
}
pub inline fn isARM(arch: Arch) bool {
return switch (arch) {
.arm, .armeb => true,
else => false,
};
}
pub inline fn isAARCH64(arch: Arch) bool {
return switch (arch) {
.aarch64, .aarch64_be, .aarch64_32 => true,
else => false,
};
}
pub inline fn isThumb(arch: Arch) bool {
return switch (arch) {
.thumb, .thumbeb => true,
else => false,
};
}
pub inline fn isArmOrThumb(arch: Arch) bool {
return arch.isARM() or arch.isThumb();
}
pub inline fn isWasm(arch: Arch) bool {
return switch (arch) {
.wasm32, .wasm64 => true,
else => false,
};
}
pub inline fn isRISCV(arch: Arch) bool {
return switch (arch) {
.riscv32, .riscv64 => true,
else => false,
};
}
pub inline fn isMIPS(arch: Arch) bool {
return switch (arch) {
.mips, .mipsel, .mips64, .mips64el => true,
else => false,
};
}
pub inline fn isPPC(arch: Arch) bool {
return switch (arch) {
.powerpc, .powerpcle => true,
else => false,
};
}
pub inline fn isPPC64(arch: Arch) bool {
return switch (arch) {
.powerpc64, .powerpc64le => true,
else => false,
};
}
pub inline fn isSPARC(arch: Arch) bool {
return switch (arch) {
.sparc, .sparcel, .sparc64 => true,
else => false,
};
}
pub inline fn isSpirV(arch: Arch) bool {
return switch (arch) {
.spirv32, .spirv64 => true,
else => false,
};
}
pub inline fn isBpf(arch: Arch) bool {
return switch (arch) {
.bpfel, .bpfeb => true,
else => false,
};
}
pub inline fn isNvptx(arch: Arch) bool {
return switch (arch) {
.nvptx, .nvptx64 => true,
else => false,
};
}
pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model {
for (arch.allCpuModels()) |cpu| {
if (std.mem.eql(u8, cpu_name, cpu.name)) {
return cpu;
}
}
return error.UnknownCpuModel;
}
pub fn toElfMachine(arch: Arch) std.elf.EM {
return switch (arch) {
.avr => .AVR,
.msp430 => .MSP430,
.arc => .ARC,
.arm => .ARM,
.armeb => .ARM,
.hexagon => .HEXAGON,
.dxil => .NONE,
.m68k => .@"68K",
.le32 => .NONE,
.mips => .MIPS,
.mipsel => .MIPS_RS3_LE,
.powerpc, .powerpcle => .PPC,
.r600 => .NONE,
.riscv32 => .RISCV,
.sparc => .SPARC,
.sparcel => .SPARC,
.tce => .NONE,
.tcele => .NONE,
.thumb => .ARM,
.thumbeb => .ARM,
.x86 => .@"386",
.xcore => .XCORE,
.xtensa => .XTENSA,
.nvptx => .NONE,
.amdil => .NONE,
.hsail => .NONE,
.spir => .NONE,
.kalimba => .CSR_KALIMBA,
.shave => .NONE,
.lanai => .LANAI,
.wasm32 => .NONE,
.renderscript32 => .NONE,
.aarch64_32 => .AARCH64,
.aarch64 => .AARCH64,
.aarch64_be => .AARCH64,
.mips64 => .MIPS,
.mips64el => .MIPS_RS3_LE,
.powerpc64 => .PPC64,
.powerpc64le => .PPC64,
.riscv64 => .RISCV,
.x86_64 => .X86_64,
.nvptx64 => .NONE,
.le64 => .NONE,
.amdil64 => .NONE,
.hsail64 => .NONE,
.spir64 => .NONE,
.wasm64 => .NONE,
.renderscript64 => .NONE,
.amdgcn => .AMDGPU,
.bpfel => .BPF,
.bpfeb => .BPF,
.csky => .CSKY,
.sparc64 => .SPARCV9,
.s390x => .S390,
.ve => .NONE,
.spu_2 => .SPU_2,
.spirv32 => .NONE,
.spirv64 => .NONE,
.loongarch32 => .NONE,
.loongarch64 => .NONE,
};
}
pub fn toCoffMachine(arch: Arch) std.coff.MachineType {
return switch (arch) {
.avr => .Unknown,
.msp430 => .Unknown,
.arc => .Unknown,
.arm => .ARM,
.armeb => .Unknown,
.dxil => .Unknown,
.hexagon => .Unknown,
.m68k => .Unknown,
.le32 => .Unknown,
.mips => .Unknown,
.mipsel => .Unknown,
.powerpc, .powerpcle => .POWERPC,
.r600 => .Unknown,
.riscv32 => .RISCV32,
.sparc => .Unknown,
.sparcel => .Unknown,
.tce => .Unknown,
.tcele => .Unknown,
.thumb => .Thumb,
.thumbeb => .Thumb,
.x86 => .I386,
.xcore => .Unknown,
.xtensa => .Unknown,
.nvptx => .Unknown,
.amdil => .Unknown,
.hsail => .Unknown,
.spir => .Unknown,
.kalimba => .Unknown,
.shave => .Unknown,
.lanai => .Unknown,
.wasm32 => .Unknown,
.renderscript32 => .Unknown,
.aarch64_32 => .ARM64,
.aarch64 => .ARM64,
.aarch64_be => .ARM64,
.mips64 => .Unknown,
.mips64el => .Unknown,
.powerpc64 => .Unknown,
.powerpc64le => .Unknown,
.riscv64 => .RISCV64,
.x86_64 => .X64,
.nvptx64 => .Unknown,
.le64 => .Unknown,
.amdil64 => .Unknown,
.hsail64 => .Unknown,
.spir64 => .Unknown,
.wasm64 => .Unknown,
.renderscript64 => .Unknown,
.amdgcn => .Unknown,
.bpfel => .Unknown,
.bpfeb => .Unknown,
.csky => .Unknown,
.sparc64 => .Unknown,
.s390x => .Unknown,
.ve => .Unknown,
.spu_2 => .Unknown,
.spirv32 => .Unknown,
.spirv64 => .Unknown,
.loongarch32 => .Unknown,
.loongarch64 => .Unknown,
};
}
pub fn endian(arch: Arch) std.builtin.Endian {
return switch (arch) {
.avr,
.arm,
.aarch64_32,
.aarch64,
.amdgcn,
.amdil,
.amdil64,
.bpfel,
.csky,
.xtensa,
.hexagon,
.hsail,
.hsail64,
.kalimba,
.le32,
.le64,
.mipsel,
.mips64el,
.msp430,
.nvptx,
.nvptx64,
.sparcel,
.tcele,
.powerpcle,
.powerpc64le,
.r600,
.riscv32,
.riscv64,
.x86,
.x86_64,
.wasm32,
.wasm64,
.xcore,
.thumb,
.spir,
.spir64,
.renderscript32,
.renderscript64,
.shave,
.ve,
.spu_2,
.spirv32,
.spirv64,
.dxil,
.loongarch32,
.loongarch64,
.arc,
=> .little,
.armeb,
.aarch64_be,
.bpfeb,
.m68k,
.mips,
.mips64,
.powerpc,
.powerpc64,
.thumbeb,
.sparc,
.sparc64,
.tce,
.lanai,
.s390x,
=> .big,
};
}
pub fn supportsAddressSpace(arch: Arch, address_space: std.builtin.AddressSpace) bool {
const is_nvptx = arch == .nvptx or arch == .nvptx64;
const is_spirv = arch == .spirv32 or arch == .spirv64;
const is_gpu = is_nvptx or is_spirv or arch == .amdgcn;
return switch (address_space) {
.generic => true,
.fs, .gs, .ss => arch == .x86_64 or arch == .x86,
.global, .constant, .local, .shared => is_gpu,
.param => is_nvptx,
.input, .output, .uniform => is_spirv,
.flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr,
};
}
pub fn genericName(arch: Arch) []const u8 {
return switch (arch) {
.arm, .armeb, .thumb, .thumbeb => "arm",
.aarch64, .aarch64_be, .aarch64_32 => "aarch64",
.bpfel, .bpfeb => "bpf",
.loongarch32, .loongarch64 => "loongarch",
.mips, .mipsel, .mips64, .mips64el => "mips",
.powerpc, .powerpcle, .powerpc64, .powerpc64le => "powerpc",
.amdgcn => "amdgpu",
.riscv32, .riscv64 => "riscv",
.sparc, .sparc64, .sparcel => "sparc",
.s390x => "s390x",
.x86, .x86_64 => "x86",
.nvptx, .nvptx64 => "nvptx",
.wasm32, .wasm64 => "wasm",
.spirv32, .spirv64 => "spirv",
else => @tagName(arch),
};
}
pub fn allFeaturesList(arch: Arch) []const Cpu.Feature {
return switch (arch) {
.arm, .armeb, .thumb, .thumbeb => &arm.all_features,
.aarch64, .aarch64_be, .aarch64_32 => &aarch64.all_features,
.arc => &arc.all_features,
.avr => &avr.all_features,
.bpfel, .bpfeb => &bpf.all_features,
.csky => &csky.all_features,
.hexagon => &hexagon.all_features,
.loongarch32, .loongarch64 => &loongarch.all_features,
.m68k => &m68k.all_features,
.mips, .mipsel, .mips64, .mips64el => &mips.all_features,
.msp430 => &msp430.all_features,
.powerpc, .powerpcle, .powerpc64, .powerpc64le => &powerpc.all_features,
.amdgcn => &amdgpu.all_features,
.riscv32, .riscv64 => &riscv.all_features,
.sparc, .sparc64, .sparcel => &sparc.all_features,
.spirv32, .spirv64 => &spirv.all_features,
.s390x => &s390x.all_features,
.x86, .x86_64 => &x86.all_features,
.xtensa => &xtensa.all_features,
.nvptx, .nvptx64 => &nvptx.all_features,
.ve => &ve.all_features,
.wasm32, .wasm64 => &wasm.all_features,
else => &[0]Cpu.Feature{},
};
}
pub fn allCpuModels(arch: Arch) []const *const Cpu.Model {
return switch (arch) {
.arc => comptime allCpusFromDecls(arc.cpu),
.arm, .armeb, .thumb, .thumbeb => comptime allCpusFromDecls(arm.cpu),
.aarch64, .aarch64_be, .aarch64_32 => comptime allCpusFromDecls(aarch64.cpu),
.avr => comptime allCpusFromDecls(avr.cpu),
.bpfel, .bpfeb => comptime allCpusFromDecls(bpf.cpu),
.csky => comptime allCpusFromDecls(csky.cpu),
.hexagon => comptime allCpusFromDecls(hexagon.cpu),
.loongarch32, .loongarch64 => comptime allCpusFromDecls(loongarch.cpu),
.m68k => comptime allCpusFromDecls(m68k.cpu),
.mips, .mipsel, .mips64, .mips64el => comptime allCpusFromDecls(mips.cpu),
.msp430 => comptime allCpusFromDecls(msp430.cpu),
.powerpc, .powerpcle, .powerpc64, .powerpc64le => comptime allCpusFromDecls(powerpc.cpu),
.amdgcn => comptime allCpusFromDecls(amdgpu.cpu),
.riscv32, .riscv64 => comptime allCpusFromDecls(riscv.cpu),
.sparc, .sparc64, .sparcel => comptime allCpusFromDecls(sparc.cpu),
.spirv32, .spirv64 => comptime allCpusFromDecls(spirv.cpu),
.s390x => comptime allCpusFromDecls(s390x.cpu),
.x86, .x86_64 => comptime allCpusFromDecls(x86.cpu),
.xtensa => comptime allCpusFromDecls(xtensa.cpu),
.nvptx, .nvptx64 => comptime allCpusFromDecls(nvptx.cpu),
.ve => comptime allCpusFromDecls(ve.cpu),
.wasm32, .wasm64 => comptime allCpusFromDecls(wasm.cpu),
else => &[0]*const Model{},
};
}
fn allCpusFromDecls(comptime cpus: type) []const *const Cpu.Model {
const decls = @typeInfo(cpus).Struct.decls;
var array: [decls.len]*const Cpu.Model = undefined;
for (decls, 0..) |decl, i| {
array[i] = &@field(cpus, decl.name);
}
return &array;
}
};
pub const Model = struct {
name: []const u8,
llvm_name: ?[:0]const u8,
features: Feature.Set,
pub fn toCpu(model: *const Model, arch: Arch) Cpu {
var features = model.features;
features.populateDependencies(arch.allFeaturesList());
return .{
.arch = arch,
.model = model,
.features = features,
};
}
pub fn generic(arch: Arch) *const Model {
const S = struct {
const generic_model = Model{
.name = "generic",
.llvm_name = null,
.features = Cpu.Feature.Set.empty,
};
};
return switch (arch) {
.arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic,
.aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
.avr => &avr.cpu.avr2,
.bpfel, .bpfeb => &bpf.cpu.generic,
.hexagon => &hexagon.cpu.generic,
.loongarch32 => &loongarch.cpu.generic_la32,
.loongarch64 => &loongarch.cpu.generic_la64,
.m68k => &m68k.cpu.generic,
.mips, .mipsel => &mips.cpu.mips32,
.mips64, .mips64el => &mips.cpu.mips64,
.msp430 => &msp430.cpu.generic,
.powerpc => &powerpc.cpu.ppc,
.powerpcle => &powerpc.cpu.ppc,
.powerpc64 => &powerpc.cpu.ppc64,
.powerpc64le => &powerpc.cpu.ppc64le,
.amdgcn => &amdgpu.cpu.generic,
.riscv32 => &riscv.cpu.generic_rv32,
.riscv64 => &riscv.cpu.generic_rv64,
.spirv32, .spirv64 => &spirv.cpu.generic,
.sparc, .sparcel => &sparc.cpu.generic,
.sparc64 => &sparc.cpu.v9,
.s390x => &s390x.cpu.generic,
.x86 => &x86.cpu.i386,
.x86_64 => &x86.cpu.x86_64,
.nvptx, .nvptx64 => &nvptx.cpu.sm_20,
.ve => &ve.cpu.generic,
.wasm32, .wasm64 => &wasm.cpu.generic,
else => &S.generic_model,
};
}
pub fn baseline(arch: Arch) *const Model {
return switch (arch) {
.arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline,
.riscv32 => &riscv.cpu.baseline_rv32,
.riscv64 => &riscv.cpu.baseline_rv64,
.x86 => &x86.cpu.pentium4,
.nvptx, .nvptx64 => &nvptx.cpu.sm_20,
.sparc, .sparcel => &sparc.cpu.v8,
else => generic(arch),
};
}
};
pub fn baseline(arch: Arch) Cpu {
return Model.baseline(arch).toCpu(arch);
}
};
pub fn zigTriple(self: Target, allocator: Allocator) Allocator.Error![]u8 {
return Query.fromTarget(self).zigTriple(allocator);
}
pub fn linuxTripleSimple(allocator: Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![]u8 {
return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
}
pub fn linuxTriple(self: Target, allocator: Allocator) ![]u8 {
return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);
}
pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 {
return switch (os_tag) {
.windows => ".exe",
.uefi => ".efi",
.plan9 => plan9Ext(cpu_arch),
else => switch (cpu_arch) {
.wasm32, .wasm64 => ".wasm",
else => "",
},
};
}
pub fn exeFileExt(self: Target) [:0]const u8 {
return exeFileExtSimple(self.cpu.arch, self.os.tag);
}
pub fn staticLibSuffix_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 {
if (abi == .msvc) {
return ".lib";
}
switch (os_tag) {
.windows, .uefi => return ".lib",
else => return ".a",
}
}
pub fn staticLibSuffix(self: Target) [:0]const u8 {
return staticLibSuffix_os_abi(self.os.tag, self.abi);
}
pub fn dynamicLibSuffix(self: Target) [:0]const u8 {
return self.os.tag.dynamicLibSuffix();
}
pub fn libPrefix_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 {
if (abi == .msvc) {
return "";
}
switch (os_tag) {
.windows, .uefi => return "",
else => return "lib",
}
}
pub fn libPrefix(self: Target) [:0]const u8 {
return libPrefix_os_abi(self.os.tag, self.abi);
}
pub inline fn isMinGW(self: Target) bool {
return self.os.tag == .windows and self.isGnu();
}
pub inline fn isGnu(self: Target) bool {
return self.abi.isGnu();
}
pub inline fn isMusl(self: Target) bool {
return self.abi.isMusl();
}
pub inline fn isAndroid(self: Target) bool {
return self.abi == .android;
}
pub inline fn isWasm(self: Target) bool {
return self.cpu.arch.isWasm();
}
pub inline fn isDarwin(self: Target) bool {
return self.os.tag.isDarwin();
}
pub inline fn isBSD(self: Target) bool {
return self.os.tag.isBSD();
}
pub inline fn isBpfFreestanding(self: Target) bool {
return self.cpu.arch.isBpf() and self.os.tag == .freestanding;
}
pub inline fn isGnuLibC_os_tag_abi(os_tag: Os.Tag, abi: Abi) bool {
return os_tag == .linux and abi.isGnu();
}
pub inline fn isGnuLibC(self: Target) bool {
return isGnuLibC_os_tag_abi(self.os.tag, self.abi);
}
pub inline fn supportsNewStackCall(self: Target) bool {
return !self.cpu.arch.isWasm();
}
pub inline fn isSpirV(self: Target) bool {
return self.cpu.arch.isSpirV();
}
pub const FloatAbi = enum {
hard,
soft,
};
pub inline fn getFloatAbi(self: Target) FloatAbi {
return self.abi.floatAbi();
}
pub inline fn hasDynamicLinker(self: Target) bool {
if (self.cpu.arch.isWasm()) {
return false;
}
switch (self.os.tag) {
.freestanding,
.ios,
.tvos,
.watchos,
.macos,
.uefi,
.windows,
.emscripten,
.opencl,
.glsl450,
.vulkan,
.plan9,
.other,
=> return false,
else => return true,
}
}
pub const DynamicLinker = struct {
buffer: [255]u8,
max_byte: ?u8,
pub const none: DynamicLinker = .{
.buffer = undefined,
.max_byte = null,
};
pub fn init(dl_or_null: ?[]const u8) DynamicLinker {
var result: DynamicLinker = undefined;
result.set(dl_or_null);
return result;
}
pub fn get(self: *const DynamicLinker) ?[]const u8 {
const m: usize = self.max_byte orelse return null;
return self.buffer[0 .. m + 1];
}
pub fn set(self: *DynamicLinker, dl_or_null: ?[]const u8) void {
if (dl_or_null) |dl| {
@memcpy(self.buffer[0..dl.len], dl);
self.max_byte = @intCast(dl.len - 1);
} else {
self.max_byte = null;
}
}
pub fn eql(a: DynamicLinker, b: DynamicLinker) bool {
const a_m = a.max_byte orelse return b.max_byte == null;
const b_m = b.max_byte orelse return false;
if (a_m != b_m) return false;
const a_s = a.buffer[0 .. a_m + 1];
const b_s = b.buffer[0 .. a_m + 1];
return std.mem.eql(u8, a_s, b_s);
}
};
pub fn standardDynamicLinkerPath(target: Target) DynamicLinker {
return standardDynamicLinkerPath_cpu_os_abi(target.cpu, target.os.tag, target.abi);
}
pub fn standardDynamicLinkerPath_cpu_os_abi(cpu: Cpu, os_tag: Os.Tag, abi: Abi) DynamicLinker {
var result = DynamicLinker.none;
const S = struct {
fn print(r: *DynamicLinker, comptime fmt: []const u8, args: anytype) DynamicLinker {
r.max_byte = @as(u8, @intCast((std.fmt.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1));
return r.*;
}
fn copy(r: *DynamicLinker, s: []const u8) DynamicLinker {
@memcpy(r.buffer[0..s.len], s);
r.max_byte = @as(u8, @intCast(s.len - 1));
return r.*;
}
};
const print = S.print;
const copy = S.copy;
if (abi == .android) {
const suffix = if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64" else "";
return print(&result, "/system/bin/linker{s}", .{suffix});
}
if (abi.isMusl()) {
const is_arm = switch (cpu.arch) {
.arm, .armeb, .thumb, .thumbeb => true,
else => false,
};
const arch_part = switch (cpu.arch) {
.arm, .thumb => "arm",
.armeb, .thumbeb => "armeb",
else => |arch| @tagName(arch),
};
const arch_suffix = if (is_arm and abi.floatAbi() == .hard) "hf" else "";
return print(&result, "/lib/ld-musl-{s}{s}.so.1", .{ arch_part, arch_suffix });
}
switch (os_tag) {
.freebsd => return copy(&result, "/libexec/ld-elf.so.1"),
.netbsd => return copy(&result, "/libexec/ld.elf_so"),
.openbsd => return copy(&result, "/usr/libexec/ld.so"),
.dragonfly => return copy(&result, "/libexec/ld-elf.so.2"),
.solaris, .illumos => return copy(&result, "/lib/64/ld.so.1"),
.linux => switch (cpu.arch) {
.x86,
.sparc,
.sparcel,
=> return copy(&result, "/lib/ld-linux.so.2"),
.aarch64 => return copy(&result, "/lib/ld-linux-aarch64.so.1"),
.aarch64_be => return copy(&result, "/lib/ld-linux-aarch64_be.so.1"),
.aarch64_32 => return copy(&result, "/lib/ld-linux-aarch64_32.so.1"),
.arm,
.armeb,
.thumb,
.thumbeb,
=> return copy(&result, switch (abi.floatAbi()) {
.hard => "/lib/ld-linux-armhf.so.3",
else => "/lib/ld-linux.so.3",
}),
.mips,
.mipsel,
.mips64,
.mips64el,
=> {
const lib_suffix = switch (abi) {
.gnuabin32, .gnux32 => "32",
.gnuabi64 => "64",
else => "",
};
const is_nan_2008 = mips.featureSetHas(cpu.features, .nan2008);
const loader = if (is_nan_2008) "ld-linux-mipsn8.so.1" else "ld.so.1";
return print(&result, "/lib{s}/{s}", .{ lib_suffix, loader });
},
.powerpc, .powerpcle => return copy(&result, "/lib/ld.so.1"),
.powerpc64, .powerpc64le => return copy(&result, "/lib64/ld64.so.2"),
.s390x => return copy(&result, "/lib64/ld64.so.1"),
.sparc64 => return copy(&result, "/lib64/ld-linux.so.2"),
.x86_64 => return copy(&result, switch (abi) {
.gnux32 => "/libx32/ld-linux-x32.so.2",
else => "/lib64/ld-linux-x86-64.so.2",
}),
.riscv32 => return copy(&result, "/lib/ld-linux-riscv32-ilp32.so.1"),
.riscv64 => return copy(&result, "/lib/ld-linux-riscv64-lp64.so.1"),
.wasm32,
.wasm64,
.bpfel,
.bpfeb,
.nvptx,
.nvptx64,
.spu_2,
.avr,
.spirv32,
.spirv64,
=> return result,
.arc,
.csky,
.hexagon,
.m68k,
.msp430,
.r600,
.amdgcn,
.tce,
.tcele,
.xcore,
.le32,
.le64,
.amdil,
.amdil64,
.hsail,
.hsail64,
.spir,
.spir64,
.kalimba,
.shave,
.lanai,
.renderscript32,
.renderscript64,
.ve,
.dxil,
.loongarch32,
.loongarch64,
.xtensa,
=> return result,
},
.ios,
.tvos,
.watchos,
.macos,
=> return copy(&result, "/usr/lib/dyld"),
.freestanding,
.uefi,
.windows,
.emscripten,
.wasi,
.opencl,
.glsl450,
.vulkan,
.other,
.plan9,
=> return result,
.haiku => return copy(&result, "/system/runtime_loader"),
.ananas,
.cloudabi,
.fuchsia,
.kfreebsd,
.lv2,
.zos,
.minix,
.rtems,
.nacl,
.aix,
.cuda,
.nvcl,
.amdhsa,
.ps4,
.ps5,
.elfiamcu,
.mesa3d,
.contiki,
.amdpal,
.hermit,
.hurd,
.driverkit,
.shadermodel,
.liteos,
=> return result,
}
}
pub fn plan9Ext(cpu_arch: Cpu.Arch) [:0]const u8 {
return switch (cpu_arch) {
.arm => ".5",
.x86_64 => ".6",
.aarch64 => ".7",
.x86 => ".8",
.sparc => ".k",
.powerpc, .powerpcle => ".q",
.mips, .mipsel => ".v",
else => ".X",
};
}
pub fn maxIntAlignment(target: Target) u16 {
return switch (target.cpu.arch) {
.avr => 1,
.msp430 => 2,
.xcore => 4,
.arm,
.armeb,
.thumb,
.thumbeb,
.hexagon,
.mips,
.mipsel,
.powerpc,
.powerpcle,
.r600,
.amdgcn,
.riscv32,
.sparc,
.sparcel,
.s390x,
.lanai,
.wasm32,
.wasm64,
=> 8,
.x86 => if (target.ofmt == .c) 16 else return switch (target.os.tag) {
.windows, .uefi => 8,
else => 4,
},
.x86_64,
.powerpc64,
.powerpc64le,
.mips64,
.mips64el,
.sparc64,
=> return switch (target.ofmt) {
.c => 16,
else => 8,
},
.aarch64,
.aarch64_be,
.aarch64_32,
.riscv64,
.bpfel,
.bpfeb,
.nvptx,
.nvptx64,
=> 16,
.spu_2,
.csky,
.arc,
.m68k,
.tce,
.tcele,
.le32,
.amdil,
.hsail,
.spir,
.kalimba,
.renderscript32,
.spirv32,
.shave,
.le64,
.amdil64,
.hsail64,
.spir64,
.renderscript64,
.ve,
.spirv64,
.dxil,
.loongarch32,
.loongarch64,
.xtensa,
=> 16,
};
}
pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 {
switch (abi) {
.gnux32, .muslx32, .gnuabin32, .gnuilp32 => return 32,
.gnuabi64 => return 64,
else => {},
}
return switch (cpu.arch) {
.avr,
.msp430,
.spu_2,
=> 16,
.arc,
.arm,
.armeb,
.csky,
.hexagon,
.m68k,
.le32,
.mips,
.mipsel,
.powerpc,
.powerpcle,
.r600,
.riscv32,
.sparcel,
.tce,
.tcele,
.thumb,
.thumbeb,
.x86,
.xcore,
.nvptx,
.amdil,
.hsail,
.spir,
.kalimba,
.shave,
.lanai,
.wasm32,
.renderscript32,
.aarch64_32,
.spirv32,
.loongarch32,
.dxil,
.xtensa,
=> 32,
.aarch64,
.aarch64_be,
.mips64,
.mips64el,
.powerpc64,
.powerpc64le,
.riscv64,
.x86_64,
.nvptx64,
.le64,
.amdil64,
.hsail64,
.spir64,
.wasm64,
.renderscript64,
.amdgcn,
.bpfel,
.bpfeb,
.sparc64,
.s390x,
.ve,
.spirv64,
.loongarch64,
=> 64,
.sparc => if (std.Target.sparc.featureSetHas(cpu.features, .v9)) 64 else 32,
};
}
pub fn ptrBitWidth(target: Target) u16 {
return ptrBitWidth_cpu_abi(target.cpu, target.abi);
}
pub fn stackAlignment(target: Target) u16 {
return switch (target.cpu.arch) {
.m68k => 2,
.amdgcn => 4,
.x86 => switch (target.os.tag) {
.windows, .uefi => 4,
else => 16,
},
.arm,
.armeb,
.thumb,
.thumbeb,
.mips,
.mipsel,
.sparc,
.sparcel,
=> 8,
.aarch64,
.aarch64_be,
.aarch64_32,
.bpfeb,
.bpfel,
.mips64,
.mips64el,
.riscv32,
.riscv64,
.sparc64,
.x86_64,
.ve,
.wasm32,
.wasm64,
=> 16,
.powerpc64,
.powerpc64le,
=> switch (target.os.tag) {
else => 8,
.linux => 16,
},
else => @divExact(target.ptrBitWidth(), 8),
};
}
pub fn charSignedness(target: Target) std.builtin.Signedness {
switch (target.cpu.arch) {
.aarch64,
.aarch64_32,
.aarch64_be,
.arm,
.armeb,
.thumb,
.thumbeb,
=> return if (target.os.tag.isDarwin() or target.os.tag == .windows) .signed else .unsigned,
.powerpc, .powerpc64 => return if (target.os.tag.isDarwin()) .signed else .unsigned,
.powerpcle,
.powerpc64le,
.s390x,
.xcore,
.arc,
.msp430,
.riscv32,
.riscv64,
=> return .unsigned,
else => return .signed,
}
}
pub const CType = enum {
char,
short,
ushort,
int,
uint,
long,
ulong,
longlong,
ulonglong,
float,
double,
longdouble,
};
pub fn c_type_byte_size(t: Target, c_type: CType) u16 {
return switch (c_type) {
.char,
.short,
.ushort,
.int,
.uint,
.long,
.ulong,
.longlong,
.ulonglong,
.float,
.double,
=> @divExact(c_type_bit_size(t, c_type), 8),
.longdouble => switch (c_type_bit_size(t, c_type)) {
16 => 2,
32 => 4,
64 => 8,
80 => @as(u16, @intCast(std.mem.alignForward(usize, 10, c_type_alignment(t, .longdouble)))),
128 => 16,
else => unreachable,
},
};
}
pub fn c_type_bit_size(target: Target, c_type: CType) u16 {
switch (target.os.tag) {
.freestanding, .other => switch (target.cpu.arch) {
.msp430 => switch (c_type) {
.char => return 8,
.short, .ushort, .int, .uint => return 16,
.float, .long, .ulong => return 32,
.longlong, .ulonglong, .double, .longdouble => return 64,
},
.avr => switch (c_type) {
.char => return 8,
.short, .ushort, .int, .uint => return 16,
.long, .ulong, .float, .double, .longdouble => return 32,
.longlong, .ulonglong => return 64,
},
.tce, .tcele => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .long, .ulong, .longlong, .ulonglong => return 32,
.float, .double, .longdouble => return 32,
},
.mips64, .mips64el => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .float => return 32,
.long, .ulong => return if (target.abi != .gnuabin32) 64 else 32,
.longlong, .ulonglong, .double => return 64,
.longdouble => return 128,
},
.x86_64 => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .float => return 32,
.long, .ulong => switch (target.abi) {
.gnux32, .muslx32 => return 32,
else => return 64,
},
.longlong, .ulonglong, .double => return 64,
.longdouble => return 80,
},
else => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .float => return 32,
.long, .ulong => return target.ptrBitWidth(),
.longlong, .ulonglong, .double => return 64,
.longdouble => switch (target.cpu.arch) {
.x86 => switch (target.abi) {
.android => return 64,
else => return 80,
},
.powerpc,
.powerpcle,
.powerpc64,
.powerpc64le,
=> switch (target.abi) {
.musl,
.musleabi,
.musleabihf,
.muslx32,
=> return 64,
else => return 128,
},
.riscv32,
.riscv64,
.aarch64,
.aarch64_be,
.aarch64_32,
.s390x,
.sparc,
.sparc64,
.sparcel,
.wasm32,
.wasm64,
=> return 128,
else => return 64,
},
},
},
.linux,
.freebsd,
.netbsd,
.dragonfly,
.openbsd,
.wasi,
.emscripten,
.plan9,
.solaris,
.illumos,
.haiku,
.ananas,
.fuchsia,
.minix,
=> switch (target.cpu.arch) {
.msp430 => switch (c_type) {
.char => return 8,
.short, .ushort, .int, .uint => return 16,
.long, .ulong, .float => return 32,
.longlong, .ulonglong, .double, .longdouble => return 64,
},
.avr => switch (c_type) {
.char => return 8,
.short, .ushort, .int, .uint => return 16,
.long, .ulong, .float, .double, .longdouble => return 32,
.longlong, .ulonglong => return 64,
},
.tce, .tcele => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .long, .ulong, .longlong, .ulonglong => return 32,
.float, .double, .longdouble => return 32,
},
.mips64, .mips64el => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .float => return 32,
.long, .ulong => return if (target.abi != .gnuabin32) 64 else 32,
.longlong, .ulonglong, .double => return 64,
.longdouble => if (target.os.tag == .freebsd) return 64 else return 128,
},
.x86_64 => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .float => return 32,
.long, .ulong => switch (target.abi) {
.gnux32, .muslx32 => return 32,
else => return 64,
},
.longlong, .ulonglong, .double => return 64,
.longdouble => return 80,
},
else => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .float => return 32,
.long, .ulong => return target.ptrBitWidth(),
.longlong, .ulonglong, .double => return 64,
.longdouble => switch (target.cpu.arch) {
.x86 => switch (target.abi) {
.android => return 64,
else => return 80,
},
.powerpc,
.powerpcle,
=> switch (target.abi) {
.musl,
.musleabi,
.musleabihf,
.muslx32,
=> return 64,
else => switch (target.os.tag) {
.freebsd, .netbsd, .openbsd => return 64,
else => return 128,
},
},
.powerpc64,
.powerpc64le,
=> switch (target.abi) {
.musl,
.musleabi,
.musleabihf,
.muslx32,
=> return 64,
else => switch (target.os.tag) {
.freebsd, .openbsd => return 64,
else => return 128,
},
},
.riscv32,
.riscv64,
.aarch64,
.aarch64_be,
.aarch64_32,
.s390x,
.mips64,
.mips64el,
.sparc,
.sparc64,
.sparcel,
.wasm32,
.wasm64,
=> return 128,
else => return 64,
},
},
},
.windows, .uefi => switch (target.cpu.arch) {
.x86 => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .float => return 32,
.long, .ulong => return 32,
.longlong, .ulonglong, .double => return 64,
.longdouble => switch (target.abi) {
.gnu, .gnuilp32, .cygnus => return 80,
else => return 64,
},
},
.x86_64 => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .float => return 32,
.long, .ulong => switch (target.abi) {
.cygnus => return 64,
else => return 32,
},
.longlong, .ulonglong, .double => return 64,
.longdouble => switch (target.abi) {
.gnu, .gnuilp32, .cygnus => return 80,
else => return 64,
},
},
else => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .float => return 32,
.long, .ulong => return 32,
.longlong, .ulonglong, .double => return 64,
.longdouble => return 64,
},
},
.macos, .ios, .tvos, .watchos => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .float => return 32,
.long, .ulong => switch (target.cpu.arch) {
.x86, .arm, .aarch64_32 => return 32,
.x86_64 => switch (target.abi) {
.gnux32, .muslx32 => return 32,
else => return 64,
},
else => return 64,
},
.longlong, .ulonglong, .double => return 64,
.longdouble => switch (target.cpu.arch) {
.x86 => switch (target.abi) {
.android => return 64,
else => return 80,
},
.x86_64 => return 80,
else => return 64,
},
},
.nvcl, .cuda => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .float => return 32,
.long, .ulong => switch (target.cpu.arch) {
.nvptx => return 32,
.nvptx64 => return 64,
else => return 64,
},
.longlong, .ulonglong, .double => return 64,
.longdouble => return 64,
},
.amdhsa, .amdpal => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .float => return 32,
.long, .ulong, .longlong, .ulonglong, .double => return 64,
.longdouble => return 128,
},
.opencl, .vulkan => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .float => return 32,
.long, .ulong, .double => return 64,
.longlong, .ulonglong => return 128,
.longdouble => return 128,
},
.ps4, .ps5 => switch (c_type) {
.char => return 8,
.short, .ushort => return 16,
.int, .uint, .float => return 32,
.long, .ulong => return 64,
.longlong, .ulonglong, .double => return 64,
.longdouble => return 80,
},
.cloudabi,
.kfreebsd,
.lv2,
.zos,
.rtems,
.nacl,
.aix,
.elfiamcu,
.mesa3d,
.contiki,
.hermit,
.hurd,
.glsl450,
.driverkit,
.shadermodel,
.liteos,
=> @panic("TODO specify the C integer and float type sizes for this OS"),
}
}
pub fn c_type_alignment(target: Target, c_type: CType) u16 {
switch (target.cpu.arch) {
.avr => return 1,
.x86 => switch (target.os.tag) {
.windows, .uefi => switch (c_type) {
.longlong, .ulonglong, .double => return 8,
.longdouble => switch (target.abi) {
.gnu, .gnuilp32, .cygnus => return 4,
else => return 8,
},
else => {},
},
else => {},
},
else => {},
}
return @min(
std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8),
switch (target.cpu.arch) {
.arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) {
.netbsd => switch (target.abi) {
.gnueabi,
.gnueabihf,
.eabi,
.eabihf,
.android,
.musleabi,
.musleabihf,
=> 8,
else => @as(u16, 4),
},
.ios, .tvos, .watchos => 4,
else => 8,
},
.msp430,
.avr,
=> 2,
.arc,
.csky,
.x86,
.xcore,
.dxil,
.loongarch32,
.tce,
.tcele,
.le32,
.amdil,
.hsail,
.spir,
.spirv32,
.kalimba,
.shave,
.renderscript32,
.ve,
.spu_2,
.xtensa,
=> 4,
.aarch64_32,
.amdgcn,
.amdil64,
.bpfel,
.bpfeb,
.hexagon,
.hsail64,
.loongarch64,
.m68k,
.mips,
.mipsel,
.sparc,
.sparcel,
.sparc64,
.lanai,
.le64,
.nvptx,
.nvptx64,
.r600,
.s390x,
.spir64,
.spirv64,
.renderscript64,
=> 8,
.aarch64,
.aarch64_be,
.mips64,
.mips64el,
.powerpc,
.powerpcle,
.powerpc64,
.powerpc64le,
.riscv32,
.riscv64,
.x86_64,
.wasm32,
.wasm64,
=> 16,
},
);
}
pub fn c_type_preferred_alignment(target: Target, c_type: CType) u16 {
switch (target.cpu.arch) {
.arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) {
.netbsd => switch (target.abi) {
.gnueabi,
.gnueabihf,
.eabi,
.eabihf,
.android,
.musleabi,
.musleabihf,
=> {},
else => switch (c_type) {
.longdouble => return 4,
else => {},
},
},
.ios, .tvos, .watchos => switch (c_type) {
.longdouble => return 4,
else => {},
},
else => {},
},
.arc => switch (c_type) {
.longdouble => return 4,
else => {},
},
.avr => switch (c_type) {
.char, .int, .uint, .long, .ulong, .float, .longdouble => return 1,
.short, .ushort => return 2,
.double => return 4,
.longlong, .ulonglong => return 8,
},
.x86 => switch (target.os.tag) {
.windows, .uefi => switch (c_type) {
.longdouble => switch (target.abi) {
.gnu, .gnuilp32, .cygnus => return 4,
else => return 8,
},
else => {},
},
else => switch (c_type) {
.longdouble => return 4,
else => {},
},
},
else => {},
}
return @min(
std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8),
switch (target.cpu.arch) {
.msp430 => @as(u16, 2),
.csky,
.xcore,
.dxil,
.loongarch32,
.tce,
.tcele,
.le32,
.amdil,
.hsail,
.spir,
.spirv32,
.kalimba,
.shave,
.renderscript32,
.ve,
.spu_2,
.xtensa,
=> 4,
.arc,
.arm,
.armeb,
.avr,
.thumb,
.thumbeb,
.aarch64_32,
.amdgcn,
.amdil64,
.bpfel,
.bpfeb,
.hexagon,
.hsail64,
.x86,
.loongarch64,
.m68k,
.mips,
.mipsel,
.sparc,
.sparcel,
.sparc64,
.lanai,
.le64,
.nvptx,
.nvptx64,
.r600,
.s390x,
.spir64,
.spirv64,
.renderscript64,
=> 8,
.aarch64,
.aarch64_be,
.mips64,
.mips64el,
.powerpc,
.powerpcle,
.powerpc64,
.powerpc64le,
.riscv32,
.riscv64,
.x86_64,
.wasm32,
.wasm64,
=> 16,
},
);
}
pub fn is_libc_lib_name(target: std.Target, name: []const u8) bool {
const ignore_case = target.os.tag == .macos or target.os.tag == .windows;
if (eqlIgnoreCase(ignore_case, name, "c"))
return true;
if (target.isMinGW()) {
if (eqlIgnoreCase(ignore_case, name, "m"))
return true;
if (eqlIgnoreCase(ignore_case, name, "mingw32"))
return true;
if (eqlIgnoreCase(ignore_case, name, "msvcrt-os"))
return true;
if (eqlIgnoreCase(ignore_case, name, "mingwex"))
return true;
if (eqlIgnoreCase(ignore_case, name, "uuid"))
return true;
if (eqlIgnoreCase(ignore_case, name, "bits"))
return true;
if (eqlIgnoreCase(ignore_case, name, "dmoguids"))
return true;
if (eqlIgnoreCase(ignore_case, name, "dxerr8"))
return true;
if (eqlIgnoreCase(ignore_case, name, "dxerr9"))
return true;
if (eqlIgnoreCase(ignore_case, name, "mfuuid"))
return true;
if (eqlIgnoreCase(ignore_case, name, "msxml2"))
return true;
if (eqlIgnoreCase(ignore_case, name, "msxml6"))
return true;
if (eqlIgnoreCase(ignore_case, name, "amstrmid"))
return true;
if (eqlIgnoreCase(ignore_case, name, "wbemuuid"))
return true;
if (eqlIgnoreCase(ignore_case, name, "wmcodecdspuuid"))
return true;
if (eqlIgnoreCase(ignore_case, name, "dxguid"))
return true;
if (eqlIgnoreCase(ignore_case, name, "ksguid"))
return true;
if (eqlIgnoreCase(ignore_case, name, "locationapi"))
return true;
if (eqlIgnoreCase(ignore_case, name, "portabledeviceguids"))
return true;
if (eqlIgnoreCase(ignore_case, name, "mfuuid"))
return true;
if (eqlIgnoreCase(ignore_case, name, "dloadhelper"))
return true;
if (eqlIgnoreCase(ignore_case, name, "strmiids"))
return true;
if (eqlIgnoreCase(ignore_case, name, "mfuuid"))
return true;
if (eqlIgnoreCase(ignore_case, name, "adsiid"))
return true;
return false;
}
if (target.abi.isGnu() or target.abi.isMusl()) {
if (eqlIgnoreCase(ignore_case, name, "m"))
return true;
if (eqlIgnoreCase(ignore_case, name, "rt"))
return true;
if (eqlIgnoreCase(ignore_case, name, "pthread"))
return true;
if (eqlIgnoreCase(ignore_case, name, "util"))
return true;
if (eqlIgnoreCase(ignore_case, name, "xnet"))
return true;
if (eqlIgnoreCase(ignore_case, name, "resolv"))
return true;
if (eqlIgnoreCase(ignore_case, name, "dl"))
return true;
}
if (target.abi.isMusl()) {
if (eqlIgnoreCase(ignore_case, name, "crypt"))
return true;
}
if (target.os.tag.isDarwin()) {
if (eqlIgnoreCase(ignore_case, name, "System"))
return true;
if (eqlIgnoreCase(ignore_case, name, "c"))
return true;
if (eqlIgnoreCase(ignore_case, name, "dbm"))
return true;
if (eqlIgnoreCase(ignore_case, name, "dl"))
return true;
if (eqlIgnoreCase(ignore_case, name, "info"))
return true;
if (eqlIgnoreCase(ignore_case, name, "m"))
return true;
if (eqlIgnoreCase(ignore_case, name, "poll"))
return true;
if (eqlIgnoreCase(ignore_case, name, "proc"))
return true;
if (eqlIgnoreCase(ignore_case, name, "pthread"))
return true;
if (eqlIgnoreCase(ignore_case, name, "rpcsvc"))
return true;
}
if (target.os.isAtLeast(.macos, .{ .major = 10, .minor = 8, .patch = 0 }) orelse false) {
if (eqlIgnoreCase(ignore_case, name, "mx"))
return true;
}
return false;
}
pub fn is_libcpp_lib_name(target: std.Target, name: []const u8) bool {
const ignore_case = target.os.tag.isDarwin() or target.os.tag == .windows;
return eqlIgnoreCase(ignore_case, name, "c++") or
eqlIgnoreCase(ignore_case, name, "stdc++") or
eqlIgnoreCase(ignore_case, name, "c++abi");
}
fn eqlIgnoreCase(ignore_case: bool, a: []const u8, b: []const u8) bool {
if (ignore_case) {
return std.ascii.eqlIgnoreCase(a, b);
} else {
return std.mem.eql(u8, a, b);
}
}
pub fn osArchName(target: std.Target) [:0]const u8 {
return switch (target.os.tag) {
.linux => switch (target.cpu.arch) {
.arm, .armeb, .thumb, .thumbeb => "arm",
.aarch64, .aarch64_be, .aarch64_32 => "aarch64",
.mips, .mipsel, .mips64, .mips64el => "mips",
.powerpc, .powerpcle, .powerpc64, .powerpc64le => "powerpc",
.riscv32, .riscv64 => "riscv",
.sparc, .sparcel, .sparc64 => "sparc",
.x86, .x86_64 => "x86",
else => @tagName(target.cpu.arch),
},
else => @tagName(target.cpu.arch),
};
}
const Target = @This();
const std = @import("std.zig");
const builtin = @import("builtin");
const Allocator = std.mem.Allocator;
test {
std.testing.refAllDecls(Cpu.Arch);
}