aboutsummaryrefslogtreecommitdiff
path: root/lib/std/target.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-02-21 14:19:20 -0500
committerGitHub <noreply@github.com>2020-02-21 14:19:20 -0500
commit10e0b071354d8a1b4ab70041dfdd06a008bd6d3d (patch)
treea705cb0f0e25fceb5263e10fc027011e0ee26f76 /lib/std/target.zig
parente381a42de9c0f0c5439a926b0ac99026a0373f49 (diff)
parent71573584cdfb1ddb176681fcb7d1544cac7a72ca (diff)
downloadzig-10e0b071354d8a1b4ab70041dfdd06a008bd6d3d.tar.gz
zig-10e0b071354d8a1b4ab70041dfdd06a008bd6d3d.zip
Merge pull request #4509 from ziglang/sub-architecture-annihilation
sub-architecture annihilation
Diffstat (limited to 'lib/std/target.zig')
-rw-r--r--lib/std/target.zig1222
1 files changed, 579 insertions, 643 deletions
diff --git a/lib/std/target.zig b/lib/std/target.zig
index bc78b2dce5..83d3dafbc2 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -47,6 +47,16 @@ pub const Target = union(enum) {
emscripten,
uefi,
other,
+
+ pub fn parse(text: []const u8) !Os {
+ const info = @typeInfo(Os);
+ inline for (info.Enum.fields) |field| {
+ if (mem.eql(u8, text, field.name)) {
+ return @field(Os, field.name);
+ }
+ }
+ return error.UnknownOperatingSystem;
+ }
};
pub const aarch64 = @import("target/aarch64.zig");
@@ -65,457 +75,6 @@ pub const Target = union(enum) {
pub const wasm = @import("target/wasm.zig");
pub const x86 = @import("target/x86.zig");
- pub const Arch = union(enum) {
- arm: Arm32,
- armeb: Arm32,
- aarch64: Arm64,
- aarch64_be: Arm64,
- aarch64_32: Arm64,
- arc,
- avr,
- bpfel,
- bpfeb,
- hexagon,
- mips,
- mipsel,
- mips64,
- mips64el,
- msp430,
- powerpc,
- powerpc64,
- powerpc64le,
- r600,
- amdgcn,
- riscv32,
- riscv64,
- sparc,
- sparcv9,
- sparcel,
- s390x,
- tce,
- tcele,
- thumb: Arm32,
- thumbeb: Arm32,
- i386,
- x86_64,
- xcore,
- nvptx,
- nvptx64,
- le32,
- le64,
- amdil,
- amdil64,
- hsail,
- hsail64,
- spir,
- spir64,
- kalimba: Kalimba,
- shave,
- lanai,
- wasm32,
- wasm64,
- renderscript32,
- renderscript64,
-
- pub const Arm32 = enum {
- v8_5a,
- v8_4a,
- v8_3a,
- v8_2a,
- v8_1a,
- v8a,
- v8r,
- v8m_baseline,
- v8m_mainline,
- v8_1m_mainline,
- v7a,
- v7em,
- v7m,
- v7s,
- v7k,
- v7ve,
- v6,
- v6m,
- v6k,
- v6t2,
- v5,
- v5te,
- v4t,
-
- pub fn version(version: Arm32) comptime_int {
- return switch (version) {
- .v8_5a, .v8_4a, .v8_3a, .v8_2a, .v8_1a, .v8a, .v8r, .v8m_baseline, .v8m_mainline, .v8_1m_mainline => 8,
- .v7a, .v7em, .v7m, .v7s, .v7k, .v7ve => 7,
- .v6, .v6m, .v6k, .v6t2 => 6,
- .v5, .v5te => 5,
- .v4t => 4,
- };
- }
- };
- pub const Arm64 = enum {
- v8_5a,
- v8_4a,
- v8_3a,
- v8_2a,
- v8_1a,
- v8a,
- };
- pub const Kalimba = enum {
- v5,
- v4,
- v3,
- };
- pub const Mips = enum {
- r6,
- };
-
- pub fn subArchName(arch: Arch) ?[]const u8 {
- return switch (arch) {
- .arm, .armeb, .thumb, .thumbeb => |arm32| @tagName(arm32),
- .aarch64, .aarch64_be, .aarch64_32 => |arm64| @tagName(arm64),
- .kalimba => |kalimba| @tagName(kalimba),
- else => return null,
- };
- }
-
- pub fn subArchFeature(arch: Arch) ?Cpu.Feature.Set.Index {
- return switch (arch) {
- .arm, .armeb, .thumb, .thumbeb => |arm32| switch (arm32) {
- .v8_5a => @enumToInt(arm.Feature.armv8_5_a),
- .v8_4a => @enumToInt(arm.Feature.armv8_4_a),
- .v8_3a => @enumToInt(arm.Feature.armv8_3_a),
- .v8_2a => @enumToInt(arm.Feature.armv8_2_a),
- .v8_1a => @enumToInt(arm.Feature.armv8_1_a),
- .v8a => @enumToInt(arm.Feature.armv8_a),
- .v8r => @enumToInt(arm.Feature.armv8_r),
- .v8m_baseline => @enumToInt(arm.Feature.armv8_m_base),
- .v8m_mainline => @enumToInt(arm.Feature.armv8_m_main),
- .v8_1m_mainline => @enumToInt(arm.Feature.armv8_1_m_main),
- .v7a => @enumToInt(arm.Feature.armv7_a),
- .v7em => @enumToInt(arm.Feature.armv7e_m),
- .v7m => @enumToInt(arm.Feature.armv7_m),
- .v7s => @enumToInt(arm.Feature.armv7s),
- .v7k => @enumToInt(arm.Feature.armv7k),
- .v7ve => @enumToInt(arm.Feature.armv7ve),
- .v6 => @enumToInt(arm.Feature.armv6),
- .v6m => @enumToInt(arm.Feature.armv6_m),
- .v6k => @enumToInt(arm.Feature.armv6k),
- .v6t2 => @enumToInt(arm.Feature.armv6t2),
- .v5 => @enumToInt(arm.Feature.armv5t),
- .v5te => @enumToInt(arm.Feature.armv5te),
- .v4t => @enumToInt(arm.Feature.armv4t),
- },
- .aarch64, .aarch64_be, .aarch64_32 => |arm64| switch (arm64) {
- .v8_5a => @enumToInt(aarch64.Feature.v8_5a),
- .v8_4a => @enumToInt(aarch64.Feature.v8_4a),
- .v8_3a => @enumToInt(aarch64.Feature.v8_3a),
- .v8_2a => @enumToInt(aarch64.Feature.v8_2a),
- .v8_1a => @enumToInt(aarch64.Feature.v8_1a),
- .v8a => @enumToInt(aarch64.Feature.v8a),
- },
- else => return null,
- };
- }
-
- pub fn isARM(arch: Arch) bool {
- return switch (arch) {
- .arm, .armeb => true,
- else => false,
- };
- }
-
- pub fn isThumb(arch: Arch) bool {
- return switch (arch) {
- .thumb, .thumbeb => true,
- else => false,
- };
- }
-
- pub fn isWasm(arch: Arch) bool {
- return switch (arch) {
- .wasm32, .wasm64 => true,
- else => false,
- };
- }
-
- pub fn isRISCV(arch: Arch) bool {
- return switch (arch) {
- .riscv32, .riscv64 => true,
- else => false,
- };
- }
-
- pub fn isMIPS(arch: Arch) bool {
- return switch (arch) {
- .mips, .mipsel, .mips64, .mips64el => true,
- else => false,
- };
- }
-
- pub fn parseCpu(arch: Arch, cpu_name: []const u8) !*const Cpu {
- for (arch.allCpus()) |cpu| {
- if (mem.eql(u8, cpu_name, cpu.name)) {
- return cpu;
- }
- }
- return error.UnknownCpu;
- }
-
- /// Comma-separated list of features, with + or - in front of each feature. This
- /// form represents a deviation from baseline CPU, which is provided as a parameter.
- /// Extra commas are ignored.
- pub fn parseCpuFeatureSet(arch: Arch, cpu: *const Cpu, features_text: []const u8) !Cpu.Feature.Set {
- const all_features = arch.allFeaturesList();
- var set = cpu.features;
- var it = mem.tokenize(features_text, ",");
- while (it.next()) |item_text| {
- var feature_name: []const u8 = undefined;
- var op: enum {
- add,
- sub,
- } = undefined;
- if (mem.startsWith(u8, item_text, "+")) {
- op = .add;
- feature_name = item_text[1..];
- } else if (mem.startsWith(u8, item_text, "-")) {
- op = .sub;
- feature_name = item_text[1..];
- } else {
- return error.InvalidCpuFeatures;
- }
- for (all_features) |feature, index_usize| {
- const index = @intCast(Cpu.Feature.Set.Index, index_usize);
- if (mem.eql(u8, feature_name, feature.name)) {
- switch (op) {
- .add => set.addFeature(index),
- .sub => set.removeFeature(index),
- }
- break;
- }
- } else {
- return error.UnknownCpuFeature;
- }
- }
- return set;
- }
-
- pub fn toElfMachine(arch: Arch) std.elf.EM {
- return switch (arch) {
- .avr => ._AVR,
- .msp430 => ._MSP430,
- .arc => ._ARC,
- .arm => ._ARM,
- .armeb => ._ARM,
- .hexagon => ._HEXAGON,
- .le32 => ._NONE,
- .mips => ._MIPS,
- .mipsel => ._MIPS_RS3_LE,
- .powerpc => ._PPC,
- .r600 => ._NONE,
- .riscv32 => ._RISCV,
- .sparc => ._SPARC,
- .sparcel => ._SPARC,
- .tce => ._NONE,
- .tcele => ._NONE,
- .thumb => ._ARM,
- .thumbeb => ._ARM,
- .i386 => ._386,
- .xcore => ._XCORE,
- .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 => ._NONE,
- .bpfel => ._BPF,
- .bpfeb => ._BPF,
- .sparcv9 => ._SPARCV9,
- .s390x => ._S390,
- };
- }
-
- pub fn endian(arch: Arch) builtin.Endian {
- return switch (arch) {
- .avr,
- .arm,
- .aarch64_32,
- .aarch64,
- .amdgcn,
- .amdil,
- .amdil64,
- .bpfel,
- .hexagon,
- .hsail,
- .hsail64,
- .kalimba,
- .le32,
- .le64,
- .mipsel,
- .mips64el,
- .msp430,
- .nvptx,
- .nvptx64,
- .sparcel,
- .tcele,
- .powerpc64le,
- .r600,
- .riscv32,
- .riscv64,
- .i386,
- .x86_64,
- .wasm32,
- .wasm64,
- .xcore,
- .thumb,
- .spir,
- .spir64,
- .renderscript32,
- .renderscript64,
- .shave,
- => .Little,
-
- .arc,
- .armeb,
- .aarch64_be,
- .bpfeb,
- .mips,
- .mips64,
- .powerpc,
- .powerpc64,
- .thumbeb,
- .sparc,
- .sparcv9,
- .tce,
- .lanai,
- .s390x,
- => .Big,
- };
- }
-
- /// Returns a name that matches the lib/std/target/* directory name.
- pub fn genericName(arch: Arch) []const u8 {
- return switch (arch) {
- .arm, .armeb, .thumb, .thumbeb => "arm",
- .aarch64, .aarch64_be, .aarch64_32 => "aarch64",
- .avr => "avr",
- .bpfel, .bpfeb => "bpf",
- .hexagon => "hexagon",
- .mips, .mipsel, .mips64, .mips64el => "mips",
- .msp430 => "msp430",
- .powerpc, .powerpc64, .powerpc64le => "powerpc",
- .amdgcn => "amdgpu",
- .riscv32, .riscv64 => "riscv",
- .sparc, .sparcv9, .sparcel => "sparc",
- .s390x => "systemz",
- .i386, .x86_64 => "x86",
- .nvptx, .nvptx64 => "nvptx",
- .wasm32, .wasm64 => "wasm",
- else => @tagName(arch),
- };
- }
-
- /// All CPU features Zig is aware of, sorted lexicographically by name.
- 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,
- .avr => &avr.all_features,
- .bpfel, .bpfeb => &bpf.all_features,
- .hexagon => &hexagon.all_features,
- .mips, .mipsel, .mips64, .mips64el => &mips.all_features,
- .msp430 => &msp430.all_features,
- .powerpc, .powerpc64, .powerpc64le => &powerpc.all_features,
- .amdgcn => &amdgpu.all_features,
- .riscv32, .riscv64 => &riscv.all_features,
- .sparc, .sparcv9, .sparcel => &sparc.all_features,
- .s390x => &systemz.all_features,
- .i386, .x86_64 => &x86.all_features,
- .nvptx, .nvptx64 => &nvptx.all_features,
- .wasm32, .wasm64 => &wasm.all_features,
-
- else => &[0]Cpu.Feature{},
- };
- }
-
- /// The "default" set of CPU features for cross-compiling. A conservative set
- /// of features that is expected to be supported on most available hardware.
- pub fn getBaselineCpuFeatures(arch: Arch) CpuFeatures {
- const S = struct {
- const generic_cpu = Cpu{
- .name = "generic",
- .llvm_name = null,
- .features = Cpu.Feature.Set.empty,
- };
- };
- const cpu = switch (arch) {
- .arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic,
- .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
- .avr => &avr.cpu.avr1,
- .bpfel, .bpfeb => &bpf.cpu.generic,
- .hexagon => &hexagon.cpu.generic,
- .mips, .mipsel => &mips.cpu.mips32,
- .mips64, .mips64el => &mips.cpu.mips64,
- .msp430 => &msp430.cpu.generic,
- .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic,
- .amdgcn => &amdgpu.cpu.generic,
- .riscv32 => &riscv.cpu.baseline_rv32,
- .riscv64 => &riscv.cpu.baseline_rv64,
- .sparc, .sparcv9, .sparcel => &sparc.cpu.generic,
- .s390x => &systemz.cpu.generic,
- .i386 => &x86.cpu.pentium4,
- .x86_64 => &x86.cpu.x86_64,
- .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
- .wasm32, .wasm64 => &wasm.cpu.generic,
-
- else => &S.generic_cpu,
- };
- return CpuFeatures.initFromCpu(arch, cpu);
- }
-
- /// All CPUs Zig is aware of, sorted lexicographically by name.
- pub fn allCpus(arch: Arch) []const *const Cpu {
- return switch (arch) {
- .arm, .armeb, .thumb, .thumbeb => arm.all_cpus,
- .aarch64, .aarch64_be, .aarch64_32 => aarch64.all_cpus,
- .avr => avr.all_cpus,
- .bpfel, .bpfeb => bpf.all_cpus,
- .hexagon => hexagon.all_cpus,
- .mips, .mipsel, .mips64, .mips64el => mips.all_cpus,
- .msp430 => msp430.all_cpus,
- .powerpc, .powerpc64, .powerpc64le => powerpc.all_cpus,
- .amdgcn => amdgpu.all_cpus,
- .riscv32, .riscv64 => riscv.all_cpus,
- .sparc, .sparcv9, .sparcel => sparc.all_cpus,
- .s390x => systemz.all_cpus,
- .i386, .x86_64 => x86.all_cpus,
- .nvptx, .nvptx64 => nvptx.all_cpus,
- .wasm32, .wasm64 => wasm.all_cpus,
-
- else => &[0]*const Cpu{},
- };
- }
- };
-
pub const Abi = enum {
none,
gnu,
@@ -539,11 +98,102 @@ pub const Target = union(enum) {
coreclr,
simulator,
macabi,
+
+ pub fn default(arch: Cpu.Arch, target_os: Os) Abi {
+ switch (arch) {
+ .wasm32, .wasm64 => return .musl,
+ else => {},
+ }
+ switch (target_os) {
+ .freestanding,
+ .ananas,
+ .cloudabi,
+ .dragonfly,
+ .lv2,
+ .solaris,
+ .haiku,
+ .minix,
+ .rtems,
+ .nacl,
+ .cnk,
+ .aix,
+ .cuda,
+ .nvcl,
+ .amdhsa,
+ .ps4,
+ .elfiamcu,
+ .mesa3d,
+ .contiki,
+ .amdpal,
+ .hermit,
+ .other,
+ => return .eabi,
+ .openbsd,
+ .macosx,
+ .freebsd,
+ .ios,
+ .tvos,
+ .watchos,
+ .fuchsia,
+ .kfreebsd,
+ .netbsd,
+ .hurd,
+ => return .gnu,
+ .windows,
+ .uefi,
+ => return .msvc,
+ .linux,
+ .wasi,
+ .emscripten,
+ => return .musl,
+ }
+ }
+
+ pub fn parse(text: []const u8) !Abi {
+ const info = @typeInfo(Abi);
+ inline for (info.Enum.fields) |field| {
+ if (mem.eql(u8, text, field.name)) {
+ return @field(Abi, field.name);
+ }
+ }
+ return error.UnknownApplicationBinaryInterface;
+ }
+ };
+
+ pub const ObjectFormat = enum {
+ unknown,
+ coff,
+ elf,
+ macho,
+ wasm,
+ };
+
+ pub const SubSystem = enum {
+ Console,
+ Windows,
+ Posix,
+ Native,
+ EfiApplication,
+ EfiBootServiceDriver,
+ EfiRom,
+ EfiRuntimeDriver,
+ };
+
+ pub const Cross = struct {
+ cpu: Cpu,
+ os: Os,
+ abi: Abi,
};
pub const Cpu = struct {
- name: []const u8,
- llvm_name: ?[:0]const u8,
+ /// Architecture
+ arch: Arch,
+
+ /// The CPU model to target. It has a set of features
+ /// which are overridden with the `features` field.
+ model: *const Model,
+
+ /// An explicit list of the entire CPU feature set. It may differ from the specific CPU model's features.
features: Feature.Set,
pub const Feature = struct {
@@ -569,7 +219,7 @@ pub const Target = union(enum) {
pub const Set = struct {
ints: [usize_count]usize,
- pub const needed_bit_count = 174;
+ pub const needed_bit_count = 154;
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(@IntType(false, usize_count * @bitSizeOf(usize)));
@@ -593,6 +243,12 @@ pub const Target = union(enum) {
set.ints[usize_index] |= @as(usize, 1) << bit_index;
}
+ /// Adds the specified feature set but not its dependencies.
+ pub fn addFeatureSet(set: *Set, other_set: Set) void {
+ set.ints = @as(@Vector(usize_count, usize), set.ints) |
+ @as(@Vector(usize_count, usize), other_set.ints);
+ }
+
/// Removes the specified feature but not its dependents.
pub fn removeFeature(set: *Set, arch_feature_index: Index) void {
const usize_index = arch_feature_index / @bitSizeOf(usize);
@@ -608,8 +264,7 @@ pub const Target = union(enum) {
for (all_features_list) |feature, index_usize| {
const index = @intCast(Index, index_usize);
if (set.isEnabled(index)) {
- set.ints = @as(@Vector(usize_count, usize), set.ints) |
- @as(@Vector(usize_count, usize), feature.dependencies.ints);
+ set.addFeatureSet(feature.dependencies);
}
}
const nothing_changed = mem.eql(usize, &old, &set.ints);
@@ -644,77 +299,360 @@ pub const Target = union(enum) {
};
}
};
- };
- pub const ObjectFormat = enum {
- unknown,
- coff,
- elf,
- macho,
- wasm,
- };
+ pub const Arch = enum {
+ arm,
+ armeb,
+ aarch64,
+ aarch64_be,
+ aarch64_32,
+ arc,
+ avr,
+ bpfel,
+ bpfeb,
+ hexagon,
+ mips,
+ mipsel,
+ mips64,
+ mips64el,
+ msp430,
+ powerpc,
+ powerpc64,
+ powerpc64le,
+ r600,
+ amdgcn,
+ riscv32,
+ riscv64,
+ sparc,
+ sparcv9,
+ sparcel,
+ s390x,
+ tce,
+ tcele,
+ thumb,
+ thumbeb,
+ i386,
+ x86_64,
+ xcore,
+ nvptx,
+ nvptx64,
+ le32,
+ le64,
+ amdil,
+ amdil64,
+ hsail,
+ hsail64,
+ spir,
+ spir64,
+ kalimba,
+ shave,
+ lanai,
+ wasm32,
+ wasm64,
+ renderscript32,
+ renderscript64,
+
+ pub fn isARM(arch: Arch) bool {
+ return switch (arch) {
+ .arm, .armeb => true,
+ else => false,
+ };
+ }
- pub const SubSystem = enum {
- Console,
- Windows,
- Posix,
- Native,
- EfiApplication,
- EfiBootServiceDriver,
- EfiRom,
- EfiRuntimeDriver,
- };
+ pub fn isThumb(arch: Arch) bool {
+ return switch (arch) {
+ .thumb, .thumbeb => true,
+ else => false,
+ };
+ }
- pub const Cross = struct {
- arch: Arch,
- os: Os,
- abi: Abi,
- cpu_features: CpuFeatures,
- };
+ pub fn isWasm(arch: Arch) bool {
+ return switch (arch) {
+ .wasm32, .wasm64 => true,
+ else => false,
+ };
+ }
- pub const CpuFeatures = struct {
- /// The CPU to target. It has a set of features
- /// which are overridden with the `features` field.
- cpu: *const Cpu,
+ pub fn isRISCV(arch: Arch) bool {
+ return switch (arch) {
+ .riscv32, .riscv64 => true,
+ else => false,
+ };
+ }
- /// Explicitly provide the entire CPU feature set.
- features: Cpu.Feature.Set,
+ pub fn isMIPS(arch: Arch) bool {
+ return switch (arch) {
+ .mips, .mipsel, .mips64, .mips64el => true,
+ else => false,
+ };
+ }
- pub fn initFromCpu(arch: Arch, cpu: *const Cpu) CpuFeatures {
- var features = cpu.features;
- if (arch.subArchFeature()) |sub_arch_index| {
- features.addFeature(sub_arch_index);
+ pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model {
+ for (arch.allCpuModels()) |cpu| {
+ if (mem.eql(u8, cpu_name, cpu.name)) {
+ return cpu;
+ }
+ }
+ return error.UnknownCpu;
+ }
+
+ pub fn toElfMachine(arch: Arch) std.elf.EM {
+ return switch (arch) {
+ .avr => ._AVR,
+ .msp430 => ._MSP430,
+ .arc => ._ARC,
+ .arm => ._ARM,
+ .armeb => ._ARM,
+ .hexagon => ._HEXAGON,
+ .le32 => ._NONE,
+ .mips => ._MIPS,
+ .mipsel => ._MIPS_RS3_LE,
+ .powerpc => ._PPC,
+ .r600 => ._NONE,
+ .riscv32 => ._RISCV,
+ .sparc => ._SPARC,
+ .sparcel => ._SPARC,
+ .tce => ._NONE,
+ .tcele => ._NONE,
+ .thumb => ._ARM,
+ .thumbeb => ._ARM,
+ .i386 => ._386,
+ .xcore => ._XCORE,
+ .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 => ._NONE,
+ .bpfel => ._BPF,
+ .bpfeb => ._BPF,
+ .sparcv9 => ._SPARCV9,
+ .s390x => ._S390,
+ };
}
- features.populateDependencies(arch.allFeaturesList());
- return CpuFeatures{
- .cpu = cpu,
- .features = features,
+
+ pub fn endian(arch: Arch) builtin.Endian {
+ return switch (arch) {
+ .avr,
+ .arm,
+ .aarch64_32,
+ .aarch64,
+ .amdgcn,
+ .amdil,
+ .amdil64,
+ .bpfel,
+ .hexagon,
+ .hsail,
+ .hsail64,
+ .kalimba,
+ .le32,
+ .le64,
+ .mipsel,
+ .mips64el,
+ .msp430,
+ .nvptx,
+ .nvptx64,
+ .sparcel,
+ .tcele,
+ .powerpc64le,
+ .r600,
+ .riscv32,
+ .riscv64,
+ .i386,
+ .x86_64,
+ .wasm32,
+ .wasm64,
+ .xcore,
+ .thumb,
+ .spir,
+ .spir64,
+ .renderscript32,
+ .renderscript64,
+ .shave,
+ => .Little,
+
+ .arc,
+ .armeb,
+ .aarch64_be,
+ .bpfeb,
+ .mips,
+ .mips64,
+ .powerpc,
+ .powerpc64,
+ .thumbeb,
+ .sparc,
+ .sparcv9,
+ .tce,
+ .lanai,
+ .s390x,
+ => .Big,
+ };
+ }
+
+ /// Returns a name that matches the lib/std/target/* directory name.
+ pub fn genericName(arch: Arch) []const u8 {
+ return switch (arch) {
+ .arm, .armeb, .thumb, .thumbeb => "arm",
+ .aarch64, .aarch64_be, .aarch64_32 => "aarch64",
+ .avr => "avr",
+ .bpfel, .bpfeb => "bpf",
+ .hexagon => "hexagon",
+ .mips, .mipsel, .mips64, .mips64el => "mips",
+ .msp430 => "msp430",
+ .powerpc, .powerpc64, .powerpc64le => "powerpc",
+ .amdgcn => "amdgpu",
+ .riscv32, .riscv64 => "riscv",
+ .sparc, .sparcv9, .sparcel => "sparc",
+ .s390x => "systemz",
+ .i386, .x86_64 => "x86",
+ .nvptx, .nvptx64 => "nvptx",
+ .wasm32, .wasm64 => "wasm",
+ else => @tagName(arch),
+ };
+ }
+
+ /// All CPU features Zig is aware of, sorted lexicographically by name.
+ 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,
+ .avr => &avr.all_features,
+ .bpfel, .bpfeb => &bpf.all_features,
+ .hexagon => &hexagon.all_features,
+ .mips, .mipsel, .mips64, .mips64el => &mips.all_features,
+ .msp430 => &msp430.all_features,
+ .powerpc, .powerpc64, .powerpc64le => &powerpc.all_features,
+ .amdgcn => &amdgpu.all_features,
+ .riscv32, .riscv64 => &riscv.all_features,
+ .sparc, .sparcv9, .sparcel => &sparc.all_features,
+ .s390x => &systemz.all_features,
+ .i386, .x86_64 => &x86.all_features,
+ .nvptx, .nvptx64 => &nvptx.all_features,
+ .wasm32, .wasm64 => &wasm.all_features,
+
+ else => &[0]Cpu.Feature{},
+ };
+ }
+
+ /// All processors Zig is aware of, sorted lexicographically by name.
+ pub fn allCpuModels(arch: Arch) []const *const Cpu.Model {
+ return switch (arch) {
+ .arm, .armeb, .thumb, .thumbeb => arm.all_cpus,
+ .aarch64, .aarch64_be, .aarch64_32 => aarch64.all_cpus,
+ .avr => avr.all_cpus,
+ .bpfel, .bpfeb => bpf.all_cpus,
+ .hexagon => hexagon.all_cpus,
+ .mips, .mipsel, .mips64, .mips64el => mips.all_cpus,
+ .msp430 => msp430.all_cpus,
+ .powerpc, .powerpc64, .powerpc64le => powerpc.all_cpus,
+ .amdgcn => amdgpu.all_cpus,
+ .riscv32, .riscv64 => riscv.all_cpus,
+ .sparc, .sparcv9, .sparcel => sparc.all_cpus,
+ .s390x => systemz.all_cpus,
+ .i386, .x86_64 => x86.all_cpus,
+ .nvptx, .nvptx64 => nvptx.all_cpus,
+ .wasm32, .wasm64 => wasm.all_cpus,
+
+ else => &[0]*const Model{},
+ };
+ }
+
+ pub fn parse(text: []const u8) !Arch {
+ const info = @typeInfo(Arch);
+ inline for (info.Enum.fields) |field| {
+ if (mem.eql(u8, text, field.name)) {
+ return @as(Arch, @field(Arch, field.name));
+ }
+ }
+ return error.UnknownArchitecture;
+ }
+ };
+
+ 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,
+ };
+ }
+ };
+
+ /// The "default" set of CPU features for cross-compiling. A conservative set
+ /// of features that is expected to be supported on most available hardware.
+ pub fn baseline(arch: Arch) Cpu {
+ const S = struct {
+ const generic_model = Model{
+ .name = "generic",
+ .llvm_name = null,
+ .features = Cpu.Feature.Set.empty,
+ };
+ };
+ const model = switch (arch) {
+ .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline,
+ .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
+ .avr => &avr.cpu.avr1,
+ .bpfel, .bpfeb => &bpf.cpu.generic,
+ .hexagon => &hexagon.cpu.generic,
+ .mips, .mipsel => &mips.cpu.mips32,
+ .mips64, .mips64el => &mips.cpu.mips64,
+ .msp430 => &msp430.cpu.generic,
+ .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic,
+ .amdgcn => &amdgpu.cpu.generic,
+ .riscv32 => &riscv.cpu.baseline_rv32,
+ .riscv64 => &riscv.cpu.baseline_rv64,
+ .sparc, .sparcv9, .sparcel => &sparc.cpu.generic,
+ .s390x => &systemz.cpu.generic,
+ .i386 => &x86.cpu.pentium4,
+ .x86_64 => &x86.cpu.x86_64,
+ .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
+ .wasm32, .wasm64 => &wasm.cpu.generic,
+
+ else => &S.generic_model,
};
+ return model.toCpu(arch);
}
};
pub const current = Target{
.Cross = Cross{
- .arch = builtin.arch,
+ .cpu = builtin.cpu,
.os = builtin.os,
.abi = builtin.abi,
- .cpu_features = builtin.cpu_features,
},
};
pub const stack_align = 16;
- pub fn getCpuFeatures(self: Target) CpuFeatures {
- return switch (self) {
- .Native => builtin.cpu_features,
- .Cross => |cross| cross.cpu_features,
- };
- }
-
pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
- return std.fmt.allocPrint(allocator, "{}{}-{}-{}", .{
+ return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
@tagName(self.getArch()),
- Target.archSubArchName(self.getArch()),
@tagName(self.getOs()),
@tagName(self.getAbi()),
});
@@ -776,139 +714,115 @@ pub const Target = union(enum) {
});
}
- /// TODO: Support CPU features here?
- /// https://github.com/ziglang/zig/issues/4261
- pub fn parse(text: []const u8) !Target {
- var it = mem.separate(text, "-");
- const arch_name = it.next() orelse return error.MissingArchitecture;
- const os_name = it.next() orelse return error.MissingOperatingSystem;
- const abi_name = it.next();
- const arch = try parseArchSub(arch_name);
+ pub const ParseOptions = struct {
+ /// This is sometimes called a "triple". It looks roughly like this:
+ /// riscv64-linux-gnu
+ /// The fields are, respectively:
+ /// * CPU Architecture
+ /// * Operating System
+ /// * C ABI (optional)
+ arch_os_abi: []const u8,
- var cross = Cross{
- .arch = arch,
- .cpu_features = arch.getBaselineCpuFeatures(),
- .os = try parseOs(os_name),
- .abi = undefined,
- };
- cross.abi = if (abi_name) |n| try parseAbi(n) else defaultAbi(cross.arch, cross.os);
- return Target{ .Cross = cross };
- }
+ /// Looks like "name+a+b-c-d+e", where "name" is a CPU Model name, "a", "b", and "e"
+ /// are examples of CPU features to add to the set, and "c" and "d" are examples of CPU features
+ /// to remove from the set.
+ cpu_features: []const u8 = "baseline",
- pub fn defaultAbi(arch: Arch, target_os: Os) Abi {
- switch (arch) {
- .wasm32, .wasm64 => return .musl,
- else => {},
- }
- switch (target_os) {
- .freestanding,
- .ananas,
- .cloudabi,
- .dragonfly,
- .lv2,
- .solaris,
- .haiku,
- .minix,
- .rtems,
- .nacl,
- .cnk,
- .aix,
- .cuda,
- .nvcl,
- .amdhsa,
- .ps4,
- .elfiamcu,
- .mesa3d,
- .contiki,
- .amdpal,
- .hermit,
- .other,
- => return .eabi,
- .openbsd,
- .macosx,
- .freebsd,
- .ios,
- .tvos,
- .watchos,
- .fuchsia,
- .kfreebsd,
- .netbsd,
- .hurd,
- => return .gnu,
- .windows,
- .uefi,
- => return .msvc,
- .linux,
- .wasi,
- .emscripten,
- => return .musl,
- }
- }
+ /// If this is provided, the function will populate some information about parsing failures,
+ /// so that user-friendly error messages can be delivered.
+ diagnostics: ?*Diagnostics = null,
- pub const ParseArchSubError = error{
- UnknownArchitecture,
- UnknownSubArchitecture,
- };
+ pub const Diagnostics = struct {
+ /// If the architecture was determined, this will be populated.
+ arch: ?Cpu.Arch = null,
- pub fn parseArchSub(text: []const u8) ParseArchSubError!Arch {
- const info = @typeInfo(Arch);
- inline for (info.Union.fields) |field| {
- if (mem.startsWith(u8, text, field.name)) {
- if (field.field_type == void) {
- return @as(Arch, @field(Arch, field.name));
- } else {
- const sub_info = @typeInfo(field.field_type);
- inline for (sub_info.Enum.fields) |sub_field| {
- const combined = field.name ++ sub_field.name;
- if (mem.eql(u8, text, combined)) {
- return @unionInit(Arch, field.name, @field(field.field_type, sub_field.name));
- }
- }
- return error.UnknownSubArchitecture;
- }
- }
- }
- return error.UnknownArchitecture;
- }
+ /// If the OS was determined, this will be populated.
+ os: ?Os = null,
- pub fn parseOs(text: []const u8) !Os {
- const info = @typeInfo(Os);
- inline for (info.Enum.fields) |field| {
- if (mem.eql(u8, text, field.name)) {
- return @field(Os, field.name);
- }
- }
- return error.UnknownOperatingSystem;
- }
+ /// If the ABI was determined, this will be populated.
+ abi: ?Abi = null,
- pub fn parseAbi(text: []const u8) !Abi {
- const info = @typeInfo(Abi);
- inline for (info.Enum.fields) |field| {
- if (mem.eql(u8, text, field.name)) {
- return @field(Abi, field.name);
- }
- }
- return error.UnknownApplicationBinaryInterface;
- }
+ /// If the CPU name was determined, this will be populated.
+ cpu_name: ?[]const u8 = null,
- fn archSubArchName(arch: Arch) []const u8 {
- return switch (arch) {
- .arm => |sub| @tagName(sub),
- .armeb => |sub| @tagName(sub),
- .thumb => |sub| @tagName(sub),
- .thumbeb => |sub| @tagName(sub),
- .aarch64 => |sub| @tagName(sub),
- .aarch64_be => |sub| @tagName(sub),
- .kalimba => |sub| @tagName(sub),
- else => "",
+ /// If error.UnknownCpuFeature is returned, this will be populated.
+ unknown_feature_name: ?[]const u8 = null,
};
- }
+ };
- pub fn subArchName(self: Target) []const u8 {
- switch (self) {
- .Native => return archSubArchName(builtin.arch),
- .Cross => |cross| return archSubArchName(cross.arch),
+ pub fn parse(args: ParseOptions) !Target {
+ var dummy_diags: ParseOptions.Diagnostics = undefined;
+ var diags = args.diagnostics orelse &dummy_diags;
+
+ var it = mem.separate(args.arch_os_abi, "-");
+ const arch_name = it.next() orelse return error.MissingArchitecture;
+ const arch = try Cpu.Arch.parse(arch_name);
+ diags.arch = arch;
+
+ const os_name = it.next() orelse return error.MissingOperatingSystem;
+ const os = try Os.parse(os_name);
+ diags.os = os;
+
+ const abi_name = it.next();
+ const abi = if (abi_name) |n| try Abi.parse(n) else Abi.default(arch, os);
+ diags.abi = abi;
+
+ if (it.next() != null) return error.UnexpectedExtraField;
+
+ const all_features = arch.allFeaturesList();
+ var index: usize = 0;
+ while (index < args.cpu_features.len and
+ args.cpu_features[index] != '+' and
+ args.cpu_features[index] != '-')
+ {
+ index += 1;
}
+ const cpu_name = args.cpu_features[0..index];
+ diags.cpu_name = cpu_name;
+
+ const cpu: Cpu = if (mem.eql(u8, cpu_name, "baseline")) Cpu.baseline(arch) else blk: {
+ const cpu_model = try arch.parseCpuModel(cpu_name);
+
+ var set = cpu_model.features;
+ while (index < args.cpu_features.len) {
+ const op = args.cpu_features[index];
+ index += 1;
+ const start = index;
+ while (index < args.cpu_features.len and
+ args.cpu_features[index] != '+' and
+ args.cpu_features[index] != '-')
+ {
+ index += 1;
+ }
+ const feature_name = args.cpu_features[start..index];
+ for (all_features) |feature, feat_index_usize| {
+ const feat_index = @intCast(Cpu.Feature.Set.Index, feat_index_usize);
+ if (mem.eql(u8, feature_name, feature.name)) {
+ switch (op) {
+ '+' => set.addFeature(feat_index),
+ '-' => set.removeFeature(feat_index),
+ else => unreachable,
+ }
+ break;
+ }
+ } else {
+ diags.unknown_feature_name = feature_name;
+ return error.UnknownCpuFeature;
+ }
+ }
+ set.populateDependencies(all_features);
+ break :blk .{
+ .arch = arch,
+ .model = cpu_model,
+ .features = set,
+ };
+ };
+ var cross = Cross{
+ .cpu = cpu,
+ .os = os,
+ .abi = abi,
+ };
+ return Target{ .Cross = cross };
}
pub fn oFileExt(self: Target) []const u8 {
@@ -967,11 +881,15 @@ pub const Target = union(enum) {
};
}
- pub fn getArch(self: Target) Arch {
- switch (self) {
- .Native => return builtin.arch,
- .Cross => |t| return t.arch,
- }
+ pub fn getCpu(self: Target) Cpu {
+ return switch (self) {
+ .Native => builtin.cpu,
+ .Cross => |cross| cross.cpu,
+ };
+ }
+
+ pub fn getArch(self: Target) Cpu.Arch {
+ return self.getCpu().arch;
}
pub fn getAbi(self: Target) Abi {
@@ -1372,14 +1290,32 @@ pub const Target = union(enum) {
}
};
-test "parseCpuFeatureSet" {
- const arch: Target.Arch = .x86_64;
- const baseline = arch.getBaselineCpuFeatures();
- const set = try arch.parseCpuFeatureSet(baseline.cpu, "-sse,-avx,-cx8");
- std.testing.expect(!Target.x86.featureSetHas(set, .sse));
- std.testing.expect(!Target.x86.featureSetHas(set, .avx));
- std.testing.expect(!Target.x86.featureSetHas(set, .cx8));
- // These are expected because they are part of the baseline
- std.testing.expect(Target.x86.featureSetHas(set, .cmov));
- std.testing.expect(Target.x86.featureSetHas(set, .fxsr));
+test "Target.parse" {
+ {
+ const target = (try Target.parse(.{
+ .arch_os_abi = "x86_64-linux-gnu",
+ .cpu_features = "x86_64-sse-sse2-avx-cx8",
+ })).Cross;
+
+ std.testing.expect(target.os == .linux);
+ std.testing.expect(target.abi == .gnu);
+ std.testing.expect(target.cpu.arch == .x86_64);
+ std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .sse));
+ std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .avx));
+ std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .cx8));
+ std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .cmov));
+ std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .fxsr));
+ }
+ {
+ const target = (try Target.parse(.{
+ .arch_os_abi = "arm-linux-musleabihf",
+ .cpu_features = "generic+v8a",
+ })).Cross;
+
+ std.testing.expect(target.os == .linux);
+ std.testing.expect(target.abi == .musleabihf);
+ std.testing.expect(target.cpu.arch == .arm);
+ std.testing.expect(target.cpu.model == &Target.arm.cpu.generic);
+ std.testing.expect(Target.arm.featureSetHas(target.cpu.features, .v8a));
+ }
}