| ... | @@ -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); |
| 55 | | 55 | |
| 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 { |
| 65 | const SparcCpuinfoParser = CpuinfoParser(SparcCpuinfoImpl); | 65 | const SparcCpuinfoParser = CpuinfoParser(SparcCpuinfoImpl); |
| 66 | | 66 | |
| 67 | test "cpuinfo: SPARC" { | 67 | test "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 FPU | 70 | \\fpu : UltraSparc T2 integrated FPU |
| 71 | \\pmu : niagara2 | 71 | \\pmu : niagara2 |
| ... | @@ -119,7 +119,7 @@ const PowerpcCpuinfoImpl = struct { | ... | @@ -119,7 +119,7 @@ const PowerpcCpuinfoImpl = struct { |
| 119 | } | 119 | } |
| 120 | | 120 | |
| 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 { |
| 131 | const PowerpcCpuinfoParser = CpuinfoParser(PowerpcCpuinfoImpl); | 131 | const PowerpcCpuinfoParser = CpuinfoParser(PowerpcCpuinfoImpl); |
| 132 | | 132 | |
| 133 | test "cpuinfo: PowerPC" { | 133 | test "cpuinfo: PowerPC" { |
| 134 | try testParser(PowerpcCpuinfoParser, &Target.powerpc.cpu.@"970", | 134 | try testParser(PowerpcCpuinfoParser, .powerpc, &Target.powerpc.cpu.@"970", |
| 135 | \\processor	: 0 | 135 | \\processor	: 0 |
| 136 | \\cpu		: PPC970MP, altivec supported | 136 | \\cpu		: PPC970MP, altivec supported |
| 137 | \\clock		: 1250.000000MHz | 137 | \\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	: 0 | 141 | \\processor	: 0 |
| 142 | \\cpu		: POWER8 (raw), altivec supported | 142 | \\cpu		: POWER8 (raw), altivec supported |
| 143 | \\clock		: 2926.000000MHz | 143 | \\clock		: 2926.000000MHz |
| ... | @@ -145,9 +145,275 @@ test "cpuinfo: PowerPC" { | ... | @@ -145,9 +145,275 @@ test "cpuinfo: PowerPC" { |
| 145 | ); | 145 | ); |
| 146 | } | 146 | } |
| 147 | | 147 | |
| 148 | fn testParser(parser: anytype, expected_model: *const Target.Cpu.Model, input: []const u8) !void { | 148 | const 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 | const E = struct { |
| | 167 | part: u16, |
| | 168 | variant: ?u8 = null, // null if matches any variant |
| | 169 | m32: ?*const Target.Cpu.Model = null, |
| | 170 | m64: ?*const Target.Cpu.Model = null, |
| | 171 | }; |
| | 172 | |
| | 173 | // implementer = 0x41 |
| | 174 | const ARM = [_]E{ |
| | 175 | E{ .part = 0x926, .m32 = &A32.arm926ej_s, .m64 = null }, |
| | 176 | E{ .part = 0xb02, .m32 = &A32.mpcore, .m64 = null }, |
| | 177 | E{ .part = 0xb36, .m32 = &A32.arm1136j_s, .m64 = null }, |
| | 178 | E{ .part = 0xb56, .m32 = &A32.arm1156t2_s, .m64 = null }, |
| | 179 | E{ .part = 0xb76, .m32 = &A32.arm1176jz_s, .m64 = null }, |
| | 180 | E{ .part = 0xc05, .m32 = &A32.cortex_a5, .m64 = null }, |
| | 181 | E{ .part = 0xc07, .m32 = &A32.cortex_a7, .m64 = null }, |
| | 182 | E{ .part = 0xc08, .m32 = &A32.cortex_a8, .m64 = null }, |
| | 183 | E{ .part = 0xc09, .m32 = &A32.cortex_a9, .m64 = null }, |
| | 184 | E{ .part = 0xc0d, .m32 = &A32.cortex_a17, .m64 = null }, |
| | 185 | E{ .part = 0xc0f, .m32 = &A32.cortex_a15, .m64 = null }, |
| | 186 | E{ .part = 0xc0e, .m32 = &A32.cortex_a17, .m64 = null }, |
| | 187 | E{ .part = 0xc14, .m32 = &A32.cortex_r4, .m64 = null }, |
| | 188 | E{ .part = 0xc15, .m32 = &A32.cortex_r5, .m64 = null }, |
| | 189 | E{ .part = 0xc17, .m32 = &A32.cortex_r7, .m64 = null }, |
| | 190 | E{ .part = 0xc18, .m32 = &A32.cortex_r8, .m64 = null }, |
| | 191 | E{ .part = 0xc20, .m32 = &A32.cortex_m0, .m64 = null }, |
| | 192 | E{ .part = 0xc21, .m32 = &A32.cortex_m1, .m64 = null }, |
| | 193 | E{ .part = 0xc23, .m32 = &A32.cortex_m3, .m64 = null }, |
| | 194 | E{ .part = 0xc24, .m32 = &A32.cortex_m4, .m64 = null }, |
| | 195 | E{ .part = 0xc27, .m32 = &A32.cortex_m7, .m64 = null }, |
| | 196 | E{ .part = 0xc60, .m32 = &A32.cortex_m0plus, .m64 = null }, |
| | 197 | E{ .part = 0xd01, .m32 = &A32.cortex_a32, .m64 = null }, |
| | 198 | E{ .part = 0xd03, .m32 = &A32.cortex_a53, .m64 = &A64.cortex_a53 }, |
| | 199 | E{ .part = 0xd04, .m32 = &A32.cortex_a35, .m64 = &A64.cortex_a35 }, |
| | 200 | E{ .part = 0xd05, .m32 = &A32.cortex_a55, .m64 = &A64.cortex_a55 }, |
| | 201 | E{ .part = 0xd07, .m32 = &A32.cortex_a57, .m64 = &A64.cortex_a57 }, |
| | 202 | E{ .part = 0xd08, .m32 = &A32.cortex_a72, .m64 = &A64.cortex_a72 }, |
| | 203 | E{ .part = 0xd09, .m32 = &A32.cortex_a73, .m64 = &A64.cortex_a73 }, |
| | 204 | E{ .part = 0xd0a, .m32 = &A32.cortex_a75, .m64 = &A64.cortex_a75 }, |
| | 205 | E{ .part = 0xd0b, .m32 = &A32.cortex_a76, .m64 = &A64.cortex_a76 }, |
| | 206 | E{ .part = 0xd0c, .m32 = &A32.neoverse_n1, .m64 = null }, |
| | 207 | E{ .part = 0xd0d, .m32 = &A32.cortex_a77, .m64 = &A64.cortex_a77 }, |
| | 208 | E{ .part = 0xd13, .m32 = &A32.cortex_r52, .m64 = null }, |
| | 209 | E{ .part = 0xd20, .m32 = &A32.cortex_m23, .m64 = null }, |
| | 210 | E{ .part = 0xd21, .m32 = &A32.cortex_m33, .m64 = null }, |
| | 211 | E{ .part = 0xd41, .m32 = &A32.cortex_a78, .m64 = &A64.cortex_a78 }, |
| | 212 | E{ .part = 0xd4b, .m32 = &A32.cortex_a78c, .m64 = &A64.cortex_a78c }, |
| | 213 | E{ .part = 0xd44, .m32 = &A32.cortex_x1, .m64 = &A64.cortex_x1 }, |
| | 214 | E{ .part = 0xd02, .m64 = &A64.cortex_a34 }, |
| | 215 | E{ .part = 0xd06, .m64 = &A64.cortex_a65 }, |
| | 216 | E{ .part = 0xd43, .m64 = &A64.cortex_a65ae }, |
| | 217 | }; |
| | 218 | // implementer = 0x42 |
| | 219 | const Broadcom = [_]E{ |
| | 220 | E{ .part = 0x516, .m64 = &A64.thunderx2t99 }, |
| | 221 | }; |
| | 222 | // implementer = 0x43 |
| | 223 | const Cavium = [_]E{ |
| | 224 | E{ .part = 0x0a0, .m64 = &A64.thunderx }, |
| | 225 | E{ .part = 0x0a2, .m64 = &A64.thunderxt81 }, |
| | 226 | E{ .part = 0x0a3, .m64 = &A64.thunderxt83 }, |
| | 227 | E{ .part = 0x0a1, .m64 = &A64.thunderxt88 }, |
| | 228 | E{ .part = 0x0af, .m64 = &A64.thunderx2t99 }, |
| | 229 | }; |
| | 230 | // implementer = 0x46 |
| | 231 | const Fujitsu = [_]E{ |
| | 232 | E{ .part = 0x001, .m64 = &A64.a64fx }, |
| | 233 | }; |
| | 234 | // implementer = 0x48 |
| | 235 | const HiSilicon = [_]E{ |
| | 236 | E{ .part = 0xd01, .m64 = &A64.tsv110 }, |
| | 237 | }; |
| | 238 | // implementer = 0x4e |
| | 239 | const Nvidia = [_]E{ |
| | 240 | E{ .part = 0x004, .m64 = &A64.carmel }, |
| | 241 | }; |
| | 242 | // implementer = 0x50 |
| | 243 | const Ampere = [_]E{ |
| | 244 | E{ .part = 0x000, .variant = 3, .m64 = &A64.emag }, |
| | 245 | E{ .part = 0x000, .m64 = &A64.xgene1 }, |
| | 246 | }; |
| | 247 | // implementer = 0x51 |
| | 248 | const Qualcomm = [_]E{ |
| | 249 | E{ .part = 0x06f, .m32 = &A32.krait }, |
| | 250 | E{ .part = 0x201, .m64 = &A64.kryo, .m32 = &A64.kryo }, |
| | 251 | E{ .part = 0x205, .m64 = &A64.kryo, .m32 = &A64.kryo }, |
| | 252 | E{ .part = 0x211, .m64 = &A64.kryo, .m32 = &A64.kryo }, |
| | 253 | E{ .part = 0x800, .m64 = &A64.cortex_a73, .m32 = &A64.cortex_a73 }, |
| | 254 | E{ .part = 0x801, .m64 = &A64.cortex_a73, .m32 = &A64.cortex_a73 }, |
| | 255 | E{ .part = 0x802, .m64 = &A64.cortex_a75, .m32 = &A64.cortex_a75 }, |
| | 256 | E{ .part = 0x803, .m64 = &A64.cortex_a75, .m32 = &A64.cortex_a75 }, |
| | 257 | E{ .part = 0x804, .m64 = &A64.cortex_a76, .m32 = &A64.cortex_a76 }, |
| | 258 | E{ .part = 0x805, .m64 = &A64.cortex_a76, .m32 = &A64.cortex_a76 }, |
| | 259 | E{ .part = 0xc00, .m64 = &A64.falkor }, |
| | 260 | E{ .part = 0xc01, .m64 = &A64.saphira }, |
| | 261 | }; |
| | 262 | |
| | 263 | fn isKnown(core: CoreInfo, is_64bit: bool) ?*const Target.Cpu.Model { |
| | 264 | const models = switch (core.implementer) { |
| | 265 | 0x41 => &ARM, |
| | 266 | 0x42 => &Broadcom, |
| | 267 | 0x43 => &Cavium, |
| | 268 | 0x46 => &Fujitsu, |
| | 269 | 0x48 => &HiSilicon, |
| | 270 | 0x50 => &Ampere, |
| | 271 | 0x51 => &Qualcomm, |
| | 272 | else => return null, |
| | 273 | }; |
| | 274 | |
| | 275 | for (models) |model| { |
| | 276 | if (model.part == core.part and |
| | 277 | (model.variant == null or model.variant.? == core.variant)) |
| | 278 | return if (is_64bit) model.m64 else model.m32; |
| | 279 | } |
| | 280 | |
| | 281 | return null; |
| | 282 | } |
| | 283 | }; |
| | 284 | |
| | 285 | fn addOne(self: *ArmCpuinfoImpl) void { |
| | 286 | if (self.have_fields == 4 and self.core_no < self.cores.len) { |
| | 287 | if (self.core_no > 0) { |
| | 288 | // Deduplicate the core info. |
| | 289 | for (self.cores[0..self.core_no]) |it| { |
| | 290 | if (std.meta.eql(it, self.cores[self.core_no])) |
| | 291 | return; |
| | 292 | } |
| | 293 | } |
| | 294 | self.core_no += 1; |
| | 295 | } |
| | 296 | } |
| | 297 | |
| | 298 | fn line_hook(self: *ArmCpuinfoImpl, key: []const u8, value: []const u8) !bool { |
| | 299 | const info = &self.cores[self.core_no]; |
| | 300 | |
| | 301 | if (mem.eql(u8, key, "processor")) { |
| | 302 | // Handle both old-style and new-style cpuinfo formats. |
| | 303 | // The former prints a sequence of "processor: N" lines for each |
| | 304 | // core and then the info for the core that's executing this code(!) |
| | 305 | // while the latter prints the infos for each core right after the |
| | 306 | // "processor" key. |
| | 307 | self.have_fields = 0; |
| | 308 | self.cores[self.core_no] = .{}; |
| | 309 | } else if (mem.eql(u8, key, "CPU implementer")) { |
| | 310 | info.implementer = try fmt.parseInt(u8, value, 0); |
| | 311 | self.have_fields += 1; |
| | 312 | } else if (mem.eql(u8, key, "CPU architecture")) { |
| | 313 | // "AArch64" on older kernels. |
| | 314 | info.architecture = if (mem.startsWith(u8, value, "AArch64")) |
| | 315 | 8 |
| | 316 | else |
| | 317 | try fmt.parseInt(u8, value, 0); |
| | 318 | self.have_fields += 1; |
| | 319 | } else if (mem.eql(u8, key, "CPU variant")) { |
| | 320 | info.variant = try fmt.parseInt(u8, value, 0); |
| | 321 | self.have_fields += 1; |
| | 322 | } else if (mem.eql(u8, key, "CPU part")) { |
| | 323 | info.part = try fmt.parseInt(u16, value, 0); |
| | 324 | self.have_fields += 1; |
| | 325 | } else if (mem.eql(u8, key, "model name")) { |
| | 326 | // ARMv6 cores report "CPU architecture" equal to 7. |
| | 327 | if (mem.indexOf(u8, value, "(v6l)")) |_| { |
| | 328 | info.is_really_v6 = true; |
| | 329 | } |
| | 330 | } else if (mem.eql(u8, key, "CPU revision")) { |
| | 331 | // This field is always the last one for each CPU section. |
| | 332 | _ = self.addOne(); |
| | 333 | } |
| | 334 | |
| | 335 | return true; |
| | 336 | } |
| | 337 | |
| | 338 | fn finalize(self: *ArmCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu { |
| | 339 | if (self.core_no == 0) return null; |
| | 340 | |
| | 341 | const is_64bit = switch (arch) { |
| | 342 | .aarch64, .aarch64_be, .aarch64_32 => true, |
| | 343 | else => false, |
| | 344 | }; |
| | 345 | |
| | 346 | var known_models: [self.cores.len]?*const Target.Cpu.Model = undefined; |
| | 347 | for (self.cores[0..self.core_no]) |core, i| { |
| | 348 | known_models[i] = cpu_models.isKnown(core, is_64bit); |
| | 349 | } |
| | 350 | |
| | 351 | // XXX We pick the first core on big.LITTLE systems, hopefully the |
| | 352 | // LITTLE one. |
| | 353 | const model = known_models[0] orelse return null; |
| | 354 | return Target.Cpu{ |
| | 355 | .arch = arch, |
| | 356 | .model = model, |
| | 357 | .features = model.features, |
| | 358 | }; |
| | 359 | } |
| | 360 | }; |
| | 361 | |
| | 362 | const ArmCpuinfoParser = CpuinfoParser(ArmCpuinfoImpl); |
| | 363 | |
| | 364 | test "cpuinfo: ARM" { |
| | 365 | try testParser(ArmCpuinfoParser, .arm, &Target.arm.cpu.arm1176jz_s, |
| | 366 | \\processor : 0 |
| | 367 | \\model name : ARMv6-compatible processor rev 7 (v6l) |
| | 368 | \\BogoMIPS : 997.08 |
| | 369 | \\Features : half thumb fastmult vfp edsp java tls |
| | 370 | \\CPU implementer : 0x41 |
| | 371 | \\CPU architecture: 7 |
| | 372 | \\CPU variant : 0x0 |
| | 373 | \\CPU part : 0xb76 |
| | 374 | \\CPU revision : 7 |
| | 375 | ); |
| | 376 | try testParser(ArmCpuinfoParser, .arm, &Target.arm.cpu.cortex_a7, |
| | 377 | \\processor	: 0 |
| | 378 | \\model name	: ARMv7 Processor rev 3 (v7l) |
| | 379 | \\BogoMIPS	: 18.00 |
| | 380 | \\Features	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae |
| | 381 | \\CPU implementer	: 0x41 |
| | 382 | \\CPU architecture: 7 |
| | 383 | \\CPU variant	: 0x0 |
| | 384 | \\CPU part	: 0xc07 |
| | 385 | \\CPU revision	: 3 |
| | 386 | \\ |
| | 387 | \\processor	: 4 |
| | 388 | \\model name	: ARMv7 Processor rev 3 (v7l) |
| | 389 | \\BogoMIPS	: 90.00 |
| | 390 | \\Features	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae |
| | 391 | \\CPU implementer	: 0x41 |
| | 392 | \\CPU architecture: 7 |
| | 393 | \\CPU variant	: 0x2 |
| | 394 | \\CPU part	: 0xc0f |
| | 395 | \\CPU revision	: 3 |
| | 396 | ); |
| | 397 | try testParser(ArmCpuinfoParser, .aarch64, &Target.aarch64.cpu.cortex_a72, |
| | 398 | \\processor : 0 |
| | 399 | \\BogoMIPS : 108.00 |
| | 400 | \\Features : fp asimd evtstrm crc32 cpuid |
| | 401 | \\CPU implementer : 0x41 |
| | 402 | \\CPU architecture: 8 |
| | 403 | \\CPU variant : 0x0 |
| | 404 | \\CPU part : 0xd08 |
| | 405 | \\CPU revision : 3 |
| | 406 | ); |
| | 407 | } |
| | 408 | |
| | 409 | fn testParser( |
| | 410 | parser: anytype, |
| | 411 | arch: Target.Cpu.Arch, |
| | 412 | expected_model: *const Target.Cpu.Model, |
| | 413 | input: []const u8, |
| | 414 | ) !void { |
| 149 | var fbs = io.fixedBufferStream(input); | 415 | var fbs = io.fixedBufferStream(input); |
| 150 | const result = try parser.parse(.powerpc, fbs.reader()); | 416 | const result = try parser.parse(arch, fbs.reader()); |
| 151 | testing.expectEqual(expected_model, result.?.model); | 417 | testing.expectEqual(expected_model, result.?.model); |
| 152 | testing.expect(expected_model.features.eql(result.?.features)); | 418 | testing.expect(expected_model.features.eql(result.?.features)); |
| 153 | } | 419 | } |
| ... | @@ -186,6 +452,9 @@ pub fn detectNativeCpuAndFeatures() ?Target.Cpu { | ... | @@ -186,6 +452,9 @@ pub fn detectNativeCpuAndFeatures() ?Target.Cpu { |
| 186 | | 452 | |
| 187 | const current_arch = std.Target.current.cpu.arch; | 453 | const current_arch = std.Target.current.cpu.arch; |
| 188 | switch (current_arch) { | 454 | switch (current_arch) { |
| | 455 | .arm, .armeb, .thumb, .thumbeb, .aarch64, .aarch64_be, .aarch64_32 => { |
| | 456 | return ArmCpuinfoParser.parse(current_arch, f.reader()) catch null; |
| | 457 | }, |
| 189 | .sparcv9 => { | 458 | .sparcv9 => { |
| 190 | return SparcCpuinfoParser.parse(current_arch, f.reader()) catch null; | 459 | return SparcCpuinfoParser.parse(current_arch, f.reader()) catch null; |
| 191 | }, | 460 | }, |