authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-05-02 12:48:58+02:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-05-03 12:32:13+02:00
logb10d40b89bca0f70944434a1e0ffbfb984b4eae5
treebf91d7ec9eaf3109120f7b890f1a467515d4c399
parentc47028cd025f4ce405a9395fa979ff14a3e6349a

stage2: Implement CPU host detection for ARM/AArch64 targets


1 files changed, 219 insertions(+), 7 deletions(-)

lib/std/zig/system/linux.zig+219-7
...@@ -53,7 +53,7 @@ const SparcCpuinfoImpl = struct {...@@ -53,7 +53,7 @@ const SparcCpuinfoImpl = struct {
53 // At the moment we only support 64bit SPARC systems.53 // At the moment we only support 64bit SPARC systems.
54 assert(self.is_64bit);54 assert(self.is_64bit);
5555
56 const model = self.model orelse Target.Cpu.Model.generic(arch);56 const model = self.model orelse return null;
57 return Target.Cpu{57 return Target.Cpu{
58 .arch = arch,58 .arch = arch,
59 .model = model,59 .model = model,
...@@ -65,7 +65,7 @@ const SparcCpuinfoImpl = struct {...@@ -65,7 +65,7 @@ const SparcCpuinfoImpl = struct {
65const SparcCpuinfoParser = CpuinfoParser(SparcCpuinfoImpl);65const SparcCpuinfoParser = CpuinfoParser(SparcCpuinfoImpl);
6666
67test "cpuinfo: SPARC" {67test "cpuinfo: SPARC" {
68 try testParser(SparcCpuinfoParser, &Target.sparc.cpu.niagara2,68 try testParser(SparcCpuinfoParser, .sparcv9, &Target.sparc.cpu.niagara2,
69 \\cpu : UltraSparc T2 (Niagara2)69 \\cpu : UltraSparc T2 (Niagara2)
70 \\fpu : UltraSparc T2 integrated FPU70 \\fpu : UltraSparc T2 integrated FPU
71 \\pmu : niagara271 \\pmu : niagara2
...@@ -119,7 +119,7 @@ const PowerpcCpuinfoImpl = struct {...@@ -119,7 +119,7 @@ const PowerpcCpuinfoImpl = struct {
119 }119 }
120120
121 fn finalize(self: *const PowerpcCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {121 fn finalize(self: *const PowerpcCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
122 const model = self.model orelse Target.Cpu.Model.generic(arch);122 const model = self.model orelse return null;
123 return Target.Cpu{123 return Target.Cpu{
124 .arch = arch,124 .arch = arch,
125 .model = model,125 .model = model,
...@@ -131,13 +131,13 @@ const PowerpcCpuinfoImpl = struct {...@@ -131,13 +131,13 @@ const PowerpcCpuinfoImpl = struct {
131const PowerpcCpuinfoParser = CpuinfoParser(PowerpcCpuinfoImpl);131const PowerpcCpuinfoParser = CpuinfoParser(PowerpcCpuinfoImpl);
132132
133test "cpuinfo: PowerPC" {133test "cpuinfo: PowerPC" {
134 try testParser(PowerpcCpuinfoParser, &Target.powerpc.cpu.@"970",134 try testParser(PowerpcCpuinfoParser, .powerpc, &Target.powerpc.cpu.@"970",
135 \\processor : 0135 \\processor : 0
136 \\cpu : PPC970MP, altivec supported136 \\cpu : PPC970MP, altivec supported
137 \\clock : 1250.000000MHz137 \\clock : 1250.000000MHz
138 \\revision : 1.1 (pvr 0044 0101)138 \\revision : 1.1 (pvr 0044 0101)
139 );139 );
140 try testParser(PowerpcCpuinfoParser, &Target.powerpc.cpu.pwr8,140 try testParser(PowerpcCpuinfoParser, .powerpc64le, &Target.powerpc.cpu.pwr8,
141 \\processor : 0141 \\processor : 0
142 \\cpu : POWER8 (raw), altivec supported142 \\cpu : POWER8 (raw), altivec supported
143 \\clock : 2926.000000MHz143 \\clock : 2926.000000MHz
...@@ -145,9 +145,218 @@ test "cpuinfo: PowerPC" {...@@ -145,9 +145,218 @@ test "cpuinfo: PowerPC" {
145 );145 );
146}146}
147147
148fn testParser(parser: anytype, expected_model: *const Target.Cpu.Model, input: []const u8) !void {148const ArmCpuinfoImpl = struct {
149 cores: [4]CoreInfo = undefined,
150 core_no: usize = 0,
151 have_fields: usize = 0,
152
153 const CoreInfo = struct {
154 architecture: u8 = 0,
155 implementer: u8 = 0,
156 variant: u8 = 0,
157 part: u16 = 0,
158 is_really_v6: bool = false,
159 };
160
161 const cpu_models = struct {
162 // Shorthands to simplify the tables below.
163 const A32 = Target.arm.cpu;
164 const A64 = Target.aarch64.cpu;
165
166 // implementer = 0x41
167 const ARM = .{
168 .{ 0x926, &A32.arm926ej_s, null },
169 .{ 0xb02, &A32.mpcore, null },
170 .{ 0xb36, &A32.arm1136j_s, null },
171 .{ 0xb56, &A32.arm1156t2_s, null },
172 .{ 0xb76, &A32.arm1176jz_s, null },
173 .{ 0xc05, &A32.cortex_a5, null },
174 .{ 0xc07, &A32.cortex_a7, null },
175 .{ 0xc08, &A32.cortex_a8, null },
176 .{ 0xc09, &A32.cortex_a9, null },
177 .{ 0xc0d, &A32.cortex_a17, null },
178 .{ 0xc0f, &A32.cortex_a15, null },
179 .{ 0xc0e, &A32.cortex_a17, null },
180 .{ 0xc14, &A32.cortex_r4, null },
181 .{ 0xc15, &A32.cortex_r5, null },
182 .{ 0xc17, &A32.cortex_r7, null },
183 .{ 0xc18, &A32.cortex_r8, null },
184 .{ 0xc20, &A32.cortex_m0, null },
185 .{ 0xc21, &A32.cortex_m1, null },
186 .{ 0xc23, &A32.cortex_m3, null },
187 .{ 0xc24, &A32.cortex_m4, null },
188 .{ 0xc27, &A32.cortex_m7, null },
189 .{ 0xc60, &A32.cortex_m0plus, null },
190 .{ 0xd01, &A32.cortex_a32, null },
191 .{ 0xd03, &A32.cortex_a53, &A64.cortex_a53 },
192 .{ 0xd04, &A32.cortex_a35, &A64.cortex_a35 },
193 .{ 0xd05, &A32.cortex_a55, &A64.cortex_a55 },
194 .{ 0xd07, &A32.cortex_a57, &A64.cortex_a57 },
195 .{ 0xd08, &A32.cortex_a72, &A64.cortex_a72 },
196 .{ 0xd09, &A32.cortex_a73, &A64.cortex_a73 },
197 .{ 0xd0a, &A32.cortex_a75, &A64.cortex_a75 },
198 .{ 0xd0b, &A32.cortex_a76, &A64.cortex_a76 },
199 .{ 0xd0c, &A32.neoverse_n1, null },
200 .{ 0xd0d, &A32.cortex_a77, &A64.cortex_a77 },
201 .{ 0xd13, &A32.cortex_r52, null },
202 .{ 0xd20, &A32.cortex_m23, null },
203 .{ 0xd21, &A32.cortex_m33, null },
204 .{ 0xd41, &A32.cortex_a78, &A64.cortex_a78 },
205 .{ 0xd4b, &A32.cortex_a78c, &A64.cortex_a78c },
206 .{ 0xd44, &A32.cortex_x1, &A64.cortex_x1 },
207 .{ 0xd02, null, &A64.cortex_a34 },
208 .{ 0xd06, null, &A64.cortex_a65 },
209 .{ 0xd43, null, &A64.cortex_a65ae },
210 };
211
212 fn isKnown(implementer: u8, part: u16, is_64bit: bool) ?*const Target.Cpu.Model {
213 const models = switch (implementer) {
214 0x41 => ARM,
215 else => return null,
216 };
217
218 inline for (models) |model| {
219 if (model[0] == part)
220 return if (is_64bit) model[2] else model[1];
221 }
222
223 return null;
224 }
225 };
226
227 fn addOne(self: *ArmCpuinfoImpl) void {
228 if (self.have_fields == 4 and self.core_no < self.cores.len) {
229 if (self.core_no > 0) {
230 // Deduplicate the core info.
231 for (self.cores[0..self.core_no]) |it| {
232 if (std.meta.eql(it, self.cores[self.core_no]))
233 return;
234 }
235 }
236 self.core_no += 1;
237 }
238 }
239
240 fn line_hook(self: *ArmCpuinfoImpl, key: []const u8, value: []const u8) !bool {
241 const info = &self.cores[self.core_no];
242
243 if (mem.eql(u8, key, "processor")) {
244 // Handle both old-style and new-style cpuinfo formats.
245 // The former prints a sequence of "processor: N" lines for each
246 // core and then the info for the core that's executing this code(!)
247 // while the latter prints the infos for each core right after the
248 // "processor" key.
249 self.have_fields = 0;
250 self.cores[self.core_no] = .{};
251 } else if (mem.eql(u8, key, "CPU implementer")) {
252 info.implementer = try fmt.parseInt(u8, value, 0);
253 self.have_fields += 1;
254 } else if (mem.eql(u8, key, "CPU architecture")) {
255 // "AArch64" on older kernels.
256 info.architecture = if (mem.startsWith(u8, value, "AArch64"))
257 8
258 else
259 try fmt.parseInt(u8, value, 0);
260 self.have_fields += 1;
261 } else if (mem.eql(u8, key, "CPU variant")) {
262 info.variant = try fmt.parseInt(u8, value, 0);
263 self.have_fields += 1;
264 } else if (mem.eql(u8, key, "CPU part")) {
265 info.part = try fmt.parseInt(u16, value, 0);
266 self.have_fields += 1;
267 } else if (mem.eql(u8, key, "model name")) {
268 // ARMv6 cores report "CPU architecture" equal to 7.
269 if (mem.indexOf(u8, value, "(v6l)")) |_| {
270 info.is_really_v6 = true;
271 }
272 } else if (mem.eql(u8, key, "CPU revision")) {
273 // This field is always the last one for each CPU section.
274 _ = self.addOne();
275 }
276
277 return true;
278 }
279
280 fn finalize(self: *ArmCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
281 if (self.core_no == 0) return null;
282
283 const is_64bit = switch (arch) {
284 .aarch64, .aarch64_be, .aarch64_32 => true,
285 else => false,
286 };
287
288 var known_models: [self.cores.len]?*const Target.Cpu.Model = undefined;
289 for (self.cores[0..self.core_no]) |core, i| {
290 known_models[i] =
291 cpu_models.isKnown(core.implementer, core.part, is_64bit);
292 }
293
294 // XXX We pick the first core on big.LITTLE systems, hopefully the
295 // LITTLE one.
296 const model = known_models[0] orelse return null;
297 return Target.Cpu{
298 .arch = arch,
299 .model = model,
300 .features = model.features,
301 };
302 }
303};
304
305const ArmCpuinfoParser = CpuinfoParser(ArmCpuinfoImpl);
306
307test "cpuinfo: ARM" {
308 try testParser(ArmCpuinfoParser, .arm, &Target.arm.cpu.arm1176jz_s,
309 \\processor : 0
310 \\model name : ARMv6-compatible processor rev 7 (v6l)
311 \\BogoMIPS : 997.08
312 \\Features : half thumb fastmult vfp edsp java tls
313 \\CPU implementer : 0x41
314 \\CPU architecture: 7
315 \\CPU variant : 0x0
316 \\CPU part : 0xb76
317 \\CPU revision : 7
318 );
319 try testParser(ArmCpuinfoParser, .arm, &Target.arm.cpu.cortex_a7,
320 \\processor : 0
321 \\model name : ARMv7 Processor rev 3 (v7l)
322 \\BogoMIPS : 18.00
323 \\Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
324 \\CPU implementer : 0x41
325 \\CPU architecture: 7
326 \\CPU variant : 0x0
327 \\CPU part : 0xc07
328 \\CPU revision : 3
329 \\
330 \\processor : 4
331 \\model name : ARMv7 Processor rev 3 (v7l)
332 \\BogoMIPS : 90.00
333 \\Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
334 \\CPU implementer : 0x41
335 \\CPU architecture: 7
336 \\CPU variant : 0x2
337 \\CPU part : 0xc0f
338 \\CPU revision : 3
339 );
340 try testParser(ArmCpuinfoParser, .aarch64, &Target.aarch64.cpu.cortex_a72,
341 \\processor : 0
342 \\BogoMIPS : 108.00
343 \\Features : fp asimd evtstrm crc32 cpuid
344 \\CPU implementer : 0x41
345 \\CPU architecture: 8
346 \\CPU variant : 0x0
347 \\CPU part : 0xd08
348 \\CPU revision : 3
349 );
350}
351
352fn testParser(
353 parser: anytype,
354 arch: Target.Cpu.Arch,
355 expected_model: *const Target.Cpu.Model,
356 input: []const u8,
357) !void {
149 var fbs = io.fixedBufferStream(input);358 var fbs = io.fixedBufferStream(input);
150 const result = try parser.parse(.powerpc, fbs.reader());359 const result = try parser.parse(arch, fbs.reader());
151 testing.expectEqual(expected_model, result.?.model);360 testing.expectEqual(expected_model, result.?.model);
152 testing.expect(expected_model.features.eql(result.?.features));361 testing.expect(expected_model.features.eql(result.?.features));
153}362}
...@@ -186,6 +395,9 @@ pub fn detectNativeCpuAndFeatures() ?Target.Cpu {...@@ -186,6 +395,9 @@ pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
186395
187 const current_arch = std.Target.current.cpu.arch;396 const current_arch = std.Target.current.cpu.arch;
188 switch (current_arch) {397 switch (current_arch) {
398 .arm, .armeb, .thumb, .thumbeb, .aarch64, .aarch64_be, .aarch64_32 => {
399 return ArmCpuinfoParser.parse(current_arch, f.reader()) catch null;
400 },
189 .sparcv9 => {401 .sparcv9 => {
190 return SparcCpuinfoParser.parse(current_arch, f.reader()) catch null;402 return SparcCpuinfoParser.parse(current_arch, f.reader()) catch null;
191 },403 },