diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig index a2d265707b..16c0a64f6b 100644 --- a/lib/std/zig/cross_target.zig +++ b/lib/std/zig/cross_target.zig @@ -7,11 +7,10 @@ const mem = std.mem; /// The purpose of this abstraction is to provide meaningful and unsurprising defaults. /// This struct does reference any resources and it is copyable. pub const CrossTarget = struct { - /// `null` means native. If this is `null` then `cpu_model` must be `null`. + /// `null` means native. cpu_arch: ?Target.Cpu.Arch = null, - /// `null` means native. If this is non-null, `cpu_arch` must be specified. - cpu_model: ?*const Target.Cpu.Model = null, + cpu_model: CpuModel = CpuModel.determined_by_cpu_arch, /// Sparse set of CPU features to add to the set from `cpu_model`. cpu_features_add: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty, @@ -41,6 +40,20 @@ pub const CrossTarget = struct { /// based on the `os_tag`. dynamic_linker: DynamicLinker = DynamicLinker{}, + pub const CpuModel = union(enum) { + /// Always native + native, + + /// Always baseline + baseline, + + /// If CPU Architecture is native, then the CPU model will be native. Otherwise, + /// it will be baseline. + determined_by_cpu_arch, + + explicit: *const Target.Cpu.Model, + }; + pub const OsVersion = union(enum) { none: void, semver: SemVer, @@ -54,7 +67,7 @@ pub const CrossTarget = struct { pub fn fromTarget(target: Target) CrossTarget { var result: CrossTarget = .{ .cpu_arch = target.cpu.arch, - .cpu_model = target.cpu.model, + .cpu_model = .{ .explicit = target.cpu.model }, .os_tag = target.os.tag, .os_version_min = undefined, .os_version_max = undefined, @@ -266,11 +279,11 @@ pub const CrossTarget = struct { const add_set = &result.cpu_features_add; const sub_set = &result.cpu_features_sub; if (mem.eql(u8, cpu_name, "native")) { - result.cpu_model = null; + result.cpu_model = .native; } else if (mem.eql(u8, cpu_name, "baseline")) { - result.cpu_model = Target.Cpu.Model.baseline(arch); + result.cpu_model = .baseline; } else { - result.cpu_model = try arch.parseCpuModel(cpu_name); + result.cpu_model = .{ .explicit = try arch.parseCpuModel(cpu_name) }; } while (index < cpu_features.len) { @@ -300,10 +313,6 @@ pub const CrossTarget = struct { return error.UnknownCpuFeature; } } - } else if (arch_is_native) { - result.cpu_model = null; - } else { - result.cpu_model = Target.Cpu.Model.baseline(arch); } return result; @@ -311,24 +320,33 @@ pub const CrossTarget = struct { /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`. pub fn getCpu(self: CrossTarget) Target.Cpu { - if (self.cpu_arch) |arch| { - if (self.cpu_model) |model| { - var adjusted_model = model.toCpu(arch); - self.updateCpuFeatures(&adjusted_model.features); - return adjusted_model; - } else { - var adjusted_baseline = Target.Cpu.baseline(arch); + switch (self.cpu_model) { + .native => { + // This works when doing `zig build` because Zig generates a build executable using + // native CPU model & features. However this will not be accurate otherwise, and + // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`. + return Target.current.cpu; + }, + .baseline => { + var adjusted_baseline = Target.Cpu.baseline(self.getCpuArch()); self.updateCpuFeatures(&adjusted_baseline.features); return adjusted_baseline; - } - } else { - assert(self.cpu_model == null); - assert(self.cpu_features_sub.isEmpty()); - assert(self.cpu_features_add.isEmpty()); - // This works when doing `zig build` because Zig generates a build executable using - // native CPU model & features. However this will not be accurate otherwise, and - // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`. - return Target.current.cpu; + }, + .determined_by_cpu_arch => if (self.cpu_arch == null) { + // This works when doing `zig build` because Zig generates a build executable using + // native CPU model & features. However this will not be accurate otherwise, and + // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`. + return Target.current.cpu; + } else { + var adjusted_baseline = Target.Cpu.baseline(self.getCpuArch()); + self.updateCpuFeatures(&adjusted_baseline.features); + return adjusted_baseline; + }, + .explicit => |model| { + var adjusted_model = model.toCpu(self.getCpuArch()); + self.updateCpuFeatures(&adjusted_model.features); + return adjusted_model; + }, } } @@ -461,7 +479,8 @@ pub const CrossTarget = struct { } pub fn isNative(self: CrossTarget) bool { - return self.cpu_arch == null and self.cpu_model == null and + return self.cpu_arch == null and + (self.cpu_model == .native or self.cpu_model == .determined_by_cpu_arch) and self.cpu_features_sub.isEmpty() and self.cpu_features_add.isEmpty() and self.os_tag == null and self.os_version_min == null and self.os_version_max == null and self.abi == null and self.dynamic_linker.get() == null; diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index b712c7c062..5ff17bae23 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -191,18 +191,18 @@ pub const NativeTargetInfo = struct { /// deinitialization method. /// TODO Remove the Allocator requirement from this function. pub fn detect(allocator: *Allocator, cross_target: CrossTarget) DetectError!NativeTargetInfo { - const cpu = blk: { - const arch = cross_target.getCpuArch(); - if (cross_target.cpu_model) |model| { - var adjusted_model = model.toCpu(arch); + const cpu = switch (cross_target.cpu_model) { + .native => detectNativeCpuAndFeatures(cross_target), + .baseline => baselineCpuAndFeatures(cross_target), + .determined_by_cpu_arch => if (cross_target.cpu_arch == null) + detectNativeCpuAndFeatures(cross_target) + else + baselineCpuAndFeatures(cross_target), + .explicit => |model| blk: { + var adjusted_model = model.toCpu(cross_target.getCpuArch()); cross_target.updateCpuFeatures(&adjusted_model.features); break :blk adjusted_model; - } else { - // TODO Detect native CPU model & features. Until that is implemented we use baseline. - var adjusted_baseline = Target.Cpu.baseline(arch); - cross_target.updateCpuFeatures(&adjusted_baseline.features); - break :blk adjusted_baseline; - } + }, }; var os = Target.Os.defaultVersionRange(cross_target.getOsTag()); @@ -758,4 +758,15 @@ pub const NativeTargetInfo = struct { } } } + + fn detectNativeCpuAndFeatures(cross_target: CrossTarget) Target.Cpu { + // TODO Detect native CPU model & features. Until that is implemented we use baseline. + return baselineCpuAndFeatures(cross_target); + } + + fn baselineCpuAndFeatures(cross_target: CrossTarget) Target.Cpu { + var adjusted_baseline = Target.Cpu.baseline(cross_target.getCpuArch()); + cross_target.updateCpuFeatures(&adjusted_baseline.features); + return adjusted_baseline; + } }; diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 696d7ea760..a8aa10d91e 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -1154,7 +1154,7 @@ fn enumInt(comptime Enum: type, int: c_int) Enum { fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) !Target { var info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator, cross_target); - if (cross_target.cpu_arch == null or cross_target.cpu_model == null) { + if (cross_target.cpu_arch == null or cross_target.cpu_model == .native) { // TODO We want to just use detected_info.target but implementing // CPU model & feature detection is todo so here we rely on LLVM. const llvm = @import("llvm.zig");