| author | |
| committer | |
| log | 48c7e6c48b81e6e0423b3e4aea238402189eecb7 |
| tree | 1d585eaa73a43b473809ffdc85b4207e2e72ee9c |
| parent | c6bfece1d54c54024397d7aff9f25087cc4dbfda |
| signature | Commit is signed but in an unrecognized format. |
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 { | ... | @@ -484,6 +484,7 @@ pub const Builder = struct { |
| 484 | .arch = builtin.arch, | 484 | .arch = builtin.arch, |
| 485 | .os = builtin.os, | 485 | .os = builtin.os, |
| 486 | .abi = builtin.abi, | 486 | .abi = builtin.abi, |
| 487 | .cpu_features = builtin.cpu_features, | ||
| 487 | }, | 488 | }, |
| 488 | }).linuxTriple(self.allocator); | 489 | }).linuxTriple(self.allocator); |
| 489 | 490 | ||
| ... | @@ -1375,6 +1376,7 @@ pub const LibExeObjStep = struct { | ... | @@ -1375,6 +1376,7 @@ pub const LibExeObjStep = struct { |
| 1375 | .arch = target_arch, | 1376 | .arch = target_arch, |
| 1376 | .os = target_os, | 1377 | .os = target_os, |
| 1377 | .abi = target_abi, | 1378 | .abi = target_abi, |
| 1379 | .cpu_features = target_arch.getBaselineCpuFeatures(), | ||
| 1378 | }, | 1380 | }, |
| 1379 | }); | 1381 | }); |
| 1380 | } | 1382 | } |
| ... | @@ -1972,25 +1974,41 @@ pub const LibExeObjStep = struct { | ... | @@ -1972,25 +1974,41 @@ pub const LibExeObjStep = struct { |
| 1972 | try zig_args.append("-target"); | 1974 | try zig_args.append("-target"); |
| 1973 | try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable); | 1975 | try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable); |
| 1974 | 1976 | ||
| 1975 | switch (cross.cpu_features) { | 1977 | const all_features = self.target.getArch().allFeaturesList(); |
| 1976 | .baseline => {}, | 1978 | var populated_cpu_features = cross.cpu_features.cpu.features; |
| 1977 | .cpu => |cpu| { | 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) { | ||
| 1978 | try zig_args.append("-target-cpu"); | 1985 | try zig_args.append("-target-cpu"); |
| 1979 | try zig_args.append(cpu.name); | 1986 | try zig_args.append(cross.cpu_features.cpu.name); |
| 1980 | }, | 1987 | } |
| 1981 | .features => |features| { | 1988 | } else { |
| 1982 | try zig_args.append("-target-cpu-features"); | 1989 | try zig_args.append("-target-cpu"); |
| 1983 | 1990 | try zig_args.append(cross.cpu_features.cpu.name); | |
| 1984 | var feature_str_buffer = try std.Buffer.initSize(builder.allocator, 0); | 1991 | |
| 1985 | for (self.target.getArch().allFeaturesList()) |feature, i| { | 1992 | try zig_args.append("-target-feature"); |
| 1986 | if (features.isEnabled(@intCast(Target.Cpu.Feature.Set.Index, i))) { | 1993 | var feature_str_buffer = try std.Buffer.initSize(builder.allocator, 0); |
| 1987 | try feature_str_buffer.append(feature.name); | 1994 | for (all_features) |feature, i_usize| { |
| 1988 | try feature_str_buffer.append(","); | 1995 | const i = @intCast(Target.Cpu.Feature.Set.Index, i_usize); |
| 1989 | } | 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(','); | ||
| 1990 | } | 2006 | } |
| 1991 | 2007 | } | |
| 1992 | try zig_args.append(feature_str_buffer.toSlice()); | 2008 | if (mem.endsWith(u8, feature_str_buffer.toSliceConst(), ",")) { |
| 1993 | }, | 2009 | feature_str_buffer.shrink(feature_str_buffer.len() - 1); |
| 2010 | } | ||
| 2011 | try zig_args.append(feature_str_buffer.toSliceConst()); | ||
| 1994 | } | 2012 | } |
| 1995 | }, | 2013 | }, |
| 1996 | } | 2014 | } |
lib/std/target.zig+70-82| ... | @@ -172,6 +172,15 @@ pub const Target = union(enum) { | ... | @@ -172,6 +172,15 @@ pub const Target = union(enum) { |
| 172 | r6, | 172 | r6, |
| 173 | }; | 173 | }; |
| 174 | 174 | ||
| 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 | |||
| 175 | pub fn subArchFeature(arch: Arch) ?u8 { | 184 | pub fn subArchFeature(arch: Arch) ?u8 { |
| 176 | return switch (arch) { | 185 | return switch (arch) { |
| 177 | .arm, .armeb, .thumb, .thumbeb => |arm32| switch (arm32) { | 186 | .arm, .armeb, .thumb, .thumbeb => |arm32| switch (arm32) { |
| ... | @@ -251,24 +260,12 @@ pub const Target = union(enum) { | ... | @@ -251,24 +260,12 @@ pub const Target = union(enum) { |
| 251 | return error.UnknownCpu; | 260 | return error.UnknownCpu; |
| 252 | } | 261 | } |
| 253 | 262 | ||
| 254 | /// This parsing function supports 2 syntaxes. | 263 | /// Comma-separated list of features, with + or - in front of each feature. This |
| 255 | /// * 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. |
| 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. | ||
| 260 | /// Extra commas are ignored. | 265 | /// Extra commas are ignored. |
| 261 | pub fn parseCpuFeatureSet(arch: Arch, features_text: []const u8) !Cpu.Feature.Set { | 266 | pub fn parseCpuFeatureSet(arch: Arch, cpu: *const Cpu, features_text: []const u8) !Cpu.Feature.Set { |
| 262 | // Here we compute both and choose the correct result at the end, based | 267 | const all_features = arch.allFeaturesList(); |
| 263 | // on whether or not we saw + and - signs. | 268 | var set = cpu.features; |
| 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 | |||
| 272 | var it = mem.tokenize(features_text, ","); | 269 | var it = mem.tokenize(features_text, ","); |
| 273 | while (it.next()) |item_text| { | 270 | while (it.next()) |item_text| { |
| 274 | var feature_name: []const u8 = undefined; | 271 | var feature_name: []const u8 = undefined; |
| ... | @@ -277,40 +274,20 @@ pub const Target = union(enum) { | ... | @@ -277,40 +274,20 @@ pub const Target = union(enum) { |
| 277 | sub, | 274 | sub, |
| 278 | } = undefined; | 275 | } = undefined; |
| 279 | if (mem.startsWith(u8, item_text, "+")) { | 276 | if (mem.startsWith(u8, item_text, "+")) { |
| 280 | switch (mode) { | ||
| 281 | .unknown, .baseline => mode = .baseline, | ||
| 282 | .whitelist => return error.InvalidCpuFeatures, | ||
| 283 | } | ||
| 284 | op = .add; | 277 | op = .add; |
| 285 | feature_name = item_text[1..]; | 278 | feature_name = item_text[1..]; |
| 286 | } else if (mem.startsWith(u8, item_text, "-")) { | 279 | } else if (mem.startsWith(u8, item_text, "-")) { |
| 287 | switch (mode) { | ||
| 288 | .unknown, .baseline => mode = .baseline, | ||
| 289 | .whitelist => return error.InvalidCpuFeatures, | ||
| 290 | } | ||
| 291 | op = .sub; | 280 | op = .sub; |
| 292 | feature_name = item_text[1..]; | 281 | feature_name = item_text[1..]; |
| 293 | } else { | 282 | } else { |
| 294 | switch (mode) { | 283 | return error.InvalidCpuFeatures; |
| 295 | .unknown, .whitelist => mode = .whitelist, | ||
| 296 | .baseline => return error.InvalidCpuFeatures, | ||
| 297 | } | ||
| 298 | op = .add; | ||
| 299 | feature_name = item_text; | ||
| 300 | } | 284 | } |
| 301 | const all_features = arch.allFeaturesList(); | ||
| 302 | for (all_features) |feature, index_usize| { | 285 | for (all_features) |feature, index_usize| { |
| 303 | const index = @intCast(Cpu.Feature.Set.Index, index_usize); | 286 | const index = @intCast(Cpu.Feature.Set.Index, index_usize); |
| 304 | if (mem.eql(u8, feature_name, feature.name)) { | 287 | if (mem.eql(u8, feature_name, feature.name)) { |
| 305 | switch (op) { | 288 | switch (op) { |
| 306 | .add => { | 289 | .add => set.addFeature(index), |
| 307 | baseline_set.addFeature(index); | 290 | .sub => set.removeFeature(index), |
| 308 | whitelist_set.addFeature(index); | ||
| 309 | }, | ||
| 310 | .sub => { | ||
| 311 | baseline_set.removeFeature(index); | ||
| 312 | whitelist_set.removeFeature(index); | ||
| 313 | }, | ||
| 314 | } | 291 | } |
| 315 | break; | 292 | break; |
| 316 | } | 293 | } |
| ... | @@ -319,10 +296,8 @@ pub const Target = union(enum) { | ... | @@ -319,10 +296,8 @@ pub const Target = union(enum) { |
| 319 | } | 296 | } |
| 320 | } | 297 | } |
| 321 | 298 | ||
| 322 | return switch (mode) { | 299 | set.populateDependencies(all_features); |
| 323 | .unknown, .whitelist => whitelist_set, | 300 | return set; |
| 324 | .baseline => baseline_set, | ||
| 325 | }; | ||
| 326 | } | 301 | } |
| 327 | 302 | ||
| 328 | pub fn toElfMachine(arch: Arch) std.elf.EM { | 303 | pub fn toElfMachine(arch: Arch) std.elf.EM { |
| ... | @@ -485,29 +460,37 @@ pub const Target = union(enum) { | ... | @@ -485,29 +460,37 @@ pub const Target = union(enum) { |
| 485 | 460 | ||
| 486 | /// The "default" set of CPU features for cross-compiling. A conservative set | 461 | /// The "default" set of CPU features for cross-compiling. A conservative set |
| 487 | /// of features that is expected to be supported on most available hardware. | 462 | /// of features that is expected to be supported on most available hardware. |
| 488 | pub fn baselineFeatures(arch: Arch) Cpu.Feature.Set { | 463 | pub fn getBaselineCpuFeatures(arch: Arch) CpuFeatures { |
| 489 | return switch (arch) { | 464 | const S = struct { |
| 490 | .arm, .armeb, .thumb, .thumbeb => arm.cpu.generic.features, | 465 | const generic_cpu = Cpu{ |
| 491 | .aarch64, .aarch64_be, .aarch64_32 => aarch64.cpu.generic.features, | 466 | .name = "generic", |
| 492 | .avr => avr.baseline_features, | 467 | .llvm_name = null, |
| 493 | .bpfel, .bpfeb => bpf.cpu.generic.features, | 468 | .features = Cpu.Feature.Set.empty, |
| 494 | .hexagon => hexagon.cpu.generic.features, | 469 | }; |
| 495 | .mips, .mipsel => mips.cpu.mips32.features, | 470 | }; |
| 496 | .mips64, .mips64el => mips.cpu.mips64.features, | 471 | const cpu = switch (arch) { |
| 497 | .msp430 => msp430.cpu.generic.features, | 472 | .arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic, |
| 498 | .powerpc, .powerpc64, .powerpc64le => powerpc.cpu.generic.features, | 473 | .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic, |
| 499 | .amdgcn => amdgpu.cpu.generic.features, | 474 | .avr => &avr.cpu.avr1, |
| 500 | .riscv32 => riscv.baseline_32_features, | 475 | .bpfel, .bpfeb => &bpf.cpu.generic, |
| 501 | .riscv64 => riscv.baseline_64_features, | 476 | .hexagon => &hexagon.cpu.generic, |
| 502 | .sparc, .sparcv9, .sparcel => sparc.cpu.generic.features, | 477 | .mips, .mipsel => &mips.cpu.mips32, |
| 503 | .s390x => systemz.cpu.generic.features, | 478 | .mips64, .mips64el => &mips.cpu.mips64, |
| 504 | .i386 => x86.cpu.pentium4.features, | 479 | .msp430 => &msp430.cpu.generic, |
| 505 | .x86_64 => x86.cpu.x86_64.features, | 480 | .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic, |
| 506 | .nvptx, .nvptx64 => nvptx.cpu.sm_20.features, | 481 | .amdgcn => &amdgpu.cpu.generic, |
| 507 | .wasm32, .wasm64 => wasm.cpu.generic.features, | 482 | .riscv32 => &riscv.cpu.baseline_rv32, |
| 508 | 483 | .riscv64 => &riscv.cpu.baseline_rv64, | |
| 509 | else => Cpu.Feature.Set.empty, | 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, | ||
| 510 | }; | 492 | }; |
| 493 | return CpuFeatures.initFromCpu(arch, cpu); | ||
| 511 | } | 494 | } |
| 512 | 495 | ||
| 513 | /// All CPUs Zig is aware of, sorted lexicographically by name. | 496 | /// All CPUs Zig is aware of, sorted lexicographically by name. |
| ... | @@ -685,19 +668,28 @@ pub const Target = union(enum) { | ... | @@ -685,19 +668,28 @@ pub const Target = union(enum) { |
| 685 | arch: Arch, | 668 | arch: Arch, |
| 686 | os: Os, | 669 | os: Os, |
| 687 | abi: Abi, | 670 | abi: Abi, |
| 688 | cpu_features: CpuFeatures = .baseline, | 671 | cpu_features: CpuFeatures, |
| 689 | }; | 672 | }; |
| 690 | 673 | ||
| 691 | pub const CpuFeatures = union(enum) { | 674 | pub const CpuFeatures = struct { |
| 692 | /// The "default" set of CPU features for cross-compiling. A conservative set | 675 | /// The CPU to target. It has a set of features |
| 693 | /// of features that is expected to be supported on most available hardware. | 676 | /// which are overridden with the `features` field. |
| 694 | baseline, | ||
| 695 | |||
| 696 | /// Target one specific CPU. | ||
| 697 | cpu: *const Cpu, | 677 | cpu: *const Cpu, |
| 698 | 678 | ||
| 699 | /// Explicitly provide the entire CPU feature set. | 679 | /// Explicitly provide the entire CPU feature set. |
| 700 | features: Cpu.Feature.Set, | 680 | 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 | } | ||
| 701 | }; | 693 | }; |
| 702 | 694 | ||
| 703 | pub const current = Target{ | 695 | pub const current = Target{ |
| ... | @@ -718,14 +710,6 @@ pub const Target = union(enum) { | ... | @@ -718,14 +710,6 @@ pub const Target = union(enum) { |
| 718 | }; | 710 | }; |
| 719 | } | 711 | } |
| 720 | 712 | ||
| 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 | |||
| 729 | pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 { | 713 | pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 { |
| 730 | return std.fmt.allocPrint(allocator, "{}{}-{}-{}", .{ | 714 | return std.fmt.allocPrint(allocator, "{}{}-{}-{}", .{ |
| 731 | @tagName(self.getArch()), | 715 | @tagName(self.getArch()), |
| ... | @@ -791,14 +775,18 @@ pub const Target = union(enum) { | ... | @@ -791,14 +775,18 @@ pub const Target = union(enum) { |
| 791 | }); | 775 | }); |
| 792 | } | 776 | } |
| 793 | 777 | ||
| 778 | /// TODO: Support CPU features here? | ||
| 779 | /// https://github.com/ziglang/zig/issues/4261 | ||
| 794 | pub fn parse(text: []const u8) !Target { | 780 | pub fn parse(text: []const u8) !Target { |
| 795 | var it = mem.separate(text, "-"); | 781 | var it = mem.separate(text, "-"); |
| 796 | const arch_name = it.next() orelse return error.MissingArchitecture; | 782 | const arch_name = it.next() orelse return error.MissingArchitecture; |
| 797 | const os_name = it.next() orelse return error.MissingOperatingSystem; | 783 | const os_name = it.next() orelse return error.MissingOperatingSystem; |
| 798 | const abi_name = it.next(); | 784 | const abi_name = it.next(); |
| 785 | const arch = try parseArchSub(arch_name); | ||
| 799 | 786 | ||
| 800 | var cross = Cross{ | 787 | var cross = Cross{ |
| 801 | .arch = try parseArchSub(arch_name), | 788 | .arch = arch, |
| 789 | .cpu_features = arch.getBaselineCpuFeatures(), | ||
| 802 | .os = try parseOs(os_name), | 790 | .os = try parseOs(os_name), |
| 803 | .abi = undefined, | 791 | .abi = undefined, |
| 804 | }; | 792 | }; |
lib/std/target/avr.zig-4| ... | @@ -2378,7 +2378,3 @@ pub const all_cpus = &[_]*const Cpu{ | ... | @@ -2378,7 +2378,3 @@ pub const all_cpus = &[_]*const Cpu{ |
| 2378 | &cpu.avrxmega7, | 2378 | &cpu.avrxmega7, |
| 2379 | &cpu.m3000, | 2379 | &cpu.m3000, |
| 2380 | }; | 2380 | }; |
| 2381 | |||
| 2382 | pub const baseline_features = featureSet(&[_]Feature{ | ||
| 2383 | .avr0, | ||
| 2384 | }); |
lib/std/target/riscv.zig+30-19| ... | @@ -69,11 +69,39 @@ pub const all_features = blk: { | ... | @@ -69,11 +69,39 @@ pub const all_features = blk: { |
| 69 | }; | 69 | }; |
| 70 | 70 | ||
| 71 | pub const cpu = struct { | 71 | pub 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 | |||
| 72 | pub const generic_rv32 = Cpu{ | 99 | pub const generic_rv32 = Cpu{ |
| 73 | .name = "generic_rv32", | 100 | .name = "generic_rv32", |
| 74 | .llvm_name = "generic-rv32", | 101 | .llvm_name = "generic-rv32", |
| 75 | .features = featureSet(&[_]Feature{}), | 102 | .features = featureSet(&[_]Feature{}), |
| 76 | }; | 103 | }; |
| 104 | |||
| 77 | pub const generic_rv64 = Cpu{ | 105 | pub const generic_rv64 = Cpu{ |
| 78 | .name = "generic_rv64", | 106 | .name = "generic_rv64", |
| 79 | .llvm_name = "generic-rv64", | 107 | .llvm_name = "generic-rv64", |
| ... | @@ -87,25 +115,8 @@ pub const cpu = struct { | ... | @@ -87,25 +115,8 @@ pub const cpu = struct { |
| 87 | /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 | 115 | /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 |
| 88 | /// compiler has inefficient memory and CPU usage, affecting build times. | 116 | /// compiler has inefficient memory and CPU usage, affecting build times. |
| 89 | pub const all_cpus = &[_]*const Cpu{ | 117 | pub const all_cpus = &[_]*const Cpu{ |
| 118 | &cpu.baseline_rv32, | ||
| 119 | &cpu.baseline_rv64, | ||
| 90 | &cpu.generic_rv32, | 120 | &cpu.generic_rv32, |
| 91 | &cpu.generic_rv64, | 121 | &cpu.generic_rv64, |
| 92 | }; | 122 | }; |
| 93 | |||
| 94 | pub const baseline_32_features = featureSet(&[_]Feature{ | ||
| 95 | .a, | ||
| 96 | .c, | ||
| 97 | .d, | ||
| 98 | .f, | ||
| 99 | .m, | ||
| 100 | .relax, | ||
| 101 | }); | ||
| 102 | |||
| 103 | pub 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( | ... | @@ -227,16 +227,14 @@ pub fn cmdTargets( |
| 227 | try jws.objectField("abi"); | 227 | try jws.objectField("abi"); |
| 228 | try jws.emitString(@tagName(native_target.getAbi())); | 228 | try jws.emitString(@tagName(native_target.getAbi())); |
| 229 | try jws.objectField("cpuName"); | 229 | try jws.objectField("cpuName"); |
| 230 | switch (native_target.getCpuFeatures()) { | 230 | const cpu_features = native_target.getCpuFeatures(); |
| 231 | .baseline, .features => try jws.emitNull(), | 231 | try jws.emitString(cpu_features.cpu.name); |
| 232 | .cpu => |cpu| try jws.emitString(cpu.name), | ||
| 233 | } | ||
| 234 | { | 232 | { |
| 235 | try jws.objectField("cpuFeatures"); | 233 | try jws.objectField("cpuFeatures"); |
| 236 | try jws.beginArray(); | 234 | try jws.beginArray(); |
| 237 | const feature_set = native_target.cpuFeatureSet(); | 235 | for (native_target.getArch().allFeaturesList()) |feature, i_usize| { |
| 238 | for (native_target.getArch().allFeaturesList()) |feature, i| { | 236 | const index = @intCast(Target.Cpu.Feature.Set.Index, i_usize); |
| 239 | if (feature_set.isEnabled(@intCast(u8, i))) { | 237 | if (cpu_features.features.isEnabled(index)) { |
| 240 | try jws.arrayElem(); | 238 | try jws.arrayElem(); |
| 241 | try jws.emitString(feature.name); | 239 | try jws.emitString(feature.name); |
| 242 | } | 240 | } |
src-self-hosted/stage1.zig+140-256| ... | @@ -540,74 +540,66 @@ export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usiz | ... | @@ -540,74 +540,66 @@ export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usiz |
| 540 | node.context.maybeRefresh(); | 540 | node.context.maybeRefresh(); |
| 541 | } | 541 | } |
| 542 | 542 | ||
| 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. | ||
| 550 | fn cpuFeaturesFromLLVM( | 543 | fn cpuFeaturesFromLLVM( |
| 551 | arch: Target.Arch, | 544 | arch: Target.Arch, |
| 552 | llvm_cpu_name_z: ?[*:0]const u8, | 545 | llvm_cpu_name_z: ?[*:0]const u8, |
| 553 | llvm_cpu_features_opt: ?[*:0]const u8, | 546 | llvm_cpu_features_opt: ?[*:0]const u8, |
| 554 | ) !Target.CpuFeatures { | 547 | ) !Target.CpuFeatures { |
| 555 | var set = arch.baselineFeatures(); | 548 | var result = arch.getBaselineCpuFeatures(); |
| 556 | const llvm_cpu_features = llvm_cpu_features_opt orelse return Target.CpuFeatures{ | ||
| 557 | .features = set, | ||
| 558 | }; | ||
| 559 | 549 | ||
| 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); | ||
| 561 | 552 | ||
| 562 | var it = mem.tokenize(mem.toSliceConst(u8, llvm_cpu_features), ","); | 553 | for (arch.allCpus()) |cpu| { |
| 563 | while (it.next()) |decorated_llvm_feat| { | 554 | const this_llvm_name = cpu.llvm_name orelse continue; |
| 564 | var op: enum { | 555 | if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) { |
| 565 | add, | 556 | // Here we use the non-dependencies-populated set, |
| 566 | sub, | 557 | // so that subtracting features later in this function |
| 567 | } = undefined; | 558 | // affect the prepopulated set. |
| 568 | var llvm_feat: []const u8 = undefined; | 559 | result = Target.CpuFeatures{ |
| 569 | if (mem.startsWith(u8, decorated_llvm_feat, "+")) { | 560 | .cpu = cpu, |
| 570 | op = .add; | 561 | .features = cpu.features, |
| 571 | llvm_feat = decorated_llvm_feat[1..]; | 562 | }; |
| 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 | } | ||
| 585 | break; | 563 | break; |
| 586 | } | 564 | } |
| 587 | } | 565 | } |
| 588 | } | 566 | } |
| 589 | 567 | ||
| 590 | if (llvm_cpu_name_z) |cpu_name_z| { | 568 | const all_features = arch.allFeaturesList(); |
| 591 | const llvm_cpu_name = mem.toSliceConst(u8, cpu_name_z); | ||
| 592 | 569 | ||
| 593 | for (arch.allCpus()) |cpu| { | 570 | if (llvm_cpu_features_opt) |llvm_cpu_features| { |
| 594 | const this_llvm_name = cpu.llvm_name orelse continue; | 571 | var it = mem.tokenize(mem.toSliceConst(u8, llvm_cpu_features), ","); |
| 595 | if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) { | 572 | while (it.next()) |decorated_llvm_feat| { |
| 596 | // Only trust the CPU if the reported features exactly match. | 573 | var op: enum { |
| 597 | var populated_reported_features = set; | 574 | add, |
| 598 | populated_reported_features.populateDependencies(all_features); | 575 | sub, |
| 599 | var populated_cpu_features = cpu.features; | 576 | } = undefined; |
| 600 | populated_cpu_features.populateDependencies(all_features); | 577 | var llvm_feat: []const u8 = undefined; |
| 601 | if (populated_reported_features.eql(populated_cpu_features)) { | 578 | if (mem.startsWith(u8, decorated_llvm_feat, "+")) { |
| 602 | return Target.CpuFeatures{ .cpu = cpu }; | 579 | op = .add; |
| 603 | } else { | 580 | llvm_feat = decorated_llvm_feat[1..]; |
| 604 | return Target.CpuFeatures{ .features = set }; | 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; | ||
| 605 | } | 596 | } |
| 606 | } | 597 | } |
| 607 | } | 598 | } |
| 608 | } | 599 | } |
| 609 | 600 | ||
| 610 | return Target.CpuFeatures{ .features = set }; | 601 | result.features.populateDependencies(all_features); |
| 602 | return result; | ||
| 611 | } | 603 | } |
| 612 | 604 | ||
| 613 | // ABI warning | 605 | // ABI warning |
| ... | @@ -639,7 +631,6 @@ const Stage2CpuFeatures = struct { | ... | @@ -639,7 +631,6 @@ const Stage2CpuFeatures = struct { |
| 639 | allocator: *mem.Allocator, | 631 | allocator: *mem.Allocator, |
| 640 | cpu_features: Target.CpuFeatures, | 632 | cpu_features: Target.CpuFeatures, |
| 641 | 633 | ||
| 642 | llvm_cpu_name: ?[*:0]const u8, | ||
| 643 | llvm_features_str: ?[*:0]const u8, | 634 | llvm_features_str: ?[*:0]const u8, |
| 644 | 635 | ||
| 645 | builtin_str: [:0]const u8, | 636 | builtin_str: [:0]const u8, |
| ... | @@ -647,125 +638,64 @@ const Stage2CpuFeatures = struct { | ... | @@ -647,125 +638,64 @@ const Stage2CpuFeatures = struct { |
| 647 | 638 | ||
| 648 | const Self = @This(); | 639 | const Self = @This(); |
| 649 | 640 | ||
| 650 | fn createBaseline(allocator: *mem.Allocator, arch: Target.Arch) !*Self { | 641 | fn createFromNative(allocator: *mem.Allocator) !*Self { |
| 651 | const self = try allocator.create(Self); | 642 | const arch = Target.current.getArch(); |
| 652 | errdefer allocator.destroy(self); | 643 | const llvm = @import("llvm.zig"); |
| 653 | 644 | const llvm_cpu_name = llvm.GetHostCPUName(); | |
| 654 | const builtin_str = try std.fmt.allocPrint0(allocator, ".baseline;\n", .{}); | 645 | const llvm_cpu_features = llvm.GetNativeFeatures(); |
| 655 | errdefer allocator.free(builtin_str); | 646 | const cpu_features = try cpuFeaturesFromLLVM(arch, llvm_cpu_name, llvm_cpu_features); |
| 656 | 647 | return createFromCpuFeatures(allocator, arch, cpu_features); | |
| 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; | ||
| 737 | } | 648 | } |
| 738 | 649 | ||
| 739 | fn createFromCpuFeatures( | 650 | fn createFromCpuFeatures( |
| 740 | allocator: *mem.Allocator, | 651 | allocator: *mem.Allocator, |
| 741 | arch: Target.Arch, | 652 | arch: Target.Arch, |
| 742 | feature_set: Target.Cpu.Feature.Set, | 653 | cpu_features: Target.CpuFeatures, |
| 743 | ) !*Self { | 654 | ) !*Self { |
| 744 | const self = try allocator.create(Self); | 655 | const self = try allocator.create(Self); |
| 745 | errdefer allocator.destroy(self); | 656 | errdefer allocator.destroy(self); |
| 746 | 657 | ||
| 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 | }); | ||
| 748 | errdefer allocator.free(cache_hash); | 662 | errdefer allocator.free(cache_hash); |
| 749 | 663 | ||
| 750 | const generic_arch_name = arch.genericName(); | 664 | const generic_arch_name = arch.genericName(); |
| 751 | var builtin_str_buffer = try std.Buffer.allocPrint( | 665 | var builtin_str_buffer = try std.Buffer.allocPrint(allocator, |
| 752 | allocator, | ||
| 753 | \\CpuFeatures{{ | 666 | \\CpuFeatures{{ |
| 667 | \\ .cpu = &Target.{}.cpu.{}, | ||
| 754 | \\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{ | 668 | \\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{ |
| 755 | \\ | 669 | \\ |
| 756 | , | 670 | , .{ |
| 757 | .{ generic_arch_name, generic_arch_name }, | 671 | generic_arch_name, |
| 758 | ); | 672 | cpu_features.cpu.name, |
| 673 | generic_arch_name, | ||
| 674 | generic_arch_name, | ||
| 675 | }); | ||
| 759 | defer builtin_str_buffer.deinit(); | 676 | defer builtin_str_buffer.deinit(); |
| 760 | 677 | ||
| 761 | for (arch.allFeaturesList()) |feature, index| { | 678 | var llvm_features_buffer = try std.Buffer.initSize(allocator, 0); |
| 762 | if (!feature_set.isEnabled(@intCast(u8, index))) continue; | 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 | } | ||
| 763 | 691 | ||
| 764 | // TODO some kind of "zig identifier escape" function rather than | 692 | if (is_enabled) { |
| 765 | // unconditionally using @"" syntax | 693 | // TODO some kind of "zig identifier escape" function rather than |
| 766 | try builtin_str_buffer.append(" .@\""); | 694 | // unconditionally using @"" syntax |
| 767 | try builtin_str_buffer.append(feature.name); | 695 | try builtin_str_buffer.append(" .@\""); |
| 768 | try builtin_str_buffer.append("\",\n"); | 696 | try builtin_str_buffer.append(feature.name); |
| 697 | try builtin_str_buffer.append("\",\n"); | ||
| 698 | } | ||
| 769 | } | 699 | } |
| 770 | 700 | ||
| 771 | try builtin_str_buffer.append( | 701 | try builtin_str_buffer.append( |
| ... | @@ -774,11 +704,13 @@ const Stage2CpuFeatures = struct { | ... | @@ -774,11 +704,13 @@ const Stage2CpuFeatures = struct { |
| 774 | \\ | 704 | \\ |
| 775 | ); | 705 | ); |
| 776 | 706 | ||
| 707 | assert(mem.endsWith(u8, llvm_features_buffer.toSliceConst(), ",")); | ||
| 708 | llvm_features_buffer.shrink(llvm_features_buffer.len() - 1); | ||
| 709 | |||
| 777 | self.* = Self{ | 710 | self.* = Self{ |
| 778 | .allocator = allocator, | 711 | .allocator = allocator, |
| 779 | .cpu_features = .{ .features = feature_set }, | 712 | .cpu_features = cpu_features, |
| 780 | .llvm_cpu_name = null, | 713 | .llvm_features_str = llvm_features_buffer.toOwnedSlice().ptr, |
| 781 | .llvm_features_str = try initLLVMFeatures(allocator, arch, feature_set), | ||
| 782 | .builtin_str = builtin_str_buffer.toOwnedSlice(), | 714 | .builtin_str = builtin_str_buffer.toOwnedSlice(), |
| 783 | .cache_hash = cache_hash, | 715 | .cache_hash = cache_hash, |
| 784 | }; | 716 | }; |
| ... | @@ -794,12 +726,13 @@ const Stage2CpuFeatures = struct { | ... | @@ -794,12 +726,13 @@ const Stage2CpuFeatures = struct { |
| 794 | }; | 726 | }; |
| 795 | 727 | ||
| 796 | // ABI warning | 728 | // ABI warning |
| 797 | export fn stage2_cpu_features_parse_cpu( | 729 | export fn stage2_cpu_features_parse( |
| 798 | result: **Stage2CpuFeatures, | 730 | result: **Stage2CpuFeatures, |
| 799 | zig_triple: [*:0]const u8, | 731 | zig_triple: ?[*:0]const u8, |
| 800 | cpu_name: [*:0]const u8, | 732 | cpu_name: ?[*:0]const u8, |
| 733 | cpu_features: ?[*:0]const u8, | ||
| 801 | ) Error { | 734 | ) 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) { |
| 803 | error.OutOfMemory => return .OutOfMemory, | 736 | error.OutOfMemory => return .OutOfMemory, |
| 804 | error.UnknownArchitecture => return .UnknownArchitecture, | 737 | error.UnknownArchitecture => return .UnknownArchitecture, |
| 805 | error.UnknownSubArchitecture => return .UnknownSubArchitecture, | 738 | error.UnknownSubArchitecture => return .UnknownSubArchitecture, |
| ... | @@ -807,110 +740,61 @@ export fn stage2_cpu_features_parse_cpu( | ... | @@ -807,110 +740,61 @@ export fn stage2_cpu_features_parse_cpu( |
| 807 | error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface, | 740 | error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface, |
| 808 | error.MissingOperatingSystem => return .MissingOperatingSystem, | 741 | error.MissingOperatingSystem => return .MissingOperatingSystem, |
| 809 | error.MissingArchitecture => return .MissingArchitecture, | 742 | error.MissingArchitecture => return .MissingArchitecture, |
| 810 | }; | 743 | error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat, |
| 811 | return .None; | ||
| 812 | } | ||
| 813 | |||
| 814 | fn 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 | ||
| 835 | export 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, | ||
| 842 | error.InvalidCpuFeatures => return .InvalidCpuFeatures, | 744 | 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, | ||
| 849 | }; | 745 | }; |
| 850 | return .None; | 746 | return .None; |
| 851 | } | 747 | } |
| 852 | 748 | ||
| 853 | fn parseFeatures(zig_triple: [*:0]const u8, features_text: [*:0]const u8) !*Stage2CpuFeatures { | 749 | fn stage2ParseCpuFeatures( |
| 854 | const target = try Target.parse(mem.toSliceConst(u8, zig_triple)); | 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)); | ||
| 855 | const arch = target.Cross.arch; | 756 | 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 | } | ||
| 870 | 757 | ||
| 871 | // ABI warning | 758 | const cpu = if (cpu_name_oz) |cpu_name_z| blk: { |
| 872 | export fn stage2_cpu_features_baseline(result: **Stage2CpuFeatures, zig_triple: [*:0]const u8) Error { | 759 | const cpu_name = mem.toSliceConst(u8, cpu_name_z); |
| 873 | result.* = cpuFeaturesBaseline(zig_triple) catch |err| switch (err) { | 760 | break :blk arch.parseCpu(cpu_name) catch |err| switch (err) { |
| 874 | error.OutOfMemory => return .OutOfMemory, | 761 | error.UnknownCpu => { |
| 875 | error.UnknownArchitecture => return .UnknownArchitecture, | 762 | std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{ |
| 876 | error.UnknownSubArchitecture => return .UnknownSubArchitecture, | 763 | cpu_name, |
| 877 | error.UnknownOperatingSystem => return .UnknownOperatingSystem, | 764 | @tagName(arch), |
| 878 | error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface, | 765 | }); |
| 879 | error.MissingOperatingSystem => return .MissingOperatingSystem, | 766 | for (arch.allCpus()) |cpu| { |
| 880 | error.MissingArchitecture => return .MissingArchitecture, | 767 | std.debug.warn(" {}\n", .{cpu.name}); |
| 881 | }; | 768 | } |
| 882 | return .None; | 769 | process.exit(1); |
| 883 | } | 770 | }, |
| 884 | 771 | else => |e| return e, | |
| 885 | fn cpuFeaturesBaseline(zig_triple: [*:0]const u8) !*Stage2CpuFeatures { | 772 | }; |
| 886 | const target = try Target.parse(mem.toSliceConst(u8, zig_triple)); | 773 | } else target.Cross.cpu_features.cpu; |
| 887 | const arch = target.Cross.arch; | 774 | |
| 888 | return Stage2CpuFeatures.createBaseline(std.heap.c_allocator, arch); | 775 | var set = if (cpu_features_oz) |cpu_features_z| blk: { |
| 889 | } | 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; | ||
| 890 | 792 | ||
| 891 | // ABI warning | 793 | set.populateDependencies(arch.allFeaturesList()); |
| 892 | export fn stage2_cpu_features_llvm( | 794 | return Stage2CpuFeatures.createFromCpuFeatures(std.heap.c_allocator, arch, .{ |
| 893 | result: **Stage2CpuFeatures, | 795 | .cpu = cpu, |
| 894 | zig_triple: [*:0]const u8, | 796 | .features = set, |
| 895 | llvm_cpu_name: ?[*:0]const u8, | 797 | }); |
| 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; | ||
| 914 | } | 798 | } |
| 915 | 799 | ||
| 916 | // ABI warning | 800 | // ABI warning |
| ... | @@ -935,7 +819,7 @@ export fn stage2_cpu_features_get_builtin_str( | ... | @@ -935,7 +819,7 @@ export fn stage2_cpu_features_get_builtin_str( |
| 935 | 819 | ||
| 936 | // ABI warning | 820 | // ABI warning |
| 937 | export fn stage2_cpu_features_get_llvm_cpu(cpu_features: *const Stage2CpuFeatures) ?[*:0]const u8 { | 821 | export 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; |
| 939 | } | 823 | } |
| 940 | 824 | ||
| 941 | // ABI warning | 825 | // ABI warning |
src/codegen.cpp+1-1| ... | @@ -8581,7 +8581,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { | ... | @@ -8581,7 +8581,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 8581 | stage2_cpu_features_get_builtin_str(g->zig_target->cpu_features, &ptr, &len); | 8581 | stage2_cpu_features_get_builtin_str(g->zig_target->cpu_features, &ptr, &len); |
| 8582 | buf_append_mem(contents, ptr, len); | 8582 | buf_append_mem(contents, ptr, len); |
| 8583 | } else { | 8583 | } else { |
| 8584 | buf_append_str(contents, ".baseline;\n"); | 8584 | buf_append_str(contents, "arch.getBaselineCpuFeatures();\n"); |
| 8585 | } | 8585 | } |
| 8586 | } | 8586 | } |
| 8587 | if (g->libc_link_lib != nullptr && g->zig_target->glibc_version != nullptr) { | 8587 | 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) { | ... | @@ -866,7 +866,7 @@ int main(int argc, char **argv) { |
| 866 | cpu = argv[i]; | 866 | cpu = argv[i]; |
| 867 | } else if (strcmp(arg, "-target-feature") == 0) { | 867 | } else if (strcmp(arg, "-target-feature") == 0) { |
| 868 | features = argv[i]; | 868 | features = argv[i]; |
| 869 | }else { | 869 | } else { |
| 870 | fprintf(stderr, "Invalid argument: %s\n", arg); | 870 | fprintf(stderr, "Invalid argument: %s\n", arg); |
| 871 | return print_error_usage(arg0); | 871 | return print_error_usage(arg0); |
| 872 | } | 872 | } |
| ... | @@ -984,35 +984,10 @@ int main(int argc, char **argv) { | ... | @@ -984,35 +984,10 @@ int main(int argc, char **argv) { |
| 984 | Buf zig_triple_buf = BUF_INIT; | 984 | Buf zig_triple_buf = BUF_INIT; |
| 985 | target_triple_zig(&zig_triple_buf, &target); | 985 | target_triple_zig(&zig_triple_buf, &target); |
| 986 | 986 | ||
| 987 | if (cpu && features) { | 987 | const char *stage2_triple_arg = target.is_native ? nullptr : buf_ptr(&zig_triple_buf); |
| 988 | fprintf(stderr, "-target-cpu and -target-feature options not allowed together\n"); | 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)); | ||
| 989 | return main_exit(root_progress_node, EXIT_FAILURE); | 990 | 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 | } | ||
| 1016 | } | 991 | } |
| 1017 | 992 | ||
| 1018 | if (output_dir != nullptr && enable_cache == CacheOptOn) { | 993 | if (output_dir != nullptr && enable_cache == CacheOptOn) { |
src/userland.cpp+24-25| ... | @@ -2,7 +2,8 @@ | ... | @@ -2,7 +2,8 @@ |
| 2 | // src-self-hosted/stage1.zig | 2 | // src-self-hosted/stage1.zig |
| 3 | 3 | ||
| 4 | #include "userland.h" | 4 | #include "userland.h" |
| 5 | #include "ast_render.hpp" | 5 | #include "util.hpp" |
| 6 | #include "zig_llvm.h" | ||
| 6 | #include <stdio.h> | 7 | #include <stdio.h> |
| 7 | #include <stdlib.h> | 8 | #include <stdlib.h> |
| 8 | #include <string.h> | 9 | #include <string.h> |
| ... | @@ -96,32 +97,30 @@ struct Stage2CpuFeatures { | ... | @@ -96,32 +97,30 @@ struct Stage2CpuFeatures { |
| 96 | const char *cache_hash; | 97 | const char *cache_hash; |
| 97 | }; | 98 | }; |
| 98 | 99 | ||
| 99 | Error stage2_cpu_features_parse_cpu(Stage2CpuFeatures **out, const char *zig_triple, const char *str) { | 100 | Error stage2_cpu_features_parse(struct Stage2CpuFeatures **out, const char *zig_triple, |
| 100 | const char *msg = "stage0 called stage2_cpu_features_parse_cpu"; | 101 | const char *cpu_name, const char *cpu_features) |
| 101 | stage2_panic(msg, strlen(msg)); | ||
| 102 | } | ||
| 103 | Error 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 | } | ||
| 107 | Error 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 | } | ||
| 114 | Error stage2_cpu_features_llvm(Stage2CpuFeatures **out, const char *zig_triple, | ||
| 115 | const char *llvm_cpu_name, const char *llvm_features) | ||
| 116 | { | 102 | { |
| 117 | Stage2CpuFeatures *result = allocate<Stage2CpuFeatures>(1, "Stage2CpuFeatures"); | 103 | if (zig_triple == nullptr) { |
| 118 | result->llvm_cpu_name = llvm_cpu_name; | 104 | Stage2CpuFeatures *result = allocate<Stage2CpuFeatures>(1, "Stage2CpuFeatures"); |
| 119 | result->llvm_cpu_features = llvm_features; | 105 | result->llvm_cpu_name = ZigLLVMGetHostCPUName(); |
| 120 | result->builtin_str = ".baseline;\n"; | 106 | result->llvm_cpu_features = ZigLLVMGetNativeFeatures(); |
| 121 | result->cache_hash = "native\n\n"; | 107 | result->builtin_str = "arch.getBaselineCpuFeatures();\n"; |
| 122 | *out = result; | 108 | result->cache_hash = "native\n\n"; |
| 123 | return ErrorNone; | 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)); | ||
| 124 | } | 122 | } |
| 123 | |||
| 125 | void stage2_cpu_features_get_cache_hash(const Stage2CpuFeatures *cpu_features, | 124 | void stage2_cpu_features_get_cache_hash(const Stage2CpuFeatures *cpu_features, |
| 126 | const char **ptr, size_t *len) | 125 | const char **ptr, size_t *len) |
| 127 | { | 126 | { |
src/userland.h+2-14| ... | @@ -184,20 +184,8 @@ ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node, | ... | @@ -184,20 +184,8 @@ ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node, |
| 184 | struct Stage2CpuFeatures; | 184 | struct Stage2CpuFeatures; |
| 185 | 185 | ||
| 186 | // ABI warning | 186 | // ABI warning |
| 187 | ZIG_EXTERN_C Error stage2_cpu_features_parse_cpu(struct Stage2CpuFeatures **result, | 187 | ZIG_EXTERN_C Error stage2_cpu_features_parse(struct Stage2CpuFeatures **result, |
| 188 | const char *zig_triple, const char *cpu_name); | 188 | const char *zig_triple, const char *cpu_name, const char *cpu_features); |
| 189 | |||
| 190 | // ABI warning | ||
| 191 | ZIG_EXTERN_C Error stage2_cpu_features_parse_features(struct Stage2CpuFeatures **result, | ||
| 192 | const char *zig_triple, const char *features); | ||
| 193 | |||
| 194 | // ABI warning | ||
| 195 | ZIG_EXTERN_C Error stage2_cpu_features_baseline(struct Stage2CpuFeatures **result, | ||
| 196 | const char *zig_triple); | ||
| 197 | |||
| 198 | // ABI warning | ||
| 199 | ZIG_EXTERN_C Error stage2_cpu_features_llvm(struct Stage2CpuFeatures **result, | ||
| 200 | const char *zig_triple, const char *llvm_cpu_name, const char *llvm_features); | ||
| 201 | 189 | ||
| 202 | // ABI warning | 190 | // ABI warning |
| 203 | ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_cpu(const struct Stage2CpuFeatures *cpu_features); | 191 | ZIG_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 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const Target = @import("std").Target; | ||
| 3 | 4 | ||
| 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 5 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | cases.addTest("non-exhaustive enums", | 6 | cases.addTest("non-exhaustive enums", |
| ... | @@ -272,9 +273,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -272,9 +273,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 272 | , &[_][]const u8{ | 273 | , &[_][]const u8{ |
| 273 | "tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack", | 274 | "tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack", |
| 274 | }); | 275 | }); |
| 275 | tc.target = tests.Target{ | 276 | tc.target = Target{ |
| 276 | .Cross = tests.CrossTarget{ | 277 | .Cross = .{ |
| 277 | .arch = .wasm32, | 278 | .arch = .wasm32, |
| 279 | .cpu_features = Target.Arch.wasm32.getBaselineCpuFeatures(), | ||
| 278 | .os = .wasi, | 280 | .os = .wasi, |
| 279 | .abi = .none, | 281 | .abi = .none, |
| 280 | }, | 282 | }, |
| ... | @@ -673,9 +675,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -673,9 +675,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 673 | , &[_][]const u8{ | 675 | , &[_][]const u8{ |
| 674 | "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs", | 676 | "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs", |
| 675 | }); | 677 | }); |
| 676 | tc.target = tests.Target{ | 678 | tc.target = Target{ |
| 677 | .Cross = tests.CrossTarget{ | 679 | .Cross = .{ |
| 678 | .arch = .x86_64, | 680 | .arch = .x86_64, |
| 681 | .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(), | ||
| 679 | .os = .linux, | 682 | .os = .linux, |
| 680 | .abi = .gnu, | 683 | .abi = .gnu, |
| 681 | }, | 684 | }, |
test/tests.zig+220-196| ... | @@ -38,236 +38,260 @@ const TestTarget = struct { | ... | @@ -38,236 +38,260 @@ const TestTarget = struct { |
| 38 | disable_native: bool = false, | 38 | disable_native: bool = false, |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | const test_targets = [_]TestTarget{ | 41 | const test_targets = blk: { |
| 42 | TestTarget{}, | 42 | // getBaselineCpuFeatures calls populateDependencies which has a O(N ^ 2) algorithm |
| 43 | TestTarget{ | 43 | // (where N is roughly 160, which technically makes it O(1), but it adds up to a |
| 44 | .link_libc = true, | 44 | // lot of branches) |
| 45 | }, | 45 | @setEvalBranchQuota(50000); |
| 46 | TestTarget{ | 46 | break :blk [_]TestTarget{ |
| 47 | .single_threaded = true, | 47 | TestTarget{}, |
| 48 | }, | 48 | TestTarget{ |
| 49 | 49 | .link_libc = true, | |
| 50 | TestTarget{ | 50 | }, |
| 51 | .target = Target{ | 51 | TestTarget{ |
| 52 | .Cross = CrossTarget{ | 52 | .single_threaded = true, |
| 53 | .os = .linux, | 53 | }, |
| 54 | .arch = .x86_64, | 54 | |
| 55 | .abi = .none, | 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 | }, | ||
| 56 | }, | 63 | }, |
| 57 | }, | 64 | }, |
| 58 | }, | 65 | TestTarget{ |
| 59 | TestTarget{ | 66 | .target = Target{ |
| 60 | .target = Target{ | 67 | .Cross = CrossTarget{ |
| 61 | .Cross = CrossTarget{ | 68 | .os = .linux, |
| 62 | .os = .linux, | 69 | .arch = .x86_64, |
| 63 | .arch = .x86_64, | 70 | .abi = .gnu, |
| 64 | .abi = .gnu, | 71 | .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(), |
| 72 | }, | ||
| 65 | }, | 73 | }, |
| 74 | .link_libc = true, | ||
| 66 | }, | 75 | }, |
| 67 | .link_libc = true, | 76 | TestTarget{ |
| 68 | }, | 77 | .target = Target{ |
| 69 | TestTarget{ | 78 | .Cross = CrossTarget{ |
| 70 | .target = Target{ | 79 | .os = .linux, |
| 71 | .Cross = CrossTarget{ | 80 | .arch = .x86_64, |
| 72 | .os = .linux, | 81 | .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(), |
| 73 | .arch = .x86_64, | 82 | .abi = .musl, |
| 74 | .abi = .musl, | 83 | }, |
| 75 | }, | 84 | }, |
| 85 | .link_libc = true, | ||
| 76 | }, | 86 | }, |
| 77 | .link_libc = true, | 87 | |
| 78 | }, | 88 | TestTarget{ |
| 79 | 89 | .target = Target{ | |
| 80 | TestTarget{ | 90 | .Cross = CrossTarget{ |
| 81 | .target = Target{ | 91 | .os = .linux, |
| 82 | .Cross = CrossTarget{ | 92 | .arch = .i386, |
| 83 | .os = .linux, | 93 | .cpu_features = Target.Arch.i386.getBaselineCpuFeatures(), |
| 84 | .arch = .i386, | 94 | .abi = .none, |
| 85 | .abi = .none, | 95 | }, |
| 86 | }, | 96 | }, |
| 87 | }, | 97 | }, |
| 88 | }, | 98 | TestTarget{ |
| 89 | TestTarget{ | 99 | .target = Target{ |
| 90 | .target = Target{ | 100 | .Cross = CrossTarget{ |
| 91 | .Cross = CrossTarget{ | 101 | .os = .linux, |
| 92 | .os = .linux, | 102 | .arch = .i386, |
| 93 | .arch = .i386, | 103 | .cpu_features = Target.Arch.i386.getBaselineCpuFeatures(), |
| 94 | .abi = .musl, | 104 | .abi = .musl, |
| 105 | }, | ||
| 95 | }, | 106 | }, |
| 107 | .link_libc = true, | ||
| 96 | }, | 108 | }, |
| 97 | .link_libc = true, | 109 | |
| 98 | }, | 110 | TestTarget{ |
| 99 | 111 | .target = Target{ | |
| 100 | TestTarget{ | 112 | .Cross = CrossTarget{ |
| 101 | .target = Target{ | 113 | .os = .linux, |
| 102 | .Cross = CrossTarget{ | 114 | .arch = Target.Arch{ .aarch64 = .v8_5a }, |
| 103 | .os = .linux, | 115 | .cpu_features = (Target.Arch{ .aarch64 = .v8_5a }).getBaselineCpuFeatures(), |
| 104 | .arch = builtin.Arch{ .aarch64 = builtin.Arch.Arm64.v8_5a }, | 116 | .abi = .none, |
| 105 | .abi = .none, | 117 | }, |
| 106 | }, | 118 | }, |
| 107 | }, | 119 | }, |
| 108 | }, | 120 | TestTarget{ |
| 109 | TestTarget{ | 121 | .target = Target{ |
| 110 | .target = Target{ | 122 | .Cross = CrossTarget{ |
| 111 | .Cross = CrossTarget{ | 123 | .os = .linux, |
| 112 | .os = .linux, | 124 | .arch = Target.Arch{ .aarch64 = .v8_5a }, |
| 113 | .arch = builtin.Arch{ .aarch64 = builtin.Arch.Arm64.v8_5a }, | 125 | .cpu_features = (Target.Arch{ .aarch64 = .v8_5a }).getBaselineCpuFeatures(), |
| 114 | .abi = .musl, | 126 | .abi = .musl, |
| 127 | }, | ||
| 115 | }, | 128 | }, |
| 129 | .link_libc = true, | ||
| 116 | }, | 130 | }, |
| 117 | .link_libc = true, | 131 | TestTarget{ |
| 118 | }, | 132 | .target = Target{ |
| 119 | TestTarget{ | 133 | .Cross = CrossTarget{ |
| 120 | .target = Target{ | 134 | .os = .linux, |
| 121 | .Cross = CrossTarget{ | 135 | .arch = Target.Arch{ .aarch64 = .v8_5a }, |
| 122 | .os = .linux, | 136 | .cpu_features = (Target.Arch{ .aarch64 = .v8_5a }).getBaselineCpuFeatures(), |
| 123 | .arch = builtin.Arch{ .aarch64 = builtin.Arch.Arm64.v8_5a }, | 137 | .abi = .gnu, |
| 124 | .abi = .gnu, | 138 | }, |
| 125 | }, | 139 | }, |
| 140 | .link_libc = true, | ||
| 126 | }, | 141 | }, |
| 127 | .link_libc = true, | 142 | |
| 128 | }, | 143 | TestTarget{ |
| 129 | 144 | .target = Target{ | |
| 130 | TestTarget{ | 145 | .Cross = CrossTarget{ |
| 131 | .target = Target{ | 146 | .os = .linux, |
| 132 | .Cross = CrossTarget{ | 147 | .arch = Target.Arch{ .arm = .v8_5a }, |
| 133 | .os = .linux, | 148 | .cpu_features = (Target.Arch{ .arm = .v8_5a }).getBaselineCpuFeatures(), |
| 134 | .arch = builtin.Arch{ .arm = builtin.Arch.Arm32.v8_5a }, | 149 | .abi = .none, |
| 135 | .abi = .none, | 150 | }, |
| 136 | }, | 151 | }, |
| 137 | }, | 152 | }, |
| 138 | }, | 153 | TestTarget{ |
| 139 | TestTarget{ | 154 | .target = Target{ |
| 140 | .target = Target{ | 155 | .Cross = CrossTarget{ |
| 141 | .Cross = CrossTarget{ | 156 | .os = .linux, |
| 142 | .os = .linux, | 157 | .arch = Target.Arch{ .arm = .v8_5a }, |
| 143 | .arch = builtin.Arch{ .arm = builtin.Arch.Arm32.v8_5a }, | 158 | .cpu_features = (Target.Arch{ .arm = .v8_5a }).getBaselineCpuFeatures(), |
| 144 | .abi = .musleabihf, | 159 | .abi = .musleabihf, |
| 160 | }, | ||
| 145 | }, | 161 | }, |
| 162 | .link_libc = true, | ||
| 146 | }, | 163 | }, |
| 147 | .link_libc = true, | 164 | // TODO https://github.com/ziglang/zig/issues/3287 |
| 148 | }, | 165 | //TestTarget{ |
| 149 | // TODO https://github.com/ziglang/zig/issues/3287 | 166 | // .target = Target{ |
| 150 | //TestTarget{ | 167 | // .Cross = CrossTarget{ |
| 151 | // .target = Target{ | 168 | // .os = .linux, |
| 152 | // .Cross = CrossTarget{ | 169 | // .arch = Target.Arch{ .arm = .v8_5a }, |
| 153 | // .os = .linux, | 170 | // .cpu_features = (Target.Arch{ .arm = .v8_5a }).getBaselineCpuFeatures(), |
| 154 | // .arch = builtin.Arch{ .arm = builtin.Arch.Arm32.v8_5a }, | 171 | // .abi = .gnueabihf, |
| 155 | // .abi = .gnueabihf, | 172 | // }, |
| 156 | // }, | 173 | // }, |
| 157 | // }, | 174 | // .link_libc = true, |
| 158 | // .link_libc = true, | 175 | //}, |
| 159 | //}, | 176 | |
| 160 | 177 | TestTarget{ | |
| 161 | TestTarget{ | 178 | .target = Target{ |
| 162 | .target = Target{ | 179 | .Cross = CrossTarget{ |
| 163 | .Cross = CrossTarget{ | 180 | .os = .linux, |
| 164 | .os = .linux, | 181 | .arch = .mipsel, |
| 165 | .arch = .mipsel, | 182 | .cpu_features = Target.Arch.mipsel.getBaselineCpuFeatures(), |
| 166 | .abi = .none, | 183 | .abi = .none, |
| 184 | }, | ||
| 167 | }, | 185 | }, |
| 168 | }, | 186 | }, |
| 169 | }, | 187 | TestTarget{ |
| 170 | TestTarget{ | 188 | .target = Target{ |
| 171 | .target = Target{ | 189 | .Cross = CrossTarget{ |
| 172 | .Cross = CrossTarget{ | 190 | .os = .linux, |
| 173 | .os = .linux, | 191 | .arch = .mipsel, |
| 174 | .arch = .mipsel, | 192 | .cpu_features = Target.Arch.mipsel.getBaselineCpuFeatures(), |
| 175 | .abi = .musl, | 193 | .abi = .musl, |
| 194 | }, | ||
| 176 | }, | 195 | }, |
| 196 | .link_libc = true, | ||
| 177 | }, | 197 | }, |
| 178 | .link_libc = true, | 198 | |
| 179 | }, | 199 | TestTarget{ |
| 180 | 200 | .target = Target{ | |
| 181 | TestTarget{ | 201 | .Cross = CrossTarget{ |
| 182 | .target = Target{ | 202 | .os = .macosx, |
| 183 | .Cross = CrossTarget{ | 203 | .arch = .x86_64, |
| 184 | .os = .macosx, | 204 | .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(), |
| 185 | .arch = .x86_64, | 205 | .abi = .gnu, |
| 186 | .abi = .gnu, | 206 | }, |
| 187 | }, | 207 | }, |
| 208 | // TODO https://github.com/ziglang/zig/issues/3295 | ||
| 209 | .disable_native = true, | ||
| 188 | }, | 210 | }, |
| 189 | // TODO https://github.com/ziglang/zig/issues/3295 | 211 | |
| 190 | .disable_native = true, | 212 | TestTarget{ |
| 191 | }, | 213 | .target = Target{ |
| 192 | 214 | .Cross = CrossTarget{ | |
| 193 | TestTarget{ | 215 | .os = .windows, |
| 194 | .target = Target{ | 216 | .arch = .i386, |
| 195 | .Cross = CrossTarget{ | 217 | .cpu_features = Target.Arch.i386.getBaselineCpuFeatures(), |
| 196 | .os = .windows, | 218 | .abi = .msvc, |
| 197 | .arch = .i386, | 219 | }, |
| 198 | .abi = .msvc, | ||
| 199 | }, | 220 | }, |
| 200 | }, | 221 | }, |
| 201 | }, | 222 | |
| 202 | 223 | TestTarget{ | |
| 203 | TestTarget{ | 224 | .target = Target{ |
| 204 | .target = Target{ | 225 | .Cross = CrossTarget{ |
| 205 | .Cross = CrossTarget{ | 226 | .os = .windows, |
| 206 | .os = .windows, | 227 | .arch = .x86_64, |
| 207 | .arch = .x86_64, | 228 | .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(), |
| 208 | .abi = .msvc, | 229 | .abi = .msvc, |
| 230 | }, | ||
| 209 | }, | 231 | }, |
| 210 | }, | 232 | }, |
| 211 | }, | 233 | |
| 212 | 234 | TestTarget{ | |
| 213 | TestTarget{ | 235 | .target = Target{ |
| 214 | .target = Target{ | 236 | .Cross = CrossTarget{ |
| 215 | .Cross = CrossTarget{ | 237 | .os = .windows, |
| 216 | .os = .windows, | 238 | .arch = .i386, |
| 217 | .arch = .i386, | 239 | .cpu_features = Target.Arch.i386.getBaselineCpuFeatures(), |
| 218 | .abi = .gnu, | 240 | .abi = .gnu, |
| 241 | }, | ||
| 219 | }, | 242 | }, |
| 243 | .link_libc = true, | ||
| 220 | }, | 244 | }, |
| 221 | .link_libc = true, | 245 | |
| 222 | }, | 246 | TestTarget{ |
| 223 | 247 | .target = Target{ | |
| 224 | TestTarget{ | 248 | .Cross = CrossTarget{ |
| 225 | .target = Target{ | 249 | .os = .windows, |
| 226 | .Cross = CrossTarget{ | 250 | .arch = .x86_64, |
| 227 | .os = .windows, | 251 | .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(), |
| 228 | .arch = .x86_64, | 252 | .abi = .gnu, |
| 229 | .abi = .gnu, | 253 | }, |
| 230 | }, | 254 | }, |
| 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, | ||
| 231 | }, | 265 | }, |
| 232 | .link_libc = true, | 266 | TestTarget{ |
| 233 | }, | 267 | .mode = .ReleaseFast, |
| 234 | 268 | .single_threaded = true, | |
| 235 | // Do the release tests last because they take a long time | 269 | }, |
| 236 | TestTarget{ | 270 | |
| 237 | .mode = .ReleaseFast, | 271 | TestTarget{ |
| 238 | }, | 272 | .mode = .ReleaseSafe, |
| 239 | TestTarget{ | 273 | }, |
| 240 | .link_libc = true, | 274 | TestTarget{ |
| 241 | .mode = .ReleaseFast, | 275 | .link_libc = true, |
| 242 | }, | 276 | .mode = .ReleaseSafe, |
| 243 | TestTarget{ | 277 | }, |
| 244 | .mode = .ReleaseFast, | 278 | TestTarget{ |
| 245 | .single_threaded = true, | 279 | .mode = .ReleaseSafe, |
| 246 | }, | 280 | .single_threaded = true, |
| 247 | 281 | }, | |
| 248 | TestTarget{ | 282 | |
| 249 | .mode = .ReleaseSafe, | 283 | TestTarget{ |
| 250 | }, | 284 | .mode = .ReleaseSmall, |
| 251 | TestTarget{ | 285 | }, |
| 252 | .link_libc = true, | 286 | TestTarget{ |
| 253 | .mode = .ReleaseSafe, | 287 | .link_libc = true, |
| 254 | }, | 288 | .mode = .ReleaseSmall, |
| 255 | TestTarget{ | 289 | }, |
| 256 | .mode = .ReleaseSafe, | 290 | TestTarget{ |
| 257 | .single_threaded = true, | 291 | .mode = .ReleaseSmall, |
| 258 | }, | 292 | .single_threaded = true, |
| 259 | 293 | }, | |
| 260 | TestTarget{ | 294 | }; |
| 261 | .mode = .ReleaseSmall, | ||
| 262 | }, | ||
| 263 | TestTarget{ | ||
| 264 | .link_libc = true, | ||
| 265 | .mode = .ReleaseSmall, | ||
| 266 | }, | ||
| 267 | TestTarget{ | ||
| 268 | .mode = .ReleaseSmall, | ||
| 269 | .single_threaded = true, | ||
| 270 | }, | ||
| 271 | }; | 295 | }; |
| 272 | 296 | ||
| 273 | const max_stdout_size = 1 * 1024 * 1024; // 1 MB | 297 | const max_stdout_size = 1 * 1024 * 1024; // 1 MB |
test/translate_c.zig+19-3| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const Target = @import("std").Target; | ||
| 3 | 4 | ||
| 4 | pub fn addCases(cases: *tests.TranslateCContext) void { | 5 | pub fn addCases(cases: *tests.TranslateCContext) void { |
| 5 | cases.add("empty declaration", | 6 | cases.add("empty declaration", |
| ... | @@ -1005,7 +1006,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -1005,7 +1006,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1005 | }); | 1006 | }); |
| 1006 | 1007 | ||
| 1007 | cases.addWithTarget("Calling convention", tests.Target{ | 1008 | 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 | }, | ||
| 1009 | }, | 1015 | }, |
| 1010 | \\void __attribute__((fastcall)) foo1(float *a); | 1016 | \\void __attribute__((fastcall)) foo1(float *a); |
| 1011 | \\void __attribute__((stdcall)) foo2(float *a); | 1017 | \\void __attribute__((stdcall)) foo2(float *a); |
| ... | @@ -1021,7 +1027,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -1021,7 +1027,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1021 | }); | 1027 | }); |
| 1022 | 1028 | ||
| 1023 | cases.addWithTarget("Calling convention", tests.Target{ | 1029 | 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 | }, | ||
| 1025 | }, | 1036 | }, |
| 1026 | \\void __attribute__((pcs("aapcs"))) foo1(float *a); | 1037 | \\void __attribute__((pcs("aapcs"))) foo1(float *a); |
| 1027 | \\void __attribute__((pcs("aapcs-vfp"))) foo2(float *a); | 1038 | \\void __attribute__((pcs("aapcs-vfp"))) foo2(float *a); |
| ... | @@ -1031,7 +1042,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -1031,7 +1042,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1031 | }); | 1042 | }); |
| 1032 | 1043 | ||
| 1033 | cases.addWithTarget("Calling convention", tests.Target{ | 1044 | 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 | }, | ||
| 1035 | }, | 1051 | }, |
| 1036 | \\void __attribute__((aarch64_vector_pcs)) foo1(float *a); | 1052 | \\void __attribute__((aarch64_vector_pcs)) foo1(float *a); |
| 1037 | , &[_][]const u8{ | 1053 | , &[_][]const u8{ |