authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-11-26 21:15:59+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-11-28 17:07:34+01:00
log7473ef98e992519a4ff2478e610a6477f2aac86a
tree680ba53eab2ec88b9dec0a70fab3bc8daac92e68
parent7ea2c7fbcdc4c0555dcc45aebc1eb8e1bf4793b3

windows: implement simplistic CPU model parser


1 files changed, 78 insertions(+), 9 deletions(-)

lib/std/zig/system/windows.zig+78-9
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const mem = std.mem;
3const Target = std.Target;4const Target = std.Target;
45
5pub const WindowsVersion = std.Target.Os.WindowsVersion;6pub const WindowsVersion = std.Target.Os.WindowsVersion;
...@@ -43,20 +44,68 @@ pub fn detectRuntimeVersion() WindowsVersion {...@@ -43,20 +44,68 @@ pub fn detectRuntimeVersion() WindowsVersion {
43 return @intToEnum(WindowsVersion, version);44 return @intToEnum(WindowsVersion, version);
44}45}
4546
47const Armv8CpuInfoImpl = struct {
48 cores: [8]*const Target.Cpu.Model = undefined,
49 core_no: usize = 0,
50
51 const cpu_family_models = .{
52 // Family, Model, Revision
53 .{ 8, "D4C", 0, &Target.aarch64.cpu.microsoft_sq3 },
54 };
55
56 fn parseOne(self: *Armv8CpuInfoImpl, identifier: []const u8) void {
57 if (mem.indexOf(u8, identifier, "ARMv8") == null) return; // Sanity check
58
59 var family: ?usize = null;
60 var model: ?[]const u8 = null;
61 var revision: ?usize = null;
62
63 var tokens = mem.tokenize(u8, identifier, " ");
64 while (tokens.next()) |token| {
65 if (mem.eql(u8, token, "Family")) {
66 const raw = tokens.next() orelse continue;
67 family = std.fmt.parseInt(usize, raw, 10) catch null;
68 }
69 if (mem.eql(u8, token, "Model")) {
70 model = tokens.next();
71 }
72 if (mem.eql(u8, token, "Revision")) {
73 const raw = tokens.next() orelse continue;
74 revision = std.fmt.parseInt(usize, raw, 10) catch null;
75 }
76 }
77
78 if (family == null or model == null or revision == null) return;
79
80 inline for (cpu_family_models) |set| {
81 if (set[0] == family.? and mem.eql(u8, set[1], model.?) and set[2] == revision.?) {
82 self.cores[self.core_no] = set[3];
83 self.core_no += 1;
84 break;
85 }
86 }
87 }
88
89 fn finalize(self: Armv8CpuInfoImpl) ?*const Target.Cpu.Model {
90 if (self.core_no != 8) return null; // Implies we have seen a core we don't know much about
91 return self.cores[0];
92 }
93};
94
46fn detectCpuModelArm64() !*const Target.Cpu.Model {95fn detectCpuModelArm64() !*const Target.Cpu.Model {
47 // Pull the CPU identifier from the registry.96 // Pull the CPU identifier from the registry.
48 // Assume max number of cores to be at 128.97 // Assume max number of cores to be at 8.
49 const max_cpu_count = 128;98 const max_cpu_count = 8;
50 const cpu_count = getCpuCount();99 const cpu_count = getCpuCount();
51100
52 if (cpu_count > max_cpu_count) return error.TooManyCpus;101 if (cpu_count > max_cpu_count) return error.TooManyCpus;
53102
54 const table_size = max_cpu_count * 3 + 1;103 const table_size = max_cpu_count * 3;
55 const actual_table_size = cpu_count * 3 + 1;104 const actual_table_size = cpu_count * 3;
56 var table: [table_size]std.os.windows.RTL_QUERY_REGISTRY_TABLE = undefined;105 var table: [table_size + 1]std.os.windows.RTL_QUERY_REGISTRY_TABLE = undefined;
57106
58 // Table sentinel107 // Table sentinel
59 table[actual_table_size - 1] = .{108 table[actual_table_size] = .{
60 .QueryRoutine = null,109 .QueryRoutine = null,
61 .Flags = 0,110 .Flags = 0,
62 .Name = null,111 .Name = null,
...@@ -86,7 +135,7 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model {...@@ -86,7 +135,7 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model {
86 var next_cpu_buf: [std.math.log2(max_cpu_count)]u8 = undefined;135 var next_cpu_buf: [std.math.log2(max_cpu_count)]u8 = undefined;
87 const next_cpu = try std.fmt.bufPrint(&next_cpu_buf, "{d}", .{i});136 const next_cpu = try std.fmt.bufPrint(&next_cpu_buf, "{d}", .{i});
88137
89 var subkey: [std.math.log2(max_cpu_count) / 2]u16 = undefined;138 var subkey: [std.math.log2(max_cpu_count) + 1]u16 = undefined;
90 const subkey_len = try std.unicode.utf8ToUtf16Le(&subkey, next_cpu);139 const subkey_len = try std.unicode.utf8ToUtf16Le(&subkey, next_cpu);
91 subkey[subkey_len] = 0;140 subkey[subkey_len] = 0;
92141
...@@ -137,6 +186,8 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model {...@@ -137,6 +186,8 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model {
137 }186 }
138187
139 // Parse the models from strings188 // Parse the models from strings
189 var parser = Armv8CpuInfoImpl{};
190
140 i = 0;191 i = 0;
141 index = 0;192 index = 0;
142 while (i < cpu_count) : (i += 1) {193 while (i < cpu_count) : (i += 1) {
...@@ -146,10 +197,10 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model {...@@ -146,10 +197,10 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model {
146 var identifier_buf: [max_sz_value * 2]u8 = undefined;197 var identifier_buf: [max_sz_value * 2]u8 = undefined;
147 const len = try std.unicode.utf16leToUtf8(&identifier_buf, entry.Buffer[0 .. entry.Length / 2]);198 const len = try std.unicode.utf16leToUtf8(&identifier_buf, entry.Buffer[0 .. entry.Length / 2]);
148 const identifier = identifier_buf[0..len];199 const identifier = identifier_buf[0..len];
149 _ = identifier;200 parser.parseOne(identifier);
150 }201 }
151202
152 return &Target.aarch64.cpu.microsoft_sq3;203 return parser.finalize() orelse Target.Cpu.Model.generic(.aarch64);
153}204}
154205
155fn detectNativeCpuAndFeaturesArm64() Target.Cpu {206fn detectNativeCpuAndFeaturesArm64() Target.Cpu {
...@@ -163,23 +214,41 @@ fn detectNativeCpuAndFeaturesArm64() Target.Cpu {...@@ -163,23 +214,41 @@ fn detectNativeCpuAndFeaturesArm64() Target.Cpu {
163 .features = model.features,214 .features = model.features,
164 };215 };
165216
217 // Override any features that are either present or absent
166 if (IsProcessorFeaturePresent(PF.ARM_NEON_INSTRUCTIONS_AVAILABLE)) {218 if (IsProcessorFeaturePresent(PF.ARM_NEON_INSTRUCTIONS_AVAILABLE)) {
167 cpu.features.addFeature(@enumToInt(Feature.neon));219 cpu.features.addFeature(@enumToInt(Feature.neon));
220 } else {
221 cpu.features.removeFeature(@enumToInt(Feature.neon));
168 }222 }
223
169 if (IsProcessorFeaturePresent(PF.ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)) {224 if (IsProcessorFeaturePresent(PF.ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)) {
170 cpu.features.addFeature(@enumToInt(Feature.crc));225 cpu.features.addFeature(@enumToInt(Feature.crc));
226 } else {
227 cpu.features.removeFeature(@enumToInt(Feature.crc));
171 }228 }
229
172 if (IsProcessorFeaturePresent(PF.ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE)) {230 if (IsProcessorFeaturePresent(PF.ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE)) {
173 cpu.features.addFeature(@enumToInt(Feature.crypto));231 cpu.features.addFeature(@enumToInt(Feature.crypto));
232 } else {
233 cpu.features.removeFeature(@enumToInt(Feature.crypto));
174 }234 }
235
175 if (IsProcessorFeaturePresent(PF.ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)) {236 if (IsProcessorFeaturePresent(PF.ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)) {
176 cpu.features.addFeature(@enumToInt(Feature.lse));237 cpu.features.addFeature(@enumToInt(Feature.lse));
238 } else {
239 cpu.features.removeFeature(@enumToInt(Feature.lse));
177 }240 }
241
178 if (IsProcessorFeaturePresent(PF.ARM_V82_DP_INSTRUCTIONS_AVAILABLE)) {242 if (IsProcessorFeaturePresent(PF.ARM_V82_DP_INSTRUCTIONS_AVAILABLE)) {
179 cpu.features.addFeature(@enumToInt(Feature.dotprod));243 cpu.features.addFeature(@enumToInt(Feature.dotprod));
244 } else {
245 cpu.features.removeFeature(@enumToInt(Feature.dotprod));
180 }246 }
247
181 if (IsProcessorFeaturePresent(PF.ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)) {248 if (IsProcessorFeaturePresent(PF.ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)) {
182 cpu.features.addFeature(@enumToInt(Feature.jsconv));249 cpu.features.addFeature(@enumToInt(Feature.jsconv));
250 } else {
251 cpu.features.removeFeature(@enumToInt(Feature.jsconv));
183 }252 }
184253
185 return cpu;254 return cpu;