Merge pull request #13659 from ziglang/arm-win-cpu-features

windows: add native CPU and features detection for Armv8 chips
This commit is contained in:
Jakub Konka 2022-11-28 21:36:56 +01:00 committed by GitHub
commit d3b1cdf508
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 931 additions and 125 deletions

View File

@ -2089,6 +2089,7 @@ pub const LPWSTR = [*:0]WCHAR;
pub const LPCWSTR = [*:0]const WCHAR;
pub const PVOID = *anyopaque;
pub const PWSTR = [*:0]WCHAR;
pub const PCWSTR = [*:0]const WCHAR;
pub const SIZE_T = usize;
pub const UINT = c_uint;
pub const ULONG_PTR = usize;
@ -2104,6 +2105,7 @@ pub const USHORT = u16;
pub const SHORT = i16;
pub const ULONG = u32;
pub const LONG = i32;
pub const ULONG64 = u64;
pub const ULONGLONG = u64;
pub const LONGLONG = i64;
pub const HLOCAL = HANDLE;
@ -2504,6 +2506,7 @@ pub const STANDARD_RIGHTS_READ = READ_CONTROL;
pub const STANDARD_RIGHTS_WRITE = READ_CONTROL;
pub const STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
pub const STANDARD_RIGHTS_REQUIRED = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER;
pub const MAXIMUM_ALLOWED = 0x02000000;
// disposition for NtCreateFile
pub const FILE_SUPERSEDE = 0;
@ -2872,9 +2875,143 @@ pub const PROV_RSA_FULL = 1;
pub const REGSAM = ACCESS_MASK;
pub const ACCESS_MASK = DWORD;
pub const HKEY = *opaque {};
pub const LSTATUS = LONG;
pub const HKEY = *opaque {};
pub const HKEY_LOCAL_MACHINE: HKEY = @intToPtr(HKEY, 0x80000002);
/// Combines the STANDARD_RIGHTS_REQUIRED, KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY,
/// KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, and KEY_CREATE_LINK access rights.
pub const KEY_ALL_ACCESS = 0xF003F;
/// Reserved for system use.
pub const KEY_CREATE_LINK = 0x0020;
/// Required to create a subkey of a registry key.
pub const KEY_CREATE_SUB_KEY = 0x0004;
/// Required to enumerate the subkeys of a registry key.
pub const KEY_ENUMERATE_SUB_KEYS = 0x0008;
/// Equivalent to KEY_READ.
pub const KEY_EXECUTE = 0x20019;
/// Required to request change notifications for a registry key or for subkeys of a registry key.
pub const KEY_NOTIFY = 0x0010;
/// Required to query the values of a registry key.
pub const KEY_QUERY_VALUE = 0x0001;
/// Combines the STANDARD_RIGHTS_READ, KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY values.
pub const KEY_READ = 0x20019;
/// Required to create, delete, or set a registry value.
pub const KEY_SET_VALUE = 0x0002;
/// Indicates that an application on 64-bit Windows should operate on the 32-bit registry view.
/// This flag is ignored by 32-bit Windows.
pub const KEY_WOW64_32KEY = 0x0200;
/// Indicates that an application on 64-bit Windows should operate on the 64-bit registry view.
/// This flag is ignored by 32-bit Windows.
pub const KEY_WOW64_64KEY = 0x0100;
/// Combines the STANDARD_RIGHTS_WRITE, KEY_SET_VALUE, and KEY_CREATE_SUB_KEY access rights.
pub const KEY_WRITE = 0x20006;
/// Open symbolic link.
pub const REG_OPTION_OPEN_LINK: DWORD = 0x8;
pub const RTL_QUERY_REGISTRY_TABLE = extern struct {
QueryRoutine: RTL_QUERY_REGISTRY_ROUTINE,
Flags: ULONG,
Name: ?PWSTR,
EntryContext: ?*anyopaque,
DefaultType: ULONG,
DefaultData: ?*anyopaque,
DefaultLength: ULONG,
};
pub const RTL_QUERY_REGISTRY_ROUTINE = ?std.meta.FnPtr(fn (
PWSTR,
ULONG,
?*anyopaque,
ULONG,
?*anyopaque,
?*anyopaque,
) callconv(WINAPI) NTSTATUS);
/// Path is a full path
pub const RTL_REGISTRY_ABSOLUTE = 0;
/// \Registry\Machine\System\CurrentControlSet\Services
pub const RTL_REGISTRY_SERVICES = 1;
/// \Registry\Machine\System\CurrentControlSet\Control
pub const RTL_REGISTRY_CONTROL = 2;
/// \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion
pub const RTL_REGISTRY_WINDOWS_NT = 3;
/// \Registry\Machine\Hardware\DeviceMap
pub const RTL_REGISTRY_DEVICEMAP = 4;
/// \Registry\User\CurrentUser
pub const RTL_REGISTRY_USER = 5;
pub const RTL_REGISTRY_MAXIMUM = 6;
/// Low order bits are registry handle
pub const RTL_REGISTRY_HANDLE = 0x40000000;
/// Indicates the key node is optional
pub const RTL_REGISTRY_OPTIONAL = 0x80000000;
/// Name is a subkey and remainder of table or until next subkey are value
/// names for that subkey to look at.
pub const RTL_QUERY_REGISTRY_SUBKEY = 0x00000001;
/// Reset current key to original key for this and all following table entries.
pub const RTL_QUERY_REGISTRY_TOPKEY = 0x00000002;
/// Fail if no match found for this table entry.
pub const RTL_QUERY_REGISTRY_REQUIRED = 0x00000004;
/// Used to mark a table entry that has no value name, just wants a call out, not
/// an enumeration of all values.
pub const RTL_QUERY_REGISTRY_NOVALUE = 0x00000008;
/// Used to suppress the expansion of REG_MULTI_SZ into multiple callouts or
/// to prevent the expansion of environment variable values in REG_EXPAND_SZ.
pub const RTL_QUERY_REGISTRY_NOEXPAND = 0x00000010;
/// QueryRoutine field ignored. EntryContext field points to location to store value.
/// For null terminated strings, EntryContext points to UNICODE_STRING structure that
/// that describes maximum size of buffer. If .Buffer field is NULL then a buffer is
/// allocated.
pub const RTL_QUERY_REGISTRY_DIRECT = 0x00000020;
/// Used to delete value keys after they are queried.
pub const RTL_QUERY_REGISTRY_DELETE = 0x00000040;
/// Use this flag with the RTL_QUERY_REGISTRY_DIRECT flag to verify that the REG_XXX type
/// of the stored registry value matches the type expected by the caller.
/// If the types do not match, the call fails.
pub const RTL_QUERY_REGISTRY_TYPECHECK = 0x00000100;
pub const REG = struct {
/// No value type
pub const NONE: ULONG = 0;
/// Unicode nul terminated string
pub const SZ: ULONG = 1;
/// Unicode nul terminated string (with environment variable references)
pub const EXPAND_SZ: ULONG = 2;
/// Free form binary
pub const BINARY: ULONG = 3;
/// 32-bit number
pub const DWORD: ULONG = 4;
/// 32-bit number (same as REG_DWORD)
pub const DWORD_LITTLE_ENDIAN: ULONG = 4;
/// 32-bit number
pub const DWORD_BIG_ENDIAN: ULONG = 5;
/// Symbolic Link (unicode)
pub const LINK: ULONG = 6;
/// Multiple Unicode strings
pub const MULTI_SZ: ULONG = 7;
/// Resource list in the resource map
pub const RESOURCE_LIST: ULONG = 8;
/// Resource list in the hardware description
pub const FULL_RESOURCE_DESCRIPTOR: ULONG = 9;
pub const RESOURCE_REQUIREMENTS_LIST: ULONG = 10;
/// 64-bit number
pub const QWORD: ULONG = 11;
/// 64-bit number (same as REG_QWORD)
pub const QWORD_LITTLE_ENDIAN: ULONG = 11;
};
pub const FILE_NOTIFY_INFORMATION = extern struct {
NextEntryOffset: DWORD,
Action: DWORD,
@ -3715,3 +3852,305 @@ pub const CTRL_LOGOFF_EVENT: DWORD = 5;
pub const CTRL_SHUTDOWN_EVENT: DWORD = 6;
pub const HANDLER_ROUTINE = std.meta.FnPtr(fn (dwCtrlType: DWORD) callconv(WINAPI) BOOL);
/// Processor feature enumeration.
pub const PF = enum(DWORD) {
/// On a Pentium, a floating-point precision error can occur in rare circumstances.
FLOATING_POINT_PRECISION_ERRATA = 0,
/// Floating-point operations are emulated using software emulator.
/// This function returns a nonzero value if floating-point operations are emulated; otherwise, it returns zero.
FLOATING_POINT_EMULATED = 1,
/// The atomic compare and exchange operation (cmpxchg) is available.
COMPARE_EXCHANGE_DOUBLE = 2,
/// The MMX instruction set is available.
MMX_INSTRUCTIONS_AVAILABLE = 3,
PPC_MOVEMEM_64BIT_OK = 4,
ALPHA_BYTE_INSTRUCTIONS = 5,
/// The SSE instruction set is available.
XMMI_INSTRUCTIONS_AVAILABLE = 6,
/// The 3D-Now instruction is available.
@"3DNOW_INSTRUCTIONS_AVAILABLE" = 7,
/// The RDTSC instruction is available.
RDTSC_INSTRUCTION_AVAILABLE = 8,
/// The processor is PAE-enabled.
PAE_ENABLED = 9,
/// The SSE2 instruction set is available.
XMMI64_INSTRUCTIONS_AVAILABLE = 10,
SSE_DAZ_MODE_AVAILABLE = 11,
/// Data execution prevention is enabled.
NX_ENABLED = 12,
/// The SSE3 instruction set is available.
SSE3_INSTRUCTIONS_AVAILABLE = 13,
/// The atomic compare and exchange 128-bit operation (cmpxchg16b) is available.
COMPARE_EXCHANGE128 = 14,
/// The atomic compare 64 and exchange 128-bit operation (cmp8xchg16) is available.
COMPARE64_EXCHANGE128 = 15,
/// The processor channels are enabled.
CHANNELS_ENABLED = 16,
/// The processor implements the XSAVI and XRSTOR instructions.
XSAVE_ENABLED = 17,
/// The VFP/Neon: 32 x 64bit register bank is present.
/// This flag has the same meaning as PF_ARM_VFP_EXTENDED_REGISTERS.
ARM_VFP_32_REGISTERS_AVAILABLE = 18,
/// This ARM processor implements the ARM v8 NEON instruction set.
ARM_NEON_INSTRUCTIONS_AVAILABLE = 19,
/// Second Level Address Translation is supported by the hardware.
SECOND_LEVEL_ADDRESS_TRANSLATION = 20,
/// Virtualization is enabled in the firmware and made available by the operating system.
VIRT_FIRMWARE_ENABLED = 21,
/// RDFSBASE, RDGSBASE, WRFSBASE, and WRGSBASE instructions are available.
RDWRFSGBASE_AVAILABLE = 22,
/// _fastfail() is available.
FASTFAIL_AVAILABLE = 23,
/// The divide instruction_available.
ARM_DIVIDE_INSTRUCTION_AVAILABLE = 24,
/// The 64-bit load/store atomic instructions are available.
ARM_64BIT_LOADSTORE_ATOMIC = 25,
/// The external cache is available.
ARM_EXTERNAL_CACHE_AVAILABLE = 26,
/// The floating-point multiply-accumulate instruction is available.
ARM_FMAC_INSTRUCTIONS_AVAILABLE = 27,
RDRAND_INSTRUCTION_AVAILABLE = 28,
/// This ARM processor implements the ARM v8 instructions set.
ARM_V8_INSTRUCTIONS_AVAILABLE = 29,
/// This ARM processor implements the ARM v8 extra cryptographic instructions (i.e., AES, SHA1 and SHA2).
ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE = 30,
/// This ARM processor implements the ARM v8 extra CRC32 instructions.
ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE = 31,
RDTSCP_INSTRUCTION_AVAILABLE = 32,
RDPID_INSTRUCTION_AVAILABLE = 33,
/// This ARM processor implements the ARM v8.1 atomic instructions (e.g., CAS, SWP).
ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE = 34,
MONITORX_INSTRUCTION_AVAILABLE = 35,
/// The SSSE3 instruction set is available.
SSSE3_INSTRUCTIONS_AVAILABLE = 36,
/// The SSE4_1 instruction set is available.
SSE4_1_INSTRUCTIONS_AVAILABLE = 37,
/// The SSE4_2 instruction set is available.
SSE4_2_INSTRUCTIONS_AVAILABLE = 38,
/// The AVX instruction set is available.
AVX_INSTRUCTIONS_AVAILABLE = 39,
/// The AVX2 instruction set is available.
AVX2_INSTRUCTIONS_AVAILABLE = 40,
/// The AVX512F instruction set is available.
AVX512F_INSTRUCTIONS_AVAILABLE = 41,
ERMS_AVAILABLE = 42,
/// This ARM processor implements the ARM v8.2 Dot Product (DP) instructions.
ARM_V82_DP_INSTRUCTIONS_AVAILABLE = 43,
/// This ARM processor implements the ARM v8.3 JavaScript conversion (JSCVT) instructions.
ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE = 44,
};
pub const MAX_WOW64_SHARED_ENTRIES = 16;
pub const PROCESSOR_FEATURE_MAX = 64;
pub const MAXIMUM_XSTATE_FEATURES = 64;
pub const KSYSTEM_TIME = extern struct {
LowPart: ULONG,
High1Time: LONG,
High2Time: LONG,
};
pub const NT_PRODUCT_TYPE = enum(INT) {
NtProductWinNt = 1,
NtProductLanManNt,
NtProductServer,
};
pub const ALTERNATIVE_ARCHITECTURE_TYPE = enum(INT) {
StandardDesign,
NEC98x86,
EndAlternatives,
};
pub const XSTATE_FEATURE = extern struct {
Offset: ULONG,
Size: ULONG,
};
pub const XSTATE_CONFIGURATION = extern struct {
EnabledFeatures: ULONG64,
Size: ULONG,
OptimizedSave: ULONG,
Features: [MAXIMUM_XSTATE_FEATURES]XSTATE_FEATURE,
};
/// Shared Kernel User Data
pub const KUSER_SHARED_DATA = extern struct {
TickCountLowDeprecated: ULONG,
TickCountMultiplier: ULONG,
InterruptTime: KSYSTEM_TIME,
SystemTime: KSYSTEM_TIME,
TimeZoneBias: KSYSTEM_TIME,
ImageNumberLow: USHORT,
ImageNumberHigh: USHORT,
NtSystemRoot: [260]WCHAR,
MaxStackTraceDepth: ULONG,
CryptoExponent: ULONG,
TimeZoneId: ULONG,
LargePageMinimum: ULONG,
AitSamplingValue: ULONG,
AppCompatFlag: ULONG,
RNGSeedVersion: ULONGLONG,
GlobalValidationRunlevel: ULONG,
TimeZoneBiasStamp: LONG,
NtBuildNumber: ULONG,
NtProductType: NT_PRODUCT_TYPE,
ProductTypeIsValid: BOOLEAN,
Reserved0: [1]BOOLEAN,
NativeProcessorArchitecture: USHORT,
NtMajorVersion: ULONG,
NtMinorVersion: ULONG,
ProcessorFeatures: [PROCESSOR_FEATURE_MAX]BOOLEAN,
Reserved1: ULONG,
Reserved3: ULONG,
TimeSlip: ULONG,
AlternativeArchitecture: ALTERNATIVE_ARCHITECTURE_TYPE,
BootId: ULONG,
SystemExpirationDate: LARGE_INTEGER,
SuiteMaskY: ULONG,
KdDebuggerEnabled: BOOLEAN,
DummyUnion1: extern union {
MitigationPolicies: UCHAR,
Alt: packed struct {
NXSupportPolicy: u2,
SEHValidationPolicy: u2,
CurDirDevicesSkippedForDlls: u2,
Reserved: u2,
},
},
CyclesPerYield: USHORT,
ActiveConsoleId: ULONG,
DismountCount: ULONG,
ComPlusPackage: ULONG,
LastSystemRITEventTickCount: ULONG,
NumberOfPhysicalPages: ULONG,
SafeBootMode: BOOLEAN,
DummyUnion2: extern union {
VirtualizationFlags: UCHAR,
Alt: packed struct {
ArchStartedInEl2: u1,
QcSlIsSupported: u1,
SpareBits: u6,
},
},
Reserved12: [2]UCHAR,
DummyUnion3: extern union {
SharedDataFlags: ULONG,
Alt: packed struct {
DbgErrorPortPresent: u1,
DbgElevationEnabled: u1,
DbgVirtEnabled: u1,
DbgInstallerDetectEnabled: u1,
DbgLkgEnabled: u1,
DbgDynProcessorEnabled: u1,
DbgConsoleBrokerEnabled: u1,
DbgSecureBootEnabled: u1,
DbgMultiSessionSku: u1,
DbgMultiUsersInSessionSku: u1,
DbgStateSeparationEnabled: u1,
SpareBits: u21,
},
},
DataFlagsPad: [1]ULONG,
TestRetInstruction: ULONGLONG,
QpcFrequency: LONGLONG,
SystemCall: ULONG,
Reserved2: ULONG,
SystemCallPad: [2]ULONGLONG,
DummyUnion4: extern union {
TickCount: KSYSTEM_TIME,
TickCountQuad: ULONG64,
Alt: extern struct {
ReservedTickCountOverlay: [3]ULONG,
TickCountPad: [1]ULONG,
},
},
Cookie: ULONG,
CookiePad: [1]ULONG,
ConsoleSessionForegroundProcessId: LONGLONG,
TimeUpdateLock: ULONGLONG,
BaselineSystemTimeQpc: ULONGLONG,
BaselineInterruptTimeQpc: ULONGLONG,
QpcSystemTimeIncrement: ULONGLONG,
QpcInterruptTimeIncrement: ULONGLONG,
QpcSystemTimeIncrementShift: UCHAR,
QpcInterruptTimeIncrementShift: UCHAR,
UnparkedProcessorCount: USHORT,
EnclaveFeatureMask: [4]ULONG,
TelemetryCoverageRound: ULONG,
UserModeGlobalLogger: [16]USHORT,
ImageFileExecutionOptions: ULONG,
LangGenerationCount: ULONG,
Reserved4: ULONGLONG,
InterruptTimeBias: ULONGLONG,
QpcBias: ULONGLONG,
ActiveProcessorCount: ULONG,
ActiveGroupCount: UCHAR,
Reserved9: UCHAR,
DummyUnion5: extern union {
QpcData: USHORT,
Alt: extern struct {
QpcBypassEnabled: UCHAR,
QpcShift: UCHAR,
},
},
TimeZoneBiasEffectiveStart: LARGE_INTEGER,
TimeZoneBiasEffectiveEnd: LARGE_INTEGER,
XState: XSTATE_CONFIGURATION,
FeatureConfigurationChangeStamp: KSYSTEM_TIME,
Spare: ULONG,
UserPointerAuthMask: ULONG64,
};
/// Read-only user-mode address for the shared data.
/// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
/// https://msrc-blog.microsoft.com/2022/04/05/randomizing-the-kuser_shared_data-structure-on-windows/
pub const SharedUserData: *const KUSER_SHARED_DATA = @intToPtr(*const KUSER_SHARED_DATA, 0x7FFE0000);
pub fn IsProcessorFeaturePresent(feature: PF) bool {
if (@enumToInt(feature) >= PROCESSOR_FEATURE_MAX) return false;
return SharedUserData.ProcessorFeatures[@enumToInt(feature)] == 1;
}

View File

@ -10,6 +10,7 @@ const DWORD = windows.DWORD;
const FILE_INFO_BY_HANDLE_CLASS = windows.FILE_INFO_BY_HANDLE_CLASS;
const HANDLE = windows.HANDLE;
const HMODULE = windows.HMODULE;
const HKEY = windows.HKEY;
const HRESULT = windows.HRESULT;
const LARGE_INTEGER = windows.LARGE_INTEGER;
const LPCWSTR = windows.LPCWSTR;
@ -57,6 +58,8 @@ const UCHAR = windows.UCHAR;
const FARPROC = windows.FARPROC;
const INIT_ONCE_FN = windows.INIT_ONCE_FN;
const PMEMORY_BASIC_INFORMATION = windows.PMEMORY_BASIC_INFORMATION;
const REGSAM = windows.REGSAM;
const LSTATUS = windows.LSTATUS;
pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(WINAPI) ?*anyopaque;
pub extern "kernel32" fn RemoveVectoredExceptionHandler(Handle: HANDLE) callconv(WINAPI) c_ulong;
@ -231,6 +234,7 @@ pub extern "kernel32" fn GetQueuedCompletionStatusEx(
pub extern "kernel32" fn GetSystemInfo(lpSystemInfo: *SYSTEM_INFO) callconv(WINAPI) void;
pub extern "kernel32" fn GetSystemTimeAsFileTime(*FILETIME) callconv(WINAPI) void;
pub extern "kernel32" fn IsProcessorFeaturePresent(ProcessorFeature: DWORD) BOOL;
pub extern "kernel32" fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) callconv(WINAPI) ?HANDLE;
pub extern "kernel32" fn HeapDestroy(hHeap: HANDLE) callconv(WINAPI) BOOL;
@ -411,3 +415,11 @@ pub extern "kernel32" fn SleepConditionVariableSRW(
pub extern "kernel32" fn TryAcquireSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) BOOLEAN;
pub extern "kernel32" fn AcquireSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) void;
pub extern "kernel32" fn ReleaseSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) void;
pub extern "kernel32" fn RegOpenKeyExW(
hkey: HKEY,
lpSubKey: LPCWSTR,
ulOptions: DWORD,
samDesired: REGSAM,
phkResult: *HKEY,
) callconv(WINAPI) LSTATUS;

View File

@ -22,6 +22,8 @@ const RTL_OSVERSIONINFOW = windows.RTL_OSVERSIONINFOW;
const FILE_BASIC_INFORMATION = windows.FILE_BASIC_INFORMATION;
const SIZE_T = windows.SIZE_T;
const CURDIR = windows.CURDIR;
const PCWSTR = windows.PCWSTR;
const RTL_QUERY_REGISTRY_TABLE = windows.RTL_QUERY_REGISTRY_TABLE;
pub const THREADINFOCLASS = enum(c_int) {
ThreadBasicInformation,
@ -253,3 +255,17 @@ pub extern "ntdll" fn NtUnlockFile(
Length: *const LARGE_INTEGER,
Key: ?*ULONG,
) callconv(WINAPI) NTSTATUS;
pub extern "ntdll" fn NtOpenKey(
KeyHandle: *HANDLE,
DesiredAccess: ACCESS_MASK,
ObjectAttributes: OBJECT_ATTRIBUTES,
) callconv(WINAPI) NTSTATUS;
pub extern "ntdll" fn RtlQueryRegistryValues(
RelativeTo: ULONG,
Path: PCWSTR,
QueryTable: [*]RTL_QUERY_REGISTRY_TABLE,
Context: ?*anyopaque,
Environment: ?*anyopaque,
) callconv(WINAPI) NTSTATUS;

View File

@ -978,6 +978,7 @@ fn detectNativeCpuAndFeatures(cpu_arch: Target.Cpu.Arch, os: Target.Os, cross_ta
switch (builtin.os.tag) {
.linux => return linux.detectNativeCpuAndFeatures(),
.macos => return darwin.macos.detectNativeCpuAndFeatures(),
.windows => return windows.detectNativeCpuAndFeatures(),
else => {},
}

134
lib/std/zig/system/arm.zig Normal file
View File

@ -0,0 +1,134 @@
const std = @import("std");
pub const CoreInfo = struct {
architecture: u8 = 0,
implementer: u8 = 0,
variant: u8 = 0,
part: u16 = 0,
};
pub const cpu_models = struct {
// Shorthands to simplify the tables below.
const A32 = std.Target.arm.cpu;
const A64 = std.Target.aarch64.cpu;
const E = struct {
part: u16,
variant: ?u8 = null, // null if matches any variant
m32: ?*const std.Target.Cpu.Model = null,
m64: ?*const std.Target.Cpu.Model = null,
};
// implementer = 0x41
const ARM = [_]E{
E{ .part = 0x926, .m32 = &A32.arm926ej_s, .m64 = null },
E{ .part = 0xb02, .m32 = &A32.mpcore, .m64 = null },
E{ .part = 0xb36, .m32 = &A32.arm1136j_s, .m64 = null },
E{ .part = 0xb56, .m32 = &A32.arm1156t2_s, .m64 = null },
E{ .part = 0xb76, .m32 = &A32.arm1176jz_s, .m64 = null },
E{ .part = 0xc05, .m32 = &A32.cortex_a5, .m64 = null },
E{ .part = 0xc07, .m32 = &A32.cortex_a7, .m64 = null },
E{ .part = 0xc08, .m32 = &A32.cortex_a8, .m64 = null },
E{ .part = 0xc09, .m32 = &A32.cortex_a9, .m64 = null },
E{ .part = 0xc0d, .m32 = &A32.cortex_a17, .m64 = null },
E{ .part = 0xc0f, .m32 = &A32.cortex_a15, .m64 = null },
E{ .part = 0xc0e, .m32 = &A32.cortex_a17, .m64 = null },
E{ .part = 0xc14, .m32 = &A32.cortex_r4, .m64 = null },
E{ .part = 0xc15, .m32 = &A32.cortex_r5, .m64 = null },
E{ .part = 0xc17, .m32 = &A32.cortex_r7, .m64 = null },
E{ .part = 0xc18, .m32 = &A32.cortex_r8, .m64 = null },
E{ .part = 0xc20, .m32 = &A32.cortex_m0, .m64 = null },
E{ .part = 0xc21, .m32 = &A32.cortex_m1, .m64 = null },
E{ .part = 0xc23, .m32 = &A32.cortex_m3, .m64 = null },
E{ .part = 0xc24, .m32 = &A32.cortex_m4, .m64 = null },
E{ .part = 0xc27, .m32 = &A32.cortex_m7, .m64 = null },
E{ .part = 0xc60, .m32 = &A32.cortex_m0plus, .m64 = null },
E{ .part = 0xd01, .m32 = &A32.cortex_a32, .m64 = null },
E{ .part = 0xd03, .m32 = &A32.cortex_a53, .m64 = &A64.cortex_a53 },
E{ .part = 0xd04, .m32 = &A32.cortex_a35, .m64 = &A64.cortex_a35 },
E{ .part = 0xd05, .m32 = &A32.cortex_a55, .m64 = &A64.cortex_a55 },
E{ .part = 0xd07, .m32 = &A32.cortex_a57, .m64 = &A64.cortex_a57 },
E{ .part = 0xd08, .m32 = &A32.cortex_a72, .m64 = &A64.cortex_a72 },
E{ .part = 0xd09, .m32 = &A32.cortex_a73, .m64 = &A64.cortex_a73 },
E{ .part = 0xd0a, .m32 = &A32.cortex_a75, .m64 = &A64.cortex_a75 },
E{ .part = 0xd0b, .m32 = &A32.cortex_a76, .m64 = &A64.cortex_a76 },
E{ .part = 0xd0c, .m32 = &A32.neoverse_n1, .m64 = &A64.neoverse_n1 },
E{ .part = 0xd0d, .m32 = &A32.cortex_a77, .m64 = &A64.cortex_a77 },
E{ .part = 0xd13, .m32 = &A32.cortex_r52, .m64 = null },
E{ .part = 0xd20, .m32 = &A32.cortex_m23, .m64 = null },
E{ .part = 0xd21, .m32 = &A32.cortex_m33, .m64 = null },
E{ .part = 0xd41, .m32 = &A32.cortex_a78, .m64 = &A64.cortex_a78 },
E{ .part = 0xd4b, .m32 = &A32.cortex_a78c, .m64 = &A64.cortex_a78c },
// This is a guess based on https://www.notebookcheck.net/Qualcomm-Snapdragon-8cx-Gen-3-Processor-Benchmarks-and-Specs.652916.0.html
E{ .part = 0xd4c, .m32 = &A32.cortex_x1c, .m64 = &A64.cortex_x1c },
E{ .part = 0xd44, .m32 = &A32.cortex_x1, .m64 = &A64.cortex_x1 },
E{ .part = 0xd02, .m64 = &A64.cortex_a34 },
E{ .part = 0xd06, .m64 = &A64.cortex_a65 },
E{ .part = 0xd43, .m64 = &A64.cortex_a65ae },
};
// implementer = 0x42
const Broadcom = [_]E{
E{ .part = 0x516, .m64 = &A64.thunderx2t99 },
};
// implementer = 0x43
const Cavium = [_]E{
E{ .part = 0x0a0, .m64 = &A64.thunderx },
E{ .part = 0x0a2, .m64 = &A64.thunderxt81 },
E{ .part = 0x0a3, .m64 = &A64.thunderxt83 },
E{ .part = 0x0a1, .m64 = &A64.thunderxt88 },
E{ .part = 0x0af, .m64 = &A64.thunderx2t99 },
};
// implementer = 0x46
const Fujitsu = [_]E{
E{ .part = 0x001, .m64 = &A64.a64fx },
};
// implementer = 0x48
const HiSilicon = [_]E{
E{ .part = 0xd01, .m64 = &A64.tsv110 },
};
// implementer = 0x4e
const Nvidia = [_]E{
E{ .part = 0x004, .m64 = &A64.carmel },
};
// implementer = 0x50
const Ampere = [_]E{
E{ .part = 0x000, .variant = 3, .m64 = &A64.emag },
E{ .part = 0x000, .m64 = &A64.xgene1 },
};
// implementer = 0x51
const Qualcomm = [_]E{
E{ .part = 0x06f, .m32 = &A32.krait },
E{ .part = 0x201, .m64 = &A64.kryo, .m32 = &A64.kryo },
E{ .part = 0x205, .m64 = &A64.kryo, .m32 = &A64.kryo },
E{ .part = 0x211, .m64 = &A64.kryo, .m32 = &A64.kryo },
E{ .part = 0x800, .m64 = &A64.cortex_a73, .m32 = &A64.cortex_a73 },
E{ .part = 0x801, .m64 = &A64.cortex_a73, .m32 = &A64.cortex_a73 },
E{ .part = 0x802, .m64 = &A64.cortex_a75, .m32 = &A64.cortex_a75 },
E{ .part = 0x803, .m64 = &A64.cortex_a75, .m32 = &A64.cortex_a75 },
E{ .part = 0x804, .m64 = &A64.cortex_a76, .m32 = &A64.cortex_a76 },
E{ .part = 0x805, .m64 = &A64.cortex_a76, .m32 = &A64.cortex_a76 },
E{ .part = 0xc00, .m64 = &A64.falkor },
E{ .part = 0xc01, .m64 = &A64.saphira },
};
pub fn isKnown(core: CoreInfo, is_64bit: bool) ?*const std.Target.Cpu.Model {
const models = switch (core.implementer) {
0x41 => &ARM,
0x42 => &Broadcom,
0x43 => &Cavium,
0x46 => &Fujitsu,
0x48 => &HiSilicon,
0x50 => &Ampere,
0x51 => &Qualcomm,
else => return null,
};
for (models) |model| {
if (model.part == core.part and
(model.variant == null or model.variant.? == core.variant))
return if (is_64bit) model.m64 else model.m32;
}
return null;
}
};

View File

@ -159,129 +159,7 @@ const ArmCpuinfoImpl = struct {
is_really_v6: bool = false,
};
const cpu_models = struct {
// Shorthands to simplify the tables below.
const A32 = Target.arm.cpu;
const A64 = Target.aarch64.cpu;
const E = struct {
part: u16,
variant: ?u8 = null, // null if matches any variant
m32: ?*const Target.Cpu.Model = null,
m64: ?*const Target.Cpu.Model = null,
};
// implementer = 0x41
const ARM = [_]E{
E{ .part = 0x926, .m32 = &A32.arm926ej_s, .m64 = null },
E{ .part = 0xb02, .m32 = &A32.mpcore, .m64 = null },
E{ .part = 0xb36, .m32 = &A32.arm1136j_s, .m64 = null },
E{ .part = 0xb56, .m32 = &A32.arm1156t2_s, .m64 = null },
E{ .part = 0xb76, .m32 = &A32.arm1176jz_s, .m64 = null },
E{ .part = 0xc05, .m32 = &A32.cortex_a5, .m64 = null },
E{ .part = 0xc07, .m32 = &A32.cortex_a7, .m64 = null },
E{ .part = 0xc08, .m32 = &A32.cortex_a8, .m64 = null },
E{ .part = 0xc09, .m32 = &A32.cortex_a9, .m64 = null },
E{ .part = 0xc0d, .m32 = &A32.cortex_a17, .m64 = null },
E{ .part = 0xc0f, .m32 = &A32.cortex_a15, .m64 = null },
E{ .part = 0xc0e, .m32 = &A32.cortex_a17, .m64 = null },
E{ .part = 0xc14, .m32 = &A32.cortex_r4, .m64 = null },
E{ .part = 0xc15, .m32 = &A32.cortex_r5, .m64 = null },
E{ .part = 0xc17, .m32 = &A32.cortex_r7, .m64 = null },
E{ .part = 0xc18, .m32 = &A32.cortex_r8, .m64 = null },
E{ .part = 0xc20, .m32 = &A32.cortex_m0, .m64 = null },
E{ .part = 0xc21, .m32 = &A32.cortex_m1, .m64 = null },
E{ .part = 0xc23, .m32 = &A32.cortex_m3, .m64 = null },
E{ .part = 0xc24, .m32 = &A32.cortex_m4, .m64 = null },
E{ .part = 0xc27, .m32 = &A32.cortex_m7, .m64 = null },
E{ .part = 0xc60, .m32 = &A32.cortex_m0plus, .m64 = null },
E{ .part = 0xd01, .m32 = &A32.cortex_a32, .m64 = null },
E{ .part = 0xd03, .m32 = &A32.cortex_a53, .m64 = &A64.cortex_a53 },
E{ .part = 0xd04, .m32 = &A32.cortex_a35, .m64 = &A64.cortex_a35 },
E{ .part = 0xd05, .m32 = &A32.cortex_a55, .m64 = &A64.cortex_a55 },
E{ .part = 0xd07, .m32 = &A32.cortex_a57, .m64 = &A64.cortex_a57 },
E{ .part = 0xd08, .m32 = &A32.cortex_a72, .m64 = &A64.cortex_a72 },
E{ .part = 0xd09, .m32 = &A32.cortex_a73, .m64 = &A64.cortex_a73 },
E{ .part = 0xd0a, .m32 = &A32.cortex_a75, .m64 = &A64.cortex_a75 },
E{ .part = 0xd0b, .m32 = &A32.cortex_a76, .m64 = &A64.cortex_a76 },
E{ .part = 0xd0c, .m32 = &A32.neoverse_n1, .m64 = &A64.neoverse_n1 },
E{ .part = 0xd0d, .m32 = &A32.cortex_a77, .m64 = &A64.cortex_a77 },
E{ .part = 0xd13, .m32 = &A32.cortex_r52, .m64 = null },
E{ .part = 0xd20, .m32 = &A32.cortex_m23, .m64 = null },
E{ .part = 0xd21, .m32 = &A32.cortex_m33, .m64 = null },
E{ .part = 0xd41, .m32 = &A32.cortex_a78, .m64 = &A64.cortex_a78 },
E{ .part = 0xd4b, .m32 = &A32.cortex_a78c, .m64 = &A64.cortex_a78c },
E{ .part = 0xd44, .m32 = &A32.cortex_x1, .m64 = &A64.cortex_x1 },
E{ .part = 0xd02, .m64 = &A64.cortex_a34 },
E{ .part = 0xd06, .m64 = &A64.cortex_a65 },
E{ .part = 0xd43, .m64 = &A64.cortex_a65ae },
};
// implementer = 0x42
const Broadcom = [_]E{
E{ .part = 0x516, .m64 = &A64.thunderx2t99 },
};
// implementer = 0x43
const Cavium = [_]E{
E{ .part = 0x0a0, .m64 = &A64.thunderx },
E{ .part = 0x0a2, .m64 = &A64.thunderxt81 },
E{ .part = 0x0a3, .m64 = &A64.thunderxt83 },
E{ .part = 0x0a1, .m64 = &A64.thunderxt88 },
E{ .part = 0x0af, .m64 = &A64.thunderx2t99 },
};
// implementer = 0x46
const Fujitsu = [_]E{
E{ .part = 0x001, .m64 = &A64.a64fx },
};
// implementer = 0x48
const HiSilicon = [_]E{
E{ .part = 0xd01, .m64 = &A64.tsv110 },
};
// implementer = 0x4e
const Nvidia = [_]E{
E{ .part = 0x004, .m64 = &A64.carmel },
};
// implementer = 0x50
const Ampere = [_]E{
E{ .part = 0x000, .variant = 3, .m64 = &A64.emag },
E{ .part = 0x000, .m64 = &A64.xgene1 },
};
// implementer = 0x51
const Qualcomm = [_]E{
E{ .part = 0x06f, .m32 = &A32.krait },
E{ .part = 0x201, .m64 = &A64.kryo, .m32 = &A64.kryo },
E{ .part = 0x205, .m64 = &A64.kryo, .m32 = &A64.kryo },
E{ .part = 0x211, .m64 = &A64.kryo, .m32 = &A64.kryo },
E{ .part = 0x800, .m64 = &A64.cortex_a73, .m32 = &A64.cortex_a73 },
E{ .part = 0x801, .m64 = &A64.cortex_a73, .m32 = &A64.cortex_a73 },
E{ .part = 0x802, .m64 = &A64.cortex_a75, .m32 = &A64.cortex_a75 },
E{ .part = 0x803, .m64 = &A64.cortex_a75, .m32 = &A64.cortex_a75 },
E{ .part = 0x804, .m64 = &A64.cortex_a76, .m32 = &A64.cortex_a76 },
E{ .part = 0x805, .m64 = &A64.cortex_a76, .m32 = &A64.cortex_a76 },
E{ .part = 0xc00, .m64 = &A64.falkor },
E{ .part = 0xc01, .m64 = &A64.saphira },
};
fn isKnown(core: CoreInfo, is_64bit: bool) ?*const Target.Cpu.Model {
const models = switch (core.implementer) {
0x41 => &ARM,
0x42 => &Broadcom,
0x43 => &Cavium,
0x46 => &Fujitsu,
0x48 => &HiSilicon,
0x50 => &Ampere,
0x51 => &Qualcomm,
else => return null,
};
for (models) |model| {
if (model.part == core.part and
(model.variant == null or model.variant.? == core.variant))
return if (is_64bit) model.m64 else model.m32;
}
return null;
}
};
const cpu_models = @import("arm.zig").cpu_models;
fn addOne(self: *ArmCpuinfoImpl) void {
if (self.have_fields == 4 and self.core_no < self.cores.len) {
@ -346,7 +224,12 @@ const ArmCpuinfoImpl = struct {
var known_models: [self.cores.len]?*const Target.Cpu.Model = undefined;
for (self.cores[0..self.core_no]) |core, i| {
known_models[i] = cpu_models.isKnown(core, is_64bit);
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

View File

@ -1,6 +1,12 @@
const std = @import("std");
const builtin = @import("builtin");
const mem = std.mem;
const Target = std.Target;
pub const WindowsVersion = std.Target.Os.WindowsVersion;
pub const PF = std.os.windows.PF;
pub const REG = std.os.windows.REG;
pub const IsProcessorFeaturePresent = std.os.windows.IsProcessorFeaturePresent;
/// Returns the highest known WindowsVersion deduced from reported runtime information.
/// Discards information about in-between versions we don't differentiate.
@ -38,3 +44,318 @@ pub fn detectRuntimeVersion() WindowsVersion {
return @intToEnum(WindowsVersion, version);
}
// Technically, a registry value can be as long as 1MB. However, MS recommends storing
// values larger than 2048 bytes in a file rather than directly in the registry, and since we
// are only accessing a system hive \Registry\Machine, we stick to MS guidelines.
// https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits
const max_value_len = 2048;
const RegistryPair = struct {
key: []const u8,
value: std.os.windows.ULONG,
};
fn getCpuInfoFromRegistry(
core: usize,
comptime pairs_num: comptime_int,
comptime pairs: [pairs_num]RegistryPair,
out_buf: *[pairs_num][max_value_len]u8,
) !void {
// Originally, I wanted to issue a single call with a more complex table structure such that we
// would sequentially visit each CPU#d subkey in the registry and pull the value of interest into
// a buffer, however, NT seems to be expecting a single buffer per each table meaning we would
// end up pulling only the last CPU core info, overwriting everything else.
// If anyone can come up with a solution to this, please do!
const table_size = 1 + pairs.len;
var table: [table_size + 1]std.os.windows.RTL_QUERY_REGISTRY_TABLE = undefined;
const topkey = std.unicode.utf8ToUtf16LeStringLiteral("\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor");
const max_cpu_buf = 4;
var next_cpu_buf: [max_cpu_buf]u8 = undefined;
const next_cpu = try std.fmt.bufPrint(&next_cpu_buf, "{d}", .{core});
var subkey: [max_cpu_buf + 1]u16 = undefined;
const subkey_len = try std.unicode.utf8ToUtf16Le(&subkey, next_cpu);
subkey[subkey_len] = 0;
table[0] = .{
.QueryRoutine = null,
.Flags = std.os.windows.RTL_QUERY_REGISTRY_SUBKEY | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED,
.Name = subkey[0..subkey_len :0],
.EntryContext = null,
.DefaultType = REG.NONE,
.DefaultData = null,
.DefaultLength = 0,
};
inline for (pairs) |pair, i| {
const ctx: *anyopaque = blk: {
switch (pair.value) {
REG.SZ,
REG.EXPAND_SZ,
REG.MULTI_SZ,
=> {
var buf: [max_value_len / 2]u16 = undefined;
var unicode = std.os.windows.UNICODE_STRING{
.Length = 0,
.MaximumLength = max_value_len,
.Buffer = &buf,
};
break :blk &unicode;
},
REG.DWORD,
REG.DWORD_BIG_ENDIAN,
=> {
var buf: [4]u8 = undefined;
break :blk &buf;
},
REG.QWORD => {
var buf: [8]u8 = undefined;
break :blk &buf;
},
else => unreachable,
}
};
const key_namee = std.unicode.utf8ToUtf16LeStringLiteral(pair.key);
table[i + 1] = .{
.QueryRoutine = null,
.Flags = std.os.windows.RTL_QUERY_REGISTRY_DIRECT | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED,
.Name = @intToPtr([*:0]u16, @ptrToInt(key_namee)),
.EntryContext = ctx,
.DefaultType = REG.NONE,
.DefaultData = null,
.DefaultLength = 0,
};
}
// Table sentinel
table[table_size] = .{
.QueryRoutine = null,
.Flags = 0,
.Name = null,
.EntryContext = null,
.DefaultType = 0,
.DefaultData = null,
.DefaultLength = 0,
};
const res = std.os.windows.ntdll.RtlQueryRegistryValues(
std.os.windows.RTL_REGISTRY_ABSOLUTE,
topkey,
&table,
null,
null,
);
switch (res) {
.SUCCESS => {
inline for (pairs) |pair, i| switch (pair.value) {
REG.NONE => unreachable,
REG.SZ,
REG.EXPAND_SZ,
REG.MULTI_SZ,
=> {
const entry = @ptrCast(*align(1) const std.os.windows.UNICODE_STRING, table[i + 1].EntryContext);
const len = try std.unicode.utf16leToUtf8(out_buf[i][0..], entry.Buffer[0 .. entry.Length / 2]);
out_buf[i][len] = 0;
},
REG.DWORD,
REG.DWORD_BIG_ENDIAN,
REG.QWORD,
=> {
const entry = @ptrCast([*]align(1) const u8, table[i + 1].EntryContext);
switch (pair.value) {
REG.DWORD, REG.DWORD_BIG_ENDIAN => {
mem.copy(u8, out_buf[i][0..4], entry[0..4]);
},
REG.QWORD => {
mem.copy(u8, out_buf[i][0..8], entry[0..8]);
},
else => unreachable,
}
},
else => unreachable,
};
},
else => return error.Unexpected,
}
}
fn getCpuCount() usize {
return std.os.windows.peb().NumberOfProcessors;
}
const ArmCpuInfoImpl = struct {
cores: [4]CoreInfo = undefined,
core_no: usize = 0,
have_fields: usize = 0,
const CoreInfo = @import("arm.zig").CoreInfo;
const cpu_models = @import("arm.zig").cpu_models;
const Data = struct {
cp_4000: []const u8,
identifier: []const u8,
};
fn parseDataHook(self: *ArmCpuInfoImpl, data: Data) !void {
const info = &self.cores[self.core_no];
info.* = .{};
// CPU part
info.part = mem.readIntLittle(u16, data.cp_4000[0..2]) >> 4;
self.have_fields += 1;
// CPU implementer
info.implementer = data.cp_4000[3];
self.have_fields += 1;
var tokens = mem.tokenize(u8, data.identifier, " ");
while (tokens.next()) |token| {
if (mem.eql(u8, "Family", token)) {
// CPU architecture
const family = tokens.next() orelse continue;
info.architecture = try std.fmt.parseInt(u8, family, 10);
self.have_fields += 1;
break;
}
} else return;
self.addOne();
}
fn addOne(self: *ArmCpuInfoImpl) void {
if (self.have_fields == 3 and self.core_no < self.cores.len) {
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 finalize(self: ArmCpuInfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
if (self.core_no == 0) return null;
const is_64bit = switch (arch) {
.aarch64, .aarch64_be, .aarch64_32 => true,
else => false,
};
var known_models: [self.cores.len]?*const Target.Cpu.Model = undefined;
for (self.cores[0..self.core_no]) |core, i| {
known_models[i] = cpu_models.isKnown(core, 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);
fn CpuInfoParser(comptime impl: anytype) type {
return struct {
fn parse(arch: Target.Cpu.Arch) !?Target.Cpu {
var obj: impl = .{};
var out_buf: [2][max_value_len]u8 = undefined;
var i: usize = 0;
while (i < getCpuCount()) : (i += 1) {
try getCpuInfoFromRegistry(i, 2, .{
.{ .key = "CP 4000", .value = REG.QWORD },
.{ .key = "Identifier", .value = REG.SZ },
}, &out_buf);
const cp_4000 = out_buf[0][0..8];
const identifier = mem.sliceTo(out_buf[1][0..], 0);
try obj.parseDataHook(.{
.cp_4000 = cp_4000,
.identifier = identifier,
});
}
return obj.finalize(arch);
}
};
}
fn genericCpu(comptime arch: Target.Cpu.Arch) Target.Cpu {
return .{
.arch = arch,
.model = Target.Cpu.Model.generic(arch),
.features = Target.Cpu.Feature.Set.empty,
};
}
pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
const current_arch = builtin.cpu.arch;
switch (current_arch) {
.aarch64, .aarch64_be, .aarch64_32 => {
var cpu = cpu: {
var maybe_cpu = ArmCpuInfoParser.parse(current_arch) catch break :cpu genericCpu(current_arch);
break :cpu maybe_cpu orelse genericCpu(current_arch);
};
const Feature = Target.aarch64.Feature;
// Override any features that are either present or absent
if (IsProcessorFeaturePresent(PF.ARM_NEON_INSTRUCTIONS_AVAILABLE)) {
cpu.features.addFeature(@enumToInt(Feature.neon));
} else {
cpu.features.removeFeature(@enumToInt(Feature.neon));
}
if (IsProcessorFeaturePresent(PF.ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)) {
cpu.features.addFeature(@enumToInt(Feature.crc));
} else {
cpu.features.removeFeature(@enumToInt(Feature.crc));
}
if (IsProcessorFeaturePresent(PF.ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE)) {
cpu.features.addFeature(@enumToInt(Feature.crypto));
} else {
cpu.features.removeFeature(@enumToInt(Feature.crypto));
}
if (IsProcessorFeaturePresent(PF.ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)) {
cpu.features.addFeature(@enumToInt(Feature.lse));
} else {
cpu.features.removeFeature(@enumToInt(Feature.lse));
}
if (IsProcessorFeaturePresent(PF.ARM_V82_DP_INSTRUCTIONS_AVAILABLE)) {
cpu.features.addFeature(@enumToInt(Feature.dotprod));
} else {
cpu.features.removeFeature(@enumToInt(Feature.dotprod));
}
if (IsProcessorFeaturePresent(PF.ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)) {
cpu.features.addFeature(@enumToInt(Feature.jsconv));
} else {
cpu.features.removeFeature(@enumToInt(Feature.jsconv));
}
return cpu;
},
else => {},
}
}