authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-06 19:41:44-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-06 19:47:03-05:00
log49817c6adde3e9e98282dcecd017ab076faa1d85
treee4a9863a9cf0c8d3fbdb1e1745573e7e5b499587
parentf19918256746ccc81b6ff11d17e98665b4853400
signaturelock-open Commit is signed but in an unrecognized format.

cleanup CPU model & feature detection

Add std.Target.Cpu.Model.generic which is even more empty than baseline. CPU model and feature detection uses this rather than baseline. Rename cpu_detected to cpu_detection_unimplemented and flip the logic. It can be relied on by stage2.zig to decide whether the LLVM workaround is needed without also checking the CrossTarget. Move the CPU detection to after the OS detection, and use the detected OS for the CPU detection. This is relevant because operating systems sometimes emulate certain CPU features, so knowing the OS and version is relevant for determining CPU features. Prepare for #4592 by passing the CPU arch to the detection code, instead of having it rely on Target.current. The CPU model & feature detection logic is modified. Before: * Detect actual features * Use as hint when detecting CPU model * Populate dependencies of CPU model features * Merge that into the actual features set After: * Detect actual features * Use as hint when detecting CPU model * Add known CPU model features to actual features * Detect actual features again, overriding known CPU model features * Populate dependencies

4 files changed, 192 insertions(+), 190 deletions(-)

lib/std/target.zig+17-5
...@@ -907,7 +907,7 @@ pub const Target = struct {...@@ -907,7 +907,7 @@ pub const Target = struct {
907 };907 };
908 }908 }
909909
910 pub fn baseline(arch: Arch) *const Model {910 pub fn generic(arch: Arch) *const Model {
911 const S = struct {911 const S = struct {
912 const generic_model = Model{912 const generic_model = Model{
913 .name = "generic",913 .name = "generic",
...@@ -916,7 +916,7 @@ pub const Target = struct {...@@ -916,7 +916,7 @@ pub const Target = struct {
916 };916 };
917 };917 };
918 return switch (arch) {918 return switch (arch) {
919 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline,919 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic,
920 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,920 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
921 .avr => &avr.cpu.avr1,921 .avr => &avr.cpu.avr1,
922 .bpfel, .bpfeb => &bpf.cpu.generic,922 .bpfel, .bpfeb => &bpf.cpu.generic,
...@@ -926,11 +926,11 @@ pub const Target = struct {...@@ -926,11 +926,11 @@ pub const Target = struct {
926 .msp430 => &msp430.cpu.generic,926 .msp430 => &msp430.cpu.generic,
927 .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic,927 .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic,
928 .amdgcn => &amdgpu.cpu.generic,928 .amdgcn => &amdgpu.cpu.generic,
929 .riscv32 => &riscv.cpu.baseline_rv32,929 .riscv32 => &riscv.cpu.generic_rv32,
930 .riscv64 => &riscv.cpu.baseline_rv64,930 .riscv64 => &riscv.cpu.generic_rv64,
931 .sparc, .sparcv9, .sparcel => &sparc.cpu.generic,931 .sparc, .sparcv9, .sparcel => &sparc.cpu.generic,
932 .s390x => &systemz.cpu.generic,932 .s390x => &systemz.cpu.generic,
933 .i386 => &x86.cpu.pentium4,933 .i386 => &x86.cpu._i386,
934 .x86_64 => &x86.cpu.x86_64,934 .x86_64 => &x86.cpu.x86_64,
935 .nvptx, .nvptx64 => &nvptx.cpu.sm_20,935 .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
936 .wasm32, .wasm64 => &wasm.cpu.generic,936 .wasm32, .wasm64 => &wasm.cpu.generic,
...@@ -938,6 +938,18 @@ pub const Target = struct {...@@ -938,6 +938,18 @@ pub const Target = struct {
938 else => &S.generic_model,938 else => &S.generic_model,
939 };939 };
940 }940 }
941
942 pub fn baseline(arch: Arch) *const Model {
943 return switch (arch) {
944 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline,
945 .riscv32 => &riscv.cpu.baseline_rv32,
946 .riscv64 => &riscv.cpu.baseline_rv64,
947 .i386 => &x86.cpu.pentium4,
948 .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
949
950 else => generic(arch),
951 };
952 }
941 };953 };
942954
943 /// The "default" set of CPU features for cross-compiling. A conservative set955 /// The "default" set of CPU features for cross-compiling. A conservative set
lib/std/zig/system.zig+42-35
...@@ -171,7 +171,10 @@ pub const NativeTargetInfo = struct {...@@ -171,7 +171,10 @@ pub const NativeTargetInfo = struct {
171171
172 dynamic_linker: DynamicLinker = DynamicLinker{},172 dynamic_linker: DynamicLinker = DynamicLinker{},
173173
174 cpu_detected: bool = false,174 /// Only some architectures have CPU detection implemented. This field reveals whether
175 /// CPU detection actually occurred. When this is `true` it means that the reported
176 /// CPU is baseline only because of a missing implementation for that architecture.
177 cpu_detection_unimplemented: bool = false,
175178
176 pub const DynamicLinker = Target.DynamicLinker;179 pub const DynamicLinker = Target.DynamicLinker;
177180
...@@ -193,28 +196,6 @@ pub const NativeTargetInfo = struct {...@@ -193,28 +196,6 @@ pub const NativeTargetInfo = struct {
193 /// deinitialization method.196 /// deinitialization method.
194 /// TODO Remove the Allocator requirement from this function.197 /// TODO Remove the Allocator requirement from this function.
195 pub fn detect(allocator: *Allocator, cross_target: CrossTarget) DetectError!NativeTargetInfo {198 pub fn detect(allocator: *Allocator, cross_target: CrossTarget) DetectError!NativeTargetInfo {
196
197 var cpu_detected = true;
198
199 const cpu = switch (cross_target.cpu_model) {
200 .native => detectNativeCpuAndFeatures(cross_target),
201 .baseline => baselineCpuAndFeatures(cross_target),
202 .determined_by_cpu_arch => if (cross_target.cpu_arch == null)
203 detectNativeCpuAndFeatures(cross_target)
204 else
205 baselineCpuAndFeatures(cross_target),
206 .explicit => |model| blk: {
207 var adjusted_model = model.toCpu(cross_target.getCpuArch());
208 cross_target.updateCpuFeatures(&adjusted_model.features);
209 break :blk adjusted_model;
210 },
211 } orelse backup_cpu_detection: {
212
213 // Temporarily use LLVM's cpu info as a backup
214 cpu_detected = false;
215 break :backup_cpu_detection baselineCpuAndFeatures(cross_target);
216 };
217
218 var os = Target.Os.defaultVersionRange(cross_target.getOsTag());199 var os = Target.Os.defaultVersionRange(cross_target.getOsTag());
219 if (cross_target.os_tag == null) {200 if (cross_target.os_tag == null) {
220 switch (Target.current.os.tag) {201 switch (Target.current.os.tag) {
...@@ -299,9 +280,12 @@ pub const NativeTargetInfo = struct {...@@ -299,9 +280,12 @@ pub const NativeTargetInfo = struct {
299 }280 }
300 },281 },
301 .freebsd => {282 .freebsd => {
302 // TODO Detect native operating system version.283 // Unimplemented, fall back to default.
284 // https://github.com/ziglang/zig/issues/4582
285 },
286 else => {
287 // Unimplemented, fall back to default version range.
303 },288 },
304 else => {},
305 }289 }
306 }290 }
307291
...@@ -328,8 +312,31 @@ pub const NativeTargetInfo = struct {...@@ -328,8 +312,31 @@ pub const NativeTargetInfo = struct {
328 os.version_range.linux.glibc = glibc;312 os.version_range.linux.glibc = glibc;
329 }313 }
330314
315 var cpu_detection_unimplemented = false;
316
317 // Until https://github.com/ziglang/zig/issues/4592 is implemented (support detecting the
318 // native CPU architecture as being different than the current target), we use this:
319 const cpu_arch = cross_target.getCpuArch();
320
321 const cpu = switch (cross_target.cpu_model) {
322 .native => detectNativeCpuAndFeatures(cpu_arch, os, cross_target),
323 .baseline => baselineCpuAndFeatures(cpu_arch, cross_target),
324 .determined_by_cpu_arch => if (cross_target.cpu_arch == null)
325 detectNativeCpuAndFeatures(cpu_arch, os, cross_target)
326 else
327 baselineCpuAndFeatures(cpu_arch, cross_target),
328 .explicit => |model| blk: {
329 var adjusted_model = model.toCpu(cpu_arch);
330 cross_target.updateCpuFeatures(&adjusted_model.features);
331 break :blk adjusted_model;
332 },
333 } orelse backup_cpu_detection: {
334 cpu_detection_unimplemented = true;
335 break :backup_cpu_detection baselineCpuAndFeatures(cpu_arch, cross_target);
336 };
337
331 var target = try detectAbiAndDynamicLinker(allocator, cpu, os, cross_target);338 var target = try detectAbiAndDynamicLinker(allocator, cpu, os, cross_target);
332 target.cpu_detected = cpu_detected;339 target.cpu_detection_unimplemented = cpu_detection_unimplemented;
333 return target;340 return target;
334 }341 }
335342
...@@ -855,22 +862,22 @@ pub const NativeTargetInfo = struct {...@@ -855,22 +862,22 @@ pub const NativeTargetInfo = struct {
855 }862 }
856 }863 }
857864
858 fn detectNativeCpuAndFeatures(cross_target: CrossTarget) ?Target.Cpu {865 fn detectNativeCpuAndFeatures(cpu_arch: Target.Cpu.Arch, os: Target.Os, cross_target: CrossTarget) ?Target.Cpu {
859866 switch (cpu_arch) {
860 switch(Target.current.cpu.arch) {
861 .x86_64, .i386 => {867 .x86_64, .i386 => {
862 return @import("system/x86.zig").detectNativeCpuAndFeatures(cross_target);868 return @import("system/x86.zig").detectNativeCpuAndFeatures(cpu_arch, os, cross_target);
863 },869 },
864 else => {870 else => {
865 // TODO flesh out CPU detection for more than just x86.871 // This architecture does not have CPU model & feature detection yet.
872 // See https://github.com/ziglang/zig/issues/4591
866 return null;873 return null;
867 }874 },
868 }875 }
869 }876 }
870877
871 fn baselineCpuAndFeatures(cross_target: CrossTarget) Target.Cpu {878 fn baselineCpuAndFeatures(cpu_arch: Target.Cpu.Arch, cross_target: CrossTarget) Target.Cpu {
872 var adjusted_baseline = Target.Cpu.baseline(cross_target.getCpuArch());879 var adjusted_baseline = Target.Cpu.baseline(cpu_arch);
873 cross_target.updateCpuFeatures(&adjusted_baseline.features);880 cross_target.updateCpuFeatures(&adjusted_baseline.features);
874 return adjusted_baseline;881 return adjusted_baseline;
875 }882 }
876};
\ No newline at end of file
883};
lib/std/zig/system/x86.zig+132-149
...@@ -3,35 +3,30 @@ const Target = std.Target;...@@ -3,35 +3,30 @@ const Target = std.Target;
3const CrossTarget = std.zig.CrossTarget;3const CrossTarget = std.zig.CrossTarget;
44
5fn setFeature(cpu: *Target.Cpu, feature: Target.x86.Feature, enabled: bool) void {5fn setFeature(cpu: *Target.Cpu, feature: Target.x86.Feature, enabled: bool) void {
6
7 const idx = @as(Target.Cpu.Feature.Set.Index, @enumToInt(feature));6 const idx = @as(Target.Cpu.Feature.Set.Index, @enumToInt(feature));
87
9 if(enabled) cpu.features.addFeature(idx)8 if (enabled) cpu.features.addFeature(idx) else cpu.features.removeFeature(idx);
10 else cpu.features.removeFeature(idx);
11}9}
1210
13inline fn bit(input: u32, offset: u5) bool {11inline fn bit(input: u32, offset: u5) bool {
14 return (input >> offset) & 1 != 0;12 return (input >> offset) & 1 != 0;
15}13}
1614
17pub fn detectNativeCpuAndFeatures(cross_target: CrossTarget) Target.Cpu {15pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, os: Target.Os, cross_target: CrossTarget) Target.Cpu {
1816 var cpu = Target.Cpu{
19 var arch = cross_target.getCpuArch();
20
21 var cpu = Target.Cpu {
22 .arch = arch,17 .arch = arch,
23 .model = Target.Cpu.Model.baseline(arch),18 .model = Target.Cpu.Model.generic(arch),
24 .features = Target.Cpu.Feature.Set.empty,19 .features = Target.Cpu.Feature.Set.empty,
25 };20 };
2621
27 detectNativeFeatures(&cpu, cross_target.getOsTag());22 // First we detect features, to use as hints when detecting CPU Model.
23 detectNativeFeatures(&cpu, os.tag);
2824
29 var leaf = cpuid(0, 0);25 var leaf = cpuid(0, 0);
30 const max_leaf = leaf.eax;26 const max_leaf = leaf.eax;
31 const vendor = leaf.ebx;27 const vendor = leaf.ebx;
3228
33 if(max_leaf > 0) {29 if (max_leaf > 0) {
34
35 leaf = cpuid(0x1, 0);30 leaf = cpuid(0x1, 0);
3631
37 const brand_id = leaf.ebx & 0xff;32 const brand_id = leaf.ebx & 0xff;
...@@ -49,7 +44,8 @@ pub fn detectNativeCpuAndFeatures(cross_target: CrossTarget) Target.Cpu {...@@ -49,7 +44,8 @@ pub fn detectNativeCpuAndFeatures(cross_target: CrossTarget) Target.Cpu {
49 }44 }
50 }45 }
5146
52 switch(vendor) {47 // Now we detect the model.
48 switch (vendor) {
53 0x756e6547 => {49 0x756e6547 => {
54 detectIntelProcessor(&cpu, family, model, brand_id);50 detectIntelProcessor(&cpu, family, model, brand_id);
55 },51 },
...@@ -60,19 +56,21 @@ pub fn detectNativeCpuAndFeatures(cross_target: CrossTarget) Target.Cpu {...@@ -60,19 +56,21 @@ pub fn detectNativeCpuAndFeatures(cross_target: CrossTarget) Target.Cpu {
60 }56 }
61 }57 }
6258
63 var model_features = cpu.model.features;59 // Add the CPU model's feature set into the working set, but then
64 model_features.populateDependencies(cpu.arch.allFeaturesList());60 // override with actual detected features again.
65 cpu.features.addFeatureSet(model_features);61 cpu.features.addFeatureSet(cpu.model.features);
62 detectNativeFeatures(&cpu, os.tag);
6663
67 return cpu;64 cpu.features.populateDependencies(cpu.arch.allFeaturesList());
6865
66 return cpu;
69}67}
7068
71fn detectIntelProcessor(cpu: *Target.Cpu, family: u32, model: u32, brand_id: u32) void {69fn detectIntelProcessor(cpu: *Target.Cpu, family: u32, model: u32, brand_id: u32) void {
72 if (brand_id != 0) {70 if (brand_id != 0) {
73 return;71 return;
74 }72 }
75 switch(family) {73 switch (family) {
76 3 => {74 3 => {
77 cpu.model = &Target.x86.cpu._i386;75 cpu.model = &Target.x86.cpu._i386;
78 return;76 return;
...@@ -82,7 +80,7 @@ fn detectIntelProcessor(cpu: *Target.Cpu, family: u32, model: u32, brand_id: u32...@@ -82,7 +80,7 @@ fn detectIntelProcessor(cpu: *Target.Cpu, family: u32, model: u32, brand_id: u32
82 return;80 return;
83 },81 },
84 5 => {82 5 => {
85 if(Target.x86.featureSetHas(cpu.features, .mmx)) {83 if (Target.x86.featureSetHas(cpu.features, .mmx)) {
86 cpu.model = &Target.x86.cpu.pentium_mmx;84 cpu.model = &Target.x86.cpu.pentium_mmx;
87 return;85 return;
88 }86 }
...@@ -90,7 +88,7 @@ fn detectIntelProcessor(cpu: *Target.Cpu, family: u32, model: u32, brand_id: u32...@@ -90,7 +88,7 @@ fn detectIntelProcessor(cpu: *Target.Cpu, family: u32, model: u32, brand_id: u32
90 return;88 return;
91 },89 },
92 6 => {90 6 => {
93 switch(model) {91 switch (model) {
94 0x01 => {92 0x01 => {
95 cpu.model = &Target.x86.cpu.pentiumpro;93 cpu.model = &Target.x86.cpu.pentiumpro;
96 return;94 return;
...@@ -148,10 +146,10 @@ fn detectIntelProcessor(cpu: *Target.Cpu, family: u32, model: u32, brand_id: u32...@@ -148,10 +146,10 @@ fn detectIntelProcessor(cpu: *Target.Cpu, family: u32, model: u32, brand_id: u32
148 return;146 return;
149 },147 },
150 0x55 => {148 0x55 => {
151 if(Target.x86.featureSetHas(cpu.features, .avx512bf16)) {149 if (Target.x86.featureSetHas(cpu.features, .avx512bf16)) {
152 cpu.model = &Target.x86.cpu.cooperlake;150 cpu.model = &Target.x86.cpu.cooperlake;
153 return;151 return;
154 } else if(Target.x86.featureSetHas(cpu.features, .avx512vnni)) {152 } else if (Target.x86.featureSetHas(cpu.features, .avx512vnni)) {
155 cpu.model = &Target.x86.cpu.cascadelake;153 cpu.model = &Target.x86.cpu.cascadelake;
156 return;154 return;
157 } else {155 } else {
...@@ -199,45 +197,36 @@ fn detectIntelProcessor(cpu: *Target.Cpu, family: u32, model: u32, brand_id: u32...@@ -199,45 +197,36 @@ fn detectIntelProcessor(cpu: *Target.Cpu, family: u32, model: u32, brand_id: u32
199 cpu.model = &Target.x86.cpu.knm;197 cpu.model = &Target.x86.cpu.knm;
200 return;198 return;
201 },199 },
202 else => {200 else => return, // Unknown CPU Model
203 // Unknown CPU.
204 // Default to baseline x86_64 or i386 cpu.
205 return;
206 },
207 }201 }
208 },202 },
209 15 => {203 15 => {
210 if(Target.x86.featureSetHas(cpu.features, .@"64bit")) {204 if (Target.x86.featureSetHas(cpu.features, .@"64bit")) {
211 cpu.model = &Target.x86.cpu.nocona;205 cpu.model = &Target.x86.cpu.nocona;
212 return;206 return;
213 }207 }
214 if(Target.x86.featureSetHas(cpu.features, .sse3)) {208 if (Target.x86.featureSetHas(cpu.features, .sse3)) {
215 cpu.model = &Target.x86.cpu.prescott;209 cpu.model = &Target.x86.cpu.prescott;
216 return;210 return;
217 }211 }
218 cpu.model = &Target.x86.cpu.pentium4;212 cpu.model = &Target.x86.cpu.pentium4;
219 return;213 return;
220 },214 },
221 else => {215 else => return, // Unknown CPU Model
222 // Unknown CPU.
223 // Default to baseline x86_64 or i386 cpu.
224 return;
225 }
226 }216 }
227}217}
228218
229fn detectAMDProcessor(cpu: *Target.Cpu, family: u32, model: u32) void {219fn detectAMDProcessor(cpu: *Target.Cpu, family: u32, model: u32) void {
230 // AMD's cpuid information is less than optimal for determining a CPU model.220 // AMD's cpuid information is less than optimal for determining a CPU model.
231 // This is very unscientific, and not necessarily correct.221 // This is very unscientific, and not necessarily correct.
232 222 switch (family) {
233 switch(family) {
234 4 => {223 4 => {
235 cpu.model = &Target.x86.cpu._i486;224 cpu.model = &Target.x86.cpu._i486;
236 return;225 return;
237 },226 },
238 5 => {227 5 => {
239 cpu.model = &Target.x86.cpu.pentium;228 cpu.model = &Target.x86.cpu.pentium;
240 switch(model) {229 switch (model) {
241 6, 7 => {230 6, 7 => {
242 cpu.model = &Target.x86.cpu.k6;231 cpu.model = &Target.x86.cpu.k6;
243 return;232 return;
...@@ -259,7 +248,7 @@ fn detectAMDProcessor(cpu: *Target.Cpu, family: u32, model: u32) void {...@@ -259,7 +248,7 @@ fn detectAMDProcessor(cpu: *Target.Cpu, family: u32, model: u32) void {
259 return;248 return;
260 },249 },
261 6 => {250 6 => {
262 if(Target.x86.featureSetHas(cpu.features, .sse)) {251 if (Target.x86.featureSetHas(cpu.features, .sse)) {
263 cpu.model = &Target.x86.cpu.athlon_xp;252 cpu.model = &Target.x86.cpu.athlon_xp;
264 return;253 return;
265 }254 }
...@@ -267,7 +256,7 @@ fn detectAMDProcessor(cpu: *Target.Cpu, family: u32, model: u32) void {...@@ -267,7 +256,7 @@ fn detectAMDProcessor(cpu: *Target.Cpu, family: u32, model: u32) void {
267 return;256 return;
268 },257 },
269 15 => {258 15 => {
270 if(Target.x86.featureSetHas(cpu.features, .sse3)) {259 if (Target.x86.featureSetHas(cpu.features, .sse3)) {
271 cpu.model = &Target.x86.cpu.k8_sse3;260 cpu.model = &Target.x86.cpu.k8_sse3;
272 return;261 return;
273 }262 }
...@@ -284,15 +273,15 @@ fn detectAMDProcessor(cpu: *Target.Cpu, family: u32, model: u32) void {...@@ -284,15 +273,15 @@ fn detectAMDProcessor(cpu: *Target.Cpu, family: u32, model: u32) void {
284 },273 },
285 21 => {274 21 => {
286 cpu.model = &Target.x86.cpu.bdver1;275 cpu.model = &Target.x86.cpu.bdver1;
287 if(model >= 0x60 and model <= 0x7f) {276 if (model >= 0x60 and model <= 0x7f) {
288 cpu.model = &Target.x86.cpu.bdver4;277 cpu.model = &Target.x86.cpu.bdver4;
289 return;278 return;
290 }279 }
291 if(model >= 0x30 and model <= 0x3f) {280 if (model >= 0x30 and model <= 0x3f) {
292 cpu.model = &Target.x86.cpu.bdver3;281 cpu.model = &Target.x86.cpu.bdver3;
293 return;282 return;
294 }283 }
295 if((model >= 0x10 and model <= 0x1f) or model == 0x02) {284 if ((model >= 0x10 and model <= 0x1f) or model == 0x02) {
296 cpu.model = &Target.x86.cpu.bdver2;285 cpu.model = &Target.x86.cpu.bdver2;
297 return;286 return;
298 }287 }
...@@ -304,7 +293,7 @@ fn detectAMDProcessor(cpu: *Target.Cpu, family: u32, model: u32) void {...@@ -304,7 +293,7 @@ fn detectAMDProcessor(cpu: *Target.Cpu, family: u32, model: u32) void {
304 },293 },
305 23 => {294 23 => {
306 cpu.model = &Target.x86.cpu.znver1;295 cpu.model = &Target.x86.cpu.znver1;
307 if((model >= 0x30 and model <= 0x3f) or model == 0x71) {296 if ((model >= 0x30 and model <= 0x3f) or model == 0x71) {
308 cpu.model = &Target.x86.cpu.znver2;297 cpu.model = &Target.x86.cpu.znver2;
309 return;298 return;
310 }299 }
...@@ -312,41 +301,40 @@ fn detectAMDProcessor(cpu: *Target.Cpu, family: u32, model: u32) void {...@@ -312,41 +301,40 @@ fn detectAMDProcessor(cpu: *Target.Cpu, family: u32, model: u32) void {
312 },301 },
313 else => {302 else => {
314 return;303 return;
315 }304 },
316 }305 }
317}306}
318307
319fn detectNativeFeatures(cpu: *Target.Cpu, os_type: Target.Os.Tag) void {308fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
320
321 var leaf = cpuid(0, 0);309 var leaf = cpuid(0, 0);
322310
323 const max_level = leaf.eax;311 const max_level = leaf.eax;
324 312
325 leaf = cpuid(1, 0);313 leaf = cpuid(1, 0);
326314
327 setFeature(cpu, .cx8, bit(leaf.edx, 8));315 setFeature(cpu, .cx8, bit(leaf.edx, 8));
328 setFeature(cpu, .cx8, bit(leaf.edx, 8));316 setFeature(cpu, .cx8, bit(leaf.edx, 8));
329 setFeature(cpu, .cmov, bit(leaf.edx, 15));317 setFeature(cpu, .cmov, bit(leaf.edx, 15));
330 setFeature(cpu, .mmx, bit(leaf.edx, 23));318 setFeature(cpu, .mmx, bit(leaf.edx, 23));
331 setFeature(cpu, .fxsr, bit(leaf.edx, 24));319 setFeature(cpu, .fxsr, bit(leaf.edx, 24));
332 setFeature(cpu, .sse, bit(leaf.edx, 25));320 setFeature(cpu, .sse, bit(leaf.edx, 25));
333 setFeature(cpu, .sse2, bit(leaf.edx, 26));321 setFeature(cpu, .sse2, bit(leaf.edx, 26));
334 setFeature(cpu, .sse3, bit(leaf.ecx, 0));322 setFeature(cpu, .sse3, bit(leaf.ecx, 0));
335 setFeature(cpu, .pclmul, bit(leaf.ecx, 1));323 setFeature(cpu, .pclmul, bit(leaf.ecx, 1));
336 setFeature(cpu, .ssse3, bit(leaf.ecx, 9));324 setFeature(cpu, .ssse3, bit(leaf.ecx, 9));
337 setFeature(cpu, .cx16, bit(leaf.ecx, 13));325 setFeature(cpu, .cx16, bit(leaf.ecx, 13));
338 setFeature(cpu, .sse4_1, bit(leaf.ecx, 19));326 setFeature(cpu, .sse4_1, bit(leaf.ecx, 19));
339 setFeature(cpu, .sse4_2, bit(leaf.ecx, 20));327 setFeature(cpu, .sse4_2, bit(leaf.ecx, 20));
340 setFeature(cpu, .movbe, bit(leaf.ecx, 22));328 setFeature(cpu, .movbe, bit(leaf.ecx, 22));
341 setFeature(cpu, .popcnt, bit(leaf.ecx, 23));329 setFeature(cpu, .popcnt, bit(leaf.ecx, 23));
342 setFeature(cpu, .aes, bit(leaf.ecx, 25));330 setFeature(cpu, .aes, bit(leaf.ecx, 25));
343 setFeature(cpu, .rdrnd, bit(leaf.ecx, 30));331 setFeature(cpu, .rdrnd, bit(leaf.ecx, 30));
344332
345 leaf.eax = getXCR0();333 leaf.eax = getXCR0();
346334
347 const has_avx = bit(leaf.ecx, 27) and335 const has_avx = bit(leaf.ecx, 27) and
348 bit(leaf.ecx, 28) and336 bit(leaf.ecx, 28) and
349 ((leaf.eax & 0x6) == 0x6);337 ((leaf.eax & 0x6) == 0x6);
350338
351 // LLVM approaches avx512_save by hardcoding it to true on Darwin,339 // LLVM approaches avx512_save by hardcoding it to true on Darwin,
352 // because the kernel saves the context even if the bit is not set.340 // because the kernel saves the context even if the bit is not set.
...@@ -368,96 +356,96 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_type: Target.Os.Tag) void {...@@ -368,96 +356,96 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_type: Target.Os.Tag) void {
368 // Darwin lazily saves the AVX512 context on first use: trust that the OS will356 // Darwin lazily saves the AVX512 context on first use: trust that the OS will
369 // save the AVX512 context if we use AVX512 instructions, even if the bit is not357 // save the AVX512 context if we use AVX512 instructions, even if the bit is not
370 // set right now.358 // set right now.
371 const has_avx512_save = switch(os_type.isDarwin()) {359 const has_avx512_save = switch (os_tag.isDarwin()) {
372 true => true,360 true => true,
373 false => has_avx and ((leaf.eax & 0xE0) == 0xE0),361 false => has_avx and ((leaf.eax & 0xE0) == 0xE0),
374 };362 };
375363
376 setFeature(cpu, .avx, has_avx);364 setFeature(cpu, .avx, has_avx);
377 setFeature(cpu, .fma, has_avx and bit(leaf.ecx, 12));365 setFeature(cpu, .fma, has_avx and bit(leaf.ecx, 12));
378 // Only enable XSAVE if OS has enabled support for saving YMM state.366 // Only enable XSAVE if OS has enabled support for saving YMM state.
379 setFeature(cpu, .xsave, has_avx and bit(leaf.ecx, 26));367 setFeature(cpu, .xsave, has_avx and bit(leaf.ecx, 26));
380 setFeature(cpu, .f16c, has_avx and bit(leaf.ecx, 29));368 setFeature(cpu, .f16c, has_avx and bit(leaf.ecx, 29));
381369
382 leaf = cpuid(0x80000000, 0);370 leaf = cpuid(0x80000000, 0);
383 const max_ext_level = leaf.eax;371 const max_ext_level = leaf.eax;
384372
385 if(max_ext_level >= 0x80000001) {373 if (max_ext_level >= 0x80000001) {
386 leaf = cpuid(0x80000001, 0);374 leaf = cpuid(0x80000001, 0);
387 setFeature(cpu, .sahf, bit(leaf.ecx, 0));375 setFeature(cpu, .sahf, bit(leaf.ecx, 0));
388 setFeature(cpu, .lzcnt, bit(leaf.ecx, 5));376 setFeature(cpu, .lzcnt, bit(leaf.ecx, 5));
389 setFeature(cpu, .sse4a, bit(leaf.ecx, 6));377 setFeature(cpu, .sse4a, bit(leaf.ecx, 6));
390 setFeature(cpu, .prfchw, bit(leaf.ecx, 8));378 setFeature(cpu, .prfchw, bit(leaf.ecx, 8));
391 setFeature(cpu, .xop, bit(leaf.ecx, 11) and has_avx);379 setFeature(cpu, .xop, bit(leaf.ecx, 11) and has_avx);
392 setFeature(cpu, .lwp, bit(leaf.ecx, 15));380 setFeature(cpu, .lwp, bit(leaf.ecx, 15));
393 setFeature(cpu, .fma4, bit(leaf.ecx, 16) and has_avx);381 setFeature(cpu, .fma4, bit(leaf.ecx, 16) and has_avx);
394 setFeature(cpu, .tbm, bit(leaf.ecx, 21));382 setFeature(cpu, .tbm, bit(leaf.ecx, 21));
395 setFeature(cpu, .mwaitx, bit(leaf.ecx, 29));383 setFeature(cpu, .mwaitx, bit(leaf.ecx, 29));
396 setFeature(cpu, .@"64bit", bit(leaf.edx, 29));384 setFeature(cpu, .@"64bit", bit(leaf.edx, 29));
397 } else {385 } else {
398 for([_]Target.x86.Feature{386 for ([_]Target.x86.Feature{
399 .sahf, .lzcnt, .sse4a, .prfchw, .xop,387 .sahf, .lzcnt, .sse4a, .prfchw, .xop,
400 .lwp, .fma4, .tbm, .mwaitx, .@"64bit"388 .lwp, .fma4, .tbm, .mwaitx, .@"64bit",
401 }) |feat| {389 }) |feat| {
402 setFeature(cpu, feat, false);390 setFeature(cpu, feat, false);
403 }391 }
404 }392 }
405393
406 // Misc. memory-related features.394 // Misc. memory-related features.
407 if(max_ext_level >= 0x80000008) {395 if (max_ext_level >= 0x80000008) {
408 leaf = cpuid(0x80000008, 0);396 leaf = cpuid(0x80000008, 0);
409 setFeature(cpu, .clzero, bit(leaf.ebx, 0));397 setFeature(cpu, .clzero, bit(leaf.ebx, 0));
410 setFeature(cpu, .wbnoinvd, bit(leaf.ebx, 9));398 setFeature(cpu, .wbnoinvd, bit(leaf.ebx, 9));
411 } else {399 } else {
412 for([_]Target.x86.Feature{ .clzero, .wbnoinvd }) |feat| {400 for ([_]Target.x86.Feature{ .clzero, .wbnoinvd }) |feat| {
413 setFeature(cpu, feat, false);401 setFeature(cpu, feat, false);
414 }402 }
415 }403 }
416404
417 if(max_level >= 0x7) {405 if (max_level >= 0x7) {
418 leaf = cpuid(0x7, 0);406 leaf = cpuid(0x7, 0);
419407
420 setFeature(cpu, .fsgsbase, bit(leaf.ebx, 0));408 setFeature(cpu, .fsgsbase, bit(leaf.ebx, 0));
421 setFeature(cpu, .sgx, bit(leaf.ebx, 2));409 setFeature(cpu, .sgx, bit(leaf.ebx, 2));
422 setFeature(cpu, .bmi, bit(leaf.ebx, 3));410 setFeature(cpu, .bmi, bit(leaf.ebx, 3));
423 // AVX2 is only supported if we have the OS save support from AVX.411 // AVX2 is only supported if we have the OS save support from AVX.
424 setFeature(cpu, .avx2, bit(leaf.ebx, 5) and has_avx);412 setFeature(cpu, .avx2, bit(leaf.ebx, 5) and has_avx);
425 setFeature(cpu, .bmi2, bit(leaf.ebx, 8));413 setFeature(cpu, .bmi2, bit(leaf.ebx, 8));
426 setFeature(cpu, .invpcid, bit(leaf.ebx, 10));414 setFeature(cpu, .invpcid, bit(leaf.ebx, 10));
427 setFeature(cpu, .rtm, bit(leaf.ebx, 11));415 setFeature(cpu, .rtm, bit(leaf.ebx, 11));
428 // AVX512 is only supported if the OS supports the context save for it.416 // AVX512 is only supported if the OS supports the context save for it.
429 setFeature(cpu, .avx512f, bit(leaf.ebx, 16) and has_avx512_save);417 setFeature(cpu, .avx512f, bit(leaf.ebx, 16) and has_avx512_save);
430 setFeature(cpu, .avx512dq, bit(leaf.ebx, 17) and has_avx512_save);418 setFeature(cpu, .avx512dq, bit(leaf.ebx, 17) and has_avx512_save);
431 setFeature(cpu, .rdseed, bit(leaf.ebx, 18));419 setFeature(cpu, .rdseed, bit(leaf.ebx, 18));
432 setFeature(cpu, .adx, bit(leaf.ebx, 19));420 setFeature(cpu, .adx, bit(leaf.ebx, 19));
433 setFeature(cpu, .avx512ifma, bit(leaf.ebx, 21) and has_avx512_save);421 setFeature(cpu, .avx512ifma, bit(leaf.ebx, 21) and has_avx512_save);
434 setFeature(cpu, .clflushopt, bit(leaf.ebx, 23));422 setFeature(cpu, .clflushopt, bit(leaf.ebx, 23));
435 setFeature(cpu, .clwb, bit(leaf.ebx, 24));423 setFeature(cpu, .clwb, bit(leaf.ebx, 24));
436 setFeature(cpu, .avx512pf, bit(leaf.ebx, 26) and has_avx512_save);424 setFeature(cpu, .avx512pf, bit(leaf.ebx, 26) and has_avx512_save);
437 setFeature(cpu, .avx512er, bit(leaf.ebx, 27) and has_avx512_save);425 setFeature(cpu, .avx512er, bit(leaf.ebx, 27) and has_avx512_save);
438 setFeature(cpu, .avx512cd, bit(leaf.ebx, 28) and has_avx512_save);426 setFeature(cpu, .avx512cd, bit(leaf.ebx, 28) and has_avx512_save);
439 setFeature(cpu, .sha, bit(leaf.ebx, 29));427 setFeature(cpu, .sha, bit(leaf.ebx, 29));
440 setFeature(cpu, .avx512bw, bit(leaf.ebx, 30) and has_avx512_save);428 setFeature(cpu, .avx512bw, bit(leaf.ebx, 30) and has_avx512_save);
441 setFeature(cpu, .avx512vl, bit(leaf.ebx, 31) and has_avx512_save);429 setFeature(cpu, .avx512vl, bit(leaf.ebx, 31) and has_avx512_save);
442430
443 setFeature(cpu, .prefetchwt1, bit(leaf.ecx, 0));431 setFeature(cpu, .prefetchwt1, bit(leaf.ecx, 0));
444 setFeature(cpu, .avx512vbmi, bit(leaf.ecx, 1) and has_avx512_save);432 setFeature(cpu, .avx512vbmi, bit(leaf.ecx, 1) and has_avx512_save);
445 setFeature(cpu, .pku, bit(leaf.ecx, 4));433 setFeature(cpu, .pku, bit(leaf.ecx, 4));
446 setFeature(cpu, .waitpkg, bit(leaf.ecx, 5));434 setFeature(cpu, .waitpkg, bit(leaf.ecx, 5));
447 setFeature(cpu, .avx512vbmi2, bit(leaf.ecx, 6) and has_avx512_save);435 setFeature(cpu, .avx512vbmi2, bit(leaf.ecx, 6) and has_avx512_save);
448 setFeature(cpu, .shstk, bit(leaf.ecx, 7));436 setFeature(cpu, .shstk, bit(leaf.ecx, 7));
449 setFeature(cpu, .gfni, bit(leaf.ecx, 8));437 setFeature(cpu, .gfni, bit(leaf.ecx, 8));
450 setFeature(cpu, .vaes, bit(leaf.ecx, 9) and has_avx);438 setFeature(cpu, .vaes, bit(leaf.ecx, 9) and has_avx);
451 setFeature(cpu, .vpclmulqdq, bit(leaf.ecx, 10) and has_avx);439 setFeature(cpu, .vpclmulqdq, bit(leaf.ecx, 10) and has_avx);
452 setFeature(cpu, .avx512vnni, bit(leaf.ecx, 11) and has_avx512_save);440 setFeature(cpu, .avx512vnni, bit(leaf.ecx, 11) and has_avx512_save);
453 setFeature(cpu, .avx512bitalg, bit(leaf.ecx, 12) and has_avx512_save);441 setFeature(cpu, .avx512bitalg, bit(leaf.ecx, 12) and has_avx512_save);
454 setFeature(cpu, .avx512vpopcntdq, bit(leaf.ecx, 14) and has_avx512_save);442 setFeature(cpu, .avx512vpopcntdq, bit(leaf.ecx, 14) and has_avx512_save);
455 setFeature(cpu, .avx512vp2intersect, bit(leaf.edx, 8) and has_avx512_save);443 setFeature(cpu, .avx512vp2intersect, bit(leaf.edx, 8) and has_avx512_save);
456 setFeature(cpu, .rdpid, bit(leaf.ecx, 22));444 setFeature(cpu, .rdpid, bit(leaf.ecx, 22));
457 setFeature(cpu, .cldemote, bit(leaf.ecx, 25));445 setFeature(cpu, .cldemote, bit(leaf.ecx, 25));
458 setFeature(cpu, .movdiri, bit(leaf.ecx, 27));446 setFeature(cpu, .movdiri, bit(leaf.ecx, 27));
459 setFeature(cpu, .movdir64b, bit(leaf.ecx, 28));447 setFeature(cpu, .movdir64b, bit(leaf.ecx, 28));
460 setFeature(cpu, .enqcmd, bit(leaf.ecx, 29));448 setFeature(cpu, .enqcmd, bit(leaf.ecx, 29));
461449
462 // There are two CPUID leafs which information associated with the pconfig450 // There are two CPUID leafs which information associated with the pconfig
463 // instruction:451 // instruction:
...@@ -469,21 +457,21 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_type: Target.Os.Tag) void {...@@ -469,21 +457,21 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_type: Target.Os.Tag) void {
469 // leaves using cpuid, since that information is ignored while457 // leaves using cpuid, since that information is ignored while
470 // detecting features using the "-march=native" flag.458 // detecting features using the "-march=native" flag.
471 // For more info, see X86 ISA docs.459 // For more info, see X86 ISA docs.
472 setFeature(cpu, .pconfig, bit(leaf.edx, 18));460 setFeature(cpu, .pconfig, bit(leaf.edx, 18));
473461
474 // TODO I feel unsure about this check.462 // TODO I feel unsure about this check.
475 // It doesn't really seem to check for 7.1, just for 7.463 // It doesn't really seem to check for 7.1, just for 7.
476 // Is this a sound assumption to make?464 // Is this a sound assumption to make?
477 // Note that this is what other implementations do, so I kind of trust it.465 // Note that this is what other implementations do, so I kind of trust it.
478 const has_leaf_7_1 = max_level >= 7;466 const has_leaf_7_1 = max_level >= 7;
479 if(has_leaf_7_1) {467 if (has_leaf_7_1) {
480 leaf = cpuid(0x7, 0x1);468 leaf = cpuid(0x7, 0x1);
481 setFeature(cpu, .avx512bf16, bit(leaf.eax, 5) and has_avx512_save);469 setFeature(cpu, .avx512bf16, bit(leaf.eax, 5) and has_avx512_save);
482 } else {470 } else {
483 setFeature(cpu, .avx512bf16, false);471 setFeature(cpu, .avx512bf16, false);
484 }472 }
485 } else {473 } else {
486 for([_]Target.x86.Feature{474 for ([_]Target.x86.Feature{
487 .fsgsbase, .sgx, .bmi, .avx2,475 .fsgsbase, .sgx, .bmi, .avx2,
488 .bmi2, .invpcid, .rtm, .avx512f,476 .bmi2, .invpcid, .rtm, .avx512f,
489 .avx512dq, .rdseed, .adx, .avx512ifma,477 .avx512dq, .rdseed, .adx, .avx512ifma,
...@@ -499,26 +487,24 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_type: Target.Os.Tag) void {...@@ -499,26 +487,24 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_type: Target.Os.Tag) void {
499 }487 }
500 }488 }
501489
502 if(max_level >= 0xD and has_avx) {490 if (max_level >= 0xD and has_avx) {
503 leaf = cpuid(0xD, 0x1);491 leaf = cpuid(0xD, 0x1);
504 // Only enable XSAVE if OS has enabled support for saving YMM state.492 // Only enable XSAVE if OS has enabled support for saving YMM state.
505 setFeature(cpu, .xsaveopt, bit(leaf.eax, 0));493 setFeature(cpu, .xsaveopt, bit(leaf.eax, 0));
506 setFeature(cpu, .xsavec, bit(leaf.eax, 1));494 setFeature(cpu, .xsavec, bit(leaf.eax, 1));
507 setFeature(cpu, .xsaves, bit(leaf.eax, 3));495 setFeature(cpu, .xsaves, bit(leaf.eax, 3));
508
509 } else {496 } else {
510 for([_]Target.x86.Feature{ .xsaveopt, .xsavec, .xsaves }) |feat| {497 for ([_]Target.x86.Feature{ .xsaveopt, .xsavec, .xsaves }) |feat| {
511 setFeature(cpu, feat, false);498 setFeature(cpu, feat, false);
512 }499 }
513 }500 }
514501
515 if(max_level >= 0x14) {502 if (max_level >= 0x14) {
516 leaf = cpuid(0x14, 0);503 leaf = cpuid(0x14, 0);
517 setFeature(cpu, .ptwrite, bit(leaf.ebx, 4));504 setFeature(cpu, .ptwrite, bit(leaf.ebx, 4));
518 } else {505 } else {
519 setFeature(cpu, .ptwrite, false);506 setFeature(cpu, .ptwrite, false);
520 }507 }
521
522}508}
523509
524const CpuidLeaf = packed struct {510const CpuidLeaf = packed struct {
...@@ -532,9 +518,9 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {...@@ -532,9 +518,9 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {
532 // Workaround for https://github.com/ziglang/zig/issues/215518 // Workaround for https://github.com/ziglang/zig/issues/215
533 // Inline assembly in zig only supports one output,519 // Inline assembly in zig only supports one output,
534 // so we pass a pointer to the struct.520 // so we pass a pointer to the struct.
535 var cpuid_leaf = CpuidLeaf {.eax = 0, .ebx = 0, .ecx = 0, .edx = 0};521 var cpuid_leaf = CpuidLeaf{ .eax = 0, .ebx = 0, .ecx = 0, .edx = 0 };
536 var leaf_ptr = &cpuid_leaf;522 var leaf_ptr = &cpuid_leaf;
537 switch(Target.current.cpu.arch) {523 switch (Target.current.cpu.arch) {
538 .i386 => {524 .i386 => {
539 _ = asm volatile (525 _ = asm volatile (
540 \\ cpuid526 \\ cpuid
...@@ -542,10 +528,10 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {...@@ -542,10 +528,10 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {
542 \\ movl %%ebx, 4(%%edi)528 \\ movl %%ebx, 4(%%edi)
543 \\ movl %%ecx, 8(%%edi)529 \\ movl %%ecx, 8(%%edi)
544 \\ movl %%edx, 12(%%edi)530 \\ movl %%edx, 12(%%edi)
545 : :531 :
546 [leaf_id] "{eax}" (leaf_id),532 : [leaf_id] "{eax}" (leaf_id),
547 [subid] "{ecx}" (subid),533 [subid] "{ecx}" (subid),
548 [leaf_ptr] "{edi}" (leaf_ptr),534 [leaf_ptr] "{edi}" (leaf_ptr)
549 : "eax", "ebx", "ecx", "edx"535 : "eax", "ebx", "ecx", "edx"
550 );536 );
551 },537 },
...@@ -556,10 +542,10 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {...@@ -556,10 +542,10 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {
556 \\ movl %%ebx, 4(%%rdi)542 \\ movl %%ebx, 4(%%rdi)
557 \\ movl %%ecx, 8(%%rdi)543 \\ movl %%ecx, 8(%%rdi)
558 \\ movl %%edx, 12(%%rdi)544 \\ movl %%edx, 12(%%rdi)
559 : :545 :
560 [leaf_id] "{eax}" (leaf_id),546 : [leaf_id] "{eax}" (leaf_id),
561 [subid] "{ecx}" (subid),547 [subid] "{ecx}" (subid),
562 [leaf_ptr] "{rdi}" (leaf_ptr),548 [leaf_ptr] "{rdi}" (leaf_ptr)
563 : "eax", "ebx", "ecx", "edx"549 : "eax", "ebx", "ecx", "edx"
564 );550 );
565 },551 },
...@@ -570,14 +556,11 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {...@@ -570,14 +556,11 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {
570556
571// Read control register 0 (XCR0). Used to detect features such as AVX.557// Read control register 0 (XCR0). Used to detect features such as AVX.
572fn getXCR0() u32 {558fn getXCR0() u32 {
573
574 return asm (559 return asm (
575 \\ .byte 0x0F, 0x01, 0xD0560 \\ .byte 0x0F, 0x01, 0xD0
576 : [ret] "={eax}" (-> u32)561 : [ret] "={eax}" (-> u32)
577 : [number] "{eax}" (@as(u32, 0)),562 : [number] "{eax}" (@as(u32, 0)),
578 [number] "{edx}" (@as(u32, 0)),563 [number] "{edx}" (@as(u32, 0)),
579 [number] "{ecx}" (@as(u32, 0)),564 [number] "{ecx}" (@as(u32, 0))
580 :
581 );565 );
582}566}
583
src-self-hosted/stage2.zig+1-1
...@@ -1154,7 +1154,7 @@ fn enumInt(comptime Enum: type, int: c_int) Enum {...@@ -1154,7 +1154,7 @@ fn enumInt(comptime Enum: type, int: c_int) Enum {
11541154
1155fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) !Target {1155fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) !Target {
1156 var info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator, cross_target);1156 var info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator, cross_target);
1157 if ((cross_target.cpu_arch == null or cross_target.cpu_model == .native) and !info.cpu_detected) {1157 if (info.cpu_detection_unimplemented) {
1158 // TODO We want to just use detected_info.target but implementing1158 // TODO We want to just use detected_info.target but implementing
1159 // CPU model & feature detection is todo so here we rely on LLVM.1159 // CPU model & feature detection is todo so here we rely on LLVM.
1160 const llvm = @import("llvm.zig");1160 const llvm = @import("llvm.zig");