From 85953a78a34c862a22dbb37f1fc5755ba305d7e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 6 Sep 2026 23:16:58 +0200 Subject: [PATCH 01/24] std.elf: add AT_* constants for more OSs and namespace them properly --- lib/std/elf.zig | 266 +++++++++++++++--- lib/std/heap.zig | 2 +- lib/std/os/linux.zig | 2 +- lib/std/os/linux/test.zig | 8 +- lib/std/os/linux/vdso.zig | 2 +- lib/std/posix.zig | 8 +- lib/std/start.zig | 12 +- lib/std/zig/system/loongarch.zig | 4 +- .../glibc_compat/glibc_runtime_check.zig | 4 +- 9 files changed, 243 insertions(+), 65 deletions(-) diff --git a/lib/std/elf.zig b/lib/std/elf.zig index 8ebb002a24efe0801950ca3f4eb284b8a3c0370e..5da1c024488e4dbe115efc45574831417f7e82de 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -1,56 +1,234 @@ //! Executable and Linkable Format. +const builtin = @import("builtin"); const std = @import("std.zig"); const Io = std.Io; const math = std.math; const mem = std.mem; const assert = std.debug.assert; const Endian = std.builtin.Endian; -const native_endian = @import("builtin").target.cpu.arch.endian(); -pub const AT_NULL = 0; -pub const AT_IGNORE = 1; -pub const AT_EXECFD = 2; -pub const AT_PHDR = 3; -pub const AT_PHENT = 4; -pub const AT_PHNUM = 5; -pub const AT_PAGESZ = 6; -pub const AT_BASE = 7; -pub const AT_FLAGS = 8; -pub const AT_ENTRY = 9; -pub const AT_NOTELF = 10; -pub const AT_UID = 11; -pub const AT_EUID = 12; -pub const AT_GID = 13; -pub const AT_EGID = 14; -pub const AT_CLKTCK = 17; -pub const AT_PLATFORM = 15; -pub const AT_HWCAP = 16; -pub const AT_FPUCW = 18; -pub const AT_DCACHEBSIZE = 19; -pub const AT_ICACHEBSIZE = 20; -pub const AT_UCACHEBSIZE = 21; -pub const AT_IGNOREPPC = 22; -pub const AT_SECURE = 23; -pub const AT_BASE_PLATFORM = 24; -pub const AT_RANDOM = 25; -pub const AT_HWCAP2 = 26; -pub const AT_EXECFN = 31; -pub const AT_SYSINFO = 32; -pub const AT_SYSINFO_EHDR = 33; -pub const AT_L1I_CACHESHAPE = 34; -pub const AT_L1D_CACHESHAPE = 35; -pub const AT_L2_CACHESHAPE = 36; -pub const AT_L3_CACHESHAPE = 37; -pub const AT_L1I_CACHESIZE = 40; -pub const AT_L1I_CACHEGEOMETRY = 41; -pub const AT_L1D_CACHESIZE = 42; -pub const AT_L1D_CACHEGEOMETRY = 43; -pub const AT_L2_CACHESIZE = 44; -pub const AT_L2_CACHEGEOMETRY = 45; -pub const AT_L3_CACHESIZE = 46; -pub const AT_L3_CACHEGEOMETRY = 47; -pub const AT_MINSIGSTKSZ = 51; +const native_endian = builtin.target.cpu.arch.endian(); +const native_os = builtin.target.os.tag; + +pub const AT = switch (native_os) { + .dragonfly => struct { + pub const NULL = 0; + pub const IGNORE = 1; + pub const EXECFD = 2; + pub const PHDR = 3; + pub const PHENT = 4; + pub const PHNUM = 5; + pub const PAGESZ = 6; + pub const BASE = 7; + pub const FLAGS = 8; + pub const ENTRY = 9; + pub const NOTELF = 10; + pub const UID = 11; + pub const EUID = 12; + pub const GID = 13; + pub const EGID = 14; + pub const EXECPATH = 15; + pub const CANARY = 16; + pub const CANARYLEN = 17; + pub const OSRELDATE = 18; + pub const NCPUS = 19; + pub const PAGESIZES = 20; + pub const PAGESIZESLEN = 21; + pub const STACKPROT = 23; + }, + .freebsd => struct { + pub const NULL = 0; + pub const IGNORE = 1; + pub const EXECFD = 2; + pub const PHDR = 3; + pub const PHENT = 4; + pub const PHNUM = 5; + pub const PAGESZ = 6; + pub const BASE = 7; + pub const FLAGS = 8; + pub const ENTRY = 9; + pub const NOTELF = 10; + pub const UID = 11; + pub const EUID = 12; + pub const GID = 13; + pub const EGID = 14; + pub const EXECPATH = 15; + pub const CANARY = 16; + pub const CANARYLEN = 17; + pub const OSRELDATE = 18; + pub const NCPUS = 19; + pub const PAGESIZES = 20; + pub const PAGESIZESLEN = 21; + pub const TIMEKEEP = 22; + pub const STACKPROT = 23; + pub const EHDRFLAGS = 24; + pub const HWCAP = 25; + pub const HWCAP2 = 26; + pub const BSDFLAGS = 27; + pub const ARGC = 28; + pub const ARGV = 29; + pub const ENVC = 30; + pub const ENVV = 31; + pub const PS_STRINGS = 32; + pub const FXRNG = 33; + pub const KPRELOAD = 34; + pub const USRSTACKBASE = 35; + pub const USRSTACKLIM = 36; + pub const CHERI_STATS = 37; + pub const HWCAP3 = 38; + pub const HWCAP4 = 39; + }, + .illumos => struct { + pub const NULL = 0; + pub const IGNORE = 1; + pub const EXECFD = 2; + pub const PHDR = 3; + pub const PHENT = 4; + pub const PHNUM = 5; + pub const PAGESZ = 6; + pub const BASE = 7; + pub const FLAGS = 8; + pub const ENTRY = 9; + pub const NOTELF = 10; + pub const UID = 11; + pub const EUID = 12; + pub const GID = 13; + pub const EGID = 14; + pub const EXECPATH = 15; + pub const CANARY = 16; + pub const CANARYLEN = 17; + pub const OSRELDATE = 18; + pub const NCPUS = 19; + pub const PAGESIZES = 20; + pub const PAGESIZESLEN = 21; + pub const TIMEKEEP = 22; + pub const STACKPROT = 23; + }, + .linux => struct { + pub const NULL = 0; + pub const IGNORE = 1; + pub const EXECFD = 2; + pub const PHDR = 3; + pub const PHENT = 4; + pub const PHNUM = 5; + pub const PAGESZ = 6; + pub const BASE = 7; + pub const FLAGS = 8; + pub const ENTRY = 9; + pub const NOTELF = 10; + pub const UID = 11; + pub const EUID = 12; + pub const GID = 13; + pub const EGID = 14; + pub const CLKTCK = 17; + pub const PLATFORM = 15; + pub const HWCAP = 16; + pub const FPUCW = 18; + pub const DCACHEBSIZE = 19; + pub const ICACHEBSIZE = 20; + pub const UCACHEBSIZE = 21; + pub const IGNOREPPC = 22; + pub const SECURE = 23; + pub const BASE_PLATFORM = 24; + pub const RANDOM = 25; + pub const HWCAP2 = 26; + pub const EXECFN = 31; + pub const SYSINFO = 32; + pub const SYSINFO_EHDR = 33; + pub const L1I_CACHESHAPE = 34; + pub const L1D_CACHESHAPE = 35; + pub const L2_CACHESHAPE = 36; + pub const L3_CACHESHAPE = 37; + pub const L1I_CACHESIZE = 40; + pub const L1I_CACHEGEOMETRY = 41; + pub const L1D_CACHESIZE = 42; + pub const L1D_CACHEGEOMETRY = 43; + pub const L2_CACHESIZE = 44; + pub const L2_CACHEGEOMETRY = 45; + pub const L3_CACHESIZE = 46; + pub const L3_CACHEGEOMETRY = 47; + pub const MINSIGSTKSZ = 51; + }, + .netbsd => struct { + pub const NULL = 0; + pub const IGNORE = 1; + pub const EXECFD = 2; + pub const PHDR = 3; + pub const PHENT = 4; + pub const PHNUM = 5; + pub const PAGESZ = 6; + pub const BASE = 7; + pub const FLAGS = 8; + pub const ENTRY = 9; + pub const MIPS_NOTELF = 10; + pub const DCACHEBSIZE = 10; + pub const ICACHEBSIZE = 11; + pub const UCACHEBSIZE = 12; + pub const STACKBASE = 13; + pub const EUID = 2000; + pub const RUID = 2001; + pub const EGID = 2002; + pub const RGID = 2003; + pub const SUN_LDELF = 2004; + pub const SUN_LDSHDR = 2005; + pub const SUN_LDNAME = 2006; + pub const SUN_LPGSIZE = 2007; + pub const SUN_PLATFORM = 2008; + pub const SUN_HWCAP = 2009; + pub const SUN_IFLUSH = 2010; + pub const SUN_CPU = 2011; + pub const SUN_EMUL_ENTRY = 2012; + pub const SUN_EMUL_EXECFD = 2013; + pub const SUN_EXECNAME = 2014; + }, + .openbsd => struct { + pub const NULL = 0; + pub const IGNORE = 1; + pub const PAGESZ = 6; + pub const HWCAP = 25; + pub const HWCAP2 = 26; + }, + .serenity => struct { + pub const NULL = 0; + pub const IGNORE = 1; + pub const EXECFD = 2; + pub const PHDR = 3; + pub const PHENT = 4; + pub const PHNUM = 5; + pub const PAGESZ = 6; + pub const BASE = 7; + pub const FLAGS = 8; + pub const ENTRY = 9; + pub const NOTELF = 10; + pub const UID = 11; + pub const EUID = 12; + pub const GID = 13; + pub const PLATFORM = 15; + pub const HWCAP = 16; + pub const CLKTCK = 17; + pub const SECURE = 23; + pub const BASE_PLATFORM = 24; + pub const RANDOM = 25; + pub const HWCAP2 = 26; + pub const EXECFN = 31; + pub const EXE_BASE = 32; + pub const EXE_SIZE = 33; + }, + else => struct { + pub const NULL = 0; + pub const IGNORE = 1; + pub const EXECFD = 2; + pub const PHDR = 3; + pub const PHENT = 4; + pub const PHNUM = 5; + pub const PAGESZ = 6; + pub const BASE = 7; + pub const FLAGS = 8; + pub const ENTRY = 9; + pub const NOTELF = 10; + }, +}; pub const DT_NULL = 0; pub const DT_NEEDED = 1; diff --git a/lib/std/heap.zig b/lib/std/heap.zig index 45c509e09bb74bcb834543461b9ad99dc54ce5fd..12a7f0a52eb131492e9dc5be72b42acec263373b 100644 --- a/lib/std/heap.zig +++ b/lib/std/heap.zig @@ -80,7 +80,7 @@ pub fn defaultQueryPageSize() usize { .linux => if (builtin.link_libc) @max(std.c.sysconf(@backingInt(std.c._SC.PAGESIZE)), 0) else - std.os.linux.getauxval(std.elf.AT_PAGESZ), + std.os.linux.getauxval(std.elf.AT.PAGESZ), .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => { const task_port = std.c.mach_task_self(); // mach_task_self may fail "if there are any resource failures or other errors". diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 80d25ef865f6ac69fc58b711dccbed5d6cebe27a..0f90d004262bc5baf645fe120af4246022d89e49 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -705,7 +705,7 @@ fn getauxvalImpl(index: usize) callconv(.c) usize { @disableInstrumentation(); const auxv = elf_aux_maybe orelse return 0; var i: usize = 0; - while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) { + while (auxv[i].a_type != std.elf.AT.NULL) : (i += 1) { if (auxv[i].a_type == index) return auxv[i].a_un.a_val; } diff --git a/lib/std/os/linux/test.zig b/lib/std/os/linux/test.zig index 56c7c96c9432055945b71bca80de990d58df497d..1a22e8f24a264d960040adde43a0070dc9d2fc96 100644 --- a/lib/std/os/linux/test.zig +++ b/lib/std/os/linux/test.zig @@ -106,10 +106,10 @@ test "statx" { test "user and group ids" { if (builtin.link_libc) return error.SkipZigTest; - try expectEqual(linux.getauxval(elf.AT_UID), linux.getuid()); - try expectEqual(linux.getauxval(elf.AT_GID), linux.getgid()); - try expectEqual(linux.getauxval(elf.AT_EUID), linux.geteuid()); - try expectEqual(linux.getauxval(elf.AT_EGID), linux.getegid()); + try expectEqual(linux.getauxval(elf.AT.UID), linux.getuid()); + try expectEqual(linux.getauxval(elf.AT.GID), linux.getgid()); + try expectEqual(linux.getauxval(elf.AT.EUID), linux.geteuid()); + try expectEqual(linux.getauxval(elf.AT.EGID), linux.getegid()); } test "fadvise" { diff --git a/lib/std/os/linux/vdso.zig b/lib/std/os/linux/vdso.zig index 53be1bf9d51f0048d57074313fa49aff65e0e6a2..bdf46337b59ecc863a543d3722ddf47bd967374a 100644 --- a/lib/std/os/linux/vdso.zig +++ b/lib/std/os/linux/vdso.zig @@ -5,7 +5,7 @@ const mem = std.mem; const maxInt = std.math.maxInt; pub fn lookup(vername: []const u8, name: []const u8) usize { - const vdso_addr = linux.getauxval(std.elf.AT_SYSINFO_EHDR); + const vdso_addr = linux.getauxval(std.elf.AT.SYSINFO_EHDR); if (vdso_addr == 0) return 0; const eh = @as(*elf.Ehdr, @ptrFromInt(vdso_addr)); diff --git a/lib/std/posix.zig b/lib/std/posix.zig index 803fa9a9054f974ee2371011c938a96b8b72e02d..712b093e71f458810d4a8e11e451c7a44f9905d1 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -775,9 +775,9 @@ pub fn sysctl( pub fn getSelfPhdrs() []std.elf.ElfN.Phdr { const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval; - assert(getauxval(std.elf.AT_PHENT) == @sizeOf(std.elf.ElfN.Phdr)); - const phdrs: [*]std.elf.ElfN.Phdr = @ptrFromInt(getauxval(std.elf.AT_PHDR)); - return phdrs[0..getauxval(std.elf.AT_PHNUM)]; + assert(getauxval(std.elf.AT.PHENT) == @sizeOf(std.elf.ElfN.Phdr)); + const phdrs: [*]std.elf.ElfN.Phdr = @ptrFromInt(getauxval(std.elf.AT.PHDR)); + return phdrs[0..getauxval(std.elf.AT.PHNUM)]; } pub fn dl_iterate_phdr( @@ -819,7 +819,7 @@ pub fn dl_iterate_phdr( .PHDR => break @intFromPtr(phdrs.ptr) - phdr.vaddr, else => {}, } else unreachable, - .name = switch (getauxval(std.elf.AT_EXECFN)) { + .name = switch (getauxval(std.elf.AT.EXECFN)) { 0 => "/proc/self/exe", else => |name| @ptrFromInt(name), }, diff --git a/lib/std/start.zig b/lib/std/start.zig index 28b997fd7ee2bd7d49034d189b638a5d8cd5f69b..d86e6172523d7b3999e04c3fee07633792630a9d 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -617,11 +617,11 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { var i: usize = 0; var at_phdr: usize = 0; var at_phnum: usize = 0; - while (auxv[i].a_type != elf.AT_NULL) : (i += 1) { + while (auxv[i].a_type != elf.AT.NULL) : (i += 1) { switch (auxv[i].a_type) { - elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val, - elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val, - elf.AT_HWCAP => at_hwcap = auxv[i].a_un.a_val, + elf.AT.PHNUM => at_phnum = auxv[i].a_un.a_val, + elf.AT.PHDR => at_phdr = auxv[i].a_un.a_val, + elf.AT.HWCAP => at_hwcap = auxv[i].a_un.a_val, else => continue, } } @@ -736,8 +736,8 @@ fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) cal switch (builtin.os.tag) { .linux => { - const at_phdr = std.c.getauxval(elf.AT_PHDR); - const at_phnum = std.c.getauxval(elf.AT_PHNUM); + const at_phdr = std.c.getauxval(elf.AT.PHDR); + const at_phnum = std.c.getauxval(elf.AT.PHNUM); const phdrs = (@as([*]elf.ElfN.Phdr, @ptrFromInt(at_phdr)))[0..at_phnum]; expandStackSize(phdrs); }, diff --git a/lib/std/zig/system/loongarch.zig b/lib/std/zig/system/loongarch.zig index eee112462d9de7e17466c34578069c3a6058d4f3..1476eab209d5851974b4fa3b866ad40778cf0560 100644 --- a/lib/std/zig/system/loongarch.zig +++ b/lib/std/zig/system/loongarch.zig @@ -52,9 +52,9 @@ pub fn detectNativeCpuAndFeatures( if (builtin.os.tag == .linux) { const HWCAP = std.os.linux.HWCAP; const hwcap_bits: usize = if (builtin.link_libc) - std.c.getauxval(std.elf.AT_HWCAP) + std.c.getauxval(std.elf.AT.HWCAP) else - std.os.linux.getauxval(std.elf.AT_HWCAP); + std.os.linux.getauxval(std.elf.AT.HWCAP); setFeature(&cpu, .ual, (hwcap_bits & HWCAP.UAL) != 0); diff --git a/test/standalone/glibc_compat/glibc_runtime_check.zig b/test/standalone/glibc_compat/glibc_runtime_check.zig index 7c5e10e9e94edc71ec0e1ec3dabbb1e38b3ab88c..2dc565cbe7c926170a59b395f694180fdfe7612b 100644 --- a/test/standalone/glibc_compat/glibc_runtime_check.zig +++ b/test/standalone/glibc_compat/glibc_runtime_check.zig @@ -65,8 +65,8 @@ fn checkGetAuxVal() !void { } fn checkGetAuxVal_v2_16() !void { - const base = std.c.getauxval(std.elf.AT_BASE); - const pgsz = std.c.getauxval(std.elf.AT_PAGESZ); + const base = std.c.getauxval(std.elf.AT.BASE); + const pgsz = std.c.getauxval(std.elf.AT.PAGESZ); assert(base != 0); assert(pgsz != 0); -- 2.54.0 From 5dfebdcc07a3035fb41f79d9608beceb0c4bdc6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Sep 2026 01:15:14 +0200 Subject: [PATCH 02/24] std.elf: add missing AT_* constants for linux --- lib/std/elf.zig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/std/elf.zig b/lib/std/elf.zig index 5da1c024488e4dbe115efc45574831417f7e82de..fded67b2909156b03621c40bd1047941bdbde4c3 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -133,6 +133,10 @@ pub const AT = switch (native_os) { pub const BASE_PLATFORM = 24; pub const RANDOM = 25; pub const HWCAP2 = 26; + pub const RSEQ_FEATURE_SIZE = 27; + pub const RSEQ_ALIGN = 28; + pub const HWCAP3 = 29; + pub const HWCAP4 = 30; pub const EXECFN = 31; pub const SYSINFO = 32; pub const SYSINFO_EHDR = 33; -- 2.54.0 From eebbb2dfec16216987c2bab13495725512b46ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 6 Sep 2026 23:19:55 +0200 Subject: [PATCH 03/24] std.os.linux: add missing HWCAP constants for arm --- lib/std/os/linux.zig | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 0f90d004262bc5baf645fe120af4246022d89e49..cc25ec9d82ccf6bc2e10ba8686f8edd9daf6d44a 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -643,6 +643,22 @@ pub const HWCAP = switch (native_arch) { pub const IDIV = IDIVA | IDIVT; pub const LPAE = 1 << 20; pub const EVTSTRM = 1 << 21; + pub const FPHP = 1 << 22; + pub const ASIMDHP = 1 << 23; + pub const ASIMDDP = 1 << 24; + pub const ASIMDFHM = 1 << 25; + pub const ASIMDBF16 = 1 << 26; + pub const I8MM = 1 << 27; + + pub const @"2" = struct { + pub const AES = 1 << 0; + pub const PMULL = 1 << 1; + pub const SHA1 = 1 << 2; + pub const SHA2 = 1 << 3; + pub const CRC32 = 1 << 4; + pub const SB = 1 << 5; + pub const SSBS = 1 << 6; + }; }, .loongarch32, .loongarch64 => struct { pub const CPUCFG = 1 << 0; -- 2.54.0 From 69fd0387cec1a3e2e6980d1fa773ff01f4b28ae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 6 Sep 2026 23:26:01 +0200 Subject: [PATCH 04/24] std.os.linux: add missing HWCAP.LAM_BH constant for loongarch --- lib/std/os/linux.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index cc25ec9d82ccf6bc2e10ba8686f8edd9daf6d44a..99a1bf62548a1fb4066dd7de2455256379659743 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -677,6 +677,7 @@ pub const HWCAP = switch (native_arch) { pub const PTW = 1 << 13; pub const LSPW = 1 << 14; pub const SCQ = 1 << 15; + pub const LAM_BH = 1 << 16; }, else => struct {}, }; -- 2.54.0 From 4e311163dbe3a56f1cc5519a59f8434b75599b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 6 Sep 2026 23:25:18 +0200 Subject: [PATCH 05/24] std.os.linux: add HWCAP constants for aarch64 --- lib/std/os/linux.zig | 132 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 99a1bf62548a1fb4066dd7de2455256379659743..2d062be1c1d90843b4cac93e9ce81b7bf34eeeed 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -619,6 +619,138 @@ pub const O = switch (native_arch) { }; pub const HWCAP = switch (native_arch) { + .aarch64, .aarch64_be => struct { + pub const FP = 1 << 0; + pub const ASIMD = 1 << 1; + pub const EVTSTRM = 1 << 2; + pub const AES = 1 << 3; + pub const PMULL = 1 << 4; + pub const SHA1 = 1 << 5; + pub const SHA2 = 1 << 6; + pub const CRC32 = 1 << 7; + pub const ATOMICS = 1 << 8; + pub const FPHP = 1 << 9; + pub const ASIMDHP = 1 << 10; + pub const CPUID = 1 << 11; + pub const ASIMDRDM = 1 << 12; + pub const JSCVT = 1 << 13; + pub const FCMA = 1 << 14; + pub const LRCPC = 1 << 15; + pub const DCPOP = 1 << 16; + pub const SHA3 = 1 << 17; + pub const SM3 = 1 << 18; + pub const SM4 = 1 << 19; + pub const ASIMDDP = 1 << 20; + pub const SHA512 = 1 << 21; + pub const SVE = 1 << 22; + pub const ASIMDFHM = 1 << 23; + pub const DIT = 1 << 24; + pub const USCAT = 1 << 25; + pub const ILRCPC = 1 << 26; + pub const FLAGM = 1 << 27; + pub const SSBS = 1 << 28; + pub const SB = 1 << 29; + pub const PACA = 1 << 30; + pub const PACG = 1 << 31; + pub const GCS = 1 << 32; + pub const CMPBR = 1 << 33; + pub const FPRCVT = 1 << 34; + pub const F8MM8 = 1 << 35; + pub const F8MM4 = 1 << 36; + pub const SVE_F16MM = 1 << 37; + pub const SVE_ELTPERM = 1 << 38; + pub const SVE_AES2 = 1 << 39; + pub const SVE_BFSCALE = 1 << 40; + pub const SVE2P2 = 1 << 41; + pub const SME2P2 = 1 << 42; + pub const SME_SBITPERM = 1 << 43; + pub const SME_AES = 1 << 44; + pub const SME_SFEXPA = 1 << 45; + pub const SME_STMOP = 1 << 46; + pub const SME_SMOP4 = 1 << 47; + + pub const @"2" = struct { + pub const DCPODP = 1 << 0; + pub const SVE2 = 1 << 1; + pub const SVEAES = 1 << 2; + pub const SVEPMULL = 1 << 3; + pub const SVEBITPERM = 1 << 4; + pub const SVESHA3 = 1 << 5; + pub const SVESM4 = 1 << 6; + pub const FLAGM2 = 1 << 7; + pub const FRINT = 1 << 8; + pub const SVEI8MM = 1 << 9; + pub const SVEF32MM = 1 << 10; + pub const SVEF64MM = 1 << 11; + pub const SVEBF16 = 1 << 12; + pub const I8MM = 1 << 13; + pub const BF16 = 1 << 14; + pub const DGH = 1 << 15; + pub const RNG = 1 << 16; + pub const BTI = 1 << 17; + pub const MTE = 1 << 18; + pub const ECV = 1 << 19; + pub const AFP = 1 << 20; + pub const RPRES = 1 << 21; + pub const MTE3 = 1 << 22; + pub const SME = 1 << 23; + pub const SME_I16I64 = 1 << 24; + pub const SME_F64F64 = 1 << 25; + pub const SME_I8I32 = 1 << 26; + pub const SME_F16F32 = 1 << 27; + pub const SME_B16F32 = 1 << 28; + pub const SME_F32F32 = 1 << 29; + pub const SME_FA64 = 1 << 30; + pub const WFXT = 1 << 31; + pub const EBF16 = 1 << 32; + pub const SVE_EBF16 = 1 << 33; + pub const CSSC = 1 << 34; + pub const RPRFM = 1 << 35; + pub const SVE2P1 = 1 << 36; + pub const SME2 = 1 << 37; + pub const SME2P1 = 1 << 38; + pub const SME_I16I32 = 1 << 39; + pub const SME_BI32I32 = 1 << 40; + pub const SME_B16B16 = 1 << 41; + pub const SME_F16F16 = 1 << 42; + pub const MOPS = 1 << 43; + pub const HBC = 1 << 44; + pub const SVE_B16B16 = 1 << 45; + pub const LRCPC3 = 1 << 46; + pub const LSE128 = 1 << 47; + pub const FPMR = 1 << 48; + pub const LUT = 1 << 49; + pub const FAMINMAX = 1 << 50; + pub const F8CVT = 1 << 51; + pub const F8FMA = 1 << 52; + pub const F8DP4 = 1 << 53; + pub const F8DP2 = 1 << 54; + pub const F8E4M3 = 1 << 55; + pub const F8E5M2 = 1 << 56; + pub const SME_LUTV2 = 1 << 57; + pub const SME_F8F16 = 1 << 58; + pub const SME_F8F32 = 1 << 59; + pub const SME_SF8FMA = 1 << 60; + pub const SME_SF8DP4 = 1 << 61; + pub const SME_SF8DP2 = 1 << 62; + pub const POE = 1 << 63; + }; + + pub const @"3" = struct { + pub const MTE_FAR = 1 << 0; + pub const MTE_STORE_ONLY = 1 << 1; + pub const LSFE = 1 << 2; + pub const LS64 = 1 << 3; + pub const SVE_B16MM = 1 << 4; + pub const SVE2P3 = 1 << 5; + pub const SME_LUT6 = 1 << 6; + pub const SME2P3 = 1 << 7; + pub const F16MM = 1 << 8; + pub const F16F32DOT = 1 << 9; + pub const F16F32MM = 1 << 10; + pub const SVE_LUT6 = 1 << 11; + }; + }, .arm, .armeb, .thumb, .thumbeb => struct { pub const SWP = 1 << 0; pub const HALF = 1 << 1; -- 2.54.0 From e5f752f84c66a32122dcf514851852c75afe8235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 6 Sep 2026 23:44:12 +0200 Subject: [PATCH 06/24] std.os.linux: add HWCAP constants for mips --- lib/std/os/linux.zig | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 2d062be1c1d90843b4cac93e9ce81b7bf34eeeed..1047215136e3d9b6469a4f935e790642950c43de 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -811,6 +811,23 @@ pub const HWCAP = switch (native_arch) { pub const SCQ = 1 << 15; pub const LAM_BH = 1 << 16; }, + .mips, .mipsel, .mips64, .mips64el => struct { + pub const R6 = 1 << 0; + pub const MSA = 1 << 1; + pub const CRC32 = 1 << 2; + pub const MIPS16 = 1 << 3; + pub const MDMX = 1 << 4; + pub const MIPS3D = 1 << 5; + pub const SMARTMIPS = 1 << 6; + pub const DSP = 1 << 7; + pub const DSP2 = 1 << 8; + pub const DSP3 = 1 << 9; + pub const MIPS16E2 = 1 << 10; + pub const LOONGSON_MMI = 1 << 11; + pub const LOONGSON_EXT = 1 << 12; + pub const LOONGSON_EXT2 = 1 << 13; + pub const LOONGSON_CPUCFG = 1 << 14; + }, else => struct {}, }; -- 2.54.0 From f0b0bafe6e0b7a1bb86184edae9d84f43c79118f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 6 Sep 2026 23:44:26 +0200 Subject: [PATCH 07/24] std.os.linux: add HWCAP constants for s390x --- lib/std/os/linux.zig | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 1047215136e3d9b6469a4f935e790642950c43de..888ff2ed7711db77f058669d2589d0bc865ee2e7 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -828,6 +828,31 @@ pub const HWCAP = switch (native_arch) { pub const LOONGSON_EXT2 = 1 << 13; pub const LOONGSON_CPUCFG = 1 << 14; }, + .s390x => struct { + pub const ESAN3 = 1 << 0; + pub const ZARCH = 1 << 1; + pub const STFLE = 1 << 2; + pub const MSA = 1 << 3; + pub const LDISP = 1 << 4; + pub const EIMM = 1 << 5; + pub const DFP = 1 << 6; + pub const HPAGE = 1 << 7; + pub const ETF3EH = 1 << 8; + pub const HIGH_GPRS = 1 << 9; + pub const TE = 1 << 10; + pub const VXRS = 1 << 11; + pub const VXRS_BCD = 1 << 12; + pub const VXRS_EXT = 1 << 13; + pub const GS = 1 << 14; + pub const VXRS_EXT2 = 1 << 15; + pub const VXRS_PDE = 1 << 16; + pub const SORT = 1 << 17; + pub const DFLT = 1 << 18; + pub const VXRS_PDE2 = 1 << 19; + pub const NNPA = 1 << 20; + pub const PCI_MIO = 1 << 21; + pub const SIE = 1 << 22; + }, else => struct {}, }; -- 2.54.0 From 211e35aa2b6fa0abf9c943f95922ab6c21343cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 6 Sep 2026 23:44:34 +0200 Subject: [PATCH 08/24] std.os.linux: add HWCAP constants for sparc --- lib/std/os/linux.zig | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 888ff2ed7711db77f058669d2589d0bc865ee2e7..889019fa6d165a6a155b2ccbe07a4edf3e2e7cc1 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -853,6 +853,36 @@ pub const HWCAP = switch (native_arch) { pub const PCI_MIO = 1 << 21; pub const SIE = 1 << 22; }, + .sparc, .sparc64 => struct { + pub const FLUSH = 1 << 0; + pub const STBAR = 1 << 1; + pub const SWAP = 1 << 2; + pub const MULDIV = 1 << 3; + pub const V9 = 1 << 4; + pub const ULTRA3 = 1 << 5; + pub const BLKINIT = 1 << 6; + pub const N2 = 1 << 7; + pub const MUL32 = 1 << 8; + pub const DIV32 = 1 << 9; + pub const FSMULD = 1 << 10; + pub const V8PLUS = 1 << 11; + pub const POPC = 1 << 12; + pub const VIS = 1 << 13; + pub const VIS2 = 1 << 14; + pub const ASI_BLK_INIT = 1 << 15; + pub const FMAF = 1 << 16; + pub const VIS3 = 1 << 17; + pub const HPC = 1 << 18; + pub const RANDOM = 1 << 19; + pub const TRANS = 1 << 20; + pub const FJFMAU = 1 << 21; + pub const IMA = 1 << 22; + pub const ASI_CACHE_SPARING = 1 << 23; + pub const PAUSE = 1 << 24; + pub const CBCOND = 1 << 25; + pub const CRYPTO = 1 << 26; + pub const ADI = 1 << 27; + }, else => struct {}, }; -- 2.54.0 From 1c96211cc5125b2f46dc882c5e656e57a569d7bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 6 Sep 2026 23:58:29 +0200 Subject: [PATCH 09/24] std.os.linux: add HWCAP constants for powerpc --- lib/std/os/linux.zig | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 889019fa6d165a6a155b2ccbe07a4edf3e2e7cc1..e9abc71566618c49caab326225770ab02d5f298c 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -828,6 +828,56 @@ pub const HWCAP = switch (native_arch) { pub const LOONGSON_EXT2 = 1 << 13; pub const LOONGSON_CPUCFG = 1 << 14; }, + .powerpc, .powerpcle, .powerpc64, .powerpc64le => struct { + pub const PPC_LE = 1 << 0; + pub const TRUE_LE = 1 << 1; + pub const PSERIES_PERFMON_COMPAT = 1 << 6; + pub const HAS_VSX = 1 << 7; + pub const ARCH_2_06 = 1 << 8; + pub const POWER6_EXT = 1 << 9; + pub const HAS_DFP = 1 << 10; + pub const PA6T = 1 << 11; + pub const ARCH_2_05 = 1 << 12; + pub const ICACHE_SNOOP = 1 << 13; + pub const SMT = 1 << 14; + pub const BOOKE = 1 << 15; + pub const CELL = 1 << 16; + pub const POWER5_PLUS = 1 << 17; + pub const POWER5 = 1 << 18; + pub const POWER4 = 1 << 19; + pub const NO_TB = 1 << 20; + pub const HAS_EFP_DOUBLE = 1 << 21; + pub const HAS_EFP_SINGLE = 1 << 22; + pub const HAS_SPE = 1 << 23; + pub const UNIFIED_CACHE = 1 << 24; + pub const HAS_4xxMAC = 1 << 25; + pub const HAS_MMU = 1 << 26; + pub const HAS_FPU = 1 << 27; + pub const HAS_ALTIVEC = 1 << 28; + pub const @"601_INSTR" = 1 << 29; + pub const @"64" = 1 << 30; + pub const @"32" = 1 << 31; + + pub const @"2" = struct { + pub const DMF = 1 << 15; + pub const ARCH_3_2 = 1 << 16; + pub const MMA = 1 << 17; + pub const ARCH_3_1 = 1 << 18; + pub const HTM_NO_SUSPEND = 1 << 19; + pub const SCV = 1 << 20; + pub const DARN = 1 << 21; + pub const HAS_IEEE128 = 1 << 22; + pub const ARCH_3_00 = 1 << 23; + pub const HTM_NOSC = 1 << 24; + pub const VEC_CRYPTO = 1 << 25; + pub const TAR = 1 << 26; + pub const ISEL = 1 << 27; + pub const EBB = 1 << 28; + pub const DSCR = 1 << 29; + pub const HTM = 1 << 30; + pub const ARCH_2_07 = 1 << 31; + }; + }, .s390x => struct { pub const ESAN3 = 1 << 0; pub const ZARCH = 1 << 1; -- 2.54.0 From 4eb24f4f8e2e6f226cced6f3691d8e5a9f7de7ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Sep 2026 00:32:56 +0200 Subject: [PATCH 10/24] std.os.linux: add HWCAP constants for x86 --- lib/std/os/linux.zig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index e9abc71566618c49caab326225770ab02d5f298c..80cf271418f593870fd1913159838c78a7c1dc97 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -933,6 +933,12 @@ pub const HWCAP = switch (native_arch) { pub const CRYPTO = 1 << 26; pub const ADI = 1 << 27; }, + .x86, .x86_64 => struct { + pub const @"2" = struct { + pub const RING3MWAIT = 1 << 0; + pub const FSGSBASE = 1 << 1; + }; + }, else => struct {}, }; -- 2.54.0 From f283057bee8874a497908f420c7853606d5c98d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Sep 2026 01:05:33 +0200 Subject: [PATCH 11/24] std.os.linux: add HWCAP constants for riscv --- lib/std/os/linux.zig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 80cf271418f593870fd1913159838c78a7c1dc97..fd892a548f2074366d28b135d9c834f090849d66 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -878,6 +878,15 @@ pub const HWCAP = switch (native_arch) { pub const ARCH_2_07 = 1 << 31; }; }, + .riscv32, .riscv64 => struct { + pub const ISA_A = 1 << 0; + pub const ISA_C = 1 << 2; + pub const ISA_D = 1 << 3; + pub const ISA_F = 1 << 5; + pub const ISA_I = 1 << 8; + pub const ISA_M = 1 << 12; + pub const ISA_V = 1 << 21; + }, .s390x => struct { pub const ESAN3 = 1 << 0; pub const ZARCH = 1 << 1; -- 2.54.0 From c09af800431ccb1fc8bab6c51a966a8de3fe8b0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 6 Sep 2026 23:15:00 +0200 Subject: [PATCH 12/24] std.c: add elf_aux_info() --- lib/std/c.zig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/std/c.zig b/lib/std/c.zig index ae616664cb0cfc3699948431c50fd1d64936b8f7..b4d3ec8961eea0026f642cfec32f5b38085de5c2 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -10533,8 +10533,9 @@ pub const sendfile = switch (native_os) { .linux => private.sendfile, else => {}, }; -/// See std.elf for constants for this -pub extern "c" fn getauxval(__type: c_ulong) c_ulong; + +pub extern "c" fn getauxval(type: c_ulong) c_ulong; +pub extern "c" fn elf_aux_info(aux: c_int, buf: *anyopaque, buflen: c_int) c_int; pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*anyopaque) c_int; -- 2.54.0 From 96b1105ddaa12dbefa5c9f489da0c52c7e35f201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Sep 2026 01:20:53 +0200 Subject: [PATCH 13/24] std.c: add HWCAP definition for freebsd, illumos, linux, openbsd --- lib/std/c.zig | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/lib/std/c.zig b/lib/std/c.zig index b4d3ec8961eea0026f642cfec32f5b38085de5c2..a316335353c3492b132e7bb6f7d165fa5114bdee 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -10537,6 +10537,131 @@ pub const sendfile = switch (native_os) { pub extern "c" fn getauxval(type: c_ulong) c_ulong; pub extern "c" fn elf_aux_info(aux: c_int, buf: *anyopaque, buflen: c_int) c_int; +pub const HWCAP = switch (native_os) { + .freebsd => switch (native_arch) { + // FreeBSD deliberately matches the Linux ABI for AT_HWCAP... + else => std.os.linux.HWCAP, + // ... but because Linux went the SYS_riscv_hwprobe route, FreeBSD + // defines more bits than Linux does: + .riscv64 => struct { + pub const ISA_A = 1 << 0; + pub const ISA_B = 1 << 1; + pub const ISA_C = 1 << 2; + pub const ISA_D = 1 << 3; + pub const ISA_F = 1 << 5; + pub const ISA_H = 1 << 7; + pub const ISA_I = 1 << 8; + pub const ISA_M = 1 << 12; + pub const ISA_V = 1 << 21; + }, + }, + .illumos => switch (native_arch) { + .x86, .x86_64 => struct { + pub const FPU = 1 << 0; + pub const TSC = 1 << 1; + pub const CX8 = 1 << 2; + pub const SEP = 1 << 3; + pub const AMD_SYSC = 1 << 4; + pub const CMOV = 1 << 5; + pub const MMX = 1 << 6; + pub const AMD_MMX = 1 << 7; + pub const AMD_3DNow = 1 << 8; + pub const AMD_3DNowx = 1 << 9; + pub const FXSR = 1 << 10; + pub const SSE = 1 << 11; + pub const SSE2 = 1 << 12; + pub const PAUSE = 1 << 13; + pub const SSE3 = 1 << 14; + pub const MON = 1 << 15; + pub const CX16 = 1 << 16; + pub const AHF = 1 << 17; + pub const TSCP = 1 << 18; + pub const AMD_SSE4A = 1 << 19; + pub const POPCNT = 1 << 20; + pub const AMD_LZCNT = 1 << 21; + pub const SSSE3 = 1 << 22; + pub const SSE4_1 = 1 << 23; + pub const SSE4_2 = 1 << 24; + pub const MOVBE = 1 << 25; + pub const AES = 1 << 26; + pub const PCLMULQDQ = 1 << 27; + pub const XSAVE = 1 << 28; + pub const AVX = 1 << 29; + pub const VMX = 1 << 30; + pub const AMD_SVM = 1 << 31; + + pub const @"2" = struct { + pub const F16C = 1 << 0; + pub const RDRAND = 1 << 1; + pub const BMI1 = 1 << 2; + pub const BMI2 = 1 << 3; + pub const FMA = 1 << 4; + pub const AVX2 = 1 << 5; + pub const ADX = 1 << 6; + pub const RDSEED = 1 << 7; + pub const AVX512F = 1 << 8; + pub const AVX512DQ = 1 << 9; + pub const AVX512IFMA = 1 << 10; + pub const AVX512PF = 1 << 11; + pub const AVX512ER = 1 << 12; + pub const AVX512CD = 1 << 13; + pub const AVX512BW = 1 << 14; + pub const AVX512VL = 1 << 15; + pub const AVX512VBMI = 1 << 16; + pub const AVX512VPOPCDQ = 1 << 17; + pub const AVX512_4NNIW = 1 << 18; + pub const AVX512_4FMAPS = 1 << 19; + pub const SHA = 1 << 20; + pub const FSGSBASE = 1 << 21; + pub const CLFLUSHOPT = 1 << 22; + pub const CLWB = 1 << 23; + pub const MONITORX = 1 << 24; + pub const CLZERO = 1 << 25; + pub const AVX512_VNNI = 1 << 26; + pub const VPCLMULQDQ = 1 << 27; + pub const VAES = 1 << 28; + }; + }, + else => struct {}, + }, + .linux => std.os.linux.HWCAP, + .openbsd => switch (native_arch) { + // Same deal as for FreeBSD. + else => std.os.linux.HWCAP, + .riscv64 => struct { + pub const ISA_A = 1 << 0; + pub const ISA_B = 1 << 1; + pub const ISA_C = 1 << 2; + pub const ISA_D = 1 << 3; + pub const ISA_F = 1 << 5; + pub const ISA_H = 1 << 7; + pub const ISA_I = 1 << 8; + pub const ISA_M = 1 << 12; + pub const ISA_V = 1 << 21; + + pub const @"2" = struct { + pub const ISA_ZBA = 1 << 0; + pub const ISA_ZBB = 1 << 1; + pub const ISA_ZBC = 1 << 2; + pub const ISA_ZBS = 1 << 3; + pub const ISA_ZFH = 1 << 4; + pub const ISA_ZKT = 1 << 5; + pub const ISA_ZVBB = 1 << 6; + pub const ISA_ZVBC = 1 << 7; + pub const ISA_ZVFH = 1 << 8; + pub const ISA_ZVKG = 1 << 9; + pub const ISA_ZVKNED = 1 << 10; + pub const ISA_ZVKNHA = 1 << 11; + pub const ISA_ZVKNHB = 1 << 12; + pub const ISA_ZVKSED = 1 << 13; + pub const ISA_ZVKSH = 1 << 14; + pub const ISA_ZVKT = 1 << 15; + }; + }, + }, + else => struct {}, +}; + pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*anyopaque) c_int; pub const sigaltstack = switch (native_os) { -- 2.54.0 From 0e78d77d4dbfec26bfeb240962cd46cd7b2e40c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 6 Sep 2026 23:27:39 +0200 Subject: [PATCH 14/24] std.zig.system.loongarch: use hwcap for lam_bh detection --- lib/std/zig/system/loongarch.zig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/std/zig/system/loongarch.zig b/lib/std/zig/system/loongarch.zig index 1476eab209d5851974b4fa3b866ad40778cf0560..afc26d5db1be83ad95b105dfbd60ba7967ce30c5 100644 --- a/lib/std/zig/system/loongarch.zig +++ b/lib/std/zig/system/loongarch.zig @@ -66,6 +66,8 @@ pub fn detectNativeCpuAndFeatures( setFeature(&cpu, .lvz, (hwcap_bits & HWCAP.LVZ) != 0); setFeature(&cpu, .lbt, (hwcap_bits & HWCAP.LBT_X86) != 0 and (hwcap_bits & HWCAP.LBT_ARM) != 0 and (hwcap_bits & HWCAP.LBT_MIPS) != 0); + + setFeature(&cpu, .lam_bh, (hwcap_bits & HWCAP.LAM_BH) != 0); } else { setFeature(&cpu, .ual, false); @@ -76,11 +78,12 @@ pub fn detectNativeCpuAndFeatures( setFeature(&cpu, .lvz, false); setFeature(&cpu, .lbt, false); + + setFeature(&cpu, .lam_bh, false); } setFeature(&cpu, .frecipe, bit(cfg2, 25)); setFeature(&cpu, .div32, bit(cfg2, 26)); - setFeature(&cpu, .lam_bh, bit(cfg2, 27)); setFeature(&cpu, .lamcas, bit(cfg2, 28)); setFeature(&cpu, .scq, bit(cfg2, 30)); -- 2.54.0 From b686b84ff3ce184094d2bd949f56c7f8271c22f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Sep 2026 01:56:52 +0200 Subject: [PATCH 15/24] std.zig.system.linux: some corrections to powerpc CPU model list --- lib/std/zig/system/linux.zig | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index d712792bf1504d02dd1a22c6f5bcd6a1c2bd5e91..b1375aa17aad7f77cc986c36de5ef817ba53c35c 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -127,23 +127,20 @@ const PowerpcCpuinfoImpl = struct { .{ "604", &Target.powerpc.cpu.@"604" }, .{ "7400", &Target.powerpc.cpu.@"7400" }, .{ "7410", &Target.powerpc.cpu.@"7400" }, - .{ "7447", &Target.powerpc.cpu.@"7400" }, + .{ "7447/7457", &Target.powerpc.cpu.@"7450" }, + .{ "7447A", &Target.powerpc.cpu.@"7450" }, .{ "7455", &Target.powerpc.cpu.@"7450" }, - .{ "G4", &Target.powerpc.cpu.g4 }, - .{ "POWER4", &Target.powerpc.cpu.@"970" }, - .{ "PPC970FX", &Target.powerpc.cpu.@"970" }, - .{ "PPC970MP", &Target.powerpc.cpu.@"970" }, - .{ "G5", &Target.powerpc.cpu.g5 }, .{ "POWER5", &Target.powerpc.cpu.g5 }, - .{ "A2", &Target.powerpc.cpu.a2 }, .{ "POWER6", &Target.powerpc.cpu.pwr6 }, .{ "POWER7", &Target.powerpc.cpu.pwr7 }, - .{ "POWER8", &Target.powerpc.cpu.pwr8 }, .{ "POWER8E", &Target.powerpc.cpu.pwr8 }, .{ "POWER8NVL", &Target.powerpc.cpu.pwr8 }, + .{ "POWER8", &Target.powerpc.cpu.pwr8 }, .{ "POWER9", &Target.powerpc.cpu.pwr9 }, .{ "POWER10", &Target.powerpc.cpu.pwr10 }, - .{ "POWER11", &Target.powerpc.cpu.pwr11 }, + .{ "Power11", &Target.powerpc.cpu.pwr11 }, + .{ "PPC970FX", &Target.powerpc.cpu.@"970" }, + .{ "PPC970MP", &Target.powerpc.cpu.@"970" }, }; fn line_hook(self: *PowerpcCpuinfoImpl, key: []const u8, value: []const u8) !bool { -- 2.54.0 From 603798d409a963ccdf5ab2273a6a02ef04d0952b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Sep 2026 02:27:38 +0200 Subject: [PATCH 16/24] std.zig.system.linux: some corrections to riscv CPU model list --- lib/std/zig/system/linux.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index b1375aa17aad7f77cc986c36de5ef817ba53c35c..a1c1eb5137b9d1db37717265823ad544a60e5933 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -71,10 +71,11 @@ const RiscvCpuinfoImpl = struct { const cpu_names = .{ .{ "andestech,ax45mp", &Target.riscv.cpu.andes_ax45 }, + .{ "sifive,bullet0", &Target.riscv.cpu.sifive_u74 }, .{ "sifive,p550", &Target.riscv.cpu.sifive_p550 }, .{ "sifive,u54", &Target.riscv.cpu.sifive_u54 }, .{ "sifive,u54-mc", &Target.riscv.cpu.sifive_u54 }, - .{ "sifive,u7", &Target.riscv.cpu.sifive_7_series }, + .{ "sifive,u7", &Target.riscv.cpu.sifive_u74 }, .{ "sifive,u74", &Target.riscv.cpu.sifive_u74 }, .{ "sifive,u74-mc", &Target.riscv.cpu.sifive_u74 }, .{ "sifive,x280", &Target.riscv.cpu.sifive_x280 }, -- 2.54.0 From a098e693f0498cf87e9eac488ae715915de2fb3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Sep 2026 02:21:57 +0200 Subject: [PATCH 17/24] std.zig.system.linux: some corrections to sparc CPU model list --- lib/std/zig/system/linux.zig | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index a1c1eb5137b9d1db37717265823ad544a60e5933..ab6a6b02f8b05d4fa49f2de571934047c850aa8f 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -13,23 +13,32 @@ const SparcCpuinfoImpl = struct { model: ?*const Target.Cpu.Model = null, const cpu_names = .{ - .{ "SuperSparc", &Target.sparc.cpu.supersparc }, - .{ "HyperSparc", &Target.sparc.cpu.hypersparc }, - .{ "SpitFire", &Target.sparc.cpu.ultrasparc }, .{ "BlackBird", &Target.sparc.cpu.ultrasparc }, - .{ "Sabre", &Target.sparc.cpu.ultrasparc }, - .{ "Hummingbird", &Target.sparc.cpu.ultrasparc }, .{ "Cheetah", &Target.sparc.cpu.ultrasparc3 }, - .{ "Jalapeno", &Target.sparc.cpu.ultrasparc3 }, + .{ "Hummingbird", &Target.sparc.cpu.ultrasparc }, + .{ "HyperSparc", &Target.sparc.cpu.hypersparc }, .{ "Jaguar", &Target.sparc.cpu.ultrasparc3 }, + .{ "Jalapeno", &Target.sparc.cpu.ultrasparc3 }, + .{ "LEON", &Target.sparc.cpu.leon3 }, + .{ "MB86904", &Target.sparc.cpu.v8 }, + .{ "MB86907", &Target.sparc.cpu.v8 }, + .{ "MicroSparc II", &Target.sparc.cpu.v8 }, + .{ "MicroSparc", &Target.sparc.cpu.v8 }, .{ "Panther", &Target.sparc.cpu.ultrasparc3 }, + .{ "Sabre", &Target.sparc.cpu.ultrasparc }, .{ "Serrano", &Target.sparc.cpu.ultrasparc3 }, + .{ "SPARC-M6", &Target.sparc.cpu.niagara4 }, + .{ "SPARC-M7", &Target.sparc.cpu.niagara4 }, + .{ "SPARC-M8", &Target.sparc.cpu.niagara4 }, + .{ "SPARC-SN", &Target.sparc.cpu.niagara4 }, + .{ "SPARC64-X", &Target.sparc.cpu.ultrasparc3 }, + .{ "SpitFire", &Target.sparc.cpu.ultrasparc }, + .{ "SuperSparc", &Target.sparc.cpu.supersparc }, .{ "UltraSparc T1", &Target.sparc.cpu.niagara }, .{ "UltraSparc T2", &Target.sparc.cpu.niagara2 }, .{ "UltraSparc T3", &Target.sparc.cpu.niagara3 }, .{ "UltraSparc T4", &Target.sparc.cpu.niagara4 }, .{ "UltraSparc T5", &Target.sparc.cpu.niagara4 }, - .{ "LEON", &Target.sparc.cpu.leon3 }, }; fn line_hook(self: *SparcCpuinfoImpl, key: []const u8, value: []const u8) !bool { -- 2.54.0 From de64c05f0baab5e9c0ec7c72d8ba13271dbc2a30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Sep 2026 10:24:43 +0200 Subject: [PATCH 18/24] std.zig.system.linux: refactor Also fix a couple minor edge case bugs. --- lib/std/zig/system/linux.zig | 1188 ++++++++++++++++++---------------- 1 file changed, 637 insertions(+), 551 deletions(-) diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index ab6a6b02f8b05d4fa49f2de571934047c850aa8f..01f09b60b7a69e3165820c616f7e6957adc266a9 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -9,427 +9,8 @@ const testing = std.testing; const Target = std.Target; const assert = std.debug.assert; -const SparcCpuinfoImpl = struct { - model: ?*const Target.Cpu.Model = null, - - const cpu_names = .{ - .{ "BlackBird", &Target.sparc.cpu.ultrasparc }, - .{ "Cheetah", &Target.sparc.cpu.ultrasparc3 }, - .{ "Hummingbird", &Target.sparc.cpu.ultrasparc }, - .{ "HyperSparc", &Target.sparc.cpu.hypersparc }, - .{ "Jaguar", &Target.sparc.cpu.ultrasparc3 }, - .{ "Jalapeno", &Target.sparc.cpu.ultrasparc3 }, - .{ "LEON", &Target.sparc.cpu.leon3 }, - .{ "MB86904", &Target.sparc.cpu.v8 }, - .{ "MB86907", &Target.sparc.cpu.v8 }, - .{ "MicroSparc II", &Target.sparc.cpu.v8 }, - .{ "MicroSparc", &Target.sparc.cpu.v8 }, - .{ "Panther", &Target.sparc.cpu.ultrasparc3 }, - .{ "Sabre", &Target.sparc.cpu.ultrasparc }, - .{ "Serrano", &Target.sparc.cpu.ultrasparc3 }, - .{ "SPARC-M6", &Target.sparc.cpu.niagara4 }, - .{ "SPARC-M7", &Target.sparc.cpu.niagara4 }, - .{ "SPARC-M8", &Target.sparc.cpu.niagara4 }, - .{ "SPARC-SN", &Target.sparc.cpu.niagara4 }, - .{ "SPARC64-X", &Target.sparc.cpu.ultrasparc3 }, - .{ "SpitFire", &Target.sparc.cpu.ultrasparc }, - .{ "SuperSparc", &Target.sparc.cpu.supersparc }, - .{ "UltraSparc T1", &Target.sparc.cpu.niagara }, - .{ "UltraSparc T2", &Target.sparc.cpu.niagara2 }, - .{ "UltraSparc T3", &Target.sparc.cpu.niagara3 }, - .{ "UltraSparc T4", &Target.sparc.cpu.niagara4 }, - .{ "UltraSparc T5", &Target.sparc.cpu.niagara4 }, - }; - - fn line_hook(self: *SparcCpuinfoImpl, key: []const u8, value: []const u8) !bool { - if (mem.eql(u8, key, "cpu")) { - inline for (cpu_names) |pair| { - if (mem.findPos(u8, value, 0, pair[0]) != null) { - self.model = pair[1]; - break; - } - } - } - - return true; - } - - fn finalize(self: *const SparcCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu { - const model = self.model orelse return null; - return Target.Cpu{ - .arch = arch, - .model = model, - .features = model.features, - }; - } -}; - -const SparcCpuinfoParser = CpuinfoParser(SparcCpuinfoImpl); - -test "cpuinfo: SPARC" { - try testParser(SparcCpuinfoParser, .sparc64, &Target.sparc.cpu.niagara2, - \\cpu : UltraSparc T2 (Niagara2) - \\fpu : UltraSparc T2 integrated FPU - \\pmu : niagara2 - \\type : sun4v - ); -} - -const RiscvCpuinfoImpl = struct { - model: ?*const Target.Cpu.Model = null, - - const cpu_names = .{ - .{ "andestech,ax45mp", &Target.riscv.cpu.andes_ax45 }, - .{ "sifive,bullet0", &Target.riscv.cpu.sifive_u74 }, - .{ "sifive,p550", &Target.riscv.cpu.sifive_p550 }, - .{ "sifive,u54", &Target.riscv.cpu.sifive_u54 }, - .{ "sifive,u54-mc", &Target.riscv.cpu.sifive_u54 }, - .{ "sifive,u7", &Target.riscv.cpu.sifive_u74 }, - .{ "sifive,u74", &Target.riscv.cpu.sifive_u74 }, - .{ "sifive,u74-mc", &Target.riscv.cpu.sifive_u74 }, - .{ "sifive,x280", &Target.riscv.cpu.sifive_x280 }, - .{ "spacemit,x60", &Target.riscv.cpu.spacemit_x60 }, - .{ "spacemit,x100", &Target.riscv.cpu.spacemit_x100 }, - }; - - fn line_hook(self: *RiscvCpuinfoImpl, key: []const u8, value: []const u8) !bool { - if (mem.eql(u8, key, "uarch")) { - inline for (cpu_names) |pair| { - if (mem.eql(u8, value, pair[0])) { - self.model = pair[1]; - break; - } - } - return false; - } - - return true; - } - - fn finalize(self: *const RiscvCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu { - const model = self.model orelse return null; - return Target.Cpu{ - .arch = arch, - .model = model, - .features = model.features, - }; - } -}; - -const RiscvCpuinfoParser = CpuinfoParser(RiscvCpuinfoImpl); - -test "cpuinfo: RISC-V" { - try testParser(RiscvCpuinfoParser, .riscv64, &Target.riscv.cpu.sifive_u74, - \\processor : 0 - \\hart : 1 - \\isa : rv64imafdc - \\mmu : sv39 - \\isa-ext : - \\uarch : sifive,u74-mc - ); -} - -const PowerpcCpuinfoImpl = struct { - model: ?*const Target.Cpu.Model = null, - - const cpu_names = .{ - .{ "604e", &Target.powerpc.cpu.@"604e" }, - .{ "604", &Target.powerpc.cpu.@"604" }, - .{ "7400", &Target.powerpc.cpu.@"7400" }, - .{ "7410", &Target.powerpc.cpu.@"7400" }, - .{ "7447/7457", &Target.powerpc.cpu.@"7450" }, - .{ "7447A", &Target.powerpc.cpu.@"7450" }, - .{ "7455", &Target.powerpc.cpu.@"7450" }, - .{ "POWER5", &Target.powerpc.cpu.g5 }, - .{ "POWER6", &Target.powerpc.cpu.pwr6 }, - .{ "POWER7", &Target.powerpc.cpu.pwr7 }, - .{ "POWER8E", &Target.powerpc.cpu.pwr8 }, - .{ "POWER8NVL", &Target.powerpc.cpu.pwr8 }, - .{ "POWER8", &Target.powerpc.cpu.pwr8 }, - .{ "POWER9", &Target.powerpc.cpu.pwr9 }, - .{ "POWER10", &Target.powerpc.cpu.pwr10 }, - .{ "Power11", &Target.powerpc.cpu.pwr11 }, - .{ "PPC970FX", &Target.powerpc.cpu.@"970" }, - .{ "PPC970MP", &Target.powerpc.cpu.@"970" }, - }; - - fn line_hook(self: *PowerpcCpuinfoImpl, key: []const u8, value: []const u8) !bool { - if (mem.eql(u8, key, "cpu")) { - // The model name is often followed by a comma or space and extra - // info. - inline for (cpu_names) |pair| { - const end_index = mem.findAny(u8, value, ", ") orelse value.len; - if (mem.eql(u8, value[0..end_index], pair[0])) { - self.model = pair[1]; - break; - } - } - - // Stop the detection once we've seen the first core. - return false; - } - - return true; - } - - fn finalize(self: *const PowerpcCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu { - const model = self.model orelse return null; - return Target.Cpu{ - .arch = arch, - .model = model, - .features = model.features, - }; - } -}; - -const PowerpcCpuinfoParser = CpuinfoParser(PowerpcCpuinfoImpl); - -test "cpuinfo: PowerPC" { - try testParser(PowerpcCpuinfoParser, .powerpc, &Target.powerpc.cpu.@"970", - \\processor : 0 - \\cpu : PPC970MP, altivec supported - \\clock : 1250.000000MHz - \\revision : 1.1 (pvr 0044 0101) - ); - try testParser(PowerpcCpuinfoParser, .powerpc64le, &Target.powerpc.cpu.pwr8, - \\processor : 0 - \\cpu : POWER8 (raw), altivec supported - \\clock : 2926.000000MHz - \\revision : 2.0 (pvr 004d 0200) - ); -} - -const S390xCpuinfoImpl = struct { - model: ?*const Target.Cpu.Model = null, - - const cpu_names = .{ - // z900: 2064, 2066 - // z990: 2084, 2086 - // z9: 2094, 2096 - - .{ "2097", &Target.s390x.cpu.z10 }, - .{ "2098", &Target.s390x.cpu.z10 }, - .{ "2817", &Target.s390x.cpu.z196 }, - .{ "2818", &Target.s390x.cpu.z196 }, - .{ "2827", &Target.s390x.cpu.zEC12 }, - .{ "2828", &Target.s390x.cpu.zEC12 }, - .{ "2964", &Target.s390x.cpu.z13 }, - .{ "2965", &Target.s390x.cpu.z13 }, - .{ "3906", &Target.s390x.cpu.z14 }, - .{ "3907", &Target.s390x.cpu.z14 }, - .{ "8561", &Target.s390x.cpu.z15 }, - .{ "8562", &Target.s390x.cpu.z15 }, - .{ "3931", &Target.s390x.cpu.z16 }, - .{ "3932", &Target.s390x.cpu.z16 }, - .{ "9175", &Target.s390x.cpu.z17 }, - .{ "9176", &Target.s390x.cpu.z17 }, - }; - - fn line_hook(self: *S390xCpuinfoImpl, key: []const u8, value: []const u8) !bool { - if (mem.eql(u8, key, "machine")) { - inline for (cpu_names) |pair| { - if (mem.eql(u8, value, pair[0])) { - self.model = pair[1]; - break; - } - } - - return false; - } - - return true; - } - - fn finalize(self: *const S390xCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu { - const model = self.model orelse return null; - return Target.Cpu{ - .arch = arch, - .model = model, - .features = model.features, - }; - } -}; - -const S390xCpuinfoParser = CpuinfoParser(S390xCpuinfoImpl); - -test "cpuinfo: S390x" { - try testParser(S390xCpuinfoParser, .s390x, &Target.s390x.cpu.z15, - \\physical id : 5 - \\core id : 5 - \\book id : 5 - \\drawer id : 5 - \\dedicated : 0 - \\address : 5 - \\siblings : 1 - \\cpu cores : 1 - \\version : FF - \\identification : 09DD98 - \\machine : 8561 - \\cpu MHz dynamic : 5200 - \\cpu MHz static : 5200 - ); -} - -const ArmCpuinfoImpl = struct { - const num_cores = 4; - - cores: [num_cores]CoreInfo = undefined, - core_no: usize = 0, - have_fields: usize = 0, - - const CoreInfo = struct { - architecture: u8 = 0, - implementer: u8 = 0, - variant: u8 = 0, - part: u16 = 0, - is_really_v6: bool = false, - }; - - const cpu_models = @import("arm.zig").cpu_models; - - fn addOne(self: *ArmCpuinfoImpl) void { - if (self.have_fields == 4 and self.core_no < num_cores) { - if (self.core_no > 0) { - // Deduplicate the core info. - for (self.cores[0..self.core_no]) |it| { - if (std.meta.eql(it, self.cores[self.core_no])) - return; - } - } - self.core_no += 1; - } - } - - fn line_hook(self: *ArmCpuinfoImpl, key: []const u8, value: []const u8) !bool { - const info = &self.cores[self.core_no]; - - if (mem.eql(u8, key, "processor")) { - // Handle both old-style and new-style cpuinfo formats. - // The former prints a sequence of "processor: N" lines for each - // core and then the info for the core that's executing this code(!) - // while the latter prints the infos for each core right after the - // "processor" key. - self.have_fields = 0; - self.cores[self.core_no] = .{}; - } else if (mem.eql(u8, key, "CPU implementer")) { - info.implementer = try fmt.parseInt(u8, value, 0); - self.have_fields += 1; - } else if (mem.eql(u8, key, "CPU architecture")) { - // "AArch64" on older kernels. - info.architecture = if (mem.startsWith(u8, value, "AArch64")) - 8 - else - try fmt.parseInt(u8, value, 0); - self.have_fields += 1; - } else if (mem.eql(u8, key, "CPU variant")) { - info.variant = try fmt.parseInt(u8, value, 0); - self.have_fields += 1; - } else if (mem.eql(u8, key, "CPU part")) { - info.part = try fmt.parseInt(u16, value, 0); - self.have_fields += 1; - } else if (mem.eql(u8, key, "model name")) { - // ARMv6 cores report "CPU architecture" equal to 7. - if (mem.find(u8, value, "(v6l)")) |_| { - info.is_really_v6 = true; - } - } else if (mem.eql(u8, key, "CPU revision")) { - // This field is always the last one for each CPU section. - _ = self.addOne(); - } - - return true; - } - - fn finalize(self: *ArmCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu { - if (self.core_no == 0) return null; - - const is_64bit = switch (arch) { - .aarch64, .aarch64_be => true, - else => false, - }; - - var known_models: [num_cores]?*const Target.Cpu.Model = undefined; - for (self.cores[0..self.core_no], 0..) |core, i| { - known_models[i] = cpu_models.isKnown(.{ - .architecture = core.architecture, - .implementer = core.implementer, - .variant = core.variant, - .part = core.part, - }, is_64bit); - } - - // XXX We pick the first core on big.LITTLE systems, hopefully the - // LITTLE one. - const model = known_models[0] orelse return null; - return Target.Cpu{ - .arch = arch, - .model = model, - .features = model.features, - }; - } -}; - -const ArmCpuinfoParser = CpuinfoParser(ArmCpuinfoImpl); - -test "cpuinfo: ARM" { - try testParser(ArmCpuinfoParser, .arm, &Target.arm.cpu.arm1176jz_s, - \\processor : 0 - \\model name : ARMv6-compatible processor rev 7 (v6l) - \\BogoMIPS : 997.08 - \\Features : half thumb fastmult vfp edsp java tls - \\CPU implementer : 0x41 - \\CPU architecture: 7 - \\CPU variant : 0x0 - \\CPU part : 0xb76 - \\CPU revision : 7 - ); - try testParser(ArmCpuinfoParser, .arm, &Target.arm.cpu.cortex_a7, - \\processor : 0 - \\model name : ARMv7 Processor rev 3 (v7l) - \\BogoMIPS : 18.00 - \\Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae - \\CPU implementer : 0x41 - \\CPU architecture: 7 - \\CPU variant : 0x0 - \\CPU part : 0xc07 - \\CPU revision : 3 - \\ - \\processor : 4 - \\model name : ARMv7 Processor rev 3 (v7l) - \\BogoMIPS : 90.00 - \\Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae - \\CPU implementer : 0x41 - \\CPU architecture: 7 - \\CPU variant : 0x2 - \\CPU part : 0xc0f - \\CPU revision : 3 - ); - try testParser(ArmCpuinfoParser, .aarch64, &Target.aarch64.cpu.cortex_a72, - \\processor : 0 - \\BogoMIPS : 108.00 - \\Features : fp asimd evtstrm crc32 cpuid - \\CPU implementer : 0x41 - \\CPU architecture: 8 - \\CPU variant : 0x0 - \\CPU part : 0xd08 - \\CPU revision : 3 - ); -} - -fn testParser( - parser: anytype, - arch: Target.Cpu.Arch, - expected_model: *const Target.Cpu.Model, - input: []const u8, -) !void { - var r: Io.Reader = .fixed(input); - const result = try parser.parse(arch, &r); - try testing.expectEqual(expected_model, result.?.model); - try testing.expect(expected_model.features.eql(result.?.features)); -} - // The generic implementation of a /proc/cpuinfo parser. -// For every line it invokes the line_hook method with the key and value strings +// For every line it invokes the lineHook method with the key and value strings // as first and second parameters. Returning false from the hook function stops // the iteration without raising an error. // When all the lines have been analyzed the finalize method is called. @@ -441,24 +22,360 @@ fn CpuinfoParser(comptime impl: anytype) type { const colon_pos = mem.findScalar(u8, line, ':') orelse continue; const key = mem.trimEnd(u8, line[0..colon_pos], " \t"); const value = mem.trimStart(u8, line[colon_pos + 1 ..], " \t"); - if (!try obj.line_hook(key, value)) break; + if (!try obj.lineHook(key, value)) break; } return obj.finalize(arch); } }; } +fn testParser( + parser: anytype, + arch: Target.Cpu.Arch, + expected_model: *const Target.Cpu.Model, + input: []const u8, +) !void { + var r: Io.Reader = .fixed(input); + const result = try parser.parse(arch, &r); + try testing.expectEqual(expected_model, result.?.model); + try testing.expect(expected_model.features.eql(result.?.features)); +} + const aarch64 = struct { inline fn mrs(comptime feat_reg: []const u8) u64 { return asm ("mrs %[ret], " ++ feat_reg : [ret] "=r" (-> u64), ); } + + pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch) ?Target.Cpu { + const registers = [12]u64{ + mrs("MIDR_EL1"), + mrs("ID_AA64PFR0_EL1"), + mrs("ID_AA64PFR1_EL1"), + mrs("ID_AA64DFR0_EL1"), + mrs("ID_AA64DFR1_EL1"), + mrs("ID_AA64AFR0_EL1"), + mrs("ID_AA64AFR1_EL1"), + mrs("ID_AA64ISAR0_EL1"), + mrs("ID_AA64ISAR1_EL1"), + mrs("ID_AA64MMFR0_EL1"), + mrs("ID_AA64MMFR1_EL1"), + mrs("ID_AA64MMFR2_EL1"), + }; + + return @import("arm.zig").aarch64.detectNativeCpuAndFeatures(arch, registers); + } +}; + +const arm = struct { + const cpuinfo = struct { + const Impl = struct { + const num_cores = 4; + + cores: [num_cores]CoreInfo = undefined, + core_no: usize = 0, + have_fields: usize = 0, + + const CoreInfo = struct { + architecture: u8 = 0, + implementer: u8 = 0, + variant: u8 = 0, + part: u16 = 0, + is_really_v6: bool = false, + }; + + const cpu_models = @import("arm.zig").cpu_models; + + fn addOne(self: *Impl) void { + if (self.have_fields == 4 and self.core_no < num_cores) { + if (self.core_no > 0) { + // Deduplicate the core info. + for (self.cores[0..self.core_no]) |it| { + if (std.meta.eql(it, self.cores[self.core_no])) + return; + } + } + self.core_no += 1; + } + } + + fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool { + const info = &self.cores[self.core_no]; + + if (mem.eql(u8, key, "processor")) { + // Handle both old-style and new-style cpuinfo formats. + // The former prints a sequence of "processor: N" lines for each + // core and then the info for the core that's executing this code(!) + // while the latter prints the infos for each core right after the + // "processor" key. + self.have_fields = 0; + self.cores[self.core_no] = .{}; + } else if (mem.eql(u8, key, "CPU implementer")) { + info.implementer = try fmt.parseInt(u8, value, 0); + self.have_fields += 1; + } else if (mem.eql(u8, key, "CPU architecture")) { + // "AArch64" on older kernels. + info.architecture = if (mem.startsWith(u8, value, "AArch64")) + 8 + else + try fmt.parseInt(u8, value, 0); + self.have_fields += 1; + } else if (mem.eql(u8, key, "CPU variant")) { + info.variant = try fmt.parseInt(u8, value, 0); + self.have_fields += 1; + } else if (mem.eql(u8, key, "CPU part")) { + info.part = try fmt.parseInt(u16, value, 0); + self.have_fields += 1; + } else if (mem.eql(u8, key, "model name")) { + // ARMv6 cores report "CPU architecture" equal to 7. + if (mem.find(u8, value, "(v6l)")) |_| { + info.is_really_v6 = true; + } + } else if (mem.eql(u8, key, "CPU revision")) { + // This field is always the last one for each CPU section. + _ = self.addOne(); + } + + return true; + } + + fn finalize(self: *Impl, arch: Target.Cpu.Arch) ?Target.Cpu { + if (self.core_no == 0) return null; + + const is_64bit = switch (arch) { + .aarch64, .aarch64_be => true, + else => false, + }; + + var known_models: [num_cores]?*const Target.Cpu.Model = undefined; + for (self.cores[0..self.core_no], 0..) |core, i| { + known_models[i] = cpu_models.isKnown(.{ + .architecture = core.architecture, + .implementer = core.implementer, + .variant = core.variant, + .part = core.part, + }, is_64bit); + } + + // XXX We pick the first core on big.LITTLE systems, hopefully the + // LITTLE one. + const model = known_models[0] orelse return null; + return Target.Cpu{ + .arch = arch, + .model = model, + .features = model.features, + }; + } + }; + + const Parser = CpuinfoParser(Impl); + }; + + test cpuinfo { + try testParser(cpuinfo.Parser, .arm, &Target.arm.cpu.arm1176jz_s, + \\processor : 0 + \\model name : ARMv6-compatible processor rev 7 (v6l) + \\BogoMIPS : 997.08 + \\Features : half thumb fastmult vfp edsp java tls + \\CPU implementer : 0x41 + \\CPU architecture: 7 + \\CPU variant : 0x0 + \\CPU part : 0xb76 + \\CPU revision : 7 + ); + try testParser(cpuinfo.Parser, .arm, &Target.arm.cpu.cortex_a7, + \\processor : 0 + \\model name : ARMv7 Processor rev 3 (v7l) + \\BogoMIPS : 18.00 + \\Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae + \\CPU implementer : 0x41 + \\CPU architecture: 7 + \\CPU variant : 0x0 + \\CPU part : 0xc07 + \\CPU revision : 3 + \\ + \\processor : 4 + \\model name : ARMv7 Processor rev 3 (v7l) + \\BogoMIPS : 90.00 + \\Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae + \\CPU implementer : 0x41 + \\CPU architecture: 7 + \\CPU variant : 0x2 + \\CPU part : 0xc0f + \\CPU revision : 3 + ); + try testParser(cpuinfo.Parser, .aarch64, &Target.aarch64.cpu.cortex_a72, + \\processor : 0 + \\BogoMIPS : 108.00 + \\Features : fp asimd evtstrm crc32 cpuid + \\CPU implementer : 0x41 + \\CPU architecture: 8 + \\CPU variant : 0x0 + \\CPU part : 0xd08 + \\CPU revision : 3 + ); + } + + pub fn detectNativeCpu(io: Io, arch: Target.Cpu.Arch) ?Target.Cpu { + var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch return null; + defer file.close(io); + + var buffer: [4096]u8 = undefined; + var file_reader = file.reader(io, &buffer); + + var cpu = (cpuinfo.Parser.parse(arch, &file_reader.interface) catch null) orelse return null; + + cpu.features.populateDependencies(cpu.arch.allFeaturesList()); + + return cpu; + } +}; + +const powerpc = struct { + const cpuinfo = struct { + const Impl = struct { + model: ?*const Target.Cpu.Model = null, + + const cpu_names = .{ + .{ "604e", &Target.powerpc.cpu.@"604e" }, + .{ "604", &Target.powerpc.cpu.@"604" }, + .{ "7400", &Target.powerpc.cpu.@"7400" }, + .{ "7410", &Target.powerpc.cpu.@"7400" }, + .{ "7447/7457", &Target.powerpc.cpu.@"7450" }, + .{ "7447A", &Target.powerpc.cpu.@"7450" }, + .{ "7455", &Target.powerpc.cpu.@"7450" }, + .{ "POWER5", &Target.powerpc.cpu.g5 }, + .{ "POWER6", &Target.powerpc.cpu.pwr6 }, + .{ "POWER7", &Target.powerpc.cpu.pwr7 }, + .{ "POWER8E", &Target.powerpc.cpu.pwr8 }, + .{ "POWER8NVL", &Target.powerpc.cpu.pwr8 }, + .{ "POWER8", &Target.powerpc.cpu.pwr8 }, + .{ "POWER9", &Target.powerpc.cpu.pwr9 }, + .{ "POWER10", &Target.powerpc.cpu.pwr10 }, + .{ "Power11", &Target.powerpc.cpu.pwr11 }, + .{ "PPC970FX", &Target.powerpc.cpu.@"970" }, + .{ "PPC970MP", &Target.powerpc.cpu.@"970" }, + }; + + fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool { + if (mem.eql(u8, key, "cpu")) { + // The model name is often followed by a comma or space and extra + // info. + inline for (cpu_names) |pair| { + const end_index = mem.findAny(u8, value, ", ") orelse value.len; + if (mem.eql(u8, value[0..end_index], pair[0])) { + self.model = pair[1]; + break; + } + } + + // Stop the detection once we've seen the first core. + return false; + } + + return true; + } + + fn finalize(self: *const Impl, arch: Target.Cpu.Arch) ?Target.Cpu { + const model = self.model orelse return null; + return Target.Cpu{ + .arch = arch, + .model = model, + .features = model.features, + }; + } + }; + + const Parser = CpuinfoParser(Impl); + }; + + test cpuinfo { + try testParser(cpuinfo.Parser, .powerpc, &Target.powerpc.cpu.@"970", + \\processor : 0 + \\cpu : PPC970MP, altivec supported + \\clock : 1250.000000MHz + \\revision : 1.1 (pvr 0044 0101) + ); + try testParser(cpuinfo.Parser, .powerpc64le, &Target.powerpc.cpu.pwr8, + \\processor : 0 + \\cpu : POWER8 (raw), altivec supported + \\clock : 2926.000000MHz + \\revision : 2.0 (pvr 004d 0200) + ); + } + + pub fn detectNativeCpu(io: Io, arch: Target.Cpu.Arch) ?Target.Cpu { + var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch return null; + defer file.close(io); + + var buffer: [4096]u8 = undefined; + var file_reader = file.reader(io, &buffer); + + var cpu = (cpuinfo.Parser.parse(arch, &file_reader.interface) catch null) orelse return null; + + cpu.features.populateDependencies(cpu.arch.allFeaturesList()); + + return cpu; + } }; const riscv = struct { - const linux = std.os.linux; - const RISCV_HWPROBE = linux.RISCV_HWPROBE; + const cpuinfo = struct { + const Impl = struct { + model: ?*const Target.Cpu.Model = null, + + const cpu_names = .{ + .{ "andestech,ax45mp", &Target.riscv.cpu.andes_ax45 }, + .{ "sifive,bullet0", &Target.riscv.cpu.sifive_u74 }, + .{ "sifive,p550", &Target.riscv.cpu.sifive_p550 }, + .{ "sifive,u54", &Target.riscv.cpu.sifive_u54 }, + .{ "sifive,u54-mc", &Target.riscv.cpu.sifive_u54 }, + .{ "sifive,u7", &Target.riscv.cpu.sifive_u74 }, + .{ "sifive,u74", &Target.riscv.cpu.sifive_u74 }, + .{ "sifive,u74-mc", &Target.riscv.cpu.sifive_u74 }, + .{ "sifive,x280", &Target.riscv.cpu.sifive_x280 }, + .{ "spacemit,x60", &Target.riscv.cpu.spacemit_x60 }, + .{ "spacemit,x100", &Target.riscv.cpu.spacemit_x100 }, + }; + + fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool { + if (mem.eql(u8, key, "uarch")) { + inline for (cpu_names) |pair| { + if (mem.eql(u8, value, pair[0])) { + self.model = pair[1]; + break; + } + } + return false; + } + + return true; + } + + fn finalize(self: *const Impl, arch: Target.Cpu.Arch) ?Target.Cpu { + const model = self.model orelse return null; + return Target.Cpu{ + .arch = arch, + .model = model, + .features = model.features, + }; + } + }; + + const Parser = CpuinfoParser(Impl); + }; + + test cpuinfo { + try testParser(cpuinfo.Parser, .riscv64, &Target.riscv.cpu.sifive_u74, + \\processor : 0 + \\hart : 1 + \\isa : rv64imafdc + \\mmu : sv39 + \\isa-ext : + \\uarch : sifive,u74-mc + ); + } fn setFeature(cpu: *Target.Cpu, feature: Target.riscv.Feature, enabled: bool) void { const idx = @as(Target.Cpu.Feature.Set.Index, @backingInt(feature)); @@ -470,8 +387,18 @@ const riscv = struct { return (value & mask) == mask; } - pub fn detectCpuFeatures(cpu: *Target.Cpu) void { - var probes = [_]linux.riscv_hwprobe{ + pub fn detectNativeCpuAndFeatures(io: Io, arch: Target.Cpu.Arch) ?Target.Cpu { + var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch return null; + defer file.close(io); + + var buffer: [4096]u8 = undefined; + var file_reader = file.reader(io, &buffer); + + const maybe_cpu = cpuinfo.Parser.parse(arch, &file_reader.interface) catch null; + + const RISCV_HWPROBE = std.os.linux.RISCV_HWPROBE; + + var probes = [_]std.os.linux.riscv_hwprobe{ .{ .key = RISCV_HWPROBE.KEY.BASE_BEHAVIOR, .value = 0 }, .{ .key = RISCV_HWPROBE.KEY.IMA_EXT_0, .value = 0 }, .{ .key = RISCV_HWPROBE.KEY.MISALIGNED_SCALAR_PERF, .value = 0 }, @@ -481,9 +408,25 @@ const riscv = struct { .{ .key = RISCV_HWPROBE.KEY.IMA_EXT_1, .value = 0 }, }; - const rc = linux.sys_riscv_hwprobe(&probes, probes.len, 0, null, 0); - if (linux.errno(rc) == .NOSYS) - return; + const rc = std.os.linux.sys_riscv_hwprobe(&probes, probes.len, 0, null, 0); + if (std.os.linux.errno(rc) == .NOSYS) { + // Even if SYS_riscv_hwprobe is unavailable, we should still return + // the model if we managed to detect it. + var cpu = maybe_cpu orelse return null; + + cpu.features.populateDependencies(cpu.arch.allFeaturesList()); + + return cpu; + } + + var cpu: Target.Cpu = maybe_cpu orelse cpu: { + const model = Target.Cpu.Model.generic(arch); + break :cpu .{ + .arch = arch, + .model = model, + .features = model.features, + }; + }; var ima_support = false; for (probes) |probe| { @@ -493,153 +436,296 @@ const riscv = struct { -1 => continue, // The running kernel doesn't know this key. RISCV_HWPROBE.KEY.BASE_BEHAVIOR => { ima_support = set(value, RISCV_HWPROBE.BASE_BEHAVIOR_IMA); - setFeature(cpu, Target.riscv.Feature.i, ima_support); - setFeature(cpu, Target.riscv.Feature.m, ima_support); - setFeature(cpu, Target.riscv.Feature.a, ima_support); + setFeature(&cpu, Target.riscv.Feature.i, ima_support); + setFeature(&cpu, Target.riscv.Feature.m, ima_support); + setFeature(&cpu, Target.riscv.Feature.a, ima_support); }, RISCV_HWPROBE.KEY.IMA_EXT_0 => { // https://bugzilla.kernel.org/show_bug.cgi?id=221874 const fd_support = set(value, RISCV_HWPROBE.IMA_EXT_0.IMA_FD); - setFeature(cpu, .f, ima_support and fd_support); - setFeature(cpu, .d, ima_support and fd_support); - setFeature(cpu, .c, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.IMA_C)); - setFeature(cpu, .v, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.IMA_V)); - setFeature(cpu, .zba, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBA)); - setFeature(cpu, .zbb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBB)); - setFeature(cpu, .zbs, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBS)); - setFeature(cpu, .zicboz, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOZ)); - setFeature(cpu, .zbc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBC)); - setFeature(cpu, .zbkb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKB)); - setFeature(cpu, .zbkc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKC)); - setFeature(cpu, .zbkx, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKX)); - setFeature(cpu, .zknd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKND)); - setFeature(cpu, .zkne, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKNE)); - setFeature(cpu, .zknh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKNH)); - setFeature(cpu, .zksed, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKSED)); - setFeature(cpu, .zksh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKSH)); - setFeature(cpu, .zkt, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKT)); - setFeature(cpu, .zvbb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVBB)); - setFeature(cpu, .zvbc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVBC)); - setFeature(cpu, .zvkb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKB)); - setFeature(cpu, .zvkg, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKG)); - setFeature(cpu, .zvkned, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNED)); - setFeature(cpu, .zvknha, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNHA)); - setFeature(cpu, .zvknhb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNHB)); - setFeature(cpu, .zvksed, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKSED)); - setFeature(cpu, .zvksh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKSH)); - setFeature(cpu, .zvkt, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKT)); - setFeature(cpu, .zfh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFH)); - setFeature(cpu, .zfhmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFHMIN)); - setFeature(cpu, .zihintntl, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHINTNTL)); - setFeature(cpu, .zvfh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFH)); - setFeature(cpu, .zvfhmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFHMIN)); - setFeature(cpu, .zfa, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFA)); - setFeature(cpu, .ztso, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZTSO)); - setFeature(cpu, .zacas, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZACAS)); - setFeature(cpu, .zicntr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICNTR)); - setFeature(cpu, .zicond, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICOND)); - setFeature(cpu, .zihintpause, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHINTPAUSE)); - setFeature(cpu, .zihpm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHPM)); - setFeature(cpu, .zve32x, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE32X)); - setFeature(cpu, .zve32f, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE32F)); - setFeature(cpu, .zve64x, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64X)); - setFeature(cpu, .zve64f, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64F)); - setFeature(cpu, .zve64d, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64D)); - setFeature(cpu, .zimop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIMOP)); - setFeature(cpu, .zca, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCA)); - setFeature(cpu, .zcb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCB)); - setFeature(cpu, .zcd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCD)); - setFeature(cpu, .zcf, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCF)); - setFeature(cpu, .zcmop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCMOP)); - setFeature(cpu, .zawrs, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZAWRS)); - setFeature(cpu, .supm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_SUPM)); - setFeature(cpu, .zicntr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICNTR)); - setFeature(cpu, .zihpm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHPM)); - setFeature(cpu, .zfbfmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFBFMIN)); - setFeature(cpu, .zvfbfmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFBFMIN)); - setFeature(cpu, .zvfbfwma, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFBFWMA)); - setFeature(cpu, .zicbom, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOM)); - setFeature(cpu, .zaamo, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZAAMO)); - setFeature(cpu, .zalrsc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZALRSC)); - setFeature(cpu, .zabha, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZABHA)); - setFeature(cpu, .zalasr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZALASR)); - setFeature(cpu, .zicbop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOP)); - setFeature(cpu, .zilsd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZILSD)); - setFeature(cpu, .zclsd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCLSD)); - setFeature(cpu, .experimental_zicfilp, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICFILP)); + setFeature(&cpu, .f, ima_support and fd_support); + setFeature(&cpu, .d, ima_support and fd_support); + setFeature(&cpu, .c, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.IMA_C)); + setFeature(&cpu, .v, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.IMA_V)); + setFeature(&cpu, .zba, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBA)); + setFeature(&cpu, .zbb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBB)); + setFeature(&cpu, .zbs, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBS)); + setFeature(&cpu, .zicboz, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOZ)); + setFeature(&cpu, .zbc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBC)); + setFeature(&cpu, .zbkb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKB)); + setFeature(&cpu, .zbkc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKC)); + setFeature(&cpu, .zbkx, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZBKX)); + setFeature(&cpu, .zknd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKND)); + setFeature(&cpu, .zkne, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKNE)); + setFeature(&cpu, .zknh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKNH)); + setFeature(&cpu, .zksed, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKSED)); + setFeature(&cpu, .zksh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKSH)); + setFeature(&cpu, .zkt, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZKT)); + setFeature(&cpu, .zvbb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVBB)); + setFeature(&cpu, .zvbc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVBC)); + setFeature(&cpu, .zvkb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKB)); + setFeature(&cpu, .zvkg, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKG)); + setFeature(&cpu, .zvkned, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNED)); + setFeature(&cpu, .zvknha, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNHA)); + setFeature(&cpu, .zvknhb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKNHB)); + setFeature(&cpu, .zvksed, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKSED)); + setFeature(&cpu, .zvksh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKSH)); + setFeature(&cpu, .zvkt, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVKT)); + setFeature(&cpu, .zfh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFH)); + setFeature(&cpu, .zfhmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFHMIN)); + setFeature(&cpu, .zihintntl, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHINTNTL)); + setFeature(&cpu, .zvfh, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFH)); + setFeature(&cpu, .zvfhmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFHMIN)); + setFeature(&cpu, .zfa, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFA)); + setFeature(&cpu, .ztso, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZTSO)); + setFeature(&cpu, .zacas, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZACAS)); + setFeature(&cpu, .zicntr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICNTR)); + setFeature(&cpu, .zicond, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICOND)); + setFeature(&cpu, .zihintpause, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHINTPAUSE)); + setFeature(&cpu, .zihpm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHPM)); + setFeature(&cpu, .zve32x, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE32X)); + setFeature(&cpu, .zve32f, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE32F)); + setFeature(&cpu, .zve64x, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64X)); + setFeature(&cpu, .zve64f, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64F)); + setFeature(&cpu, .zve64d, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVE64D)); + setFeature(&cpu, .zimop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIMOP)); + setFeature(&cpu, .zca, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCA)); + setFeature(&cpu, .zcb, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCB)); + setFeature(&cpu, .zcd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCD)); + setFeature(&cpu, .zcf, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCF)); + setFeature(&cpu, .zcmop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCMOP)); + setFeature(&cpu, .zawrs, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZAWRS)); + setFeature(&cpu, .supm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_SUPM)); + setFeature(&cpu, .zicntr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICNTR)); + setFeature(&cpu, .zihpm, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZIHPM)); + setFeature(&cpu, .zfbfmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZFBFMIN)); + setFeature(&cpu, .zvfbfmin, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFBFMIN)); + setFeature(&cpu, .zvfbfwma, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZVFBFWMA)); + setFeature(&cpu, .zicbom, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOM)); + setFeature(&cpu, .zaamo, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZAAMO)); + setFeature(&cpu, .zalrsc, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZALRSC)); + setFeature(&cpu, .zabha, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZABHA)); + setFeature(&cpu, .zalasr, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZALASR)); + setFeature(&cpu, .zicbop, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICBOP)); + setFeature(&cpu, .zilsd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZILSD)); + setFeature(&cpu, .zclsd, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZCLSD)); + setFeature(&cpu, .experimental_zicfilp, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_0.EXT_ZICFILP)); }, RISCV_HWPROBE.KEY.MISALIGNED_SCALAR_PERF => { - setFeature(cpu, .unaligned_scalar_mem, value == RISCV_HWPROBE.MISALIGNED_SCALAR.FAST); + setFeature(&cpu, .unaligned_scalar_mem, value == RISCV_HWPROBE.MISALIGNED_SCALAR.FAST); }, RISCV_HWPROBE.KEY.MISALIGNED_VECTOR_PERF => { - setFeature(cpu, .unaligned_vector_mem, value == RISCV_HWPROBE.MISALIGNED_VECTOR.FAST); + setFeature(&cpu, .unaligned_vector_mem, value == RISCV_HWPROBE.MISALIGNED_VECTOR.FAST); }, RISCV_HWPROBE.KEY.VENDOR_EXT_MIPS_0 => { - setFeature(cpu, .xmipsexectl, ima_support and set(value, RISCV_HWPROBE.MIPS_VENDOR_EXT_XMIPSEXECTL)); + setFeature(&cpu, .xmipsexectl, ima_support and set(value, RISCV_HWPROBE.MIPS_VENDOR_EXT_XMIPSEXECTL)); }, RISCV_HWPROBE.KEY.VENDOR_EXT_SIFIVE_0 => { - setFeature(cpu, .xsfvqmaccdod, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVQMACCDOD)); - setFeature(cpu, .xsfvqmaccqoq, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVQMACCQOQ)); - setFeature(cpu, .xsfvfnrclipxfqf, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVFNRCLIPXFQF)); - setFeature(cpu, .xsfvfwmaccqqq, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVFWMACCQQQ)); + setFeature(&cpu, .xsfvqmaccdod, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVQMACCDOD)); + setFeature(&cpu, .xsfvqmaccqoq, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVQMACCQOQ)); + setFeature(&cpu, .xsfvfnrclipxfqf, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVFNRCLIPXFQF)); + setFeature(&cpu, .xsfvfwmaccqqq, ima_support and set(value, RISCV_HWPROBE.SIFIVE_VENDOR_EXT.XSFVFWMACCQQQ)); }, RISCV_HWPROBE.KEY.IMA_EXT_1 => { - setFeature(cpu, .experimental_zicfiss, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_1_EXT_ZICFISS)); + setFeature(&cpu, .experimental_zicfiss, ima_support and set(value, RISCV_HWPROBE.IMA_EXT_1_EXT_ZICFISS)); }, else => unreachable, } } + + cpu.features.populateDependencies(cpu.arch.allFeaturesList()); + + return cpu; + } +}; + +const s390x = struct { + const cpuinfo = struct { + const Impl = struct { + model: ?*const Target.Cpu.Model = null, + + const cpu_names = .{ + .{ "2097", &Target.s390x.cpu.z10 }, + .{ "2098", &Target.s390x.cpu.z10 }, + .{ "2817", &Target.s390x.cpu.z196 }, + .{ "2818", &Target.s390x.cpu.z196 }, + .{ "2827", &Target.s390x.cpu.zEC12 }, + .{ "2828", &Target.s390x.cpu.zEC12 }, + .{ "2964", &Target.s390x.cpu.z13 }, + .{ "2965", &Target.s390x.cpu.z13 }, + .{ "3906", &Target.s390x.cpu.z14 }, + .{ "3907", &Target.s390x.cpu.z14 }, + .{ "8561", &Target.s390x.cpu.z15 }, + .{ "8562", &Target.s390x.cpu.z15 }, + .{ "3931", &Target.s390x.cpu.z16 }, + .{ "3932", &Target.s390x.cpu.z16 }, + .{ "9175", &Target.s390x.cpu.z17 }, + .{ "9176", &Target.s390x.cpu.z17 }, + }; + + fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool { + if (mem.eql(u8, key, "machine")) { + inline for (cpu_names) |pair| { + if (mem.eql(u8, value, pair[0])) { + self.model = pair[1]; + break; + } + } + + return false; + } + + return true; + } + + fn finalize(self: *const Impl, arch: Target.Cpu.Arch) ?Target.Cpu { + const model = self.model orelse return null; + return Target.Cpu{ + .arch = arch, + .model = model, + .features = model.features, + }; + } + }; + + const Parser = CpuinfoParser(Impl); + }; + + test cpuinfo { + try testParser(cpuinfo.Parser, .s390x, &Target.s390x.cpu.z15, + \\physical id : 5 + \\core id : 5 + \\book id : 5 + \\drawer id : 5 + \\dedicated : 0 + \\address : 5 + \\siblings : 1 + \\cpu cores : 1 + \\version : FF + \\identification : 09DD98 + \\machine : 8561 + \\cpu MHz dynamic : 5200 + \\cpu MHz static : 5200 + ); + } + + pub fn detectNativeCpu(io: Io, arch: Target.Cpu.Arch) ?Target.Cpu { + var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch return null; + defer file.close(io); + + var buffer: [4096]u8 = undefined; + var file_reader = file.reader(io, &buffer); + + var cpu = (cpuinfo.Parser.parse(arch, &file_reader.interface) catch null) orelse return null; + + cpu.features.populateDependencies(cpu.arch.allFeaturesList()); + + return cpu; + } +}; + +const sparc = struct { + const cpuinfo = struct { + const Impl = struct { + model: ?*const Target.Cpu.Model = null, + + const cpu_names = .{ + .{ "BlackBird", &Target.sparc.cpu.ultrasparc }, + .{ "Cheetah", &Target.sparc.cpu.ultrasparc3 }, + .{ "Hummingbird", &Target.sparc.cpu.ultrasparc }, + .{ "HyperSparc", &Target.sparc.cpu.hypersparc }, + .{ "Jaguar", &Target.sparc.cpu.ultrasparc3 }, + .{ "Jalapeno", &Target.sparc.cpu.ultrasparc3 }, + .{ "LEON", &Target.sparc.cpu.leon3 }, + .{ "MB86904", &Target.sparc.cpu.v8 }, + .{ "MB86907", &Target.sparc.cpu.v8 }, + .{ "MicroSparc II", &Target.sparc.cpu.v8 }, + .{ "MicroSparc", &Target.sparc.cpu.v8 }, + .{ "Panther", &Target.sparc.cpu.ultrasparc3 }, + .{ "Sabre", &Target.sparc.cpu.ultrasparc }, + .{ "Serrano", &Target.sparc.cpu.ultrasparc3 }, + .{ "SPARC-M6", &Target.sparc.cpu.niagara4 }, + .{ "SPARC-M7", &Target.sparc.cpu.niagara4 }, + .{ "SPARC-M8", &Target.sparc.cpu.niagara4 }, + .{ "SPARC-SN", &Target.sparc.cpu.niagara4 }, + .{ "SPARC64-X", &Target.sparc.cpu.ultrasparc3 }, + .{ "SpitFire", &Target.sparc.cpu.ultrasparc }, + .{ "SuperSparc", &Target.sparc.cpu.supersparc }, + .{ "UltraSparc T1", &Target.sparc.cpu.niagara }, + .{ "UltraSparc T2", &Target.sparc.cpu.niagara2 }, + .{ "UltraSparc T3", &Target.sparc.cpu.niagara3 }, + .{ "UltraSparc T4", &Target.sparc.cpu.niagara4 }, + .{ "UltraSparc T5", &Target.sparc.cpu.niagara4 }, + }; + + fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool { + if (mem.eql(u8, key, "cpu")) { + inline for (cpu_names) |pair| { + if (mem.findPos(u8, value, 0, pair[0]) != null) { + self.model = pair[1]; + break; + } + } + } + + return true; + } + + fn finalize(self: *const Impl, arch: Target.Cpu.Arch) ?Target.Cpu { + const model = self.model orelse return null; + return Target.Cpu{ + .arch = arch, + .model = model, + .features = model.features, + }; + } + }; + + const Parser = CpuinfoParser(Impl); + }; + + test cpuinfo { + try testParser(cpuinfo.Parser, .sparc64, &Target.sparc.cpu.niagara2, + \\cpu : UltraSparc T2 (Niagara2) + \\fpu : UltraSparc T2 integrated FPU + \\pmu : niagara2 + \\type : sun4v + ); + } + + pub fn detectNativeCpu(io: Io, arch: Target.Cpu.Arch) ?Target.Cpu { + var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch return null; + defer file.close(io); + + var buffer: [4096]u8 = undefined; + var file_reader = file.reader(io, &buffer); + + var cpu = (cpuinfo.Parser.parse(arch, &file_reader.interface) catch null) orelse return null; + + cpu.features.populateDependencies(cpu.arch.allFeaturesList()); + + return cpu; } }; pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu { - var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch |err| switch (err) { - else => return null, - }; - defer file.close(io); - - var buffer: [4096]u8 = undefined; // "flags" lines can get pretty long. - var file_reader = file.reader(io, &buffer); - const current_arch = builtin.cpu.arch; return switch (current_arch) { - .aarch64, .aarch64_be => b: { - const registers = [12]u64{ - aarch64.mrs("MIDR_EL1"), - aarch64.mrs("ID_AA64PFR0_EL1"), - aarch64.mrs("ID_AA64PFR1_EL1"), - aarch64.mrs("ID_AA64DFR0_EL1"), - aarch64.mrs("ID_AA64DFR1_EL1"), - aarch64.mrs("ID_AA64AFR0_EL1"), - aarch64.mrs("ID_AA64AFR1_EL1"), - aarch64.mrs("ID_AA64ISAR0_EL1"), - aarch64.mrs("ID_AA64ISAR1_EL1"), - aarch64.mrs("ID_AA64MMFR0_EL1"), - aarch64.mrs("ID_AA64MMFR1_EL1"), - aarch64.mrs("ID_AA64MMFR2_EL1"), - }; - - break :b @import("arm.zig").aarch64.detectNativeCpuAndFeatures(current_arch, registers); - }, - .arm, .armeb, .thumb, .thumbeb => ArmCpuinfoParser.parse(current_arch, &file_reader.interface) catch null, - .powerpc, .powerpcle, .powerpc64, .powerpc64le => PowerpcCpuinfoParser.parse(current_arch, &file_reader.interface) catch null, - .riscv64, .riscv32 => b: { - var cpu = (RiscvCpuinfoParser.parse(current_arch, &file_reader.interface) catch null) orelse cpu: { - const model = Target.Cpu.Model.generic(current_arch); - break :cpu Target.Cpu{ - .arch = current_arch, - .model = model, - .features = model.features, - }; - }; - - riscv.detectCpuFeatures(&cpu); - cpu.features.populateDependencies(cpu.arch.allFeaturesList()); - - break :b cpu; - }, - .s390x => S390xCpuinfoParser.parse(current_arch, &file_reader.interface) catch null, - .sparc, .sparc64 => SparcCpuinfoParser.parse(current_arch, &file_reader.interface) catch null, + .aarch64, .aarch64_be => aarch64.detectNativeCpuAndFeatures(current_arch), + .arm, .armeb, .thumb, .thumbeb => arm.detectNativeCpu(io, current_arch), + .powerpc, .powerpcle, .powerpc64, .powerpc64le => powerpc.detectNativeCpu(io, current_arch), + .riscv64, .riscv32 => riscv.detectNativeCpuAndFeatures(io, current_arch), + .s390x => s390x.detectNativeCpu(io, current_arch), + .sparc, .sparc64 => sparc.detectNativeCpu(io, current_arch), else => null, }; } + +test { + _ = aarch64; + _ = arm; + _ = powerpc; + _ = riscv; + _ = s390x; + _ = sparc; +} -- 2.54.0 From b529ea661e34e35f45a7b6032e87937cd56ee53a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Sep 2026 11:38:43 +0200 Subject: [PATCH 19/24] std.zig.system.linux: more corrections/additions to powerpc CPU model list --- lib/std/zig/system/linux.zig | 46 +++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index 01f09b60b7a69e3165820c616f7e6957adc266a9..eb9169008897be0eacb7cbd18cd5d85a6a88ed1c 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -238,24 +238,68 @@ const powerpc = struct { model: ?*const Target.Cpu.Model = null, const cpu_names = .{ + .{ "440EPX", &Target.powerpc.cpu.@"440" }, + .{ "440EP", &Target.powerpc.cpu.@"440" }, + .{ "460EX", &Target.powerpc.cpu.@"440" }, + .{ "440GP", &Target.powerpc.cpu.@"440" }, + .{ "440GRX", &Target.powerpc.cpu.@"440" }, + .{ "440GR", &Target.powerpc.cpu.@"440" }, + .{ "460GT", &Target.powerpc.cpu.@"440" }, + .{ "440GX", &Target.powerpc.cpu.@"440" }, + .{ "440SPe", &Target.powerpc.cpu.@"440" }, + .{ "440SP", &Target.powerpc.cpu.@"440" }, + .{ "460SX", &Target.powerpc.cpu.@"440" }, + .{ "603ev", &Target.powerpc.cpu.@"603ev" }, + .{ "603e", &Target.powerpc.cpu.@"603e" }, + .{ "603", &Target.powerpc.cpu.@"603" }, + .{ "604ev", &Target.powerpc.cpu.@"604e" }, .{ "604e", &Target.powerpc.cpu.@"604e" }, + .{ "604r", &Target.powerpc.cpu.@"603e" }, .{ "604", &Target.powerpc.cpu.@"604" }, .{ "7400", &Target.powerpc.cpu.@"7400" }, .{ "7410", &Target.powerpc.cpu.@"7400" }, .{ "7447/7457", &Target.powerpc.cpu.@"7450" }, .{ "7447A", &Target.powerpc.cpu.@"7450" }, + .{ "7448", &Target.powerpc.cpu.@"7450" }, + .{ "7450", &Target.powerpc.cpu.@"7450" }, .{ "7455", &Target.powerpc.cpu.@"7450" }, - .{ "POWER5", &Target.powerpc.cpu.g5 }, + .{ "740/750", &Target.powerpc.cpu.@"750" }, + .{ "745/755", &Target.powerpc.cpu.@"750" }, + .{ "750CL", &Target.powerpc.cpu.@"750" }, + .{ "750CXe", &Target.powerpc.cpu.@"750" }, + .{ "750CX", &Target.powerpc.cpu.@"750" }, + .{ "750FX", &Target.powerpc.cpu.@"750" }, + .{ "750GX", &Target.powerpc.cpu.@"750" }, + .{ "82xx", &Target.powerpc.cpu.@"603e" }, + .{ "APM821XX", &Target.powerpc.cpu.@"440" }, + .{ "Cell", &Target.powerpc.cpu.ppc64 }, // TODO: Change with LLVM 23. + .{ "e300c1", &Target.powerpc.cpu.@"603e" }, + .{ "e300c2", &Target.powerpc.cpu.@"603e" }, + .{ "e300c3", &Target.powerpc.cpu.@"603e" }, + .{ "e300c4", &Target.powerpc.cpu.@"603e" }, + .{ "e500mc", &Target.powerpc.cpu.e500mc }, + .{ "e500v2", &Target.powerpc.cpu.e500 }, // TODO: Change with LLVM 23. + .{ "e500", &Target.powerpc.cpu.e500 }, + .{ "e5500", &Target.powerpc.cpu.e5500 }, + .{ "e6500", &Target.powerpc.cpu.e5500 }, // TODO: Change with LLVM 23. + .{ "G2_LE", &Target.powerpc.cpu.@"603e" }, + .{ "HX-C2000", &Target.powerpc.cpu.pwr8 }, + .{ "POWER5+", &Target.powerpc.cpu.pwr5x }, + .{ "POWER5", &Target.powerpc.cpu.pwr5 }, .{ "POWER6", &Target.powerpc.cpu.pwr6 }, + .{ "POWER7+", &Target.powerpc.cpu.pwr7 }, .{ "POWER7", &Target.powerpc.cpu.pwr7 }, .{ "POWER8E", &Target.powerpc.cpu.pwr8 }, .{ "POWER8NVL", &Target.powerpc.cpu.pwr8 }, .{ "POWER8", &Target.powerpc.cpu.pwr8 }, + .{ "POWER9P", &Target.powerpc.cpu.pwr9 }, .{ "POWER9", &Target.powerpc.cpu.pwr9 }, .{ "POWER10", &Target.powerpc.cpu.pwr10 }, .{ "Power11", &Target.powerpc.cpu.pwr11 }, .{ "PPC970FX", &Target.powerpc.cpu.@"970" }, + .{ "PPC970GX", &Target.powerpc.cpu.@"970" }, .{ "PPC970MP", &Target.powerpc.cpu.@"970" }, + .{ "PPC970", &Target.powerpc.cpu.@"970" }, }; fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool { -- 2.54.0 From c4fec122cd829c3502e47e22b08ed220aaabda0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Sep 2026 10:43:18 +0200 Subject: [PATCH 20/24] std.zig.system.linux: add csky CPU model detection --- lib/std/zig/system/linux.zig | 61 ++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index eb9169008897be0eacb7cbd18cd5d85a6a88ed1c..f8055e853bf8255a2af6370f3818812c1504ff15 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -232,6 +232,66 @@ const arm = struct { } }; +const csky = struct { + const cpuinfo = struct { + const Impl = struct { + model: ?*const Target.Cpu.Model = null, + + const cpu_names = .{ + .{ "ck807", &Target.csky.cpu.ck807 }, + .{ "ck807f", &Target.csky.cpu.ck807f }, + .{ "ck810", &Target.csky.cpu.ck810 }, + .{ "ck810f", &Target.csky.cpu.ck810f }, + .{ "ck810t", &Target.csky.cpu.ck810t }, + .{ "ck810ft", &Target.csky.cpu.ck810ft }, + .{ "ck860", &Target.csky.cpu.ck860 }, + .{ "ck860f", &Target.csky.cpu.ck860f }, + .{ "ck860fv", &Target.csky.cpu.ck860fv }, + }; + + fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool { + if (mem.eql(u8, key, "C-SKY CPU model")) { + inline for (cpu_names) |pair| { + if (mem.eql(u8, value, pair[0])) { + self.model = pair[1]; + break; + } + } + + return false; + } + + return true; + } + + fn finalize(self: *const Impl, arch: Target.Cpu.Arch) ?Target.Cpu { + const model = self.model orelse return null; + return .{ + .arch = arch, + .model = model, + .features = model.features, + }; + } + }; + + const Parser = CpuinfoParser(Impl); + }; + + pub fn detectNativeCpu(io: Io, arch: Target.Cpu.Arch) ?Target.Cpu { + var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch return null; + defer file.close(io); + + var buffer: [4096]u8 = undefined; + var file_reader = file.reader(io, &buffer); + + var cpu = (cpuinfo.Parser.parse(arch, &file_reader.interface) catch null) orelse return null; + + cpu.features.populateDependencies(cpu.arch.allFeaturesList()); + + return cpu; + } +}; + const powerpc = struct { const cpuinfo = struct { const Impl = struct { @@ -757,6 +817,7 @@ pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu { return switch (current_arch) { .aarch64, .aarch64_be => aarch64.detectNativeCpuAndFeatures(current_arch), .arm, .armeb, .thumb, .thumbeb => arm.detectNativeCpu(io, current_arch), + .csky => csky.detectNativeCpu(io, current_arch), .powerpc, .powerpcle, .powerpc64, .powerpc64le => powerpc.detectNativeCpu(io, current_arch), .riscv64, .riscv32 => riscv.detectNativeCpuAndFeatures(io, current_arch), .s390x => s390x.detectNativeCpu(io, current_arch), -- 2.54.0 From 99650e773abf536d6b44f33e2fa4c5e6968592f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Sep 2026 10:54:51 +0200 Subject: [PATCH 21/24] std.zig.system.linux: add m68k CPU model detection --- lib/std/zig/system/linux.zig | 56 ++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index f8055e853bf8255a2af6370f3818812c1504ff15..504d9eb8ba860dc35ffcaa1d9b7d448be033559c 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -292,6 +292,61 @@ const csky = struct { } }; +const m68k = struct { + const cpuinfo = struct { + const Impl = struct { + model: ?*const Target.Cpu.Model = null, + + const cpu_names = .{ + .{ "68020", &Target.m68k.cpu.M68020 }, + .{ "68030", &Target.m68k.cpu.M68030 }, + .{ "68040", &Target.m68k.cpu.M68040 }, + .{ "68060", &Target.m68k.cpu.M68060 }, + }; + + fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool { + if (mem.eql(u8, key, "CPU")) { + inline for (cpu_names) |pair| { + if (mem.eql(u8, value, pair[0])) { + self.model = pair[1]; + break; + } + } + + return false; + } + + return true; + } + + fn finalize(self: *const Impl, arch: Target.Cpu.Arch) ?Target.Cpu { + const model = self.model orelse return null; + return .{ + .arch = arch, + .model = model, + .features = model.features, + }; + } + }; + + const Parser = CpuinfoParser(Impl); + }; + + pub fn detectNativeCpu(io: Io, arch: Target.Cpu.Arch) ?Target.Cpu { + var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch return null; + defer file.close(io); + + var buffer: [4096]u8 = undefined; + var file_reader = file.reader(io, &buffer); + + var cpu = (cpuinfo.Parser.parse(arch, &file_reader.interface) catch null) orelse return null; + + cpu.features.populateDependencies(cpu.arch.allFeaturesList()); + + return cpu; + } +}; + const powerpc = struct { const cpuinfo = struct { const Impl = struct { @@ -818,6 +873,7 @@ pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu { .aarch64, .aarch64_be => aarch64.detectNativeCpuAndFeatures(current_arch), .arm, .armeb, .thumb, .thumbeb => arm.detectNativeCpu(io, current_arch), .csky => csky.detectNativeCpu(io, current_arch), + .m68k => m68k.detectNativeCpu(io, current_arch), .powerpc, .powerpcle, .powerpc64, .powerpc64le => powerpc.detectNativeCpu(io, current_arch), .riscv64, .riscv32 => riscv.detectNativeCpuAndFeatures(io, current_arch), .s390x => s390x.detectNativeCpu(io, current_arch), -- 2.54.0 From 201a2142ae3c77a31c9cc274c13c5d24f4a31223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Sep 2026 12:16:34 +0200 Subject: [PATCH 22/24] std.zig.system.linux: add mips CPU model detection closes https://codeberg.org/ziglang/zig/issues/36778 --- lib/std/zig/system/linux.zig | 109 +++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index 504d9eb8ba860dc35ffcaa1d9b7d448be033559c..034f9c50a5c881ce05b4b7d26700bae7a94547e1 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -347,6 +347,114 @@ const m68k = struct { } }; +const mips = struct { + const cpuinfo = struct { + const Impl = struct { + model: ?*const Target.Cpu.Model = null, + + const cpu_names = .{ + .{ "Cavium Octeon III", &Target.mips.cpu.@"octeon+" }, + .{ "Cavium Octeon II", &Target.mips.cpu.@"octeon+" }, + .{ "Cavium Octeon+", &Target.mips.cpu.@"octeon+" }, + .{ "Cavium Octeon", &Target.mips.cpu.octeon }, + .{ "MIPS I6400", &Target.mips.cpu.i6400 }, + .{ "MIPS I6500", &Target.mips.cpu.i6500 }, + .{ "MIPS P5600", &Target.mips.cpu.p5600 }, + .{ "R3000A", &Target.mips.cpu.r3000a }, + }; + + const isa_names = .{ + .{ "mips64r6", &Target.mips.cpu.mips64r6 }, + .{ "mips64r5", &Target.mips.cpu.mips64r5 }, + .{ "mips64r2", &Target.mips.cpu.mips64r2 }, + .{ "mips64r1", &Target.mips.cpu.mips64 }, + .{ "mips32r6", &Target.mips.cpu.mips32r6 }, + .{ "mips32r5", &Target.mips.cpu.mips32r5 }, + .{ "mips32r2", &Target.mips.cpu.mips32r2 }, + .{ "mips32r1", &Target.mips.cpu.mips32 }, + .{ "mips5", &Target.mips.cpu.mips5 }, + .{ "mips4", &Target.mips.cpu.mips4 }, + .{ "mips3", &Target.mips.cpu.mips3 }, + .{ "mips2", &Target.mips.cpu.mips2 }, + .{ "mips1", &Target.mips.cpu.mips1 }, + }; + + fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool { + // The `cpu model` line always comes before `isa`, which is perfect for us since we + // want the explicit model to take precedence over the generic ISA identifier. + if (mem.eql(u8, key, "cpu model")) { + inline for (cpu_names) |pair| { + if (mem.find(u8, value, pair[0]) != null) { + self.model = pair[1]; + return false; + } + } + } else if (mem.eql(u8, key, "isa")) { + inline for (isa_names) |pair| { + if (mem.find(u8, value, pair[0]) != null) { + self.model = pair[1]; + break; + } + } + + // If we haven't found anything useful by here, we we may as well stop. + return false; + } + + return true; + } + + fn finalize(self: *const Impl, arch: Target.Cpu.Arch) ?Target.Cpu { + const model = self.model orelse return null; + return .{ + .arch = arch, + .model = model, + .features = model.features, + }; + } + }; + + const Parser = CpuinfoParser(Impl); + }; + + test cpuinfo { + try testParser(cpuinfo.Parser, .mips64, &Target.mips.cpu.@"octeon+", + \\system type : UBNT_E300 + \\machine : Unknown + \\processor : 0 + \\cpu model : Cavium Octeon III V0.2 FPU V0.0 + \\BogoMIPS : 2000.00 + \\wait instruction : yes + \\microsecond timers : yes + \\tlb_entries : 256 + \\extra interrupt vector : yes + \\hardware watchpoint : yes, count: 2, address/irw mask: [0x0ffc, 0x0ffb] + \\isa : mips1 mips2 mips3 mips4 mips5 mips64r2 + \\ASEs implemented : vz + \\shadow register sets : 1 + \\kscratch registers : 4 + \\package : 0 + \\core : 0 + \\VCED exceptions : not available + \\VCEI exceptions : not available + ); + } + + pub fn detectNativeCpu(io: Io, arch: Target.Cpu.Arch) ?Target.Cpu { + var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch return null; + defer file.close(io); + + var buffer: [4096]u8 = undefined; + var file_reader = file.reader(io, &buffer); + + var cpu = (cpuinfo.Parser.parse(arch, &file_reader.interface) catch null) orelse return null; + + cpu.features.populateDependencies(cpu.arch.allFeaturesList()); + + return cpu; + } +}; + const powerpc = struct { const cpuinfo = struct { const Impl = struct { @@ -874,6 +982,7 @@ pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu { .arm, .armeb, .thumb, .thumbeb => arm.detectNativeCpu(io, current_arch), .csky => csky.detectNativeCpu(io, current_arch), .m68k => m68k.detectNativeCpu(io, current_arch), + .mips, .mipsel, .mips64, .mips64el => mips.detectNativeCpu(io, current_arch), .powerpc, .powerpcle, .powerpc64, .powerpc64le => powerpc.detectNativeCpu(io, current_arch), .riscv64, .riscv32 => riscv.detectNativeCpuAndFeatures(io, current_arch), .s390x => s390x.detectNativeCpu(io, current_arch), -- 2.54.0 From ea6fa69ef558531300e67fd07abf81c92b86949c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Sep 2026 13:59:44 +0200 Subject: [PATCH 23/24] std.zig.system.linux: simplify arm.cpuinfo We no longer support kernels that are old enough to need most of this logic. --- lib/std/zig/system/linux.zig | 91 ++++++++---------------------------- 1 file changed, 19 insertions(+), 72 deletions(-) diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index 034f9c50a5c881ce05b4b7d26700bae7a94547e1..2d395b2a6323cf93eea9484e7886f43d60425353 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -71,97 +71,44 @@ const aarch64 = struct { const arm = struct { const cpuinfo = struct { const Impl = struct { - const num_cores = 4; + implementer: u8 = 0, + variant: u8 = 0, + part: u16 = 0, - cores: [num_cores]CoreInfo = undefined, - core_no: usize = 0, - have_fields: usize = 0, - - const CoreInfo = struct { - architecture: u8 = 0, - implementer: u8 = 0, - variant: u8 = 0, - part: u16 = 0, - is_really_v6: bool = false, - }; + have_fields: u8 = 0, const cpu_models = @import("arm.zig").cpu_models; - fn addOne(self: *Impl) void { - if (self.have_fields == 4 and self.core_no < num_cores) { - if (self.core_no > 0) { - // Deduplicate the core info. - for (self.cores[0..self.core_no]) |it| { - if (std.meta.eql(it, self.cores[self.core_no])) - return; - } - } - self.core_no += 1; - } - } - fn lineHook(self: *Impl, key: []const u8, value: []const u8) !bool { - const info = &self.cores[self.core_no]; - - if (mem.eql(u8, key, "processor")) { - // Handle both old-style and new-style cpuinfo formats. - // The former prints a sequence of "processor: N" lines for each - // core and then the info for the core that's executing this code(!) - // while the latter prints the infos for each core right after the - // "processor" key. - self.have_fields = 0; - self.cores[self.core_no] = .{}; - } else if (mem.eql(u8, key, "CPU implementer")) { - info.implementer = try fmt.parseInt(u8, value, 0); - self.have_fields += 1; - } else if (mem.eql(u8, key, "CPU architecture")) { - // "AArch64" on older kernels. - info.architecture = if (mem.startsWith(u8, value, "AArch64")) - 8 - else - try fmt.parseInt(u8, value, 0); + if (mem.eql(u8, key, "CPU implementer")) { + self.implementer = try fmt.parseInt(u8, value, 0); self.have_fields += 1; } else if (mem.eql(u8, key, "CPU variant")) { - info.variant = try fmt.parseInt(u8, value, 0); + self.variant = try fmt.parseInt(u8, value, 0); self.have_fields += 1; } else if (mem.eql(u8, key, "CPU part")) { - info.part = try fmt.parseInt(u16, value, 0); + self.part = try fmt.parseInt(u16, value, 0); self.have_fields += 1; - } else if (mem.eql(u8, key, "model name")) { - // ARMv6 cores report "CPU architecture" equal to 7. - if (mem.find(u8, value, "(v6l)")) |_| { - info.is_really_v6 = true; - } } else if (mem.eql(u8, key, "CPU revision")) { // This field is always the last one for each CPU section. - _ = self.addOne(); + return false; } return true; } fn finalize(self: *Impl, arch: Target.Cpu.Arch) ?Target.Cpu { - if (self.core_no == 0) return null; + if (self.have_fields != 3) return null; - const is_64bit = switch (arch) { - .aarch64, .aarch64_be => true, - else => false, - }; + const model = cpu_models.isKnown(.{ + .architecture = undefined, // unused for the lookup + .implementer = self.implementer, + .variant = self.variant, + .part = self.part, + }, false) orelse return null; - var known_models: [num_cores]?*const Target.Cpu.Model = undefined; - for (self.cores[0..self.core_no], 0..) |core, i| { - known_models[i] = cpu_models.isKnown(.{ - .architecture = core.architecture, - .implementer = core.implementer, - .variant = core.variant, - .part = core.part, - }, is_64bit); - } - - // XXX We pick the first core on big.LITTLE systems, hopefully the - // LITTLE one. - const model = known_models[0] orelse return null; - return Target.Cpu{ + // We pick the first core on big.LITTLE systems, hopefully the LITTLE one. + return .{ .arch = arch, .model = model, .features = model.features, @@ -205,7 +152,7 @@ const arm = struct { \\CPU part : 0xc0f \\CPU revision : 3 ); - try testParser(cpuinfo.Parser, .aarch64, &Target.aarch64.cpu.cortex_a72, + try testParser(cpuinfo.Parser, .arm, &Target.arm.cpu.cortex_a72, \\processor : 0 \\BogoMIPS : 108.00 \\Features : fp asimd evtstrm crc32 cpuid -- 2.54.0 From f4c38a3686f190ec2b9c58cfeea1636d19e5c896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Sep 2026 09:57:43 +0200 Subject: [PATCH 24/24] std.zig.system.openbsd: return aarch64 model even if registers are unavailable --- lib/std/zig/system/openbsd.zig | 38 ++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/lib/std/zig/system/openbsd.zig b/lib/std/zig/system/openbsd.zig index 6549cd906055ab09243290288c17793cc7e779e1..b04adbf7c17625c9d9c23bb758ccefa6d510e2e3 100644 --- a/lib/std/zig/system/openbsd.zig +++ b/lib/std/zig/system/openbsd.zig @@ -113,32 +113,38 @@ const aarch64 = struct { } fn detectNativeCpuAndFeatures(arch: std.Target.Cpu.Arch) ?std.Target.Cpu { - const model: *const std.Target.Cpu.Model = blk: { + const maybe_model: ?*const std.Target.Cpu.Model = blk: { var buf: [64:0]u8 = undefined; - const name = hwModelName(&buf) orelse return null; + const name = hwModelName(&buf) orelse break :blk null; inline for (models) |pair| { if (std.mem.startsWith(u8, name, pair[0])) break :blk pair[1]; } - break :blk .generic(arch); + break :blk null; }; - const registers = [11]u64{ - sysctlReg(std.c.CPU.AA64PFR0) orelse return null, - sysctlReg(std.c.CPU.AA64PFR1) orelse return null, - 0, // ID_AA64DFR0_EL1 - 0, // ID_AA64DFR1_EL1 - 0, // ID_AA64AFR0_EL1 - 0, // ID_AA64AFR1_EL1 - sysctlReg(std.c.CPU.ID_AA64ISAR0) orelse return null, - sysctlReg(std.c.CPU.ID_AA64ISAR1) orelse return null, - sysctlReg(std.c.CPU.ID_AA64MMFR0) orelse return null, - sysctlReg(std.c.CPU.ID_AA64MMFR1) orelse return null, - sysctlReg(std.c.CPU.ID_AA64MMFR2) orelse return null, + const registers = blk: { + break :blk [11]u64{ + sysctlReg(std.c.CPU.AA64PFR0) orelse break :blk null, + sysctlReg(std.c.CPU.AA64PFR1) orelse break :blk null, + 0, // ID_AA64DFR0_EL1 + 0, // ID_AA64DFR1_EL1 + 0, // ID_AA64AFR0_EL1 + 0, // ID_AA64AFR1_EL1 + sysctlReg(std.c.CPU.ID_AA64ISAR0) orelse break :blk null, + sysctlReg(std.c.CPU.ID_AA64ISAR1) orelse break :blk null, + sysctlReg(std.c.CPU.ID_AA64MMFR0) orelse break :blk null, + sysctlReg(std.c.CPU.ID_AA64MMFR1) orelse break :blk null, + sysctlReg(std.c.CPU.ID_AA64MMFR2) orelse break :blk null, + }; + } orelse { + // Even if the registers are unavailable, we should still return the + // model if we managed to detect it. + return if (maybe_model) |m| m.toCpu(arch) else null; }; - return @import("arm.zig").aarch64.detectNativeFeatures(arch, model, registers); + return @import("arm.zig").aarch64.detectNativeFeatures(arch, maybe_model orelse .generic(arch), registers); } }; -- 2.54.0