| author | |
| committer | |
| log | a313f153841df8caa3af8fc80966c8f61a856f51 |
| tree | c3bec9cc198079ee945c3e5c6d5734dd5c8183e6 |
| parent | a867b43366c7fb132ec44a03f9b40ead888900fb |
| signature | Commit is signed but in an unrecognized format. |
4 files changed, 172 insertions(+), 72 deletions(-)
src-self-hosted/stage1.zig+106-40| ... | ... | @@ -632,24 +632,77 @@ const Stage2CpuFeatures = struct { |
| 632 | 632 | |
| 633 | 633 | const Self = @This(); |
| 634 | 634 | |
| 635 | fn initBaseline(allocator: *mem.Allocator) !Self { | |
| 636 | const builtin_str = try std.fmt.allocPrint0(allocator, "CpuFeatures.baseline;\n"); | |
| 635 | fn createBaseline(allocator: *mem.Allocator) !*Self { | |
| 636 | const self = try allocator.create(Self); | |
| 637 | errdefer allocator.destroy(self); | |
| 638 | ||
| 639 | const builtin_str = try std.fmt.allocPrint0(allocator, ".baseline;\n"); | |
| 637 | 640 | errdefer allocator.free(builtin_str); |
| 638 | 641 | |
| 639 | 642 | const cache_hash = try std.fmt.allocPrint0(allocator, "\n\n"); |
| 640 | 643 | errdefer allocator.free(cache_hash); |
| 641 | 644 | |
| 642 | return Self{ | |
| 645 | self.* = Self{ | |
| 643 | 646 | .allocator = allocator, |
| 644 | .cpu_features = .{ .cpu = cpu }, | |
| 647 | .cpu_features = .baseline, | |
| 645 | 648 | .llvm_cpu_name = null, |
| 646 | 649 | .llvm_features_str = null, |
| 647 | 650 | .builtin_str = builtin_str, |
| 648 | 651 | .cache_hash = cache_hash, |
| 649 | 652 | }; |
| 653 | return self; | |
| 654 | } | |
| 655 | ||
| 656 | fn createFromLLVM( | |
| 657 | allocator: *mem.Allocator, | |
| 658 | arch: [*:0]const u8, | |
| 659 | llvm_cpu_name_z: [*:0]const u8, | |
| 660 | llvm_cpu_features: [*:0]const u8, | |
| 661 | ) !*Self { | |
| 662 | const arch = try Target.parseArchSub(mem.toSliceConst(u8, arch_name)); | |
| 663 | const llvm_cpu_name = mem.toSliceConst(u8, llvm_cpu_name_z); | |
| 664 | ||
| 665 | for (arch.allCpus()) |cpu| { | |
| 666 | const this_llvm_name = cpu.llvm_name orelse continue; | |
| 667 | if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) { | |
| 668 | return createFromCpu(allocator, arch, cpu); | |
| 669 | } | |
| 670 | } | |
| 671 | ||
| 672 | var set = arch.baselineFeatures(); | |
| 673 | var it = mem.tokenize(mem.toSliceConst(u8, llvm_cpu_features), ","); | |
| 674 | while (it.next()) |decorated_llvm_feat| { | |
| 675 | var op: enum { | |
| 676 | add, | |
| 677 | sub, | |
| 678 | } = undefined; | |
| 679 | var llvm_feat: []const u8 = undefined; | |
| 680 | if (mem.startsWith(u8, decorated_llvm_feat, "+")) { | |
| 681 | op = .add; | |
| 682 | llvm_feat = decorated_llvm_feat[1..]; | |
| 683 | } else if (mem.startsWith(u8, decorated_llvm_feat, "-")) { | |
| 684 | op = .sub; | |
| 685 | llvm_feat = decorated_llvm_feat[1..]; | |
| 686 | } else { | |
| 687 | return error.InvalidLlvmCpuFeaturesFormat; | |
| 688 | } | |
| 689 | for (arch.allFeaturesList()) |feature, index| { | |
| 690 | if (mem.eql(u8, feature_name, feature.name)) { | |
| 691 | switch (op) { | |
| 692 | .add => set |= 1 << index, | |
| 693 | .sub => set &= ~@as(Target.Cpu.Feature.Set, 1 << index), | |
| 694 | } | |
| 695 | break; | |
| 696 | } | |
| 697 | } | |
| 698 | } | |
| 699 | return createFromCpuFeatures(allocator, arch, set); | |
| 650 | 700 | } |
| 651 | 701 | |
| 652 | fn initCpu(allocator: *mem.Allocator, arch: Target.Arch, cpu: *const Target.Cpu) !Self { | |
| 702 | fn createFromCpu(allocator: *mem.Allocator, arch: Target.Arch, cpu: *const Target.Cpu) !*Self { | |
| 703 | const self = try allocator.create(Self); | |
| 704 | errdefer allocator.destroy(self); | |
| 705 | ||
| 653 | 706 | const builtin_str = try std.fmt.allocPrint0( |
| 654 | 707 | allocator, |
| 655 | 708 | "CpuFeatures{{ .cpu = &Arch.{}.cpu.{} }};\n", |
| ... | ... | @@ -661,7 +714,7 @@ const Stage2CpuFeatures = struct { |
| 661 | 714 | const cache_hash = try std.fmt.allocPrint0(allocator, "{}\n{x}", cpu.name, cpu.features); |
| 662 | 715 | errdefer allocator.free(cache_hash); |
| 663 | 716 | |
| 664 | return Self{ | |
| 717 | self.* = Self{ | |
| 665 | 718 | .allocator = allocator, |
| 666 | 719 | .cpu_features = .{ .cpu = cpu }, |
| 667 | 720 | .llvm_cpu_name = cpu.llvm_name, |
| ... | ... | @@ -669,13 +722,17 @@ const Stage2CpuFeatures = struct { |
| 669 | 722 | .builtin_str = builtin_str, |
| 670 | 723 | .cache_hash = cache_hash, |
| 671 | 724 | }; |
| 725 | return self; | |
| 672 | 726 | } |
| 673 | 727 | |
| 674 | fn initFeatures( | |
| 728 | fn createFromCpuFeatures( | |
| 675 | 729 | allocator: *mem.Allocator, |
| 676 | 730 | arch: Target.Arch, |
| 677 | 731 | features: Target.Cpu.Feature.Set, |
| 678 | ) !Self { | |
| 732 | ) !*Self { | |
| 733 | const self = try allocator.create(Self); | |
| 734 | errdefer allocator.destroy(self); | |
| 735 | ||
| 679 | 736 | const cache_hash = try std.fmt.allocPrint0(allocator, "\n{x}", features); |
| 680 | 737 | errdefer allocator.free(cache_hash); |
| 681 | 738 | |
| ... | ... | @@ -719,7 +776,7 @@ const Stage2CpuFeatures = struct { |
| 719 | 776 | |
| 720 | 777 | try builtin_str_buffer.append("})};\n"); |
| 721 | 778 | |
| 722 | return Self{ | |
| 779 | self.* = Self{ | |
| 723 | 780 | .allocator = allocator, |
| 724 | 781 | .cpu_features = .{ .features = features }, |
| 725 | 782 | .llvm_cpu_name = null, |
| ... | ... | @@ -727,68 +784,77 @@ const Stage2CpuFeatures = struct { |
| 727 | 784 | .builtin_str = builtin_str_buffer.toOwnedSlice(), |
| 728 | 785 | .cache_hash = cache_hash, |
| 729 | 786 | }; |
| 787 | return self; | |
| 730 | 788 | } |
| 731 | 789 | |
| 732 | fn deinit(self: *Self) void { | |
| 790 | fn destroy(self: *Self) void { | |
| 733 | 791 | self.allocator.free(self.cache_hash); |
| 734 | 792 | self.allocator.free(self.builtin_str); |
| 735 | 793 | if (self.llvm_features_str) |llvm_features_str| self.allocator.free(llvm_features_str); |
| 736 | self.* = undefined; | |
| 794 | self.allocator.destroy(self); | |
| 737 | 795 | } |
| 738 | 796 | }; |
| 739 | 797 | |
| 740 | 798 | // ABI warning |
| 741 | export fn stage2_cpu_features_parse_cpu(arch_name: [*:0]const u8, cpu_name: [*:0]const u8) *Stage2CpuFeatures { | |
| 742 | return parseCpu(arch_name, cpu_name) catch |err| switch (err) { | |
| 743 | error.OutOfMemory => @panic("out of memory"), | |
| 799 | export fn stage2_cpu_features_parse_cpu( | |
| 800 | result: **Stage2CpuFeatures, | |
| 801 | arch_name: [*:0]const u8, | |
| 802 | cpu_name: [*:0]const u8, | |
| 803 | ) Error { | |
| 804 | result.* = parseCpu(arch_name, cpu_name) catch |err| switch (err) { | |
| 805 | error.OutOfMemory => return .OutOfMemory, | |
| 744 | 806 | }; |
| 807 | return .None; | |
| 745 | 808 | } |
| 746 | 809 | |
| 747 | 810 | fn parseCpu(arch_name: [*:0]const u8, cpu_name: [*:0]const u8) !*Stage2CpuFeatures { |
| 748 | 811 | const arch = try Target.parseArchSub(mem.toSliceConst(u8, arch_name)); |
| 749 | 812 | const cpu = try arch.parseCpu(mem.toSliceConst(u8, cpu_name)); |
| 750 | ||
| 751 | const ptr = try allocator.create(Stage2CpuFeatures); | |
| 752 | errdefer std.heap.c_allocator.destroy(ptr); | |
| 753 | ||
| 754 | ptr.* = try Stage2CpuFeatures.initCpu(std.heap.c_allocator, arch, cpu); | |
| 755 | errdefer ptr.deinit(); | |
| 756 | ||
| 757 | return ptr; | |
| 813 | return Stage2CpuFeatures.createFromCpu(std.heap.c_allocator, arch, cpu); | |
| 758 | 814 | } |
| 759 | 815 | |
| 760 | 816 | // ABI warning |
| 761 | 817 | export fn stage2_cpu_features_parse_features( |
| 818 | result: **Stage2CpuFeatures, | |
| 762 | 819 | arch_name: [*:0]const u8, |
| 763 | 820 | features_text: [*:0]const u8, |
| 764 | ) *Stage2CpuFeatures { | |
| 765 | return parseFeatures(arch_name, features_text) catch |err| switch (err) { | |
| 766 | error.OutOfMemory => @panic("out of memory"), | |
| 821 | ) Error { | |
| 822 | result.* = parseFeatures(arch_name, features_text) catch |err| switch (err) { | |
| 823 | error.OutOfMemory => return .OutOfMemory, | |
| 767 | 824 | }; |
| 825 | return .None; | |
| 768 | 826 | } |
| 769 | 827 | |
| 770 | 828 | fn parseFeatures(arch_name: [*:0]const u8, features_text: [*:0]const u8) !*Stage2CpuFeatures { |
| 771 | 829 | const arch = try Target.parseArchSub(mem.toSliceConst(u8, arch_name)); |
| 772 | 830 | const set = try arch.parseCpuFeatureSet(mem.toSliceConst(u8, features_text)); |
| 773 | ||
| 774 | const ptr = try std.heap.c_allocator.create(Stage2CpuFeatures); | |
| 775 | errdefer std.heap.c_allocator.destroy(ptr); | |
| 776 | ||
| 777 | ptr.* = try Stage2CpuFeatures.initFeatures(std.heap.c_allocator, arch, set); | |
| 778 | errdefer ptr.deinit(); | |
| 779 | ||
| 780 | return ptr; | |
| 831 | return Stage2CpuFeatures.createFromCpuFeatures(std.heap.c_allocator, arch, set); | |
| 781 | 832 | } |
| 782 | 833 | |
| 783 | 834 | // ABI warning |
| 784 | export fn stage2_cpu_features_baseline() *Stage2CpuFeatures { | |
| 785 | const ptr = try std.heap.c_allocator.create(Stage2CpuFeatures); | |
| 786 | errdefer std.heap.c_allocator.destroy(ptr); | |
| 787 | ||
| 788 | ptr.* = try Stage2CpuFeatures.initBaseline(std.heap.c_allocator); | |
| 789 | errdefer ptr.deinit(); | |
| 835 | export fn stage2_cpu_features_baseline(result: **Stage2CpuFeatures) Error { | |
| 836 | result.* = Stage2CpuFeatures.createBaseline(std.heap.c_allocator) catch |err| switch (err) { | |
| 837 | error.OutOfMemory => return .OutOfMemory, | |
| 838 | }; | |
| 839 | return .None; | |
| 840 | } | |
| 790 | 841 | |
| 791 | return ptr; | |
| 842 | // ABI warning | |
| 843 | export fn stage2_cpu_features_llvm( | |
| 844 | result: **Stage2CpuFeatures, | |
| 845 | arch_name: [*:0]const u8, | |
| 846 | llvm_cpu_name: [*:0]const u8, | |
| 847 | llvm_cpu_features: [*:0]const u8, | |
| 848 | ) Error { | |
| 849 | result.* = Stage2CpuFeatures.createFromLLVM( | |
| 850 | std.heap.c_allocator, | |
| 851 | arch_name, | |
| 852 | llvm_cpu_name, | |
| 853 | llvm_cpu_features, | |
| 854 | ) catch |err| switch (err) { | |
| 855 | error.OutOfMemory => return .OutOfMemory, | |
| 856 | }; | |
| 857 | return .None; | |
| 792 | 858 | } |
| 793 | 859 | |
| 794 | 860 | // ABI warning |
src/main.cpp+20-12| ... | ... | @@ -100,8 +100,8 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { |
| 100 | 100 | " --override-lib-dir [arg] override path to Zig lib directory\n" |
| 101 | 101 | " -ffunction-sections places each function in a separate section\n" |
| 102 | 102 | " -D[macro]=[value] define C [macro] to [value] (1 if [value] omitted)\n" |
| 103 | " --cpu [cpu] compile for [cpu] on the current target\n" | |
| 104 | " --features [feature_str] compile with features in [feature_str] on the current target\n" | |
| 103 | " -target-cpu [cpu] target one specific CPU by name\n" | |
| 104 | " -target-feature [features] specify the set of CPU features to target\n" | |
| 105 | 105 | "\n" |
| 106 | 106 | "Link Options:\n" |
| 107 | 107 | " --bundle-compiler-rt for static libraries, include compiler-rt symbols\n" |
| ... | ... | @@ -1078,22 +1078,30 @@ int main(int argc, char **argv) { |
| 1078 | 1078 | fprintf(stderr, "-target-cpu and -target-feature options not allowed together\n"); |
| 1079 | 1079 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1080 | 1080 | } else if (cpu) { |
| 1081 | target.cpu_features = stage2_cpu_features_parse_cpu(target_arch_name(target.arch), cpu); | |
| 1082 | if (!target.cpu_features) { | |
| 1083 | fprintf(stderr, "invalid -target-cpu value\n"); | |
| 1081 | if ((err = stage2_cpu_features_parse_cpu(&target.cpu_features, target_arch_name(target.arch), cpu))) { | |
| 1082 | fprintf(stderr, "-target-cpu error: %s\n", err_str(err)); | |
| 1084 | 1083 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1085 | 1084 | } |
| 1086 | 1085 | } else if (features) { |
| 1087 | target.cpu_features = stage2_cpu_features_parse_features(target_arch_name(target.arch), features); | |
| 1088 | if (!target.cpu_features) { | |
| 1089 | fprintf(stderr, "invalid -target-feature value\n"); | |
| 1086 | if ((err = stage2_cpu_features_parse_features(&target.cpu_features, target_arch_name(target.arch), | |
| 1087 | features))) | |
| 1088 | { | |
| 1089 | fprintf(stderr, "-target-feature error: %s\n", err_str(err)); | |
| 1090 | return main_exit(root_progress_node, EXIT_FAILURE); | |
| 1091 | } | |
| 1092 | } else if (target.is_native) { | |
| 1093 | const char *cpu_name = ZigLLVMGetHostCPUName(); | |
| 1094 | const char *cpu_features = ZigLLVMGetNativeFeatures(); | |
| 1095 | if ((err = stage2_cpu_features_llvm(&target.cpu_features, target_arch_name(target.arch), | |
| 1096 | cpu_name, cpu_features))) | |
| 1097 | { | |
| 1098 | fprintf(stderr, "unable to determine native CPU features: %s\n", err_str(err)); | |
| 1090 | 1099 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1091 | 1100 | } |
| 1092 | 1101 | } else { |
| 1093 | // If no details are specified and we are not native, load | |
| 1094 | // cross-compilation default features. | |
| 1095 | if (!target.is_native) { | |
| 1096 | target.cpu_features = stage2_cpu_features_baseline(); | |
| 1102 | if ((err = stage2_cpu_features_baseline(&target.cpu_features))) { | |
| 1103 | fprintf(stderr, "unable to determine baseline CPU features: %s\n", err_str(err)); | |
| 1104 | return main_exit(root_progress_node, EXIT_FAILURE); | |
| 1097 | 1105 | } |
| 1098 | 1106 | } |
| 1099 | 1107 |
src/userland.cpp+33-13| ... | ... | @@ -98,35 +98,55 @@ void stage2_list_cpus_for_arch(const char *arch_name_ptr, size_t arch_name_len, |
| 98 | 98 | const char *msg = "stage0 called stage2_list_cpus_for_arch"; |
| 99 | 99 | stage2_panic(msg, strlen(msg)); |
| 100 | 100 | } |
| 101 | Stage2CpuFeatures *stage2_cpu_features_parse_cpu(const char *arch, const char *str) { | |
| 101 | ||
| 102 | struct Stage2CpuFeatures { | |
| 103 | const char *llvm_cpu_name; | |
| 104 | const char *llvm_cpu_features; | |
| 105 | const char *builtin_str; | |
| 106 | const char *cache_hash; | |
| 107 | }; | |
| 108 | ||
| 109 | Error stage2_cpu_features_parse_cpu(Stage2CpuFeatures **out, const char *arch, const char *str) { | |
| 102 | 110 | const char *msg = "stage0 called stage2_cpu_features_parse_cpu"; |
| 103 | 111 | stage2_panic(msg, strlen(msg)); |
| 104 | 112 | } |
| 105 | Stage2CpuFeatures *stage2_cpu_features_parse_features(const char *arch, const char *str) { | |
| 113 | Error stage2_cpu_features_parse_features(Stage2CpuFeatures **out, const char *arch, const char *str) { | |
| 106 | 114 | const char *msg = "stage0 called stage2_cpu_features_parse_features"; |
| 107 | 115 | stage2_panic(msg, strlen(msg)); |
| 108 | 116 | } |
| 109 | Stage2CpuFeatures *stage2_cpu_features_baseline(void) { | |
| 110 | const char *msg = "stage0 called stage2_cpu_features_baseline"; | |
| 111 | stage2_panic(msg, strlen(msg)); | |
| 117 | Error stage2_cpu_features_baseline(Stage2CpuFeatures **out) { | |
| 118 | Stage2CpuFeatures *result = allocate<Stage2CpuFeatures>(1, "Stage2CpuFeatures"); | |
| 119 | result->builtin_str = ".baseline;\n"; | |
| 120 | result->cache_hash = "\n\n"; | |
| 121 | *out = result; | |
| 122 | return ErrorNone; | |
| 123 | } | |
| 124 | Error stage2_cpu_features_llvm(Stage2CpuFeatures **out, const char *arch, | |
| 125 | const char *llvm_cpu_name, const char *llvm_features) | |
| 126 | { | |
| 127 | Stage2CpuFeatures *result = allocate<Stage2CpuFeatures>(1, "Stage2CpuFeatures"); | |
| 128 | result->llvm_cpu_name = llvm_cpu_name; | |
| 129 | result->llvm_cpu_features = llvm_features; | |
| 130 | result->builtin_str = ".baseline;\n"; | |
| 131 | result->cache_hash = "native\n\n"; | |
| 132 | *out = result; | |
| 133 | return ErrorNone; | |
| 112 | 134 | } |
| 113 | 135 | void stage2_cpu_features_get_cache_hash(const Stage2CpuFeatures *cpu_features, |
| 114 | 136 | const char **ptr, size_t *len) |
| 115 | 137 | { |
| 116 | const char *msg = "stage0 called stage2_cpu_features_get_cache_hash"; | |
| 117 | stage2_panic(msg, strlen(msg)); | |
| 138 | *ptr = cpu_features->cache_hash; | |
| 139 | *len = strlen(cpu_features->cache_hash); | |
| 118 | 140 | } |
| 119 | 141 | const char *stage2_cpu_features_get_llvm_cpu(const Stage2CpuFeatures *cpu_features) { |
| 120 | const char *msg = "stage0 called stage2_cpu_features_get_llvm_cpu"; | |
| 121 | stage2_panic(msg, strlen(msg)); | |
| 142 | return cpu_features->llvm_cpu_name; | |
| 122 | 143 | } |
| 123 | 144 | const char *stage2_cpu_features_get_llvm_features(const Stage2CpuFeatures *cpu_features) { |
| 124 | const char *msg = "stage0 called stage2_cpu_features_get_llvm_features"; | |
| 125 | stage2_panic(msg, strlen(msg)); | |
| 145 | return cpu_features->llvm_cpu_features; | |
| 126 | 146 | } |
| 127 | 147 | void stage2_cpu_features_get_builtin_str(const Stage2CpuFeatures *cpu_features, |
| 128 | 148 | const char **ptr, size_t *len) |
| 129 | 149 | { |
| 130 | const char *msg = "stage0 called stage2_cpu_features_get_builtin_str"; | |
| 131 | stage2_panic(msg, strlen(msg)); | |
| 150 | *ptr = cpu_features->builtin_str; | |
| 151 | *len = strlen(cpu_features->builtin_str); | |
| 132 | 152 | } |
src/userland.h+13-7| ... | ... | @@ -184,26 +184,32 @@ ZIG_EXTERN_C void stage2_list_cpus_for_arch(const char *arch_name_ptr, size_t ar |
| 184 | 184 | struct Stage2CpuFeatures; |
| 185 | 185 | |
| 186 | 186 | // ABI warning |
| 187 | ZIG_EXTERN_C Stage2CpuFeatures *stage2_cpu_features_parse_cpu(const char *arch, const char *cpu_name); | |
| 187 | ZIG_EXTERN_C Error stage2_cpu_features_parse_cpu(struct Stage2CpuFeatures **result, | |
| 188 | const char *arch, const char *cpu_name); | |
| 188 | 189 | |
| 189 | 190 | // ABI warning |
| 190 | ZIG_EXTERN_C Stage2CpuFeatures *stage2_cpu_features_parse_features(const char *arch, const char *features); | |
| 191 | ZIG_EXTERN_C Error stage2_cpu_features_parse_features(struct Stage2CpuFeatures **result, | |
| 192 | const char *arch, const char *features); | |
| 191 | 193 | |
| 192 | 194 | // ABI warning |
| 193 | ZIG_EXTERN_C Stage2CpuFeatures *stage2_cpu_features_baseline(void); | |
| 195 | ZIG_EXTERN_C Error stage2_cpu_features_baseline(struct Stage2CpuFeatures **result); | |
| 194 | 196 | |
| 195 | 197 | // ABI warning |
| 196 | ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_cpu(const Stage2CpuFeatures *cpu_features); | |
| 198 | ZIG_EXTERN_C Error stage2_cpu_features_llvm(struct Stage2CpuFeatures **result, | |
| 199 | const char *arch, const char *llvm_cpu_name, const char *llvm_features); | |
| 197 | 200 | |
| 198 | 201 | // ABI warning |
| 199 | ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_features(const Stage2CpuFeatures *cpu_features); | |
| 202 | ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_cpu(const struct Stage2CpuFeatures *cpu_features); | |
| 200 | 203 | |
| 201 | 204 | // ABI warning |
| 202 | ZIG_EXTERN_C void stage2_cpu_features_get_builtin_str(const Stage2CpuFeatures *cpu_features, | |
| 205 | ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_features(const struct Stage2CpuFeatures *cpu_features); | |
| 206 | ||
| 207 | // ABI warning | |
| 208 | ZIG_EXTERN_C void stage2_cpu_features_get_builtin_str(const struct Stage2CpuFeatures *cpu_features, | |
| 203 | 209 | const char **ptr, size_t *len); |
| 204 | 210 | |
| 205 | 211 | // ABI warning |
| 206 | ZIG_EXTERN_C void stage2_cpu_features_get_cache_hash(const Stage2CpuFeatures *cpu_features, | |
| 212 | ZIG_EXTERN_C void stage2_cpu_features_get_cache_hash(const struct Stage2CpuFeatures *cpu_features, | |
| 207 | 213 | const char **ptr, size_t *len); |
| 208 | 214 | |
| 209 | 215 | #endif |