| ... | @@ -242,6 +242,10 @@ pub const aarch64 = struct { | ... | @@ -242,6 +242,10 @@ pub const aarch64 = struct { |
| 242 | return @as(u4, @truncate(input >> offset)); | 242 | return @as(u4, @truncate(input >> offset)); |
| 243 | } | 243 | } |
| 244 | | 244 | |
| | 245 | inline fn signedBitField(input: u64, offset: u6) i4 { |
| | 246 | return @as(i4, @bitCast(@as(u4, @truncate(input >> offset)))); |
| | 247 | } |
| | 248 | |
| 245 | /// Input array should consist of readouts from 12 system registers such that: | 249 | /// Input array should consist of readouts from 12 system registers such that: |
| 246 | /// 0 -> MIDR_EL1 | 250 | /// 0 -> MIDR_EL1 |
| 247 | /// 1 -> ID_AA64PFR0_EL1 | 251 | /// 1 -> ID_AA64PFR0_EL1 |
| ... | @@ -255,18 +259,22 @@ pub const aarch64 = struct { | ... | @@ -255,18 +259,22 @@ pub const aarch64 = struct { |
| 255 | /// 9 -> ID_AA64MMFR0_EL1 | 259 | /// 9 -> ID_AA64MMFR0_EL1 |
| 256 | /// 10 -> ID_AA64MMFR1_EL1 | 260 | /// 10 -> ID_AA64MMFR1_EL1 |
| 257 | /// 11 -> ID_AA64MMFR2_EL1 | 261 | /// 11 -> ID_AA64MMFR2_EL1 |
| 258 | pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, registers: [12]u64) ?Target.Cpu { | 262 | pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, registers: [12]u64) Target.Cpu { |
| 259 | const info = detectNativeCoreInfo(registers[0]); | 263 | const info = detectNativeCoreInfo(registers[0]); |
| 260 | const model = cpu_models.isKnown(info, true) orelse return null; | 264 | const model = cpu_models.isKnown(info, true) orelse Target.Cpu.Model.generic(arch); |
| 261 | | 265 | |
| 262 | var cpu = Target.Cpu{ | 266 | var cpu = Target.Cpu{ |
| 263 | .arch = arch, | 267 | .arch = arch, |
| 264 | .model = model, | 268 | .model = model, |
| 265 | .features = Target.Cpu.Feature.Set.empty, | 269 | .features = .empty, |
| 266 | }; | 270 | }; |
| 267 | | 271 | |
| | 272 | cpu.features.addFeatureSet(model.features); |
| | 273 | |
| 268 | detectNativeCpuFeatures(&cpu, registers[1..12]); | 274 | detectNativeCpuFeatures(&cpu, registers[1..12]); |
| 269 | addInstructionFusions(&cpu, info); | 275 | addInstructionFusions(&cpu); |
| | 276 | |
| | 277 | cpu.features.populateDependencies(cpu.arch.allFeaturesList()); |
| 270 | | 278 | |
| 271 | return cpu; | 279 | return cpu; |
| 272 | } | 280 | } |
| ... | @@ -318,14 +326,9 @@ pub const aarch64 = struct { | ... | @@ -318,14 +326,9 @@ pub const aarch64 = struct { |
| 318 | setFeature(cpu, .sve, bitField(registers[0], 32) >= 1); | 326 | setFeature(cpu, .sve, bitField(registers[0], 32) >= 1); |
| 319 | setFeature(cpu, .el3, bitField(registers[0], 12) >= 1); | 327 | setFeature(cpu, .el3, bitField(registers[0], 12) >= 1); |
| 320 | setFeature(cpu, .ras, bitField(registers[0], 28) >= 1); | 328 | setFeature(cpu, .ras, bitField(registers[0], 28) >= 1); |
| 321 | | 329 | setFeature(cpu, .fp_armv8, signedBitField(registers[0], 16) >= 0); |
| 322 | if (bitField(registers[0], 20) < 0xF) blk: { | 330 | setFeature(cpu, .neon, signedBitField(registers[0], 20) >= 0); |
| 323 | if (bitField(registers[0], 16) != bitField(registers[0], 20)) break :blk; // This should never occur | 331 | setFeature(cpu, .fullfp16, signedBitField(registers[0], 16) >= 1 and signedBitField(registers[0], 20) >= 1); |
| 324 | | | |
| 325 | setFeature(cpu, .neon, true); | | |
| 326 | setFeature(cpu, .fp_armv8, true); | | |
| 327 | setFeature(cpu, .fullfp16, bitField(registers[0], 20) > 0); | | |
| 328 | } | | |
| 329 | | 332 | |
| 330 | // ID_AA64PFR1_EL1 | 333 | // ID_AA64PFR1_EL1 |
| 331 | setFeature(cpu, .mpam, bitField(registers[1], 16) > 0 and bitField(registers[0], 40) == 0); // MPAM v0.1 | 334 | setFeature(cpu, .mpam, bitField(registers[1], 16) > 0 and bitField(registers[0], 40) == 0); // MPAM v0.1 |
| ... | @@ -336,7 +339,7 @@ pub const aarch64 = struct { | ... | @@ -336,7 +339,7 @@ pub const aarch64 = struct { |
| 336 | // ID_AA64DFR0_EL1 | 339 | // ID_AA64DFR0_EL1 |
| 337 | setFeature(cpu, .tracev8_4, bitField(registers[2], 40) >= 1); | 340 | setFeature(cpu, .tracev8_4, bitField(registers[2], 40) >= 1); |
| 338 | setFeature(cpu, .spe, bitField(registers[2], 32) >= 1); | 341 | setFeature(cpu, .spe, bitField(registers[2], 32) >= 1); |
| 339 | setFeature(cpu, .perfmon, bitField(registers[2], 8) >= 1 and bitField(registers[2], 8) < 0xF); | 342 | setFeature(cpu, .perfmon, signedBitField(registers[2], 8) >= 1); |
| 340 | | 343 | |
| 341 | // ID_AA64DFR1_EL1 reserved | 344 | // ID_AA64DFR1_EL1 reserved |
| 342 | // ID_AA64AFR0_EL1 reserved / implementation defined | 345 | // ID_AA64AFR0_EL1 reserved / implementation defined |
| ... | @@ -387,17 +390,14 @@ pub const aarch64 = struct { | ... | @@ -387,17 +390,14 @@ pub const aarch64 = struct { |
| 387 | setFeature(cpu, .uaops, bitField(registers[10], 4) >= 1); | 390 | setFeature(cpu, .uaops, bitField(registers[10], 4) >= 1); |
| 388 | } | 391 | } |
| 389 | | 392 | |
| 390 | fn addInstructionFusions(cpu: *Target.Cpu, info: CoreInfo) void { | 393 | fn addInstructionFusions(cpu: *Target.Cpu) void { |
| 391 | switch (info.implementer) { | 394 | const m = cpu.model; |
| 392 | 0x41 => switch (info.part) { | 395 | const c = Target.aarch64.cpu; |
| 393 | 0xd4b, 0xd4c => { | 396 | |
| 394 | // According to A78C/X1C Core Software Optimization Guide, CPU fuses certain instructions. | 397 | if (m == &c.cortex_a78c or m == &c.cortex_x1c) { |
| 395 | setFeature(cpu, .cmp_bcc_fusion, true); | 398 | // According to A78C/X1C Core Software Optimization Guide, CPU fuses certain instructions. |
| 396 | setFeature(cpu, .fuse_aes, true); | 399 | setFeature(cpu, .cmp_bcc_fusion, true); |
| 397 | }, | 400 | setFeature(cpu, .fuse_aes, true); |
| 398 | else => {}, | | |
| 399 | }, | | |
| 400 | else => {}, | | |
| 401 | } | 401 | } |
| 402 | } | 402 | } |
| 403 | }; | 403 | }; |