authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-09-17 15:20:56+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-09-18 12:42:24+02:00
log6208e74145791c2f03e80e93caec4f87c60e638f
treeb9079c44e84e7b9640e8773374f907dcbce5e282
parentf1c2ae271cd0e9caac332a456ff8dbd2fc4c277a
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

std.zig.system: implement native CPU detection for LoongArch

ref #4591

3 files changed, 63 insertions(+), 6 deletions(-)

lib/std/zig/system.zig+2-3
......@@ -468,9 +468,8 @@ fn detectNativeCpuAndFeatures(cpu_arch: Target.Cpu.Arch, os: Target.Os, query: T
468468 // although it is a runtime value, is guaranteed to be one of the architectures in the set
469469 // of the respective switch prong.
470470 switch (builtin.cpu.arch) {
471 .x86_64, .x86 => {
472 return @import("system/x86.zig").detectNativeCpuAndFeatures(cpu_arch, os, query);
473 },
471 .loongarch32, .loongarch64 => return @import("system/loongarch.zig").detectNativeCpuAndFeatures(cpu_arch, os, query),
472 .x86_64, .x86 => return @import("system/x86.zig").detectNativeCpuAndFeatures(cpu_arch, os, query),
474473 else => {},
475474 }
476475
lib/std/zig/system/loongarch.zig created+48
......@@ -0,0 +1,48 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4pub fn detectNativeCpuAndFeatures(
5 arch: std.Target.Cpu.Arch,
6 os: std.Target.Os,
7 query: std.Target.Query,
8) ?std.Target.Cpu {
9 _ = os;
10 _ = query;
11
12 // Clearly this code could do better in the future by actually querying specific CPU features
13 // with the cpucfg instruction like on x86. But with the small number of well-known LoongArch
14 // models that exist at the moment, simply checking the PRID is plenty.
15 var cpu: std.Target.Cpu = .{
16 .arch = arch,
17 .model = switch (cpucfg(0) & 0xf000) {
18 else => return null,
19 0xc000 => &std.Target.loongarch.cpu.la464,
20 0xd000 => &std.Target.loongarch.cpu.la664,
21 },
22 .features = .empty,
23 };
24
25 cpu.features.addFeatureSet(cpu.model.features);
26 cpu.features.populateDependencies(cpu.arch.allFeaturesList());
27
28 return cpu;
29}
30
31/// This is a workaround for the C backend until zig has the ability to put
32/// C code in inline assembly.
33extern fn zig_loongarch_cpucfg(word: u32, result: *u32) callconv(.c) void;
34
35fn cpucfg(word: u32) u32 {
36 var result: u32 = undefined;
37
38 if (builtin.zig_backend == .stage2_c) {
39 zig_loongarch_cpucfg(word, &result);
40 } else {
41 asm ("cpucfg %[result], %[word]"
42 : [result] "=r" (result),
43 : [word] "r" (word),
44 );
45 }
46
47 return result;
48}
lib/zig.h+13-3
......@@ -4195,7 +4195,17 @@ static inline void* zig_x86_64_windows_teb(void) {
41954195
41964196#endif
41974197
4198#if defined(zig_x86)
4198#if defined(zig_loongarch)
4199
4200static inline void zig_loongarch_cpucfg(uint32_t word, uint32_t* result) {
4201#if defined(zig_gnuc_asm)
4202 __asm__("cpucfg %[result], %[word]" : [result] "=r" (result) : [word] "r" (word));
4203#else
4204 *result = 0;
4205#endif
4206}
4207
4208#elif defined(zig_x86)
41994209
42004210static inline void zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) {
42014211#if defined(zig_msvc)
......@@ -4206,7 +4216,7 @@ static inline void zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax
42064216 *ecx = (uint32_t)cpu_info[2];
42074217 *edx = (uint32_t)cpu_info[3];
42084218#elif defined(zig_gnuc_asm)
4209 __asm__("cpuid" : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) : "a"(leaf_id), "c"(subid));
4219 __asm__("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) : "a" (leaf_id), "c" (subid));
42104220#else
42114221 *eax = 0;
42124222 *ebx = 0;
......@@ -4221,7 +4231,7 @@ static inline uint32_t zig_x86_get_xcr0(void) {
42214231#elif defined(zig_gnuc_asm)
42224232 uint32_t eax;
42234233 uint32_t edx;
4224 __asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
4234 __asm__("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0));
42254235 return eax;
42264236#else
42274237 *eax = 0;