authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-22 17:13:31-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-22 17:13:31-05:00
log48c7e6c48b81e6e0423b3e4aea238402189eecb7
tree1d585eaa73a43b473809ffdc85b4207e2e72ee9c
parentc6bfece1d54c54024397d7aff9f25087cc4dbfda
signaturelock-open Commit is signed but in an unrecognized format.

std.Target.CpuFeatures is now a struct with both CPU and feature set

Previously it was a tagged union which was one of: * baseline * a specific CPU * a set of features Now, it's possible to have a CPU but also modify the CPU's feature set on top of that. This is closer to what LLVM does. This is more correct because Zig's notion of CPUs (and LLVM's) is not exact CPU models. For example "skylake" is not one very specific model; there are several different pieces of hardware that match "skylake" that have different feature sets enabled.

13 files changed, 557 insertions(+), 657 deletions(-)

lib/std/build.zig+35-17
......@@ -484,6 +484,7 @@ pub const Builder = struct {
484484 .arch = builtin.arch,
485485 .os = builtin.os,
486486 .abi = builtin.abi,
487 .cpu_features = builtin.cpu_features,
487488 },
488489 }).linuxTriple(self.allocator);
489490
......@@ -1375,6 +1376,7 @@ pub const LibExeObjStep = struct {
13751376 .arch = target_arch,
13761377 .os = target_os,
13771378 .abi = target_abi,
1379 .cpu_features = target_arch.getBaselineCpuFeatures(),
13781380 },
13791381 });
13801382 }
......@@ -1972,25 +1974,41 @@ pub const LibExeObjStep = struct {
19721974 try zig_args.append("-target");
19731975 try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable);
19741976
1975 switch (cross.cpu_features) {
1976 .baseline => {},
1977 .cpu => |cpu| {
1977 const all_features = self.target.getArch().allFeaturesList();
1978 var populated_cpu_features = cross.cpu_features.cpu.features;
1979 populated_cpu_features.populateDependencies(all_features);
1980
1981 if (populated_cpu_features.eql(cross.cpu_features.features)) {
1982 // The CPU name alone is sufficient.
1983 // If it is the baseline CPU, no command line args are required.
1984 if (cross.cpu_features.cpu != self.target.getArch().getBaselineCpuFeatures().cpu) {
19781985 try zig_args.append("-target-cpu");
1979 try zig_args.append(cpu.name);
1980 },
1981 .features => |features| {
1982 try zig_args.append("-target-cpu-features");
1983
1984 var feature_str_buffer = try std.Buffer.initSize(builder.allocator, 0);
1985 for (self.target.getArch().allFeaturesList()) |feature, i| {
1986 if (features.isEnabled(@intCast(Target.Cpu.Feature.Set.Index, i))) {
1987 try feature_str_buffer.append(feature.name);
1988 try feature_str_buffer.append(",");
1989 }
1986 try zig_args.append(cross.cpu_features.cpu.name);
1987 }
1988 } else {
1989 try zig_args.append("-target-cpu");
1990 try zig_args.append(cross.cpu_features.cpu.name);
1991
1992 try zig_args.append("-target-feature");
1993 var feature_str_buffer = try std.Buffer.initSize(builder.allocator, 0);
1994 for (all_features) |feature, i_usize| {
1995 const i = @intCast(Target.Cpu.Feature.Set.Index, i_usize);
1996 const in_cpu_set = populated_cpu_features.isEnabled(i);
1997 const in_actual_set = cross.cpu_features.features.isEnabled(i);
1998 if (in_cpu_set and !in_actual_set) {
1999 try feature_str_buffer.appendByte('-');
2000 try feature_str_buffer.append(feature.name);
2001 try feature_str_buffer.appendByte(',');
2002 } else if (!in_cpu_set and in_actual_set) {
2003 try feature_str_buffer.appendByte('+');
2004 try feature_str_buffer.append(feature.name);
2005 try feature_str_buffer.appendByte(',');
19902006 }
1991
1992 try zig_args.append(feature_str_buffer.toSlice());
1993 },
2007 }
2008 if (mem.endsWith(u8, feature_str_buffer.toSliceConst(), ",")) {
2009 feature_str_buffer.shrink(feature_str_buffer.len() - 1);
2010 }
2011 try zig_args.append(feature_str_buffer.toSliceConst());
19942012 }
19952013 },
19962014 }
lib/std/target.zig+70-82
......@@ -172,6 +172,15 @@ pub const Target = union(enum) {
172172 r6,
173173 };
174174
175 pub fn subArchName(arch: Arch) ?[]const u8 {
176 return switch (arch) {
177 .arm, .armeb, .thumb, .thumbeb => |arm32| @tagName(arm32),
178 .aarch64, .aarch64_be, .aarch64_32 => |arm64| @tagName(arm64),
179 .kalimba => |kalimba| @tagName(kalimba),
180 else => return null,
181 };
182 }
183
175184 pub fn subArchFeature(arch: Arch) ?u8 {
176185 return switch (arch) {
177186 .arm, .armeb, .thumb, .thumbeb => |arm32| switch (arm32) {
......@@ -251,24 +260,12 @@ pub const Target = union(enum) {
251260 return error.UnknownCpu;
252261 }
253262
254 /// This parsing function supports 2 syntaxes.
255 /// * Comma-separated list of features, with + or - in front of each feature. This
256 /// form represents a deviation from baseline.
257 /// * Comma-separated list of features, with no + or - in front of each feature. This
258 /// form represents an exclusive list of enabled features; no other features besides
259 /// the ones listed, and their dependencies, will be enabled.
263 /// Comma-separated list of features, with + or - in front of each feature. This
264 /// form represents a deviation from baseline CPU, which is provided as a parameter.
260265 /// Extra commas are ignored.
261 pub fn parseCpuFeatureSet(arch: Arch, features_text: []const u8) !Cpu.Feature.Set {
262 // Here we compute both and choose the correct result at the end, based
263 // on whether or not we saw + and - signs.
264 var whitelist_set = Cpu.Feature.Set.empty;
265 var baseline_set = arch.baselineFeatures();
266 var mode: enum {
267 unknown,
268 baseline,
269 whitelist,
270 } = .unknown;
271
266 pub fn parseCpuFeatureSet(arch: Arch, cpu: *const Cpu, features_text: []const u8) !Cpu.Feature.Set {
267 const all_features = arch.allFeaturesList();
268 var set = cpu.features;
272269 var it = mem.tokenize(features_text, ",");
273270 while (it.next()) |item_text| {
274271 var feature_name: []const u8 = undefined;
......@@ -277,40 +274,20 @@ pub const Target = union(enum) {
277274 sub,
278275 } = undefined;
279276 if (mem.startsWith(u8, item_text, "+")) {
280 switch (mode) {
281 .unknown, .baseline => mode = .baseline,
282 .whitelist => return error.InvalidCpuFeatures,
283 }
284277 op = .add;
285278 feature_name = item_text[1..];
286279 } else if (mem.startsWith(u8, item_text, "-")) {
287 switch (mode) {
288 .unknown, .baseline => mode = .baseline,
289 .whitelist => return error.InvalidCpuFeatures,
290 }
291280 op = .sub;
292281 feature_name = item_text[1..];
293282 } else {
294 switch (mode) {
295 .unknown, .whitelist => mode = .whitelist,
296 .baseline => return error.InvalidCpuFeatures,
297 }
298 op = .add;
299 feature_name = item_text;
283 return error.InvalidCpuFeatures;
300284 }
301 const all_features = arch.allFeaturesList();
302285 for (all_features) |feature, index_usize| {
303286 const index = @intCast(Cpu.Feature.Set.Index, index_usize);
304287 if (mem.eql(u8, feature_name, feature.name)) {
305288 switch (op) {
306 .add => {
307 baseline_set.addFeature(index);
308 whitelist_set.addFeature(index);
309 },
310 .sub => {
311 baseline_set.removeFeature(index);
312 whitelist_set.removeFeature(index);
313 },
289 .add => set.addFeature(index),
290 .sub => set.removeFeature(index),
314291 }
315292 break;
316293 }
......@@ -319,10 +296,8 @@ pub const Target = union(enum) {
319296 }
320297 }
321298
322 return switch (mode) {
323 .unknown, .whitelist => whitelist_set,
324 .baseline => baseline_set,
325 };
299 set.populateDependencies(all_features);
300 return set;
326301 }
327302
328303 pub fn toElfMachine(arch: Arch) std.elf.EM {
......@@ -485,29 +460,37 @@ pub const Target = union(enum) {
485460
486461 /// The "default" set of CPU features for cross-compiling. A conservative set
487462 /// of features that is expected to be supported on most available hardware.
488 pub fn baselineFeatures(arch: Arch) Cpu.Feature.Set {
489 return switch (arch) {
490 .arm, .armeb, .thumb, .thumbeb => arm.cpu.generic.features,
491 .aarch64, .aarch64_be, .aarch64_32 => aarch64.cpu.generic.features,
492 .avr => avr.baseline_features,
493 .bpfel, .bpfeb => bpf.cpu.generic.features,
494 .hexagon => hexagon.cpu.generic.features,
495 .mips, .mipsel => mips.cpu.mips32.features,
496 .mips64, .mips64el => mips.cpu.mips64.features,
497 .msp430 => msp430.cpu.generic.features,
498 .powerpc, .powerpc64, .powerpc64le => powerpc.cpu.generic.features,
499 .amdgcn => amdgpu.cpu.generic.features,
500 .riscv32 => riscv.baseline_32_features,
501 .riscv64 => riscv.baseline_64_features,
502 .sparc, .sparcv9, .sparcel => sparc.cpu.generic.features,
503 .s390x => systemz.cpu.generic.features,
504 .i386 => x86.cpu.pentium4.features,
505 .x86_64 => x86.cpu.x86_64.features,
506 .nvptx, .nvptx64 => nvptx.cpu.sm_20.features,
507 .wasm32, .wasm64 => wasm.cpu.generic.features,
508
509 else => Cpu.Feature.Set.empty,
463 pub fn getBaselineCpuFeatures(arch: Arch) CpuFeatures {
464 const S = struct {
465 const generic_cpu = Cpu{
466 .name = "generic",
467 .llvm_name = null,
468 .features = Cpu.Feature.Set.empty,
469 };
470 };
471 const cpu = switch (arch) {
472 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic,
473 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
474 .avr => &avr.cpu.avr1,
475 .bpfel, .bpfeb => &bpf.cpu.generic,
476 .hexagon => &hexagon.cpu.generic,
477 .mips, .mipsel => &mips.cpu.mips32,
478 .mips64, .mips64el => &mips.cpu.mips64,
479 .msp430 => &msp430.cpu.generic,
480 .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic,
481 .amdgcn => &amdgpu.cpu.generic,
482 .riscv32 => &riscv.cpu.baseline_rv32,
483 .riscv64 => &riscv.cpu.baseline_rv64,
484 .sparc, .sparcv9, .sparcel => &sparc.cpu.generic,
485 .s390x => &systemz.cpu.generic,
486 .i386 => &x86.cpu.pentium4,
487 .x86_64 => &x86.cpu.x86_64,
488 .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
489 .wasm32, .wasm64 => &wasm.cpu.generic,
490
491 else => &S.generic_cpu,
510492 };
493 return CpuFeatures.initFromCpu(arch, cpu);
511494 }
512495
513496 /// All CPUs Zig is aware of, sorted lexicographically by name.
......@@ -685,19 +668,28 @@ pub const Target = union(enum) {
685668 arch: Arch,
686669 os: Os,
687670 abi: Abi,
688 cpu_features: CpuFeatures = .baseline,
671 cpu_features: CpuFeatures,
689672 };
690673
691 pub const CpuFeatures = union(enum) {
692 /// The "default" set of CPU features for cross-compiling. A conservative set
693 /// of features that is expected to be supported on most available hardware.
694 baseline,
695
696 /// Target one specific CPU.
674 pub const CpuFeatures = struct {
675 /// The CPU to target. It has a set of features
676 /// which are overridden with the `features` field.
697677 cpu: *const Cpu,
698678
699679 /// Explicitly provide the entire CPU feature set.
700680 features: Cpu.Feature.Set,
681
682 pub fn initFromCpu(arch: Arch, cpu: *const Cpu) CpuFeatures {
683 var features = cpu.features;
684 if (arch.subArchFeature()) |sub_arch_index| {
685 features.addFeature(sub_arch_index);
686 }
687 features.populateDependencies(arch.allFeaturesList());
688 return CpuFeatures{
689 .cpu = cpu,
690 .features = features,
691 };
692 }
701693 };
702694
703695 pub const current = Target{
......@@ -718,14 +710,6 @@ pub const Target = union(enum) {
718710 };
719711 }
720712
721 pub fn cpuFeatureSet(self: Target) Cpu.Feature.Set {
722 return switch (self.getCpuFeatures()) {
723 .baseline => self.getArch().baselineFeatures(),
724 .cpu => |cpu| cpu.features,
725 .features => |features| features,
726 };
727 }
728
729713 pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
730714 return std.fmt.allocPrint(allocator, "{}{}-{}-{}", .{
731715 @tagName(self.getArch()),
......@@ -791,14 +775,18 @@ pub const Target = union(enum) {
791775 });
792776 }
793777
778 /// TODO: Support CPU features here?
779 /// https://github.com/ziglang/zig/issues/4261
794780 pub fn parse(text: []const u8) !Target {
795781 var it = mem.separate(text, "-");
796782 const arch_name = it.next() orelse return error.MissingArchitecture;
797783 const os_name = it.next() orelse return error.MissingOperatingSystem;
798784 const abi_name = it.next();
785 const arch = try parseArchSub(arch_name);
799786
800787 var cross = Cross{
801 .arch = try parseArchSub(arch_name),
788 .arch = arch,
789 .cpu_features = arch.getBaselineCpuFeatures(),
802790 .os = try parseOs(os_name),
803791 .abi = undefined,
804792 };
lib/std/target/avr.zig-4
......@@ -2378,7 +2378,3 @@ pub const all_cpus = &[_]*const Cpu{
23782378 &cpu.avrxmega7,
23792379 &cpu.m3000,
23802380};
2381
2382pub const baseline_features = featureSet(&[_]Feature{
2383 .avr0,
2384});
lib/std/target/riscv.zig+30-19
......@@ -69,11 +69,39 @@ pub const all_features = blk: {
6969};
7070
7171pub const cpu = struct {
72 pub const baseline_rv32 = Cpu{
73 .name = "baseline_rv32",
74 .llvm_name = "generic-rv32",
75 .features = featureSet(&[_]Feature{
76 .a,
77 .c,
78 .d,
79 .f,
80 .m,
81 .relax,
82 }),
83 };
84
85 pub const baseline_rv64 = Cpu{
86 .name = "baseline_rv64",
87 .llvm_name = "generic-rv64",
88 .features = featureSet(&[_]Feature{
89 .@"64bit",
90 .a,
91 .c,
92 .d,
93 .f,
94 .m,
95 .relax,
96 }),
97 };
98
7299 pub const generic_rv32 = Cpu{
73100 .name = "generic_rv32",
74101 .llvm_name = "generic-rv32",
75102 .features = featureSet(&[_]Feature{}),
76103 };
104
77105 pub const generic_rv64 = Cpu{
78106 .name = "generic_rv64",
79107 .llvm_name = "generic-rv64",
......@@ -87,25 +115,8 @@ pub const cpu = struct {
87115/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1
88116/// compiler has inefficient memory and CPU usage, affecting build times.
89117pub const all_cpus = &[_]*const Cpu{
118 &cpu.baseline_rv32,
119 &cpu.baseline_rv64,
90120 &cpu.generic_rv32,
91121 &cpu.generic_rv64,
92122};
93
94pub const baseline_32_features = featureSet(&[_]Feature{
95 .a,
96 .c,
97 .d,
98 .f,
99 .m,
100 .relax,
101});
102
103pub const baseline_64_features = featureSet(&[_]Feature{
104 .@"64bit",
105 .a,
106 .c,
107 .d,
108 .f,
109 .m,
110 .relax,
111});
src-self-hosted/print_targets.zig+5-7
......@@ -227,16 +227,14 @@ pub fn cmdTargets(
227227 try jws.objectField("abi");
228228 try jws.emitString(@tagName(native_target.getAbi()));
229229 try jws.objectField("cpuName");
230 switch (native_target.getCpuFeatures()) {
231 .baseline, .features => try jws.emitNull(),
232 .cpu => |cpu| try jws.emitString(cpu.name),
233 }
230 const cpu_features = native_target.getCpuFeatures();
231 try jws.emitString(cpu_features.cpu.name);
234232 {
235233 try jws.objectField("cpuFeatures");
236234 try jws.beginArray();
237 const feature_set = native_target.cpuFeatureSet();
238 for (native_target.getArch().allFeaturesList()) |feature, i| {
239 if (feature_set.isEnabled(@intCast(u8, i))) {
235 for (native_target.getArch().allFeaturesList()) |feature, i_usize| {
236 const index = @intCast(Target.Cpu.Feature.Set.Index, i_usize);
237 if (cpu_features.features.isEnabled(index)) {
240238 try jws.arrayElem();
241239 try jws.emitString(feature.name);
242240 }
src-self-hosted/stage1.zig+140-256
......@@ -540,74 +540,66 @@ export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usiz
540540 node.context.maybeRefresh();
541541}
542542
543/// I have observed the CPU name reported by LLVM being incorrect. On
544/// the SourceHut build services, LLVM 9.0 reports the CPU as "athlon-xp",
545/// which is a 32-bit CPU, even though the system is 64-bit and the reported
546/// CPU features include, among other things, +64bit.
547/// So the strategy taken here is that we observe both reported CPU, and the
548/// reported CPU features. The features are trusted more; but if the features
549/// match exactly the features of the reported CPU, then we trust the reported CPU.
550543fn cpuFeaturesFromLLVM(
551544 arch: Target.Arch,
552545 llvm_cpu_name_z: ?[*:0]const u8,
553546 llvm_cpu_features_opt: ?[*:0]const u8,
554547) !Target.CpuFeatures {
555 var set = arch.baselineFeatures();
556 const llvm_cpu_features = llvm_cpu_features_opt orelse return Target.CpuFeatures{
557 .features = set,
558 };
548 var result = arch.getBaselineCpuFeatures();
559549
560 const all_features = arch.allFeaturesList();
550 if (llvm_cpu_name_z) |cpu_name_z| {
551 const llvm_cpu_name = mem.toSliceConst(u8, cpu_name_z);
561552
562 var it = mem.tokenize(mem.toSliceConst(u8, llvm_cpu_features), ",");
563 while (it.next()) |decorated_llvm_feat| {
564 var op: enum {
565 add,
566 sub,
567 } = undefined;
568 var llvm_feat: []const u8 = undefined;
569 if (mem.startsWith(u8, decorated_llvm_feat, "+")) {
570 op = .add;
571 llvm_feat = decorated_llvm_feat[1..];
572 } else if (mem.startsWith(u8, decorated_llvm_feat, "-")) {
573 op = .sub;
574 llvm_feat = decorated_llvm_feat[1..];
575 } else {
576 return error.InvalidLlvmCpuFeaturesFormat;
577 }
578 for (all_features) |feature, index| {
579 const this_llvm_name = feature.llvm_name orelse continue;
580 if (mem.eql(u8, llvm_feat, this_llvm_name)) {
581 switch (op) {
582 .add => set.addFeature(@intCast(u8, index)),
583 .sub => set.removeFeature(@intCast(u8, index)),
584 }
553 for (arch.allCpus()) |cpu| {
554 const this_llvm_name = cpu.llvm_name orelse continue;
555 if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) {
556 // Here we use the non-dependencies-populated set,
557 // so that subtracting features later in this function
558 // affect the prepopulated set.
559 result = Target.CpuFeatures{
560 .cpu = cpu,
561 .features = cpu.features,
562 };
585563 break;
586564 }
587565 }
588566 }
589567
590 if (llvm_cpu_name_z) |cpu_name_z| {
591 const llvm_cpu_name = mem.toSliceConst(u8, cpu_name_z);
568 const all_features = arch.allFeaturesList();
592569
593 for (arch.allCpus()) |cpu| {
594 const this_llvm_name = cpu.llvm_name orelse continue;
595 if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) {
596 // Only trust the CPU if the reported features exactly match.
597 var populated_reported_features = set;
598 populated_reported_features.populateDependencies(all_features);
599 var populated_cpu_features = cpu.features;
600 populated_cpu_features.populateDependencies(all_features);
601 if (populated_reported_features.eql(populated_cpu_features)) {
602 return Target.CpuFeatures{ .cpu = cpu };
603 } else {
604 return Target.CpuFeatures{ .features = set };
570 if (llvm_cpu_features_opt) |llvm_cpu_features| {
571 var it = mem.tokenize(mem.toSliceConst(u8, llvm_cpu_features), ",");
572 while (it.next()) |decorated_llvm_feat| {
573 var op: enum {
574 add,
575 sub,
576 } = undefined;
577 var llvm_feat: []const u8 = undefined;
578 if (mem.startsWith(u8, decorated_llvm_feat, "+")) {
579 op = .add;
580 llvm_feat = decorated_llvm_feat[1..];
581 } else if (mem.startsWith(u8, decorated_llvm_feat, "-")) {
582 op = .sub;
583 llvm_feat = decorated_llvm_feat[1..];
584 } else {
585 return error.InvalidLlvmCpuFeaturesFormat;
586 }
587 for (all_features) |feature, index_usize| {
588 const this_llvm_name = feature.llvm_name orelse continue;
589 if (mem.eql(u8, llvm_feat, this_llvm_name)) {
590 const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
591 switch (op) {
592 .add => result.features.addFeature(index),
593 .sub => result.features.removeFeature(index),
594 }
595 break;
605596 }
606597 }
607598 }
608599 }
609600
610 return Target.CpuFeatures{ .features = set };
601 result.features.populateDependencies(all_features);
602 return result;
611603}
612604
613605// ABI warning
......@@ -639,7 +631,6 @@ const Stage2CpuFeatures = struct {
639631 allocator: *mem.Allocator,
640632 cpu_features: Target.CpuFeatures,
641633
642 llvm_cpu_name: ?[*:0]const u8,
643634 llvm_features_str: ?[*:0]const u8,
644635
645636 builtin_str: [:0]const u8,
......@@ -647,125 +638,64 @@ const Stage2CpuFeatures = struct {
647638
648639 const Self = @This();
649640
650 fn createBaseline(allocator: *mem.Allocator, arch: Target.Arch) !*Self {
651 const self = try allocator.create(Self);
652 errdefer allocator.destroy(self);
653
654 const builtin_str = try std.fmt.allocPrint0(allocator, ".baseline;\n", .{});
655 errdefer allocator.free(builtin_str);
656
657 const cache_hash = try std.fmt.allocPrint0(allocator, "\n\n", .{});
658 errdefer allocator.free(cache_hash);
659
660 self.* = Self{
661 .allocator = allocator,
662 .cpu_features = .baseline,
663 .llvm_cpu_name = null,
664 .llvm_features_str = try initLLVMFeatures(allocator, arch, arch.baselineFeatures()),
665 .builtin_str = builtin_str,
666 .cache_hash = cache_hash,
667 };
668
669 return self;
670 }
671
672 fn createFromLLVM(
673 allocator: *mem.Allocator,
674 zig_triple: [*:0]const u8,
675 llvm_cpu_name_z: ?[*:0]const u8,
676 llvm_cpu_features: ?[*:0]const u8,
677 ) !*Self {
678 const target = try Target.parse(mem.toSliceConst(u8, zig_triple));
679 const arch = target.Cross.arch;
680 const cpu_features = try cpuFeaturesFromLLVM(arch, llvm_cpu_name_z, llvm_cpu_features);
681 switch (cpu_features) {
682 .baseline => return createBaseline(allocator, arch),
683 .cpu => |cpu| return createFromCpu(allocator, arch, cpu),
684 .features => |features| return createFromCpuFeatures(allocator, arch, features),
685 }
686 }
687
688 fn createFromCpu(allocator: *mem.Allocator, arch: Target.Arch, cpu: *const Target.Cpu) !*Self {
689 const self = try allocator.create(Self);
690 errdefer allocator.destroy(self);
691
692 const builtin_str = try std.fmt.allocPrint0(allocator, "CpuFeatures{{ .cpu = &Target.{}.cpu.{} }};\n", .{
693 arch.genericName(),
694 cpu.name,
695 });
696 errdefer allocator.free(builtin_str);
697
698 const cache_hash = try std.fmt.allocPrint0(allocator, "{}\n{}", .{ cpu.name, cpu.features.asBytes() });
699 errdefer allocator.free(cache_hash);
700
701 self.* = Self{
702 .allocator = allocator,
703 .cpu_features = .{ .cpu = cpu },
704 .llvm_cpu_name = if (cpu.llvm_name) |n| n.ptr else null,
705 .llvm_features_str = null,
706 .builtin_str = builtin_str,
707 .cache_hash = cache_hash,
708 };
709 return self;
710 }
711
712 fn initLLVMFeatures(
713 allocator: *mem.Allocator,
714 arch: Target.Arch,
715 feature_set: Target.Cpu.Feature.Set,
716 ) ![*:0]const u8 {
717 var llvm_features_buffer = try std.Buffer.initSize(allocator, 0);
718 defer llvm_features_buffer.deinit();
719
720 const all_features = arch.allFeaturesList();
721 var populated_feature_set = feature_set;
722 if (arch.subArchFeature()) |sub_arch_index| {
723 populated_feature_set.addFeature(sub_arch_index);
724 }
725 populated_feature_set.populateDependencies(all_features);
726 for (all_features) |feature, index| {
727 const llvm_name = feature.llvm_name orelse continue;
728 const plus_or_minus = "-+"[@boolToInt(populated_feature_set.isEnabled(@intCast(u8, index)))];
729 try llvm_features_buffer.appendByte(plus_or_minus);
730 try llvm_features_buffer.append(llvm_name);
731 try llvm_features_buffer.append(",");
732 }
733 assert(mem.endsWith(u8, llvm_features_buffer.toSliceConst(), ","));
734 llvm_features_buffer.shrink(llvm_features_buffer.len() - 1);
735
736 return llvm_features_buffer.toOwnedSlice().ptr;
641 fn createFromNative(allocator: *mem.Allocator) !*Self {
642 const arch = Target.current.getArch();
643 const llvm = @import("llvm.zig");
644 const llvm_cpu_name = llvm.GetHostCPUName();
645 const llvm_cpu_features = llvm.GetNativeFeatures();
646 const cpu_features = try cpuFeaturesFromLLVM(arch, llvm_cpu_name, llvm_cpu_features);
647 return createFromCpuFeatures(allocator, arch, cpu_features);
737648 }
738649
739650 fn createFromCpuFeatures(
740651 allocator: *mem.Allocator,
741652 arch: Target.Arch,
742 feature_set: Target.Cpu.Feature.Set,
653 cpu_features: Target.CpuFeatures,
743654 ) !*Self {
744655 const self = try allocator.create(Self);
745656 errdefer allocator.destroy(self);
746657
747 const cache_hash = try std.fmt.allocPrint0(allocator, "\n{}", .{feature_set.asBytes()});
658 const cache_hash = try std.fmt.allocPrint0(allocator, "{}\n{}", .{
659 cpu_features.cpu.name,
660 cpu_features.features.asBytes(),
661 });
748662 errdefer allocator.free(cache_hash);
749663
750664 const generic_arch_name = arch.genericName();
751 var builtin_str_buffer = try std.Buffer.allocPrint(
752 allocator,
665 var builtin_str_buffer = try std.Buffer.allocPrint(allocator,
753666 \\CpuFeatures{{
667 \\ .cpu = &Target.{}.cpu.{},
754668 \\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{
755669 \\
756 ,
757 .{ generic_arch_name, generic_arch_name },
758 );
670 , .{
671 generic_arch_name,
672 cpu_features.cpu.name,
673 generic_arch_name,
674 generic_arch_name,
675 });
759676 defer builtin_str_buffer.deinit();
760677
761 for (arch.allFeaturesList()) |feature, index| {
762 if (!feature_set.isEnabled(@intCast(u8, index))) continue;
678 var llvm_features_buffer = try std.Buffer.initSize(allocator, 0);
679 defer llvm_features_buffer.deinit();
680
681 for (arch.allFeaturesList()) |feature, index_usize| {
682 const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
683 const is_enabled = cpu_features.features.isEnabled(index);
684
685 if (feature.llvm_name) |llvm_name| {
686 const plus_or_minus = "-+"[@boolToInt(is_enabled)];
687 try llvm_features_buffer.appendByte(plus_or_minus);
688 try llvm_features_buffer.append(llvm_name);
689 try llvm_features_buffer.append(",");
690 }
763691
764 // TODO some kind of "zig identifier escape" function rather than
765 // unconditionally using @"" syntax
766 try builtin_str_buffer.append(" .@\"");
767 try builtin_str_buffer.append(feature.name);
768 try builtin_str_buffer.append("\",\n");
692 if (is_enabled) {
693 // TODO some kind of "zig identifier escape" function rather than
694 // unconditionally using @"" syntax
695 try builtin_str_buffer.append(" .@\"");
696 try builtin_str_buffer.append(feature.name);
697 try builtin_str_buffer.append("\",\n");
698 }
769699 }
770700
771701 try builtin_str_buffer.append(
......@@ -774,11 +704,13 @@ const Stage2CpuFeatures = struct {
774704 \\
775705 );
776706
707 assert(mem.endsWith(u8, llvm_features_buffer.toSliceConst(), ","));
708 llvm_features_buffer.shrink(llvm_features_buffer.len() - 1);
709
777710 self.* = Self{
778711 .allocator = allocator,
779 .cpu_features = .{ .features = feature_set },
780 .llvm_cpu_name = null,
781 .llvm_features_str = try initLLVMFeatures(allocator, arch, feature_set),
712 .cpu_features = cpu_features,
713 .llvm_features_str = llvm_features_buffer.toOwnedSlice().ptr,
782714 .builtin_str = builtin_str_buffer.toOwnedSlice(),
783715 .cache_hash = cache_hash,
784716 };
......@@ -794,12 +726,13 @@ const Stage2CpuFeatures = struct {
794726};
795727
796728// ABI warning
797export fn stage2_cpu_features_parse_cpu(
729export fn stage2_cpu_features_parse(
798730 result: **Stage2CpuFeatures,
799 zig_triple: [*:0]const u8,
800 cpu_name: [*:0]const u8,
731 zig_triple: ?[*:0]const u8,
732 cpu_name: ?[*:0]const u8,
733 cpu_features: ?[*:0]const u8,
801734) Error {
802 result.* = parseCpu(zig_triple, cpu_name) catch |err| switch (err) {
735 result.* = stage2ParseCpuFeatures(zig_triple, cpu_name, cpu_features) catch |err| switch (err) {
803736 error.OutOfMemory => return .OutOfMemory,
804737 error.UnknownArchitecture => return .UnknownArchitecture,
805738 error.UnknownSubArchitecture => return .UnknownSubArchitecture,
......@@ -807,110 +740,61 @@ export fn stage2_cpu_features_parse_cpu(
807740 error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,
808741 error.MissingOperatingSystem => return .MissingOperatingSystem,
809742 error.MissingArchitecture => return .MissingArchitecture,
810 };
811 return .None;
812}
813
814fn parseCpu(zig_triple: [*:0]const u8, cpu_name_z: [*:0]const u8) !*Stage2CpuFeatures {
815 const cpu_name = mem.toSliceConst(u8, cpu_name_z);
816 const target = try Target.parse(mem.toSliceConst(u8, zig_triple));
817 const arch = target.Cross.arch;
818 const cpu = arch.parseCpu(cpu_name) catch |err| switch (err) {
819 error.UnknownCpu => {
820 std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
821 cpu_name,
822 @tagName(arch),
823 });
824 for (arch.allCpus()) |cpu| {
825 std.debug.warn(" {}\n", .{cpu.name});
826 }
827 process.exit(1);
828 },
829 else => |e| return e,
830 };
831 return Stage2CpuFeatures.createFromCpu(std.heap.c_allocator, arch, cpu);
832}
833
834// ABI warning
835export fn stage2_cpu_features_parse_features(
836 result: **Stage2CpuFeatures,
837 zig_triple: [*:0]const u8,
838 features_text: [*:0]const u8,
839) Error {
840 result.* = parseFeatures(zig_triple, features_text) catch |err| switch (err) {
841 error.OutOfMemory => return .OutOfMemory,
743 error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat,
842744 error.InvalidCpuFeatures => return .InvalidCpuFeatures,
843 error.UnknownArchitecture => return .UnknownArchitecture,
844 error.UnknownSubArchitecture => return .UnknownSubArchitecture,
845 error.UnknownOperatingSystem => return .UnknownOperatingSystem,
846 error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,
847 error.MissingOperatingSystem => return .MissingOperatingSystem,
848 error.MissingArchitecture => return .MissingArchitecture,
849745 };
850746 return .None;
851747}
852748
853fn parseFeatures(zig_triple: [*:0]const u8, features_text: [*:0]const u8) !*Stage2CpuFeatures {
854 const target = try Target.parse(mem.toSliceConst(u8, zig_triple));
749fn stage2ParseCpuFeatures(
750 zig_triple_oz: ?[*:0]const u8,
751 cpu_name_oz: ?[*:0]const u8,
752 cpu_features_oz: ?[*:0]const u8,
753) !*Stage2CpuFeatures {
754 const zig_triple_z = zig_triple_oz orelse return Stage2CpuFeatures.createFromNative(std.heap.c_allocator);
755 const target = try Target.parse(mem.toSliceConst(u8, zig_triple_z));
855756 const arch = target.Cross.arch;
856 const set = arch.parseCpuFeatureSet(mem.toSliceConst(u8, features_text)) catch |err| switch (err) {
857 error.UnknownCpuFeature => {
858 std.debug.warn("Unknown CPU features specified.\nAvailable CPU features for architecture '{}':\n", .{
859 @tagName(arch),
860 });
861 for (arch.allFeaturesList()) |feature| {
862 std.debug.warn(" {}\n", .{feature.name});
863 }
864 process.exit(1);
865 },
866 else => |e| return e,
867 };
868 return Stage2CpuFeatures.createFromCpuFeatures(std.heap.c_allocator, arch, set);
869}
870757
871// ABI warning
872export fn stage2_cpu_features_baseline(result: **Stage2CpuFeatures, zig_triple: [*:0]const u8) Error {
873 result.* = cpuFeaturesBaseline(zig_triple) catch |err| switch (err) {
874 error.OutOfMemory => return .OutOfMemory,
875 error.UnknownArchitecture => return .UnknownArchitecture,
876 error.UnknownSubArchitecture => return .UnknownSubArchitecture,
877 error.UnknownOperatingSystem => return .UnknownOperatingSystem,
878 error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,
879 error.MissingOperatingSystem => return .MissingOperatingSystem,
880 error.MissingArchitecture => return .MissingArchitecture,
881 };
882 return .None;
883}
884
885fn cpuFeaturesBaseline(zig_triple: [*:0]const u8) !*Stage2CpuFeatures {
886 const target = try Target.parse(mem.toSliceConst(u8, zig_triple));
887 const arch = target.Cross.arch;
888 return Stage2CpuFeatures.createBaseline(std.heap.c_allocator, arch);
889}
758 const cpu = if (cpu_name_oz) |cpu_name_z| blk: {
759 const cpu_name = mem.toSliceConst(u8, cpu_name_z);
760 break :blk arch.parseCpu(cpu_name) catch |err| switch (err) {
761 error.UnknownCpu => {
762 std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
763 cpu_name,
764 @tagName(arch),
765 });
766 for (arch.allCpus()) |cpu| {
767 std.debug.warn(" {}\n", .{cpu.name});
768 }
769 process.exit(1);
770 },
771 else => |e| return e,
772 };
773 } else target.Cross.cpu_features.cpu;
774
775 var set = if (cpu_features_oz) |cpu_features_z| blk: {
776 const cpu_features = mem.toSliceConst(u8, cpu_features_z);
777 break :blk arch.parseCpuFeatureSet(cpu, cpu_features) catch |err| switch (err) {
778 error.UnknownCpuFeature => {
779 std.debug.warn(
780 \\Unknown CPU features specified.
781 \\Available CPU features for architecture '{}':
782 \\
783 , .{@tagName(arch)});
784 for (arch.allFeaturesList()) |feature| {
785 std.debug.warn(" {}\n", .{feature.name});
786 }
787 process.exit(1);
788 },
789 else => |e| return e,
790 };
791 } else cpu.features;
890792
891// ABI warning
892export fn stage2_cpu_features_llvm(
893 result: **Stage2CpuFeatures,
894 zig_triple: [*:0]const u8,
895 llvm_cpu_name: ?[*:0]const u8,
896 llvm_cpu_features: ?[*:0]const u8,
897) Error {
898 result.* = Stage2CpuFeatures.createFromLLVM(
899 std.heap.c_allocator,
900 zig_triple,
901 llvm_cpu_name,
902 llvm_cpu_features,
903 ) catch |err| switch (err) {
904 error.OutOfMemory => return .OutOfMemory,
905 error.UnknownArchitecture => return .UnknownArchitecture,
906 error.UnknownSubArchitecture => return .UnknownSubArchitecture,
907 error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat,
908 error.UnknownOperatingSystem => return .UnknownOperatingSystem,
909 error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,
910 error.MissingOperatingSystem => return .MissingOperatingSystem,
911 error.MissingArchitecture => return .MissingArchitecture,
912 };
913 return .None;
793 set.populateDependencies(arch.allFeaturesList());
794 return Stage2CpuFeatures.createFromCpuFeatures(std.heap.c_allocator, arch, .{
795 .cpu = cpu,
796 .features = set,
797 });
914798}
915799
916800// ABI warning
......@@ -935,7 +819,7 @@ export fn stage2_cpu_features_get_builtin_str(
935819
936820// ABI warning
937821export fn stage2_cpu_features_get_llvm_cpu(cpu_features: *const Stage2CpuFeatures) ?[*:0]const u8 {
938 return cpu_features.llvm_cpu_name;
822 return if (cpu_features.cpu_features.cpu.llvm_name) |s| s.ptr else null;
939823}
940824
941825// ABI warning
src/codegen.cpp+1-1
......@@ -8581,7 +8581,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
85818581 stage2_cpu_features_get_builtin_str(g->zig_target->cpu_features, &ptr, &len);
85828582 buf_append_mem(contents, ptr, len);
85838583 } else {
8584 buf_append_str(contents, ".baseline;\n");
8584 buf_append_str(contents, "arch.getBaselineCpuFeatures();\n");
85858585 }
85868586 }
85878587 if (g->libc_link_lib != nullptr && g->zig_target->glibc_version != nullptr) {
src/main.cpp+4-29
......@@ -866,7 +866,7 @@ int main(int argc, char **argv) {
866866 cpu = argv[i];
867867 } else if (strcmp(arg, "-target-feature") == 0) {
868868 features = argv[i];
869 }else {
869 } else {
870870 fprintf(stderr, "Invalid argument: %s\n", arg);
871871 return print_error_usage(arg0);
872872 }
......@@ -984,35 +984,10 @@ int main(int argc, char **argv) {
984984 Buf zig_triple_buf = BUF_INIT;
985985 target_triple_zig(&zig_triple_buf, &target);
986986
987 if (cpu && features) {
988 fprintf(stderr, "-target-cpu and -target-feature options not allowed together\n");
987 const char *stage2_triple_arg = target.is_native ? nullptr : buf_ptr(&zig_triple_buf);
988 if ((err = stage2_cpu_features_parse(&target.cpu_features, stage2_triple_arg, cpu, features))) {
989 fprintf(stderr, "unable to initialize CPU features: %s\n", err_str(err));
989990 return main_exit(root_progress_node, EXIT_FAILURE);
990 } else if (cpu) {
991 if ((err = stage2_cpu_features_parse_cpu(&target.cpu_features, buf_ptr(&zig_triple_buf), cpu))) {
992 fprintf(stderr, "-target-cpu error: %s\n", err_str(err));
993 return main_exit(root_progress_node, EXIT_FAILURE);
994 }
995 } else if (features) {
996 if ((err = stage2_cpu_features_parse_features(&target.cpu_features, buf_ptr(&zig_triple_buf),
997 features)))
998 {
999 fprintf(stderr, "-target-feature error: %s\n", err_str(err));
1000 return main_exit(root_progress_node, EXIT_FAILURE);
1001 }
1002 } else if (target.is_native) {
1003 const char *cpu_name = ZigLLVMGetHostCPUName();
1004 const char *cpu_features = ZigLLVMGetNativeFeatures();
1005 if ((err = stage2_cpu_features_llvm(&target.cpu_features, buf_ptr(&zig_triple_buf),
1006 cpu_name, cpu_features)))
1007 {
1008 fprintf(stderr, "unable to determine native CPU features: %s\n", err_str(err));
1009 return main_exit(root_progress_node, EXIT_FAILURE);
1010 }
1011 } else {
1012 if ((err = stage2_cpu_features_baseline(&target.cpu_features, buf_ptr(&zig_triple_buf)))) {
1013 fprintf(stderr, "unable to determine baseline CPU features: %s\n", err_str(err));
1014 return main_exit(root_progress_node, EXIT_FAILURE);
1015 }
1016991 }
1017992
1018993 if (output_dir != nullptr && enable_cache == CacheOptOn) {
src/userland.cpp+24-25
......@@ -2,7 +2,8 @@
22// src-self-hosted/stage1.zig
33
44#include "userland.h"
5#include "ast_render.hpp"
5#include "util.hpp"
6#include "zig_llvm.h"
67#include <stdio.h>
78#include <stdlib.h>
89#include <string.h>
......@@ -96,32 +97,30 @@ struct Stage2CpuFeatures {
9697 const char *cache_hash;
9798};
9899
99Error stage2_cpu_features_parse_cpu(Stage2CpuFeatures **out, const char *zig_triple, const char *str) {
100 const char *msg = "stage0 called stage2_cpu_features_parse_cpu";
101 stage2_panic(msg, strlen(msg));
102}
103Error stage2_cpu_features_parse_features(Stage2CpuFeatures **out, const char *zig_triple, const char *str) {
104 const char *msg = "stage0 called stage2_cpu_features_parse_features";
105 stage2_panic(msg, strlen(msg));
106}
107Error stage2_cpu_features_baseline(Stage2CpuFeatures **out, const char *zig_triple) {
108 Stage2CpuFeatures *result = allocate<Stage2CpuFeatures>(1, "Stage2CpuFeatures");
109 result->builtin_str = ".baseline;\n";
110 result->cache_hash = "\n\n";
111 *out = result;
112 return ErrorNone;
113}
114Error stage2_cpu_features_llvm(Stage2CpuFeatures **out, const char *zig_triple,
115 const char *llvm_cpu_name, const char *llvm_features)
100Error stage2_cpu_features_parse(struct Stage2CpuFeatures **out, const char *zig_triple,
101 const char *cpu_name, const char *cpu_features)
116102{
117 Stage2CpuFeatures *result = allocate<Stage2CpuFeatures>(1, "Stage2CpuFeatures");
118 result->llvm_cpu_name = llvm_cpu_name;
119 result->llvm_cpu_features = llvm_features;
120 result->builtin_str = ".baseline;\n";
121 result->cache_hash = "native\n\n";
122 *out = result;
123 return ErrorNone;
103 if (zig_triple == nullptr) {
104 Stage2CpuFeatures *result = allocate<Stage2CpuFeatures>(1, "Stage2CpuFeatures");
105 result->llvm_cpu_name = ZigLLVMGetHostCPUName();
106 result->llvm_cpu_features = ZigLLVMGetNativeFeatures();
107 result->builtin_str = "arch.getBaselineCpuFeatures();\n";
108 result->cache_hash = "native\n\n";
109 *out = result;
110 return ErrorNone;
111 }
112 if (cpu_name == nullptr && cpu_features == nullptr) {
113 Stage2CpuFeatures *result = allocate<Stage2CpuFeatures>(1, "Stage2CpuFeatures");
114 result->builtin_str = "arch.getBaselineCpuFeatures();\n";
115 result->cache_hash = "\n\n";
116 *out = result;
117 return ErrorNone;
118 }
119
120 const char *msg = "stage0 called stage2_cpu_features_parse with non-null cpu name or features";
121 stage2_panic(msg, strlen(msg));
124122}
123
125124void stage2_cpu_features_get_cache_hash(const Stage2CpuFeatures *cpu_features,
126125 const char **ptr, size_t *len)
127126{
src/userland.h+2-14
......@@ -184,20 +184,8 @@ ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node,
184184struct Stage2CpuFeatures;
185185
186186// ABI warning
187ZIG_EXTERN_C Error stage2_cpu_features_parse_cpu(struct Stage2CpuFeatures **result,
188 const char *zig_triple, const char *cpu_name);
189
190// ABI warning
191ZIG_EXTERN_C Error stage2_cpu_features_parse_features(struct Stage2CpuFeatures **result,
192 const char *zig_triple, const char *features);
193
194// ABI warning
195ZIG_EXTERN_C Error stage2_cpu_features_baseline(struct Stage2CpuFeatures **result,
196 const char *zig_triple);
197
198// ABI warning
199ZIG_EXTERN_C Error stage2_cpu_features_llvm(struct Stage2CpuFeatures **result,
200 const char *zig_triple, const char *llvm_cpu_name, const char *llvm_features);
187ZIG_EXTERN_C Error stage2_cpu_features_parse(struct Stage2CpuFeatures **result,
188 const char *zig_triple, const char *cpu_name, const char *cpu_features);
201189
202190// ABI warning
203191ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_cpu(const struct Stage2CpuFeatures *cpu_features);
test/compile_errors.zig+7-4
......@@ -1,5 +1,6 @@
11const tests = @import("tests.zig");
22const builtin = @import("builtin");
3const Target = @import("std").Target;
34
45pub fn addCases(cases: *tests.CompileErrorContext) void {
56 cases.addTest("non-exhaustive enums",
......@@ -272,9 +273,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
272273 , &[_][]const u8{
273274 "tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack",
274275 });
275 tc.target = tests.Target{
276 .Cross = tests.CrossTarget{
276 tc.target = Target{
277 .Cross = .{
277278 .arch = .wasm32,
279 .cpu_features = Target.Arch.wasm32.getBaselineCpuFeatures(),
278280 .os = .wasi,
279281 .abi = .none,
280282 },
......@@ -673,9 +675,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
673675 , &[_][]const u8{
674676 "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs",
675677 });
676 tc.target = tests.Target{
677 .Cross = tests.CrossTarget{
678 tc.target = Target{
679 .Cross = .{
678680 .arch = .x86_64,
681 .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(),
679682 .os = .linux,
680683 .abi = .gnu,
681684 },
test/tests.zig+220-196
......@@ -38,236 +38,260 @@ const TestTarget = struct {
3838 disable_native: bool = false,
3939};
4040
41const test_targets = [_]TestTarget{
42 TestTarget{},
43 TestTarget{
44 .link_libc = true,
45 },
46 TestTarget{
47 .single_threaded = true,
48 },
49
50 TestTarget{
51 .target = Target{
52 .Cross = CrossTarget{
53 .os = .linux,
54 .arch = .x86_64,
55 .abi = .none,
41const test_targets = blk: {
42 // getBaselineCpuFeatures calls populateDependencies which has a O(N ^ 2) algorithm
43 // (where N is roughly 160, which technically makes it O(1), but it adds up to a
44 // lot of branches)
45 @setEvalBranchQuota(50000);
46 break :blk [_]TestTarget{
47 TestTarget{},
48 TestTarget{
49 .link_libc = true,
50 },
51 TestTarget{
52 .single_threaded = true,
53 },
54
55 TestTarget{
56 .target = Target{
57 .Cross = CrossTarget{
58 .os = .linux,
59 .arch = .x86_64,
60 .abi = .none,
61 .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(),
62 },
5663 },
5764 },
58 },
59 TestTarget{
60 .target = Target{
61 .Cross = CrossTarget{
62 .os = .linux,
63 .arch = .x86_64,
64 .abi = .gnu,
65 TestTarget{
66 .target = Target{
67 .Cross = CrossTarget{
68 .os = .linux,
69 .arch = .x86_64,
70 .abi = .gnu,
71 .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(),
72 },
6573 },
74 .link_libc = true,
6675 },
67 .link_libc = true,
68 },
69 TestTarget{
70 .target = Target{
71 .Cross = CrossTarget{
72 .os = .linux,
73 .arch = .x86_64,
74 .abi = .musl,
76 TestTarget{
77 .target = Target{
78 .Cross = CrossTarget{
79 .os = .linux,
80 .arch = .x86_64,
81 .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(),
82 .abi = .musl,
83 },
7584 },
85 .link_libc = true,
7686 },
77 .link_libc = true,
78 },
79
80 TestTarget{
81 .target = Target{
82 .Cross = CrossTarget{
83 .os = .linux,
84 .arch = .i386,
85 .abi = .none,
87
88 TestTarget{
89 .target = Target{
90 .Cross = CrossTarget{
91 .os = .linux,
92 .arch = .i386,
93 .cpu_features = Target.Arch.i386.getBaselineCpuFeatures(),
94 .abi = .none,
95 },
8696 },
8797 },
88 },
89 TestTarget{
90 .target = Target{
91 .Cross = CrossTarget{
92 .os = .linux,
93 .arch = .i386,
94 .abi = .musl,
98 TestTarget{
99 .target = Target{
100 .Cross = CrossTarget{
101 .os = .linux,
102 .arch = .i386,
103 .cpu_features = Target.Arch.i386.getBaselineCpuFeatures(),
104 .abi = .musl,
105 },
95106 },
107 .link_libc = true,
96108 },
97 .link_libc = true,
98 },
99
100 TestTarget{
101 .target = Target{
102 .Cross = CrossTarget{
103 .os = .linux,
104 .arch = builtin.Arch{ .aarch64 = builtin.Arch.Arm64.v8_5a },
105 .abi = .none,
109
110 TestTarget{
111 .target = Target{
112 .Cross = CrossTarget{
113 .os = .linux,
114 .arch = Target.Arch{ .aarch64 = .v8_5a },
115 .cpu_features = (Target.Arch{ .aarch64 = .v8_5a }).getBaselineCpuFeatures(),
116 .abi = .none,
117 },
106118 },
107119 },
108 },
109 TestTarget{
110 .target = Target{
111 .Cross = CrossTarget{
112 .os = .linux,
113 .arch = builtin.Arch{ .aarch64 = builtin.Arch.Arm64.v8_5a },
114 .abi = .musl,
120 TestTarget{
121 .target = Target{
122 .Cross = CrossTarget{
123 .os = .linux,
124 .arch = Target.Arch{ .aarch64 = .v8_5a },
125 .cpu_features = (Target.Arch{ .aarch64 = .v8_5a }).getBaselineCpuFeatures(),
126 .abi = .musl,
127 },
115128 },
129 .link_libc = true,
116130 },
117 .link_libc = true,
118 },
119 TestTarget{
120 .target = Target{
121 .Cross = CrossTarget{
122 .os = .linux,
123 .arch = builtin.Arch{ .aarch64 = builtin.Arch.Arm64.v8_5a },
124 .abi = .gnu,
131 TestTarget{
132 .target = Target{
133 .Cross = CrossTarget{
134 .os = .linux,
135 .arch = Target.Arch{ .aarch64 = .v8_5a },
136 .cpu_features = (Target.Arch{ .aarch64 = .v8_5a }).getBaselineCpuFeatures(),
137 .abi = .gnu,
138 },
125139 },
140 .link_libc = true,
126141 },
127 .link_libc = true,
128 },
129
130 TestTarget{
131 .target = Target{
132 .Cross = CrossTarget{
133 .os = .linux,
134 .arch = builtin.Arch{ .arm = builtin.Arch.Arm32.v8_5a },
135 .abi = .none,
142
143 TestTarget{
144 .target = Target{
145 .Cross = CrossTarget{
146 .os = .linux,
147 .arch = Target.Arch{ .arm = .v8_5a },
148 .cpu_features = (Target.Arch{ .arm = .v8_5a }).getBaselineCpuFeatures(),
149 .abi = .none,
150 },
136151 },
137152 },
138 },
139 TestTarget{
140 .target = Target{
141 .Cross = CrossTarget{
142 .os = .linux,
143 .arch = builtin.Arch{ .arm = builtin.Arch.Arm32.v8_5a },
144 .abi = .musleabihf,
153 TestTarget{
154 .target = Target{
155 .Cross = CrossTarget{
156 .os = .linux,
157 .arch = Target.Arch{ .arm = .v8_5a },
158 .cpu_features = (Target.Arch{ .arm = .v8_5a }).getBaselineCpuFeatures(),
159 .abi = .musleabihf,
160 },
145161 },
162 .link_libc = true,
146163 },
147 .link_libc = true,
148 },
149 // TODO https://github.com/ziglang/zig/issues/3287
150 //TestTarget{
151 // .target = Target{
152 // .Cross = CrossTarget{
153 // .os = .linux,
154 // .arch = builtin.Arch{ .arm = builtin.Arch.Arm32.v8_5a },
155 // .abi = .gnueabihf,
156 // },
157 // },
158 // .link_libc = true,
159 //},
160
161 TestTarget{
162 .target = Target{
163 .Cross = CrossTarget{
164 .os = .linux,
165 .arch = .mipsel,
166 .abi = .none,
164 // TODO https://github.com/ziglang/zig/issues/3287
165 //TestTarget{
166 // .target = Target{
167 // .Cross = CrossTarget{
168 // .os = .linux,
169 // .arch = Target.Arch{ .arm = .v8_5a },
170 // .cpu_features = (Target.Arch{ .arm = .v8_5a }).getBaselineCpuFeatures(),
171 // .abi = .gnueabihf,
172 // },
173 // },
174 // .link_libc = true,
175 //},
176
177 TestTarget{
178 .target = Target{
179 .Cross = CrossTarget{
180 .os = .linux,
181 .arch = .mipsel,
182 .cpu_features = Target.Arch.mipsel.getBaselineCpuFeatures(),
183 .abi = .none,
184 },
167185 },
168186 },
169 },
170 TestTarget{
171 .target = Target{
172 .Cross = CrossTarget{
173 .os = .linux,
174 .arch = .mipsel,
175 .abi = .musl,
187 TestTarget{
188 .target = Target{
189 .Cross = CrossTarget{
190 .os = .linux,
191 .arch = .mipsel,
192 .cpu_features = Target.Arch.mipsel.getBaselineCpuFeatures(),
193 .abi = .musl,
194 },
176195 },
196 .link_libc = true,
177197 },
178 .link_libc = true,
179 },
180
181 TestTarget{
182 .target = Target{
183 .Cross = CrossTarget{
184 .os = .macosx,
185 .arch = .x86_64,
186 .abi = .gnu,
198
199 TestTarget{
200 .target = Target{
201 .Cross = CrossTarget{
202 .os = .macosx,
203 .arch = .x86_64,
204 .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(),
205 .abi = .gnu,
206 },
187207 },
208 // TODO https://github.com/ziglang/zig/issues/3295
209 .disable_native = true,
188210 },
189 // TODO https://github.com/ziglang/zig/issues/3295
190 .disable_native = true,
191 },
192
193 TestTarget{
194 .target = Target{
195 .Cross = CrossTarget{
196 .os = .windows,
197 .arch = .i386,
198 .abi = .msvc,
211
212 TestTarget{
213 .target = Target{
214 .Cross = CrossTarget{
215 .os = .windows,
216 .arch = .i386,
217 .cpu_features = Target.Arch.i386.getBaselineCpuFeatures(),
218 .abi = .msvc,
219 },
199220 },
200221 },
201 },
202
203 TestTarget{
204 .target = Target{
205 .Cross = CrossTarget{
206 .os = .windows,
207 .arch = .x86_64,
208 .abi = .msvc,
222
223 TestTarget{
224 .target = Target{
225 .Cross = CrossTarget{
226 .os = .windows,
227 .arch = .x86_64,
228 .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(),
229 .abi = .msvc,
230 },
209231 },
210232 },
211 },
212
213 TestTarget{
214 .target = Target{
215 .Cross = CrossTarget{
216 .os = .windows,
217 .arch = .i386,
218 .abi = .gnu,
233
234 TestTarget{
235 .target = Target{
236 .Cross = CrossTarget{
237 .os = .windows,
238 .arch = .i386,
239 .cpu_features = Target.Arch.i386.getBaselineCpuFeatures(),
240 .abi = .gnu,
241 },
219242 },
243 .link_libc = true,
220244 },
221 .link_libc = true,
222 },
223
224 TestTarget{
225 .target = Target{
226 .Cross = CrossTarget{
227 .os = .windows,
228 .arch = .x86_64,
229 .abi = .gnu,
245
246 TestTarget{
247 .target = Target{
248 .Cross = CrossTarget{
249 .os = .windows,
250 .arch = .x86_64,
251 .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(),
252 .abi = .gnu,
253 },
230254 },
255 .link_libc = true,
256 },
257
258 // Do the release tests last because they take a long time
259 TestTarget{
260 .mode = .ReleaseFast,
261 },
262 TestTarget{
263 .link_libc = true,
264 .mode = .ReleaseFast,
231265 },
232 .link_libc = true,
233 },
234
235 // Do the release tests last because they take a long time
236 TestTarget{
237 .mode = .ReleaseFast,
238 },
239 TestTarget{
240 .link_libc = true,
241 .mode = .ReleaseFast,
242 },
243 TestTarget{
244 .mode = .ReleaseFast,
245 .single_threaded = true,
246 },
247
248 TestTarget{
249 .mode = .ReleaseSafe,
250 },
251 TestTarget{
252 .link_libc = true,
253 .mode = .ReleaseSafe,
254 },
255 TestTarget{
256 .mode = .ReleaseSafe,
257 .single_threaded = true,
258 },
259
260 TestTarget{
261 .mode = .ReleaseSmall,
262 },
263 TestTarget{
264 .link_libc = true,
265 .mode = .ReleaseSmall,
266 },
267 TestTarget{
268 .mode = .ReleaseSmall,
269 .single_threaded = true,
270 },
266 TestTarget{
267 .mode = .ReleaseFast,
268 .single_threaded = true,
269 },
270
271 TestTarget{
272 .mode = .ReleaseSafe,
273 },
274 TestTarget{
275 .link_libc = true,
276 .mode = .ReleaseSafe,
277 },
278 TestTarget{
279 .mode = .ReleaseSafe,
280 .single_threaded = true,
281 },
282
283 TestTarget{
284 .mode = .ReleaseSmall,
285 },
286 TestTarget{
287 .link_libc = true,
288 .mode = .ReleaseSmall,
289 },
290 TestTarget{
291 .mode = .ReleaseSmall,
292 .single_threaded = true,
293 },
294 };
271295};
272296
273297const max_stdout_size = 1 * 1024 * 1024; // 1 MB
test/translate_c.zig+19-3
......@@ -1,5 +1,6 @@
11const tests = @import("tests.zig");
22const builtin = @import("builtin");
3const Target = @import("std").Target;
34
45pub fn addCases(cases: *tests.TranslateCContext) void {
56 cases.add("empty declaration",
......@@ -1005,7 +1006,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
10051006 });
10061007
10071008 cases.addWithTarget("Calling convention", tests.Target{
1008 .Cross = .{ .os = .linux, .arch = .i386, .abi = .none },
1009 .Cross = .{
1010 .os = .linux,
1011 .arch = .i386,
1012 .abi = .none,
1013 .cpu_features = Target.Arch.i386.getBaselineCpuFeatures(),
1014 },
10091015 },
10101016 \\void __attribute__((fastcall)) foo1(float *a);
10111017 \\void __attribute__((stdcall)) foo2(float *a);
......@@ -1021,7 +1027,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
10211027 });
10221028
10231029 cases.addWithTarget("Calling convention", tests.Target{
1024 .Cross = .{ .os = .linux, .arch = .{ .arm = .v8_5a }, .abi = .none },
1030 .Cross = .{
1031 .os = .linux,
1032 .arch = .{ .arm = .v8_5a },
1033 .abi = .none,
1034 .cpu_features = (Target.Arch{ .arm = .v8_5a }).getBaselineCpuFeatures(),
1035 },
10251036 },
10261037 \\void __attribute__((pcs("aapcs"))) foo1(float *a);
10271038 \\void __attribute__((pcs("aapcs-vfp"))) foo2(float *a);
......@@ -1031,7 +1042,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
10311042 });
10321043
10331044 cases.addWithTarget("Calling convention", tests.Target{
1034 .Cross = .{ .os = .linux, .arch = .{ .aarch64 = .v8_5a }, .abi = .none },
1045 .Cross = .{
1046 .os = .linux,
1047 .arch = .{ .aarch64 = .v8_5a },
1048 .abi = .none,
1049 .cpu_features = (Target.Arch{ .aarch64 = .v8_5a }).getBaselineCpuFeatures(),
1050 },
10351051 },
10361052 \\void __attribute__((aarch64_vector_pcs)) foo1(float *a);
10371053 , &[_][]const u8{