progress towards merging

see BRANCH_TODO file
This commit is contained in:
Andrew Kelley 2020-01-19 02:40:35 -05:00
parent c15623428e
commit a867b43366
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
17 changed files with 2108 additions and 2063 deletions

55
BRANCH_TODO Normal file
View File

@ -0,0 +1,55 @@
Finish these thigns before merging teh branch
* need to populate builtin.zig cpu_features, undefined is incorrect. I guess for zig0 it will be always baseline
* need to populate std.Target.current.cpu_features even for native target
* finish refactoring target/arch/*
* `zig builtin` integration
* move target details to better location
* +foo,-bar vs foo,bar
* baseline features
const riscv32_default_features: []*const std.target.Feature = &[_]*const std.target.Feature{
&std.target.riscv.feature_a,
&std.target.riscv.feature_c,
&std.target.riscv.feature_d,
&std.target.riscv.feature_f,
&std.target.riscv.feature_m,
&std.target.riscv.feature_relax,
};
const riscv64_default_features: []*const std.target.Feature = &[_]*const std.target.Feature{
&std.target.riscv.feature_bit64,
&std.target.riscv.feature_a,
&std.target.riscv.feature_c,
&std.target.riscv.feature_d,
&std.target.riscv.feature_f,
&std.target.riscv.feature_m,
&std.target.riscv.feature_relax,
};
const i386_default_features: []*const std.target.Feature = &[_]*const std.target.Feature{
&std.target.x86.feature_cmov,
&std.target.x86.feature_cx8,
&std.target.x86.feature_fxsr,
&std.target.x86.feature_mmx,
&std.target.x86.feature_nopl,
&std.target.x86.feature_sse,
&std.target.x86.feature_sse2,
&std.target.x86.feature_slowUnalignedMem16,
&std.target.x86.feature_x87,
};
// Same as above but without sse.
const i386_default_features_freestanding: []*const std.target.Feature = &[_]*const std.target.Feature{
&std.target.x86.feature_cmov,
&std.target.x86.feature_cx8,
&std.target.x86.feature_fxsr,
&std.target.x86.feature_mmx,
&std.target.x86.feature_nopl,
&std.target.x86.feature_slowUnalignedMem16,
&std.target.x86.feature_x87,
};

View File

@ -57,11 +57,11 @@ pub const Buffer = struct {
/// The caller owns the returned memory. The Buffer becomes null and /// The caller owns the returned memory. The Buffer becomes null and
/// is safe to `deinit`. /// is safe to `deinit`.
pub fn toOwnedSlice(self: *Buffer) []u8 { pub fn toOwnedSlice(self: *Buffer) [:0]u8 {
const allocator = self.list.allocator; const allocator = self.list.allocator;
const result = allocator.shrink(self.list.items, self.len()); const result = allocator.shrink(self.list.items, self.len());
self.* = initNull(allocator); self.* = initNull(allocator);
return result; return result[0 .. result.len - 1 :0];
} }
pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: var) !Buffer { pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: var) !Buffer {

View File

@ -1199,8 +1199,6 @@ pub const LibExeObjStep = struct {
subsystem: ?builtin.SubSystem = null, subsystem: ?builtin.SubSystem = null,
target_details: ?std.target.TargetDetails = null,
const LinkObject = union(enum) { const LinkObject = union(enum) {
StaticPath: []const u8, StaticPath: []const u8,
OtherStep: *LibExeObjStep, OtherStep: *LibExeObjStep,
@ -1386,10 +1384,6 @@ pub const LibExeObjStep = struct {
self.computeOutFileNames(); self.computeOutFileNames();
} }
pub fn setTargetDetails(self: *LibExeObjStep, target_details: std.target.TargetDetails) void {
self.target_details = target_details;
}
pub fn setTargetGLibC(self: *LibExeObjStep, major: u32, minor: u32, patch: u32) void { pub fn setTargetGLibC(self: *LibExeObjStep, major: u32, minor: u32, patch: u32) void {
self.target_glibc = Version{ self.target_glibc = Version{
.major = major, .major = major,
@ -1974,34 +1968,33 @@ pub const LibExeObjStep = struct {
switch (self.target) { switch (self.target) {
.Native => {}, .Native => {},
.Cross => { .Cross => |cross| {
try zig_args.append("-target"); try zig_args.append("-target");
try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable); try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable);
switch (cross.cpu_features) {
.baseline => {},
.cpu => |cpu| {
try zig_args.append("-target-cpu");
try zig_args.append(cpu.name);
},
.features => |features| {
try zig_args.append("-target-cpu-features");
var feature_str_buffer = try std.Buffer.initSize(builder.allocator, 0);
for (self.target.getArch().allFeaturesList()) |feature, i| {
if (Target.Cpu.Feature.isEnabled(features, @intCast(u7, i))) {
try feature_str_buffer.append(feature.name);
try feature_str_buffer.append(",");
}
}
try zig_args.append(feature_str_buffer.toSlice());
},
}
}, },
} }
if (self.target_details) |td| {
switch (td) {
.cpu => |cpu| {
try zig_args.append("--cpu");
try zig_args.append(cpu.name);
},
.features => |features| {
try zig_args.append("--features");
var feature_str_buffer = try std.Buffer.initSize(builder.allocator, 0);
defer feature_str_buffer.deinit();
for (features) |feature| {
try feature_str_buffer.append(feature.name);
try feature_str_buffer.append(",");
}
try zig_args.append(feature_str_buffer.toOwnedSlice());
},
}
}
if (self.target_glibc) |ver| { if (self.target_glibc) |ver| {
try zig_args.append("-target-glibc"); try zig_args.append("-target-glibc");
try zig_args.append(builder.fmt("{}.{}.{}", .{ ver.major, ver.minor, ver.patch })); try zig_args.append(builder.fmt("{}.{}.{}", .{ ver.major, ver.minor, ver.patch }));

View File

@ -15,6 +15,12 @@ pub const ObjectFormat = std.Target.ObjectFormat;
/// Deprecated: use `std.Target.SubSystem`. /// Deprecated: use `std.Target.SubSystem`.
pub const SubSystem = std.Target.SubSystem; pub const SubSystem = std.Target.SubSystem;
/// Deprecated: use `std.Target.Cross.CpuFeatures`.
pub const CpuFeatures = std.Target.Cross.CpuFeatures;
/// Deprecated: use `std.Target.Cpu`.
pub const Cpu = std.Target.Cpu;
/// `explicit_subsystem` is missing when the subsystem is automatically detected, /// `explicit_subsystem` is missing when the subsystem is automatically detected,
/// so Zig standard library has the subsystem detection logic here. This should generally be /// so Zig standard library has the subsystem detection logic here. This should generally be
/// used rather than `explicit_subsystem`. /// used rather than `explicit_subsystem`.

View File

@ -1138,6 +1138,11 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
size.* += bytes.len; size.* += bytes.len;
} }
pub fn allocPrint0(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![:0]u8 {
const result = try allocPrint(allocator, fmt ++ "\x00", args);
return result[0 .. result.len - 1 :0];
}
test "bufPrintInt" { test "bufPrintInt" {
var buffer: [100]u8 = undefined; var buffer: [100]u8 = undefined;
const buf = buffer[0..]; const buf = buffer[0..];

View File

@ -556,3 +556,21 @@ pub fn refAllDecls(comptime T: type) void {
if (!builtin.is_test) return; if (!builtin.is_test) return;
_ = declarations(T); _ = declarations(T);
} }
/// Returns a slice of pointers to public declarations of a namespace.
pub fn declList(comptime Namespace: type, comptime Decl: type) []const *const Decl {
const S = struct {
fn declNameLessThan(lhs: *const Decl, rhs: *const Decl) bool {
return mem.lessThan(u8, lhs.name, rhs.name);
}
};
comptime {
const decls = declarations(Namespace);
var array: [decls.len]*const Decl = undefined;
for (decls) |decl, i| {
array[i] = &@field(Namespace, decl.name);
}
std.sort.sort(*const Decl, &array, S.declNameLessThan);
return &array;
}
}

View File

@ -211,7 +211,7 @@ pub fn initTLS() ?*elf.Phdr {
if (tls_phdr) |phdr| { if (tls_phdr) |phdr| {
// If the cpu is arm-based, check if it supports the TLS register // If the cpu is arm-based, check if it supports the TLS register
if (builtin.arch == builtin.Arch.arm and at_hwcap & std.os.linux.HWCAP_TLS == 0) { if (builtin.arch == .arm and at_hwcap & std.os.linux.HWCAP_TLS == 0) {
// If the CPU does not support TLS via a coprocessor register, // If the CPU does not support TLS via a coprocessor register,
// a kernel helper function can be used instead on certain linux kernels. // a kernel helper function can be used instead on certain linux kernels.
// See linux/arch/arm/include/asm/tls.h and musl/src/thread/arm/__set_thread_area.c. // See linux/arch/arm/include/asm/tls.h and musl/src/thread/arm/__set_thread_area.c.

View File

@ -60,7 +60,6 @@ pub const rand = @import("rand.zig");
pub const rb = @import("rb.zig"); pub const rb = @import("rb.zig");
pub const sort = @import("sort.zig"); pub const sort = @import("sort.zig");
pub const ascii = @import("ascii.zig"); pub const ascii = @import("ascii.zig");
pub const target = @import("target.zig");
pub const testing = @import("testing.zig"); pub const testing = @import("testing.zig");
pub const time = @import("time.zig"); pub const time = @import("time.zig");
pub const unicode = @import("unicode.zig"); pub const unicode = @import("unicode.zig");

View File

@ -101,6 +101,22 @@ pub const Target = union(enum) {
renderscript32, renderscript32,
renderscript64, renderscript64,
pub const aarch64 = @import("target/aarch64.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 hexagon = @import("target/hexagon.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 systemz = @import("target/systemz.zig");
pub const wasm = @import("target/wasm.zig");
pub const x86 = @import("target/x86.zig");
pub const Arm32 = enum { pub const Arm32 = enum {
v8_5a, v8_5a,
v8_4a, v8_4a,
@ -184,6 +200,71 @@ pub const Target = union(enum) {
}; };
} }
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;
}
/// This parsing function supports 2 syntaxes.
/// * Comma-separated list of features, with + or - in front of each feature. This
/// form represents a deviation from baseline.
/// * Comma-separated list of features, with no + or - in front of each feature. This
/// form represents an exclusive list of enabled features; no other features besides
/// the ones listed, and their dependencies, will be enabled.
/// Extra commas are ignored.
pub fn parseCpuFeatureSet(arch: Arch, features_text: []const u8) !Cpu.Feature.Set {
// Here we compute both and choose the correct result at the end, based
// on whether or not we saw + and - signs.
var set: @Vector(2, Cpu.Feature.Set) = [2]Cpu.Feature.Set{ 0, arch.baselineFeatures() };
var mode: enum {
unknown,
baseline,
whitelist,
} = .unknown;
var it = mem.tokenize(features_text, ",");
while (it.next()) |item_text| {
const feature_name = blk: {
if (mem.startsWith(u8, item_text, "+")) {
switch (mode) {
.unknown, .baseline => mode = .baseline,
.whitelist => return error.InvalidCpuFeatures,
}
break :blk item_text[1..];
} else if (mem.startsWith(u8, item_text, "-")) {
switch (mode) {
.unknown, .baseline => mode = .baseline,
.whitelist => return error.InvalidCpuFeatures,
}
break :blk item_text[1..];
} else {
switch (mode) {
.unknown, .whitelist => mode = .whitelist,
.baseline => return error.InvalidCpuFeatures,
}
break :blk item_text;
}
};
for (arch.allFeaturesList()) |feature, index| {
if (mem.eql(u8, feature_name, feature.name)) {
set |= @splat(2, 1 << index);
break;
}
} else {
return error.UnknownCpuFeature;
}
}
return switch (mode) {
.unknown, .whitelist => set[0],
.baseline => set[1],
};
}
pub fn toElfMachine(arch: Arch) std.elf.EM { pub fn toElfMachine(arch: Arch) std.elf.EM {
return switch (arch) { return switch (arch) {
.avr => ._AVR, .avr => ._AVR,
@ -296,6 +377,98 @@ pub const Target = union(enum) {
=> .Big, => .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 *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]*const 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 baselineFeatures(arch: Arch) Cpu.Feature.Set {
return switch (arch) {
.arm, .armeb, .thumb, .thumbeb => arm.baseline_features,
.aarch64, .aarch64_be, .aarch64_32 => aarch64.cpu.generic.features,
.avr => avr.baseline_features,
.bpfel, .bpfeb => bpf.baseline_features,
.hexagon => hexagon.baseline_features,
.mips, .mipsel, .mips64, .mips64el => mips.baseline_features,
.msp430 => msp430.baseline_features,
.powerpc, .powerpc64, .powerpc64le => powerpc.baseline_features,
.amdgcn => amdgpu.baseline_features,
.riscv32, .riscv64 => riscv.baseline_features,
.sparc, .sparcv9, .sparcel => sparc.baseline_features,
.s390x => systemz.baseline_features,
.i386, .x86_64 => x86.baseline_features,
.nvptx, .nvptx64 => nvptx.baseline_features,
.wasm32, .wasm64 => wasm.baseline_features,
else => &[0]*const Cpu.Feature{},
};
}
/// 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 { pub const Abi = enum {
@ -323,6 +496,28 @@ pub const Target = union(enum) {
macabi, macabi,
}; };
pub const Cpu = struct {
name: []const u8,
llvm_name: ?[:0]const u8,
features: Feature.Set,
pub const Feature = struct {
/// The bit index into `Set`.
index: u8,
name: []const u8,
llvm_name: ?[:0]const u8,
description: []const u8,
dependencies: Set,
/// A bit set of all the features.
pub const Set = u128;
pub fn isEnabled(set: Set, arch_feature_index: u7) bool {
return (set & (@as(Set, 1) << arch_feature_index)) != 0;
}
};
};
pub const ObjectFormat = enum { pub const ObjectFormat = enum {
unknown, unknown,
coff, coff,
@ -346,6 +541,19 @@ pub const Target = union(enum) {
arch: Arch, arch: Arch,
os: Os, os: Os,
abi: Abi, abi: Abi,
cpu_features: CpuFeatures = .baseline,
pub const CpuFeatures = union(enum) {
/// The "default" set of CPU features for cross-compiling. A conservative set
/// of features that is expected to be supported on most available hardware.
baseline,
/// Target one specific CPU.
cpu: *const Cpu,
/// Explicitly provide the entire CPU feature set.
features: Cpu.Feature.Set,
};
}; };
pub const current = Target{ pub const current = Target{
@ -353,11 +561,20 @@ pub const Target = union(enum) {
.arch = builtin.arch, .arch = builtin.arch,
.os = builtin.os, .os = builtin.os,
.abi = builtin.abi, .abi = builtin.abi,
.cpu_features = builtin.cpu_features,
}, },
}; };
pub const stack_align = 16; pub const stack_align = 16;
pub fn cpuFeatures(self: Target) []const *const Cpu.Feature {
return switch (self.cpu_features) {
.baseline => self.arch.baselineFeatures(),
.cpu => |cpu| cpu.features,
.features => |features| features,
};
}
pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 { pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
return std.fmt.allocPrint(allocator, "{}{}-{}-{}", .{ return std.fmt.allocPrint(allocator, "{}{}-{}-{}", .{
@tagName(self.getArch()), @tagName(self.getArch()),
@ -496,7 +713,7 @@ pub const Target = union(enum) {
pub fn parseArchSub(text: []const u8) ParseArchSubError!Arch { pub fn parseArchSub(text: []const u8) ParseArchSubError!Arch {
const info = @typeInfo(Arch); const info = @typeInfo(Arch);
inline for (info.Union.fields) |field| { inline for (info.Union.fields) |field| {
if (text.len >= field.name.len and mem.eql(u8, text[0..field.name.len], field.name)) { if (mem.eql(u8, text, field.name)) {
if (field.field_type == void) { if (field.field_type == void) {
return @as(Arch, @field(Arch, field.name)); return @as(Arch, @field(Arch, field.name));
} else { } else {
@ -514,31 +731,6 @@ pub const Target = union(enum) {
return error.UnknownArchitecture; return error.UnknownArchitecture;
} }
pub fn parseArchTag(text: []const u8) ParseArchSubError!@TagType(Arch) {
const info = @typeInfo(Arch);
inline for (info.Union.fields) |field| {
if (text.len >= field.name.len and mem.eql(u8, text[0..field.name.len], field.name)) {
if (text.len == field.name.len) return @as(@TagType(Arch), @field(Arch, field.name));
if (field.field_type == void) {
return error.UnknownArchitecture;
}
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 @as(@TagType(Arch), @field(Arch, field.name));
}
}
return error.UnknownSubArchitecture;
}
}
return error.UnknownArchitecture;
}
pub fn parseOs(text: []const u8) !Os { pub fn parseOs(text: []const u8) !Os {
const info = @typeInfo(Os); const info = @typeInfo(Os);
inline for (info.Enum.fields) |field| { inline for (info.Enum.fields) |field| {
@ -841,83 +1033,3 @@ pub const Target = union(enum) {
return .unavailable; return .unavailable;
} }
}; };
pub const aarch64 = @import("target/aarch64.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 hexagon = @import("target/hexagon.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 systemz = @import("target/systemz.zig");
pub const wasm = @import("target/wasm.zig");
pub const x86 = @import("target/x86.zig");
pub const Feature = struct {
name: []const u8,
llvm_name: ?[]const u8,
description: []const u8,
dependencies: []*const Feature,
};
pub const Cpu = struct {
name: []const u8,
llvm_name: ?[]const u8,
dependencies: []*const Feature,
};
pub const TargetDetails = union(enum) {
cpu: *const Cpu,
features: []*const Feature,
};
pub fn getFeaturesForArch(arch: @TagType(Target.Arch)) []*const Feature {
return switch (arch) {
.arm, .armeb, .thumb, .thumbeb => arm.features,
.aarch64, .aarch64_be, .aarch64_32 => aarch64.features,
.avr => avr.features,
.bpfel, .bpfeb => bpf.features,
.hexagon => hexagon.features,
.mips, .mipsel, .mips64, .mips64el => mips.features,
.msp430 => msp430.features,
.powerpc, .powerpc64, .powerpc64le => powerpc.features,
.amdgcn => amdgpu.features,
.riscv32, .riscv64 => riscv.features,
.sparc, .sparcv9, .sparcel => sparc.features,
.s390x => systemz.features,
.i386, .x86_64 => x86.features,
.nvptx, .nvptx64 => nvptx.features,
.wasm32, .wasm64 => wasm.features,
else => &[_]*const Feature{},
};
}
pub fn getCpusForArch(arch: @TagType(Target.Arch)) []*const Cpu {
return switch (arch) {
.arm, .armeb, .thumb, .thumbeb => arm.cpus,
.aarch64, .aarch64_be, .aarch64_32 => aarch64.cpus,
.avr => avr.cpus,
.bpfel, .bpfeb => bpf.cpus,
.hexagon => hexagon.cpus,
.mips, .mipsel, .mips64, .mips64el => mips.cpus,
.msp430 => msp430.cpus,
.powerpc, .powerpc64, .powerpc64le => powerpc.cpus,
.amdgcn => amdgpu.cpus,
.riscv32, .riscv64 => riscv.cpus,
.sparc, .sparcv9, .sparcel => sparc.cpus,
.s390x => systemz.cpus,
.i386, .x86_64 => x86.cpus,
.nvptx, .nvptx64 => nvptx.cpus,
.wasm32, .wasm64 => wasm.cpus,
else => &[_]*const Cpu{},
};
}

File diff suppressed because it is too large Load Diff

View File

@ -81,6 +81,9 @@ const Error = extern enum {
OperationAborted, OperationAborted,
BrokenPipe, BrokenPipe,
NoSpaceLeft, NoSpaceLeft,
NotLazy,
IsAsync,
ImportOutsidePkgPath,
}; };
const FILE = std.c.FILE; const FILE = std.c.FILE;
@ -150,7 +153,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
const argc_usize = @intCast(usize, argc); const argc_usize = @intCast(usize, argc);
var arg_i: usize = 0; var arg_i: usize = 0;
while (arg_i < argc_usize) : (arg_i += 1) { while (arg_i < argc_usize) : (arg_i += 1) {
try args_list.append(std.mem.toSliceConst(u8, argv[arg_i])); try args_list.append(mem.toSliceConst(u8, argv[arg_i]));
} }
stdout = &std.io.getStdOut().outStream().stream; stdout = &std.io.getStdOut().outStream().stream;
@ -532,7 +535,7 @@ export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usiz
// ABI warning // ABI warning
export fn stage2_list_features_for_arch(arch_name_ptr: [*]const u8, arch_name_len: usize, show_dependencies: bool) void { export fn stage2_list_features_for_arch(arch_name_ptr: [*]const u8, arch_name_len: usize, show_dependencies: bool) void {
printFeaturesForArch(arch_name_ptr[0..arch_name_len], show_dependencies) catch |err| { printFeaturesForArch(arch_name_ptr[0..arch_name_len], show_dependencies) catch |err| {
std.debug.warn("Failed to list features: {}\n", .{ @errorName(err) }); std.debug.warn("Failed to list features: {}\n", .{@errorName(err)});
}; };
} }
@ -540,11 +543,11 @@ fn printFeaturesForArch(arch_name: []const u8, show_dependencies: bool) !void {
const stdout_stream = &std.io.getStdOut().outStream().stream; const stdout_stream = &std.io.getStdOut().outStream().stream;
const arch = Target.parseArchTag(arch_name) catch { const arch = Target.parseArchTag(arch_name) catch {
std.debug.warn("Failed to parse arch '{}'\nInvoke 'zig targets' for a list of valid architectures\n", .{ arch_name }); std.debug.warn("Failed to parse arch '{}'\nInvoke 'zig targets' for a list of valid architectures\n", .{arch_name});
return; return;
}; };
try stdout_stream.print("Available features for {}:\n", .{ @tagName(arch) }); try stdout_stream.print("Available features for {}:\n", .{@tagName(arch)});
const features = std.target.getFeaturesForArch(arch); const features = std.target.getFeaturesForArch(arch);
@ -556,18 +559,18 @@ fn printFeaturesForArch(arch_name: []const u8, show_dependencies: bool) !void {
} }
for (features) |feature| { for (features) |feature| {
try stdout_stream.print(" {}", .{ feature.name }); try stdout_stream.print(" {}", .{feature.name});
var i: usize = 0; var i: usize = 0;
while (i < longest_len - feature.name.len) : (i += 1) { while (i < longest_len - feature.name.len) : (i += 1) {
try stdout_stream.write(" "); try stdout_stream.write(" ");
} }
try stdout_stream.print(" - {}\n", .{ feature.description }); try stdout_stream.print(" - {}\n", .{feature.description});
if (show_dependencies and feature.dependencies.len > 0) { if (show_dependencies and feature.dependencies.len > 0) {
for (feature.dependencies) |dependency| { for (feature.dependencies) |dependency| {
try stdout_stream.print(" {}\n", .{ dependency.name }); try stdout_stream.print(" {}\n", .{dependency.name});
} }
} }
} }
@ -576,7 +579,7 @@ fn printFeaturesForArch(arch_name: []const u8, show_dependencies: bool) !void {
// ABI warning // ABI warning
export fn stage2_list_cpus_for_arch(arch_name_ptr: [*]const u8, arch_name_len: usize, show_dependencies: bool) void { export fn stage2_list_cpus_for_arch(arch_name_ptr: [*]const u8, arch_name_len: usize, show_dependencies: bool) void {
printCpusForArch(arch_name_ptr[0..arch_name_len], show_dependencies) catch |err| { printCpusForArch(arch_name_ptr[0..arch_name_len], show_dependencies) catch |err| {
std.debug.warn("Failed to list features: {}\n", .{ @errorName(err) }); std.debug.warn("Failed to list features: {}\n", .{@errorName(err)});
}; };
} }
@ -584,13 +587,13 @@ fn printCpusForArch(arch_name: []const u8, show_dependencies: bool) !void {
const stdout_stream = &std.io.getStdOut().outStream().stream; const stdout_stream = &std.io.getStdOut().outStream().stream;
const arch = Target.parseArchTag(arch_name) catch { const arch = Target.parseArchTag(arch_name) catch {
std.debug.warn("Failed to parse arch '{}'\nInvoke 'zig targets' for a list of valid architectures\n", .{ arch_name }); std.debug.warn("Failed to parse arch '{}'\nInvoke 'zig targets' for a list of valid architectures\n", .{arch_name});
return; return;
}; };
const cpus = std.target.getCpusForArch(arch); const cpus = std.target.getCpusForArch(arch);
try stdout_stream.print("Available cpus for {}:\n", .{ @tagName(arch) }); try stdout_stream.print("Available cpus for {}:\n", .{@tagName(arch)});
var longest_len: usize = 0; var longest_len: usize = 0;
for (cpus) |cpu| { for (cpus) |cpu| {
@ -600,78 +603,97 @@ fn printCpusForArch(arch_name: []const u8, show_dependencies: bool) !void {
} }
for (cpus) |cpu| { for (cpus) |cpu| {
try stdout_stream.print(" {}", .{ cpu.name }); try stdout_stream.print(" {}", .{cpu.name});
var i: usize = 0; var i: usize = 0;
while (i < longest_len - cpu.name.len) : (i += 1) { while (i < longest_len - cpu.name.len) : (i += 1) {
try stdout_stream.write(" "); try stdout_stream.write(" ");
} }
try stdout_stream.write("\n"); try stdout_stream.write("\n");
if (show_dependencies and cpu.dependencies.len > 0) { if (show_dependencies and cpu.dependencies.len > 0) {
for (cpu.dependencies) |dependency| { for (cpu.dependencies) |dependency| {
try stdout_stream.print(" {}\n", .{ dependency.name }); try stdout_stream.print(" {}\n", .{dependency.name});
} }
} }
} }
} }
const null_terminated_empty_string = (&[_]u8 { 0 })[0..0 :0]; const Stage2CpuFeatures = struct {
allocator: *mem.Allocator,
cpu_features: Target.CpuFeatures,
fn toNullTerminatedStringAlloc(allocator: *std.mem.Allocator, str: []const u8) ![:0]const u8 { llvm_cpu_name: ?[:0]const u8,
var buffer = try std.Buffer.init(allocator, str); llvm_features_str: ?[:0]const u8,
const len = buffer.len();
// Don't deinit since we steal all the buffer's memory here.
return buffer.list.toOwnedSlice()[0..len :0];
}
const Stage2TargetDetails = struct {
allocator: *std.mem.Allocator,
target_details: std.target.TargetDetails,
llvm_cpu_str: [:0]const u8,
llvm_features_str: [:0]const u8,
builtin_str: [:0]const u8, builtin_str: [:0]const u8,
cache_hash: [:0]const u8,
const Self = @This(); const Self = @This();
fn initCpu(allocator: *std.mem.Allocator, arch: @TagType(std.Target.Arch), cpu: *const std.target.Cpu) !Self { fn initBaseline(allocator: *mem.Allocator) !Self {
var builtin_str_buffer = try std.Buffer.init( const builtin_str = try std.fmt.allocPrint0(allocator, "CpuFeatures.baseline;\n");
allocator, errdefer allocator.free(builtin_str);
"@import(\"std\").target.TargetDetails{.cpu=&@import(\"std\").target.");
try builtin_str_buffer.append(@tagName(arch)); const cache_hash = try std.fmt.allocPrint0(allocator, "\n\n");
try builtin_str_buffer.append(".cpu_"); errdefer allocator.free(cache_hash);
try builtin_str_buffer.append(cpu.name);
try builtin_str_buffer.append("};");
const cpu_string = cpu.llvm_name orelse "";
return Self{ return Self{
.allocator = allocator, .allocator = allocator,
.target_details = .{ .cpu_features = .{ .cpu = cpu },
.cpu = cpu, .llvm_cpu_name = null,
}, .llvm_features_str = null,
.llvm_cpu_str = try toNullTerminatedStringAlloc(allocator, cpu_string), .builtin_str = builtin_str,
.llvm_features_str = null_terminated_empty_string, .cache_hash = cache_hash,
.builtin_str = builtin_str_buffer.toSliceConst(),
}; };
} }
fn initFeatures(allocator: *std.mem.Allocator, arch: @TagType(std.Target.Arch), features: []*const std.target.Feature) !Self { fn initCpu(allocator: *mem.Allocator, arch: Target.Arch, cpu: *const Target.Cpu) !Self {
var builtin_str_buffer = try std.Buffer.init( const builtin_str = try std.fmt.allocPrint0(
allocator, allocator,
"@import(\"std\").target.TargetDetails{.features=&[_]*const @import(\"std\").target.Feature{\n"); "CpuFeatures{{ .cpu = &Arch.{}.cpu.{} }};\n",
arch.genericName(),
cpu.name,
);
errdefer allocator.free(builtin_str);
const cache_hash = try std.fmt.allocPrint0(allocator, "{}\n{x}", cpu.name, cpu.features);
errdefer allocator.free(cache_hash);
return Self{
.allocator = allocator,
.cpu_features = .{ .cpu = cpu },
.llvm_cpu_name = cpu.llvm_name,
.llvm_features_str = null,
.builtin_str = builtin_str,
.cache_hash = cache_hash,
};
}
fn initFeatures(
allocator: *mem.Allocator,
arch: Target.Arch,
features: Target.Cpu.Feature.Set,
) !Self {
const cache_hash = try std.fmt.allocPrint0(allocator, "\n{x}", features);
errdefer allocator.free(cache_hash);
const generic_arch_name = arch.genericName();
var builtin_str_buffer = try std.Buffer.allocPrint(
allocator,
"CpuFeatures{{ .features = Arch.{}.featureSet(&[_]Arch.{}.Feature{{\n",
generic_arch_name,
generic_arch_name,
);
defer builtin_str_buffer.deinit();
var llvm_features_buffer = try std.Buffer.initSize(allocator, 0); var llvm_features_buffer = try std.Buffer.initSize(allocator, 0);
defer llvm_features_buffer.deinit();
// First, disable all features. // First, disable all features.
// This way, we only get the ones the user requests. // This way, we only get the ones the user requests.
for (std.target.getFeaturesForArch(arch)) |feature| { for (arch.allFeatures()) |feature| {
if (feature.llvm_name) |llvm_name| { if (feature.llvm_name) |llvm_name| {
try llvm_features_buffer.append("-"); try llvm_features_buffer.append("-");
try llvm_features_buffer.append(llvm_name); try llvm_features_buffer.append(llvm_name);
@ -684,232 +706,117 @@ const Stage2TargetDetails = struct {
try llvm_features_buffer.append("+"); try llvm_features_buffer.append("+");
try llvm_features_buffer.append(llvm_name); try llvm_features_buffer.append(llvm_name);
try llvm_features_buffer.append(","); try llvm_features_buffer.append(",");
try builtin_str_buffer.append("&@import(\"std\").target.");
try builtin_str_buffer.append(@tagName(arch));
try builtin_str_buffer.append(".feature_");
try builtin_str_buffer.append(feature.name);
try builtin_str_buffer.append(",");
} }
try builtin_str_buffer.append(" .");
try builtin_str_buffer.append(feature.name);
try builtin_str_buffer.append(",\n");
} }
try builtin_str_buffer.append("}};"); if (mem.endsWith(u8, llvm_features_buffer.toSliceConst(), ",")) {
llvm_features_buffer.shrink(llvm_features_buffer.len() - 1);
}
try builtin_str_buffer.append("})};\n");
return Self{ return Self{
.allocator = allocator, .allocator = allocator,
.target_details = std.target.TargetDetails{ .cpu_features = .{ .features = features },
.features = features, .llvm_cpu_name = null,
}, .llvm_features_str = llvm_features_buffer.toOwnedSlice(),
.llvm_cpu_str = null_terminated_empty_string, .builtin_str = builtin_str_buffer.toOwnedSlice(),
.llvm_features_str = llvm_features_buffer.toSliceConst(), .cache_hash = cache_hash,
.builtin_str = builtin_str_buffer.toSliceConst(),
}; };
} }
fn deinit(self: *Self) void {
self.allocator.free(self.cache_hash);
self.allocator.free(self.builtin_str);
if (self.llvm_features_str) |llvm_features_str| self.allocator.free(llvm_features_str);
self.* = undefined;
}
}; };
// ABI warning // ABI warning
export fn stage2_target_details_parse_cpu(arch_str: ?[*:0]const u8, cpu_str: ?[*:0]const u8) ?*Stage2TargetDetails { export fn stage2_cpu_features_parse_cpu(arch_name: [*:0]const u8, cpu_name: [*:0]const u8) *Stage2CpuFeatures {
if (cpu_str == null) return null; return parseCpu(arch_name, cpu_name) catch |err| switch (err) {
if (arch_str == null) return null; error.OutOfMemory => @panic("out of memory"),
const arch = Target.parseArchTag(std.mem.toSliceConst(u8, arch_str.?)) catch {
return null;
};
return parseCpu(arch, std.mem.toSliceConst(u8, cpu_str.?)) catch |err| {
switch (err) {
error.OutOfMemory => @panic("out of memory"),
else => return null,
}
}; };
} }
// ABI warning fn parseCpu(arch_name: [*:0]const u8, cpu_name: [*:0]const u8) !*Stage2CpuFeatures {
export fn stage2_target_details_parse_features(arch_str: ?[*:0]const u8, features_str: ?[*:0]const u8) ?*Stage2TargetDetails { const arch = try Target.parseArchSub(mem.toSliceConst(u8, arch_name));
if (features_str == null) return null; const cpu = try arch.parseCpu(mem.toSliceConst(u8, cpu_name));
if (arch_str == null) return null;
const arch = Target.parseArchTag(std.mem.toSliceConst(u8, arch_str.?)) catch return null;
return parseFeatures(arch, std.mem.toSliceConst(u8, features_str.?)) catch |err| {
switch (err) {
error.OutOfMemory => @panic("out of memory"),
else => return null,
}
};
}
fn parseCpu(arch: @TagType(std.Target.Arch), str: []const u8) !*Stage2TargetDetails { const ptr = try allocator.create(Stage2CpuFeatures);
const allocator = std.heap.c_allocator; errdefer std.heap.c_allocator.destroy(ptr);
const cpus = std.target.getCpusForArch(arch); ptr.* = try Stage2CpuFeatures.initCpu(std.heap.c_allocator, arch, cpu);
errdefer ptr.deinit();
for (cpus) |cpu| {
if (std.mem.eql(u8, str, cpu.name)) {
const ptr = try allocator.create(Stage2TargetDetails);
ptr.* = try Stage2TargetDetails.initCpu(std.heap.c_allocator, arch, cpu);
return ptr;
}
}
return error.InvalidCpu;
}
fn parseFeatures(arch: @TagType(std.Target.Arch), str: []const u8) !*Stage2TargetDetails {
const allocator = std.heap.c_allocator;
const known_features = std.target.getFeaturesForArch(arch);
var features = std.ArrayList(*const std.target.Feature).init(allocator);
defer features.deinit();
var start: usize = 0;
while (start < str.len) {
const next_comma_pos = std.mem.indexOfScalar(u8, str[start..], ',') orelse str.len - start;
const feature_str = std.mem.trim(u8, str[start..start+next_comma_pos], " ");
start += next_comma_pos + 1;
if (feature_str.len == 0) continue;
var feature: ?*const std.target.Feature = null;
for (known_features) |known_feature| {
if (std.mem.eql(u8, feature_str, known_feature.name)) {
feature = known_feature;
break;
}
}
if (feature) |f| {
features.append(f) catch @panic("out of memory");
} else {
return error.InvalidFeature;
}
}
const features_slice = features.toOwnedSlice();
const ptr = try allocator.create(Stage2TargetDetails);
ptr.* = try Stage2TargetDetails.initFeatures(allocator, arch, features_slice);
return ptr; return ptr;
} }
// ABI warning // ABI warning
export fn stage2_target_details_get_cache_str(target_details: ?*const Stage2TargetDetails) [*:0]const u8 { export fn stage2_cpu_features_parse_features(
if (target_details) |td| { arch_name: [*:0]const u8,
return @as([*:0]const u8, switch (td.target_details) { features_text: [*:0]const u8,
.cpu => td.llvm_cpu_str, ) *Stage2CpuFeatures {
.features => td.llvm_features_str, return parseFeatures(arch_name, features_text) catch |err| switch (err) {
}); error.OutOfMemory => @panic("out of memory"),
}
return @as([*:0]const u8, null_terminated_empty_string);
}
// ABI warning
export fn stage2_target_details_get_llvm_cpu(target_details: ?*const Stage2TargetDetails) [*:0]const u8 {
if (target_details) |td| {
return @as([*:0]const u8, td.llvm_cpu_str);
}
return @as([*:0]const u8, null_terminated_empty_string);
}
// ABI warning
export fn stage2_target_details_get_llvm_features(target_details: ?*const Stage2TargetDetails) [*:0]const u8 {
if (target_details) |td| {
return @as([*:0]const u8, td.llvm_features_str);
}
return @as([*:0]const u8, null_terminated_empty_string);
}
// ABI warning
export fn stage2_target_details_get_builtin_str(target_details: ?*const Stage2TargetDetails) [*:0]const u8 {
if (target_details) |td| {
return @as([*:0]const u8, td.builtin_str);
}
return @as([*:0]const u8, null_terminated_empty_string);
}
const riscv32_default_features: []*const std.target.Feature = &[_]*const std.target.Feature {
&std.target.riscv.feature_a,
&std.target.riscv.feature_c,
&std.target.riscv.feature_d,
&std.target.riscv.feature_f,
&std.target.riscv.feature_m,
&std.target.riscv.feature_relax,
};
const riscv64_default_features: []*const std.target.Feature = &[_]*const std.target.Feature {
&std.target.riscv.feature_bit64,
&std.target.riscv.feature_a,
&std.target.riscv.feature_c,
&std.target.riscv.feature_d,
&std.target.riscv.feature_f,
&std.target.riscv.feature_m,
&std.target.riscv.feature_relax,
};
const i386_default_features: []*const std.target.Feature = &[_]*const std.target.Feature {
&std.target.x86.feature_cmov,
&std.target.x86.feature_cx8,
&std.target.x86.feature_fxsr,
&std.target.x86.feature_mmx,
&std.target.x86.feature_nopl,
&std.target.x86.feature_sse,
&std.target.x86.feature_sse2,
&std.target.x86.feature_slowUnalignedMem16,
&std.target.x86.feature_x87,
};
// Same as above but without sse.
const i386_default_features_freestanding: []*const std.target.Feature = &[_]*const std.target.Feature {
&std.target.x86.feature_cmov,
&std.target.x86.feature_cx8,
&std.target.x86.feature_fxsr,
&std.target.x86.feature_mmx,
&std.target.x86.feature_nopl,
&std.target.x86.feature_slowUnalignedMem16,
&std.target.x86.feature_x87,
};
// ABI warning
export fn stage2_target_details_get_default(arch_str: ?[*:0]const u8, os_str: ?[*:0]const u8) ?*Stage2TargetDetails {
if (arch_str == null) return null;
if (os_str == null) return null;
const arch = Target.parseArchTag(std.mem.toSliceConst(u8, arch_str.?)) catch return null;
const os = Target.parseOs(std.mem.toSliceConst(u8, os_str.?)) catch return null;
return createDefaultTargetDetails(arch, os) catch return null;
}
fn createDefaultTargetDetails(arch: @TagType(std.Target.Arch), os: std.Target.Os) !?*Stage2TargetDetails {
const allocator = std.heap.c_allocator;
return switch (arch) {
.riscv32 => blk: {
const ptr = try allocator.create(Stage2TargetDetails);
ptr.* = try Stage2TargetDetails.initFeatures(allocator, arch, riscv32_default_features);
break :blk ptr;
},
.riscv64 => blk: {
const ptr = try allocator.create(Stage2TargetDetails);
ptr.* = try Stage2TargetDetails.initFeatures(allocator, arch, riscv64_default_features);
break :blk ptr;
},
.i386 => blk: {
const ptr = try allocator.create(Stage2TargetDetails);
const features = switch (os) {
.freestanding => i386_default_features_freestanding,
else => i386_default_features,
};
ptr.* = try Stage2TargetDetails.initFeatures(allocator, arch, features);
break :blk ptr;
},
else => null,
}; };
} }
fn parseFeatures(arch_name: [*:0]const u8, features_text: [*:0]const u8) !*Stage2CpuFeatures {
const arch = try Target.parseArchSub(mem.toSliceConst(u8, arch_name));
const set = try arch.parseCpuFeatureSet(mem.toSliceConst(u8, features_text));
const ptr = try std.heap.c_allocator.create(Stage2CpuFeatures);
errdefer std.heap.c_allocator.destroy(ptr);
ptr.* = try Stage2CpuFeatures.initFeatures(std.heap.c_allocator, arch, set);
errdefer ptr.deinit();
return ptr;
}
// ABI warning
export fn stage2_cpu_features_baseline() *Stage2CpuFeatures {
const ptr = try std.heap.c_allocator.create(Stage2CpuFeatures);
errdefer std.heap.c_allocator.destroy(ptr);
ptr.* = try Stage2CpuFeatures.initBaseline(std.heap.c_allocator);
errdefer ptr.deinit();
return ptr;
}
// ABI warning
export fn stage2_cpu_features_get_cache_hash(
cpu_features: *const Stage2CpuFeatures,
ptr: *[*:0]const u8,
len: *usize,
) void {
ptr.* = cpu_features.cache_hash.ptr;
len.* = cpu_features.cache_hash.len;
}
// ABI warning
export fn stage2_cpu_features_get_builtin_str(
cpu_features: *const Stage2CpuFeatures,
ptr: *[*:0]const u8,
len: *usize,
) void {
ptr.* = cpu_features.builtin_str.ptr;
len.* = cpu_features.builtin_str.len;
}
// ABI warning
export fn stage2_cpu_features_get_llvm_cpu(cpu_features: *const Stage2CpuFeatures) ?[*:0]const u8 {
return cpu_features.llvm_cpu_name;
}
// ABI warning
export fn stage2_cpu_features_get_llvm_features(cpu_features: *const Stage2CpuFeatures) ?[*:0]const u8 {
return cpu_features.llvm_features_str;
}

View File

@ -2215,8 +2215,6 @@ struct CodeGen {
const char **clang_argv; const char **clang_argv;
size_t clang_argv_len; size_t clang_argv_len;
Stage2TargetDetails *target_details;
}; };
struct ZigVar { struct ZigVar {

View File

@ -8573,6 +8573,17 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
buf_appendf(contents, "pub const os = Os.%s;\n", cur_os); buf_appendf(contents, "pub const os = Os.%s;\n", cur_os);
buf_appendf(contents, "pub const arch = %s;\n", cur_arch); buf_appendf(contents, "pub const arch = %s;\n", cur_arch);
buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi); buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi);
{
buf_append_str(contents, "pub const cpu_features: CpuFeatures = ");
if (g->zig_target->cpu_features != nullptr) {
const char *ptr;
size_t len;
stage2_cpu_features_get_builtin_str(g->zig_target->cpu_features, &ptr, &len);
buf_append_mem(contents, ptr, len);
} else {
buf_append_str(contents, ".baseline;\n");
}
}
if (g->libc_link_lib != nullptr && g->zig_target->glibc_version != nullptr) { if (g->libc_link_lib != nullptr && g->zig_target->glibc_version != nullptr) {
buf_appendf(contents, buf_appendf(contents,
"pub const glibc_version: ?Version = Version{.major = %d, .minor = %d, .patch = %d};\n", "pub const glibc_version: ?Version = Version{.major = %d, .minor = %d, .patch = %d};\n",
@ -8602,14 +8613,6 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
"pub var test_functions: []TestFn = undefined; // overwritten later\n" "pub var test_functions: []TestFn = undefined; // overwritten later\n"
); );
} }
buf_appendf(contents, "pub const target_details: ?@import(\"std\").target.TargetDetails = ");
if (g->target_details) {
buf_appendf(contents, "%s", stage2_target_details_get_builtin_str(g->target_details));
} else {
buf_appendf(contents, "null;");
}
buf_appendf(contents, "\n");
return contents; return contents;
} }
@ -8648,6 +8651,12 @@ static Error define_builtin_compile_vars(CodeGen *g) {
cache_int(&cache_hash, g->zig_target->vendor); cache_int(&cache_hash, g->zig_target->vendor);
cache_int(&cache_hash, g->zig_target->os); cache_int(&cache_hash, g->zig_target->os);
cache_int(&cache_hash, g->zig_target->abi); cache_int(&cache_hash, g->zig_target->abi);
if (g->zig_target->cpu_features != nullptr) {
const char *ptr;
size_t len;
stage2_cpu_features_get_cache_hash(g->zig_target->cpu_features, &ptr, &len);
cache_str(&cache_hash, ptr);
}
if (g->zig_target->glibc_version != nullptr) { if (g->zig_target->glibc_version != nullptr) {
cache_int(&cache_hash, g->zig_target->glibc_version->major); cache_int(&cache_hash, g->zig_target->glibc_version->major);
cache_int(&cache_hash, g->zig_target->glibc_version->minor); cache_int(&cache_hash, g->zig_target->glibc_version->minor);
@ -8659,10 +8668,6 @@ static Error define_builtin_compile_vars(CodeGen *g) {
cache_bool(&cache_hash, g->link_eh_frame_hdr); cache_bool(&cache_hash, g->link_eh_frame_hdr);
cache_int(&cache_hash, detect_subsystem(g)); cache_int(&cache_hash, detect_subsystem(g));
if (g->target_details) {
cache_str(&cache_hash, stage2_target_details_get_cache_str(g->target_details));
}
Buf digest = BUF_INIT; Buf digest = BUF_INIT;
buf_resize(&digest, 0); buf_resize(&digest, 0);
if ((err = cache_hit(&cache_hash, &digest))) { if ((err = cache_hit(&cache_hash, &digest))) {
@ -8793,9 +8798,9 @@ static void init(CodeGen *g) {
} }
// Override CPU and features if defined by user. // Override CPU and features if defined by user.
if (g->target_details) { if (g->zig_target->cpu_features != nullptr) {
target_specific_cpu_args = stage2_target_details_get_llvm_cpu(g->target_details); target_specific_cpu_args = stage2_cpu_features_get_llvm_cpu(g->zig_target->cpu_features);
target_specific_features = stage2_target_details_get_llvm_features(g->target_details); target_specific_features = stage2_cpu_features_get_llvm_features(g->zig_target->cpu_features);
} }
g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->llvm_triple_str), g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->llvm_triple_str),
@ -9123,15 +9128,19 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
args.append("-target"); args.append("-target");
args.append(buf_ptr(&g->llvm_triple_str)); args.append(buf_ptr(&g->llvm_triple_str));
if (g->target_details) { const char *llvm_cpu = stage2_cpu_features_get_llvm_cpu(g->zig_target->cpu_features);
if (llvm_cpu != nullptr) {
args.append("-Xclang"); args.append("-Xclang");
args.append("-target-cpu"); args.append("-target-cpu");
args.append("-Xclang"); args.append("-Xclang");
args.append(stage2_target_details_get_llvm_cpu(g->target_details)); args.append(llvm_cpu);
}
const char *llvm_target_features = stage2_cpu_features_get_llvm_features(g->zig_target->cpu_features);
if (llvm_target_features != nullptr) {
args.append("-Xclang"); args.append("-Xclang");
args.append("-target-feature"); args.append("-target-feature");
args.append("-Xclang"); args.append("-Xclang");
args.append(stage2_target_details_get_llvm_features(g->target_details)); args.append(llvm_target_features);
} }
} }
@ -10328,6 +10337,12 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
cache_int(ch, g->zig_target->vendor); cache_int(ch, g->zig_target->vendor);
cache_int(ch, g->zig_target->os); cache_int(ch, g->zig_target->os);
cache_int(ch, g->zig_target->abi); cache_int(ch, g->zig_target->abi);
if (g->zig_target->cpu_features != nullptr) {
const char *ptr;
size_t len;
stage2_cpu_features_get_cache_hash(g->zig_target->cpu_features, &ptr, &len);
cache_str(ch, ptr);
}
if (g->zig_target->glibc_version != nullptr) { if (g->zig_target->glibc_version != nullptr) {
cache_int(ch, g->zig_target->glibc_version->major); cache_int(ch, g->zig_target->glibc_version->major);
cache_int(ch, g->zig_target->glibc_version->minor); cache_int(ch, g->zig_target->glibc_version->minor);
@ -10375,10 +10390,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
cache_buf_opt(ch, g->dynamic_linker_path); cache_buf_opt(ch, g->dynamic_linker_path);
cache_buf_opt(ch, g->version_script_path); cache_buf_opt(ch, g->version_script_path);
if (g->target_details) {
cache_str(ch, stage2_target_details_get_cache_str(g->target_details));
}
// gen_c_objects appends objects to g->link_objects which we want to include in the hash // gen_c_objects appends objects to g->link_objects which we want to include in the hash
gen_c_objects(g); gen_c_objects(g);
cache_list_of_file(ch, g->link_objects.items, g->link_objects.length); cache_list_of_file(ch, g->link_objects.items, g->link_objects.length);
@ -10661,7 +10672,6 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o
CodeGen *child_gen = codegen_create(nullptr, root_src_path, parent_gen->zig_target, out_type, CodeGen *child_gen = codegen_create(nullptr, root_src_path, parent_gen->zig_target, out_type,
parent_gen->build_mode, parent_gen->zig_lib_dir, libc, get_global_cache_dir(), false, child_progress_node); parent_gen->build_mode, parent_gen->zig_lib_dir, libc, get_global_cache_dir(), false, child_progress_node);
child_gen->target_details = parent_gen->target_details;
child_gen->root_out_name = buf_create_from_str(name); child_gen->root_out_name = buf_create_from_str(name);
child_gen->disable_gen_h = true; child_gen->disable_gen_h = true;
child_gen->want_stack_check = WantStackCheckDisabled; child_gen->want_stack_check = WantStackCheckDisabled;

View File

@ -955,9 +955,9 @@ int main(int argc, char **argv) {
targets_list_features_arch = argv[i]; targets_list_features_arch = argv[i];
} else if (strcmp(arg, "--list-cpus") == 0) { } else if (strcmp(arg, "--list-cpus") == 0) {
targets_list_cpus_arch = argv[i]; targets_list_cpus_arch = argv[i];
} else if (strcmp(arg, "--cpu") == 0) { } else if (strcmp(arg, "-target-cpu") == 0) {
cpu = argv[i]; cpu = argv[i];
} else if (strcmp(arg, "--features") == 0) { } else if (strcmp(arg, "-target-feature") == 0) {
features = argv[i]; features = argv[i];
}else { }else {
fprintf(stderr, "Invalid argument: %s\n", arg); fprintf(stderr, "Invalid argument: %s\n", arg);
@ -1074,27 +1074,26 @@ int main(int argc, char **argv) {
} }
} }
Stage2TargetDetails *target_details = nullptr;
if (cpu && features) { if (cpu && features) {
fprintf(stderr, "--cpu and --features options not allowed together\n"); fprintf(stderr, "-target-cpu and -target-feature options not allowed together\n");
return main_exit(root_progress_node, EXIT_FAILURE); return main_exit(root_progress_node, EXIT_FAILURE);
} else if (cpu) { } else if (cpu) {
target_details = stage2_target_details_parse_cpu(target_arch_name(target.arch), cpu); target.cpu_features = stage2_cpu_features_parse_cpu(target_arch_name(target.arch), cpu);
if (!target_details) { if (!target.cpu_features) {
fprintf(stderr, "invalid --cpu value\n"); fprintf(stderr, "invalid -target-cpu value\n");
return main_exit(root_progress_node, EXIT_FAILURE); return main_exit(root_progress_node, EXIT_FAILURE);
} }
} else if (features) { } else if (features) {
target_details = stage2_target_details_parse_features(target_arch_name(target.arch), features); target.cpu_features = stage2_cpu_features_parse_features(target_arch_name(target.arch), features);
if (!target_details) { if (!target.cpu_features) {
fprintf(stderr, "invalid --features value\n"); fprintf(stderr, "invalid -target-feature value\n");
return main_exit(root_progress_node, EXIT_FAILURE); return main_exit(root_progress_node, EXIT_FAILURE);
} }
} else { } else {
// If no details are specified and we are not native, load // If no details are specified and we are not native, load
// cross-compilation default features. // cross-compilation default features.
if (!target.is_native) { if (!target.is_native) {
target_details = stage2_target_details_get_default(target_arch_name(target.arch), target_os_name(target.os)); target.cpu_features = stage2_cpu_features_baseline();
} }
} }
@ -1148,7 +1147,6 @@ int main(int argc, char **argv) {
g->want_stack_check = want_stack_check; g->want_stack_check = want_stack_check;
g->want_sanitize_c = want_sanitize_c; g->want_sanitize_c = want_sanitize_c;
g->want_single_threaded = want_single_threaded; g->want_single_threaded = want_single_threaded;
g->target_details = target_details;
Buf *builtin_source = codegen_generate_builtin_source(g); Buf *builtin_source = codegen_generate_builtin_source(g);
if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {
fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout))); fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout)));
@ -1303,8 +1301,6 @@ int main(int argc, char **argv) {
codegen_add_rpath(g, rpath_list.at(i)); codegen_add_rpath(g, rpath_list.at(i));
} }
g->target_details = target_details;
codegen_set_rdynamic(g, rdynamic); codegen_set_rdynamic(g, rdynamic);
if (mmacosx_version_min && mios_version_min) { if (mmacosx_version_min && mios_version_min) {
fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n"); fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n");

View File

@ -91,6 +91,7 @@ struct ZigTarget {
Os os; Os os;
ZigLLVM_EnvironmentType abi; ZigLLVM_EnvironmentType abi;
ZigGLibCVersion *glibc_version; // null means default ZigGLibCVersion *glibc_version; // null means default
Stage2CpuFeatures *cpu_features;
bool is_native; bool is_native;
}; };

View File

@ -89,26 +89,44 @@ void stage2_progress_complete_one(Stage2ProgressNode *node) {}
void stage2_progress_disable_tty(Stage2Progress *progress) {} void stage2_progress_disable_tty(Stage2Progress *progress) {}
void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){} void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){}
void stage2_list_features_for_arch(const char *arch_name_ptr, size_t arch_name_len, bool show_subfeatures) {} void stage2_list_features_for_arch(const char *arch_name_ptr, size_t arch_name_len, bool show_subfeatures) {
void stage2_list_cpus_for_arch(const char *arch_name_ptr, size_t arch_name_len, bool show_subfeatures) {} const char *msg = "stage0 called stage2_list_features_for_arch";
Stage2TargetDetails *stage2_target_details_parse_cpu(const char *arch, const char *str) { stage2_panic(msg, strlen(msg));
return nullptr;
} }
Stage2TargetDetails *stage2_target_details_parse_features(const char *arch, const char *str) {
return nullptr; void stage2_list_cpus_for_arch(const char *arch_name_ptr, size_t arch_name_len, bool show_subfeatures) {
const char *msg = "stage0 called stage2_list_cpus_for_arch";
stage2_panic(msg, strlen(msg));
} }
const char *stage2_target_details_get_cache_str(const Stage2TargetDetails *target_details) { Stage2CpuFeatures *stage2_cpu_features_parse_cpu(const char *arch, const char *str) {
return ""; const char *msg = "stage0 called stage2_cpu_features_parse_cpu";
stage2_panic(msg, strlen(msg));
} }
const char *stage2_target_details_get_llvm_cpu(const Stage2TargetDetails *target_details) { Stage2CpuFeatures *stage2_cpu_features_parse_features(const char *arch, const char *str) {
return ""; const char *msg = "stage0 called stage2_cpu_features_parse_features";
stage2_panic(msg, strlen(msg));
} }
const char *stage2_target_details_get_llvm_features(const Stage2TargetDetails *target_details) { Stage2CpuFeatures *stage2_cpu_features_baseline(void) {
return ""; const char *msg = "stage0 called stage2_cpu_features_baseline";
stage2_panic(msg, strlen(msg));
} }
const char *stage2_target_details_get_builtin_str(const Stage2TargetDetails *target_details) { void stage2_cpu_features_get_cache_hash(const Stage2CpuFeatures *cpu_features,
return ""; const char **ptr, size_t *len)
{
const char *msg = "stage0 called stage2_cpu_features_get_cache_hash";
stage2_panic(msg, strlen(msg));
} }
Stage2TargetDetails *stage2_target_details_get_default(const char *arch, const char *os) { const char *stage2_cpu_features_get_llvm_cpu(const Stage2CpuFeatures *cpu_features) {
return nullptr; const char *msg = "stage0 called stage2_cpu_features_get_llvm_cpu";
stage2_panic(msg, strlen(msg));
}
const char *stage2_cpu_features_get_llvm_features(const Stage2CpuFeatures *cpu_features) {
const char *msg = "stage0 called stage2_cpu_features_get_llvm_features";
stage2_panic(msg, strlen(msg));
}
void stage2_cpu_features_get_builtin_str(const Stage2CpuFeatures *cpu_features,
const char **ptr, size_t *len)
{
const char *msg = "stage0 called stage2_cpu_features_get_builtin_str";
stage2_panic(msg, strlen(msg));
} }

View File

@ -181,27 +181,29 @@ ZIG_EXTERN_C void stage2_list_features_for_arch(const char *arch_name_ptr, size_
ZIG_EXTERN_C void stage2_list_cpus_for_arch(const char *arch_name_ptr, size_t arch_name_len, bool show_subfeatures); ZIG_EXTERN_C void stage2_list_cpus_for_arch(const char *arch_name_ptr, size_t arch_name_len, bool show_subfeatures);
// ABI warning // ABI warning
struct Stage2TargetDetails; struct Stage2CpuFeatures;
// ABI warning // ABI warning
ZIG_EXTERN_C Stage2TargetDetails *stage2_target_details_parse_cpu(const char *arch, const char *str); ZIG_EXTERN_C Stage2CpuFeatures *stage2_cpu_features_parse_cpu(const char *arch, const char *cpu_name);
// ABI warning // ABI warning
ZIG_EXTERN_C Stage2TargetDetails *stage2_target_details_parse_features(const char *arch, const char *str); ZIG_EXTERN_C Stage2CpuFeatures *stage2_cpu_features_parse_features(const char *arch, const char *features);
// ABI warning // ABI warning
ZIG_EXTERN_C const char *stage2_target_details_get_cache_str(const Stage2TargetDetails *target_details); ZIG_EXTERN_C Stage2CpuFeatures *stage2_cpu_features_baseline(void);
// ABI warning // ABI warning
ZIG_EXTERN_C const char *stage2_target_details_get_llvm_cpu(const Stage2TargetDetails *target_details); ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_cpu(const Stage2CpuFeatures *cpu_features);
// ABI warning // ABI warning
ZIG_EXTERN_C const char *stage2_target_details_get_llvm_features(const Stage2TargetDetails *target_details); ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_features(const Stage2CpuFeatures *cpu_features);
// ABI warning // ABI warning
ZIG_EXTERN_C const char *stage2_target_details_get_builtin_str(const Stage2TargetDetails *target_details); ZIG_EXTERN_C void stage2_cpu_features_get_builtin_str(const Stage2CpuFeatures *cpu_features,
const char **ptr, size_t *len);
// ABI warning // ABI warning
ZIG_EXTERN_C Stage2TargetDetails *stage2_target_details_get_default(const char *arch, const char *os); ZIG_EXTERN_C void stage2_cpu_features_get_cache_hash(const Stage2CpuFeatures *cpu_features,
const char **ptr, size_t *len);
#endif #endif