diff --git a/HashLib.Benchmark/Delphi/PerformanceBenchmarkConsole.dpr b/HashLib.Benchmark/Delphi/PerformanceBenchmarkConsole.dpr
index 041f60d..5451c4d 100644
--- a/HashLib.Benchmark/Delphi/PerformanceBenchmarkConsole.dpr
+++ b/HashLib.Benchmark/Delphi/PerformanceBenchmarkConsole.dpr
@@ -128,6 +128,8 @@ uses
HlpX86SimdFeatures in '..\..\HashLib\src\Utils\HlpX86SimdFeatures.pas',
HlpArmSimdFeatures in '..\..\HashLib\src\Utils\HlpArmSimdFeatures.pas',
HlpSimdLevels in '..\..\HashLib\src\Utils\HlpSimdLevels.pas',
+ HlpArmHwCapProvider in '..\..\HashLib\src\Utils\HlpArmHwCapProvider.pas',
+ HlpDarwinSysCtl in '..\..\HashLib\src\Utils\HlpDarwinSysCtl.pas',
HlpHashLibTypes in '..\..\HashLib\src\Utils\HlpHashLibTypes.pas',
HlpArrayUtils in '..\..\HashLib\src\Utils\HlpArrayUtils.pas';
diff --git a/HashLib.Tests/Delphi.Tests/HashLib.Tests.dpr b/HashLib.Tests/Delphi.Tests/HashLib.Tests.dpr
index c62dc5a..c104b6f 100644
--- a/HashLib.Tests/Delphi.Tests/HashLib.Tests.dpr
+++ b/HashLib.Tests/Delphi.Tests/HashLib.Tests.dpr
@@ -146,6 +146,8 @@ uses
HlpX86SimdFeatures in '..\..\HashLib\src\Utils\HlpX86SimdFeatures.pas',
HlpArmSimdFeatures in '..\..\HashLib\src\Utils\HlpArmSimdFeatures.pas',
HlpSimdLevels in '..\..\HashLib\src\Utils\HlpSimdLevels.pas',
+ HlpArmHwCapProvider in '..\..\HashLib\src\Utils\HlpArmHwCapProvider.pas',
+ HlpDarwinSysCtl in '..\..\HashLib\src\Utils\HlpDarwinSysCtl.pas',
HlpHashLibTypes in '..\..\HashLib\src\Utils\HlpHashLibTypes.pas',
HlpArrayUtils in '..\..\HashLib\src\Utils\HlpArrayUtils.pas',
HashLibTestBase in '..\src\HashLibTestBase.pas',
diff --git a/HashLib/src/Checksum/HlpAdler32Dispatch.pas b/HashLib/src/Checksum/HlpAdler32Dispatch.pas
index 0ac6d7d..5674249 100644
--- a/HashLib/src/Checksum/HlpAdler32Dispatch.pas
+++ b/HashLib/src/Checksum/HlpAdler32Dispatch.pas
@@ -201,7 +201,7 @@ procedure InitDispatch();
end;
{$ENDIF}
{$IFDEF HASHLIB_X86_64_ASM}
- case TCpuFeatures.X86.GetSimdLevel() of
+ case TCpuFeatures.X86.GetActiveSimdLevel() of
TX86SimdLevel.AVX2:
begin
Adler32_Update := @Adler32_Update_Avx2;
diff --git a/HashLib/src/Checksum/HlpCRCDispatch.pas b/HashLib/src/Checksum/HlpCRCDispatch.pas
index dad6cdd..22e080f 100644
--- a/HashLib/src/Checksum/HlpCRCDispatch.pas
+++ b/HashLib/src/Checksum/HlpCRCDispatch.pas
@@ -521,7 +521,7 @@ procedure InitDispatch();
end;
{$ENDIF HASHLIB_I386_ASM}
{$IFDEF HASHLIB_X86_64_ASM}
- case TCpuFeatures.X86.GetSimdLevel() of
+ case TCpuFeatures.X86.GetActiveSimdLevel() of
TX86SimdLevel.AVX2, TX86SimdLevel.SSSE3, TX86SimdLevel.SSE2:
BindSse2CrcFold;
end;
diff --git a/HashLib/src/Crypto/HlpBlake2BDispatch.pas b/HashLib/src/Crypto/HlpBlake2BDispatch.pas
index a79f8e8..50ef386 100644
--- a/HashLib/src/Crypto/HlpBlake2BDispatch.pas
+++ b/HashLib/src/Crypto/HlpBlake2BDispatch.pas
@@ -140,7 +140,7 @@ procedure InitDispatch();
end;
{$ENDIF}
{$IFDEF HASHLIB_X86_64_ASM}
- case TCpuFeatures.X86.GetSimdLevel() of
+ case TCpuFeatures.X86.GetActiveSimdLevel() of
TX86SimdLevel.AVX2:
begin
Blake2B_Compress := @Blake2B_Compress_Avx2;
diff --git a/HashLib/src/Crypto/HlpBlake2SDispatch.pas b/HashLib/src/Crypto/HlpBlake2SDispatch.pas
index 04023d1..5fbf560 100644
--- a/HashLib/src/Crypto/HlpBlake2SDispatch.pas
+++ b/HashLib/src/Crypto/HlpBlake2SDispatch.pas
@@ -138,7 +138,7 @@ procedure InitDispatch();
end;
{$ENDIF}
{$IFDEF HASHLIB_X86_64_ASM}
- case TCpuFeatures.X86.GetSimdLevel() of
+ case TCpuFeatures.X86.GetActiveSimdLevel() of
TX86SimdLevel.AVX2:
begin
Blake2S_Compress := @Blake2S_Compress_Avx2;
diff --git a/HashLib/src/Crypto/HlpBlake3Dispatch.pas b/HashLib/src/Crypto/HlpBlake3Dispatch.pas
index c577bbc..aaf264d 100644
--- a/HashLib/src/Crypto/HlpBlake3Dispatch.pas
+++ b/HashLib/src/Crypto/HlpBlake3Dispatch.pas
@@ -723,7 +723,7 @@ procedure InitDispatch();
end;
{$ENDIF}
{$IFDEF HASHLIB_X86_64_ASM}
- case TCpuFeatures.X86.GetSimdLevel() of
+ case TCpuFeatures.X86.GetActiveSimdLevel() of
TX86SimdLevel.AVX2:
begin
Blake3_Compress := @Blake3_Compress_Avx2;
diff --git a/HashLib/src/Crypto/HlpSHA1Dispatch.pas b/HashLib/src/Crypto/HlpSHA1Dispatch.pas
index 57598f6..a7455fc 100644
--- a/HashLib/src/Crypto/HlpSHA1Dispatch.pas
+++ b/HashLib/src/Crypto/HlpSHA1Dispatch.pas
@@ -193,7 +193,7 @@ procedure InitDispatch();
SHA1_Compress := @SHA1_Compress_ShaNi_Wrap;
Exit;
end;
- case TCpuFeatures.X86.GetSimdLevel() of
+ case TCpuFeatures.X86.GetActiveSimdLevel() of
TX86SimdLevel.AVX2:
begin
SHA1_Compress := @SHA1_Compress_Avx2_Wrap;
diff --git a/HashLib/src/Crypto/HlpSHA2_256Dispatch.pas b/HashLib/src/Crypto/HlpSHA2_256Dispatch.pas
index 2ba4832..c79cf39 100644
--- a/HashLib/src/Crypto/HlpSHA2_256Dispatch.pas
+++ b/HashLib/src/Crypto/HlpSHA2_256Dispatch.pas
@@ -203,7 +203,7 @@ procedure InitDispatch();
SHA256_Compress := @SHA256_Compress_ShaNi_Wrap;
Exit;
end;
- case TCpuFeatures.X86.GetSimdLevel() of
+ case TCpuFeatures.X86.GetActiveSimdLevel() of
TX86SimdLevel.AVX2:
begin
SHA256_Compress := @SHA256_Compress_Avx2_Wrap;
diff --git a/HashLib/src/Crypto/HlpSHA2_512Dispatch.pas b/HashLib/src/Crypto/HlpSHA2_512Dispatch.pas
index e0c5b13..36129c9 100644
--- a/HashLib/src/Crypto/HlpSHA2_512Dispatch.pas
+++ b/HashLib/src/Crypto/HlpSHA2_512Dispatch.pas
@@ -207,7 +207,7 @@ procedure InitDispatch();
end;
{$ENDIF}
{$IFDEF HASHLIB_X86_64_ASM}
- case TCpuFeatures.X86.GetSimdLevel() of
+ case TCpuFeatures.X86.GetActiveSimdLevel() of
TX86SimdLevel.AVX2:
begin
SHA512_Compress := @SHA512_Compress_Avx2_Wrap;
diff --git a/HashLib/src/Crypto/HlpSHA3Dispatch.pas b/HashLib/src/Crypto/HlpSHA3Dispatch.pas
index 8ab3eb9..4ba7657 100644
--- a/HashLib/src/Crypto/HlpSHA3Dispatch.pas
+++ b/HashLib/src/Crypto/HlpSHA3Dispatch.pas
@@ -497,7 +497,7 @@ procedure InitDispatch();
KeccakF1600_Permute := @KeccakF1600_Scalar;
KeccakF1600_Absorb := @KeccakF1600_Absorb_Scalar;
{$IFDEF HASHLIB_X86_64_ASM}
- case TCpuFeatures.X86.GetSimdLevel() of
+ case TCpuFeatures.X86.GetActiveSimdLevel() of
TX86SimdLevel.AVX2:
begin
KeccakF1600_Permute := @KeccakF1600_Avx2_Wrap;
diff --git a/HashLib/src/Hash64/HlpXXHash3Dispatch.pas b/HashLib/src/Hash64/HlpXXHash3Dispatch.pas
index 0fedd69..5feaf1d 100644
--- a/HashLib/src/Hash64/HlpXXHash3Dispatch.pas
+++ b/HashLib/src/Hash64/HlpXXHash3Dispatch.pas
@@ -225,7 +225,7 @@ procedure InitDispatch();
end;
{$ENDIF}
{$IFDEF HASHLIB_X86_64_ASM}
- case TCpuFeatures.X86.GetSimdLevel() of
+ case TCpuFeatures.X86.GetActiveSimdLevel() of
TX86SimdLevel.AVX2:
begin
XXH3_Accumulate512 := @XXH3_Accumulate512_Avx2;
diff --git a/HashLib/src/Include/HashLib.inc b/HashLib/src/Include/HashLib.inc
index fd9bced..b35b5db 100644
--- a/HashLib/src/Include/HashLib.inc
+++ b/HashLib/src/Include/HashLib.inc
@@ -16,7 +16,7 @@
{$IFDEF FPC}
{$I HashLibFPC.inc}
{$ELSE}
- // Delphi 2010 and Above
+ // Delphi 2010 and Above
{$IF CompilerVersion < 21.0}
{$MESSAGE ERROR 'This Library requires Delphi 2010 or higher.'}
{$IFEND}
@@ -43,54 +43,54 @@
{$DEFINE HASHLIB_USE_PPL} // Use Parallel Programming Library
{$IFEND}
-{============================== CPU Architecture ==============================}
+ {============================== CPU Architecture ==============================}
-{$IF DEFINED(CPU386)}
- {$DEFINE HASHLIB_I386}
- {$IFDEF MSWINDOWS}
- {$DEFINE HASHLIB_I386_ASM}
- {$ENDIF}
-{$IFEND}
-
-{$IF DEFINED(CPUX64)}
- {$DEFINE HASHLIB_X86_64}
- {$IFDEF MSWINDOWS}
- {$DEFINE HASHLIB_X86_64_ASM}
- {$ENDIF}
-{$IFEND}
+ {$IF DEFINED(CPU386)}
+ {$DEFINE HASHLIB_I386}
+ {$IFDEF MSWINDOWS}
+ {$DEFINE HASHLIB_I386_ASM}
+ {$ENDIF}
+ {$IFEND}
-{$IFDEF CPUARM32}
- {$DEFINE HASHLIB_ARM}
-{$ENDIF}
+ {$IF DEFINED(CPUX64)}
+ {$DEFINE HASHLIB_X86_64}
+ {$IFDEF MSWINDOWS}
+ {$DEFINE HASHLIB_X86_64_ASM}
+ {$ENDIF}
+ {$IFEND}
-{$IFDEF CPUARM64}
- {$DEFINE HASHLIB_AARCH64}
-{$ENDIF}
+ {$IFDEF CPUARM32}
+ {$DEFINE HASHLIB_ARM32}
+ {$ENDIF}
-{$ENDIF}
+ {$IFDEF CPUARM64}
+ {$DEFINE HASHLIB_AARCH64}
+ {$ENDIF}
-{================================= Target OS ==================================}
+ {================================= Target OS ==================================}
-{$IFDEF MSWINDOWS}
- {$DEFINE HASHLIB_MSWINDOWS}
-{$ENDIF}
+ {$IFDEF MSWINDOWS}
+ {$DEFINE HASHLIB_MSWINDOWS}
+ {$ENDIF}
-{$IFDEF IOS}
- {$DEFINE HASHLIB_IOS}
-{$ENDIF}
+ {$IFDEF IOS}
+ {$DEFINE HASHLIB_IOS}
+ {$ENDIF}
-{$IFDEF MACOS}
- {$IFNDEF IOS}
+ {$IFDEF MACOS}
+ {$IFNDEF IOS}
{$DEFINE HASHLIB_MACOS}
- {$ENDIF}
-{$ENDIF}
+ {$ENDIF}
+ {$ENDIF}
-{$IFDEF ANDROID}
- {$DEFINE HASHLIB_ANDROID}
-{$ENDIF}
+ {$IFDEF ANDROID}
+ {$DEFINE HASHLIB_ANDROID}
+ {$ENDIF}
+
+ {$IFDEF LINUX}
+ {$DEFINE HASHLIB_LINUX}
+ {$ENDIF}
-{$IFDEF LINUX}
- {$DEFINE HASHLIB_LINUX}
{$ENDIF}
{========================== Common Compiler Settings ==========================}
@@ -102,7 +102,17 @@
{$SCOPEDENUMS ON}
{$POINTERMATH ON}
-{============================== SIMD Settings =================================}
+{========================== Common Defines Settings ===========================}
+
+{$IF DEFINED(HASHLIB_I386) OR DEFINED(HASHLIB_X86_64)}
+ {$DEFINE HASHLIB_X86}
+{$IFEND}
+
+{$IF DEFINED(HASHLIB_ARM32) OR DEFINED(HASHLIB_AARCH64)}
+ {$DEFINE HASHLIB_ARM}
+{$IFEND}
+
+{============================ Common SIMD Settings ============================}
// Uncomment to force scalar dispatch (available on all platforms):
// {$DEFINE HASHLIB_FORCE_SCALAR}
@@ -111,7 +121,7 @@
{$DEFINE HASHLIB_X86_SIMD}
{$IFEND}
-{$IF DEFINED(HASHLIB_ARM_ASM) OR DEFINED(HASHLIB_AARCH64_ASM)}
+{$IF DEFINED(HASHLIB_ARM32_ASM) OR DEFINED(HASHLIB_AARCH64_ASM)}
{$DEFINE HASHLIB_ARM_SIMD}
{$IFEND}
diff --git a/HashLib/src/Include/HashLibFPC.inc b/HashLib/src/Include/HashLibFPC.inc
index dbdd893..e9bc5bf 100644
--- a/HashLib/src/Include/HashLibFPC.inc
+++ b/HashLib/src/Include/HashLibFPC.inc
@@ -13,25 +13,25 @@
// FPC 3.2.2 and Above
{$IF FPC_FULLVERSION < 30202}
- {$MESSAGE ERROR 'This Library requires FreePascal 3.2.2 or higher.'}
+ {$MESSAGE ERROR 'This Library requires FreePascal 3.2.2 or higher.'}
{$IFEND}
{$IFDEF ENDIAN_BIG}
- {$MESSAGE FATAL 'This Library does not support "Big Endian" processors yet.'}
+ {$MESSAGE FATAL 'This Library does not support "Big Endian" processors yet.'}
{$ENDIF}
{$IFDEF FPC_LITTLE_ENDIAN}
- {$DEFINE HASHLIB_LITTLE_ENDIAN}
+ {$DEFINE HASHLIB_LITTLE_ENDIAN}
{$ENDIF}
{$IFDEF FPC_REQUIRES_PROPER_ALIGNMENT}
- {$DEFINE HASHLIB_REQUIRES_PROPER_ALIGNMENT}
+ {$DEFINE HASHLIB_REQUIRES_PROPER_ALIGNMENT}
{$ENDIF}
{========================= FPC Version Features ===============================}
{$IF FPC_FULLVERSION >= 30301}
- {.$DEFINE HASHLIB_USE_PPL} // Use Parallel Programming Library
+ {.$DEFINE HASHLIB_USE_PPL} // Use Parallel Programming Library
{$IFEND}
{$DEFINE USE_UNROLLED_VARIANT}
@@ -49,43 +49,43 @@
{$IFEND}
{$IFDEF CPUARM}
- {$DEFINE HASHLIB_ARM}
- {$DEFINE HASHLIB_ARM_ASM}
+ {$DEFINE HASHLIB_ARM32}
+ {$DEFINE HASHLIB_ARM32_ASM}
{$ENDIF}
{$IFDEF CPUAARCH64}
- {$DEFINE HASHLIB_AARCH64}
- {$DEFINE HASHLIB_AARCH64_ASM}
+ {$DEFINE HASHLIB_AARCH64}
+ {$DEFINE HASHLIB_AARCH64_ASM}
{$ENDIF}
{================================= Target OS ==================================}
{$IFDEF MSWINDOWS}
- {$DEFINE HASHLIB_MSWINDOWS}
+ {$DEFINE HASHLIB_MSWINDOWS}
{$ENDIF}
{$IFDEF ANDROID}
- {$DEFINE HASHLIB_ANDROID}
+ {$DEFINE HASHLIB_ANDROID}
{$ENDIF}
{$IFDEF IOS}
- {$DEFINE HASHLIB_IOS}
+ {$DEFINE HASHLIB_IOS}
{$ENDIF}
{$IF DEFINED(DARWIN) AND NOT DEFINED(HASHLIB_IOS)}
- {$DEFINE HASHLIB_MACOS}
+ {$DEFINE HASHLIB_MACOS}
{$IFEND}
{$IF DEFINED(FREEBSD) OR DEFINED(NETBSD) OR DEFINED(OPENBSD) OR DEFINED(DRAGONFLY)}
- {$DEFINE HASHLIB_BSD}
+ {$DEFINE HASHLIB_BSD}
{$IFEND}
{$IFDEF LINUX}
- {$DEFINE HASHLIB_LINUX}
+ {$DEFINE HASHLIB_LINUX}
{$ENDIF}
{$IFDEF SOLARIS}
- {$DEFINE HASHLIB_SOLARIS}
+ {$DEFINE HASHLIB_SOLARIS}
{$ENDIF}
{========================= Compiler Mode & Optimizations ======================}
diff --git a/HashLib/src/KDF/HlpArgon2Dispatch.pas b/HashLib/src/KDF/HlpArgon2Dispatch.pas
index 207169f..a786708 100644
--- a/HashLib/src/KDF/HlpArgon2Dispatch.pas
+++ b/HashLib/src/KDF/HlpArgon2Dispatch.pas
@@ -145,7 +145,7 @@ procedure InitDispatch();
end;
{$ENDIF}
{$IFDEF HASHLIB_X86_64_ASM}
- case TCpuFeatures.X86.GetSimdLevel() of
+ case TCpuFeatures.X86.GetActiveSimdLevel() of
TX86SimdLevel.AVX2:
begin
Argon2_FillBlock := @Argon2_FillBlock_Avx2;
diff --git a/HashLib/src/KDF/HlpScryptDispatch.pas b/HashLib/src/KDF/HlpScryptDispatch.pas
index f9c399e..6ee18e4 100644
--- a/HashLib/src/KDF/HlpScryptDispatch.pas
+++ b/HashLib/src/KDF/HlpScryptDispatch.pas
@@ -210,7 +210,7 @@ procedure InitDispatch();
end;
{$ENDIF}
{$IFDEF HASHLIB_X86_64_ASM}
- case TCpuFeatures.X86.GetSimdLevel() of
+ case TCpuFeatures.X86.GetActiveSimdLevel() of
TX86SimdLevel.AVX2:
begin
Scrypt_SalsaXor := @Scrypt_SalsaXor_Avx2;
diff --git a/HashLib/src/Packages/Delphi/HashLib4PascalPackage.dpk b/HashLib/src/Packages/Delphi/HashLib4PascalPackage.dpk
index 99a06f1..eb638f8 100644
--- a/HashLib/src/Packages/Delphi/HashLib4PascalPackage.dpk
+++ b/HashLib/src/Packages/Delphi/HashLib4PascalPackage.dpk
@@ -154,6 +154,8 @@ contains
HlpX86SimdFeatures in '..\..\Utils\HlpX86SimdFeatures.pas',
HlpArmSimdFeatures in '..\..\Utils\HlpArmSimdFeatures.pas',
HlpSimdLevels in '..\..\Utils\HlpSimdLevels.pas',
+ HlpArmHwCapProvider in '..\..\Utils\HlpArmHwCapProvider.pas',
+ HlpDarwinSysCtl in '..\..\Utils\HlpDarwinSysCtl.pas',
HlpHashLibTypes in '..\..\Utils\HlpHashLibTypes.pas',
HlpArrayUtils in '..\..\Utils\HlpArrayUtils.pas';
diff --git a/HashLib/src/Packages/FPC/HashLib4PascalPackage.lpk b/HashLib/src/Packages/FPC/HashLib4PascalPackage.lpk
index 60ffecc..646488f 100644
--- a/HashLib/src/Packages/FPC/HashLib4PascalPackage.lpk
+++ b/HashLib/src/Packages/FPC/HashLib4PascalPackage.lpk
@@ -29,7 +29,7 @@
"/>
-
+
@@ -522,6 +522,14 @@
+
+
+
+
+
+
+
+
diff --git a/HashLib/src/Packages/FPC/HashLib4PascalPackage.pas b/HashLib/src/Packages/FPC/HashLib4PascalPackage.pas
index 95346dc..cbf67c1 100644
--- a/HashLib/src/Packages/FPC/HashLib4PascalPackage.pas
+++ b/HashLib/src/Packages/FPC/HashLib4PascalPackage.pas
@@ -33,7 +33,8 @@ interface
HlpArgon2Dispatch, HlpScryptDispatch, HlpBlake3Dispatch,
HlpSHA2_256Dispatch, HlpSHA2_512Dispatch, HlpSHA1Dispatch,
HlpAdler32Dispatch, HlpGF2, HlpCRCDispatch, HlpSHA3Dispatch,
- HlpArmSimdFeatures, HlpSimdLevels, HlpX86SimdFeatures;
+ HlpArmSimdFeatures, HlpSimdLevels, HlpX86SimdFeatures, HlpArmHwCapProvider,
+ HlpDarwinSysCtl;
implementation
diff --git a/HashLib/src/Utils/HlpArmHwCapProvider.pas b/HashLib/src/Utils/HlpArmHwCapProvider.pas
new file mode 100644
index 0000000..fac493f
--- /dev/null
+++ b/HashLib/src/Utils/HlpArmHwCapProvider.pas
@@ -0,0 +1,264 @@
+unit HlpArmHwCapProvider;
+
+{$I ..\Include\HashLib.inc}
+
+interface
+
+{$IF DEFINED(HASHLIB_ARM)}
+
+{$IF DEFINED(HASHLIB_LINUX) OR DEFINED(HASHLIB_ANDROID) OR DEFINED(HASHLIB_BSD)}
+uses
+ {$IFDEF FPC}
+ dl;
+ {$ELSE}
+ Posix.Dlfcn;
+ {$ENDIF}
+{$IFEND}
+
+{$IF DEFINED(HASHLIB_MSWINDOWS)}
+uses
+ Windows;
+{$IFEND}
+
+{ ===== AArch64 HWCAP bit definitions (from asm/hwcap.h) ===== }
+{ These constants are shared by Linux, Android, and BSD on AArch64. }
+
+{$IF DEFINED(HASHLIB_LINUX) OR DEFINED(HASHLIB_ANDROID) OR DEFINED(HASHLIB_BSD)}
+
+{$IF DEFINED(HASHLIB_AARCH64)}
+const
+ AT_HWCAP = 16;
+ AT_HWCAP2 = 26;
+
+ HWCAP_ASIMD = UInt64(1) shl 1;
+ HWCAP_AES = UInt64(1) shl 3;
+ HWCAP_PMULL = UInt64(1) shl 4;
+ HWCAP_SHA1 = UInt64(1) shl 5;
+ HWCAP_SHA2 = UInt64(1) shl 6;
+ HWCAP_CRC32 = UInt64(1) shl 7;
+ HWCAP_SHA3 = UInt64(1) shl 17;
+ HWCAP_SHA512 = UInt64(1) shl 21;
+ HWCAP_SVE = UInt64(1) shl 22;
+
+ HWCAP2_SVE2 = UInt64(1) shl 1;
+{$IFEND}
+
+{ ===== ARM32 HWCAP bit definitions (from asm/hwcap.h) ===== }
+{ These constants are shared by Linux, Android, and BSD on ARM32. }
+
+{$IF DEFINED(HASHLIB_ARM32)}
+const
+ AT_HWCAP = 16;
+ AT_HWCAP2 = 26;
+
+ HWCAP_NEON = UInt64(1) shl 12;
+
+ HWCAP2_AES = UInt64(1) shl 0;
+ HWCAP2_PMULL = UInt64(1) shl 1;
+ HWCAP2_SHA1 = UInt64(1) shl 2;
+ HWCAP2_SHA2 = UInt64(1) shl 3;
+ HWCAP2_CRC32 = UInt64(1) shl 4;
+{$IFEND}
+
+{$IFEND} // HASHLIB_LINUX OR HASHLIB_ANDROID OR HASHLIB_BSD
+
+{ ===== Windows ARM64 PF_ARM_* constants ===== }
+
+{$IF DEFINED(HASHLIB_MSWINDOWS)}
+const
+ // Standard constants (always available)
+ PF_ARM_NEON_INSTRUCTIONS_AVAILABLE = 19;
+ PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE = 30; // Bundles AES, PMULL, SHA1, SHA256
+ PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE = 31;
+ // Newer constants (SDK 22621+, defined here to avoid SDK version dependency)
+ PF_ARM_V82_SHA3_INSTRUCTIONS_AVAILABLE = 46;
+ PF_ARM_V82_SHA512_INSTRUCTIONS_AVAILABLE = 47;
+{$IFEND}
+
+type
+ ///
+ /// Provides ARM hardware capability information across platforms.
+ /// Linux/Android: resolves getauxval via dlsym.
+ /// BSD: resolves elf_aux_info / _elf_aux_info via dlsym.
+ /// Windows: wraps IsProcessorFeaturePresent from the Windows unit.
+ ///
+ TArmHwCapProvider = class sealed
+
+{$IF DEFINED(HASHLIB_LINUX) OR DEFINED(HASHLIB_ANDROID)}
+ strict private
+ type
+ TGetAuxValFunc = function(AType: UInt64): UInt64; cdecl;
+
+ strict private
+ class var
+ FGetAuxVal: TGetAuxValFunc;
+ FResolved: Boolean;
+
+ strict private
+ class procedure ResolveOnce(); static;
+
+ public
+ class function GetHwCap(): UInt64; static;
+ class function GetHwCap2(): UInt64; static;
+{$IFEND}
+
+{$IF DEFINED(HASHLIB_BSD)}
+ strict private
+ type
+ TElfAuxInfoFunc = function(AAuxType: Int32; ABuf: Pointer; ABufLen: Int32): Int32; cdecl;
+
+ strict private
+ class var
+ FElfAuxInfo: TElfAuxInfoFunc;
+ FResolved: Boolean;
+
+ strict private
+ class procedure ResolveOnce(); static;
+
+ public
+ class function GetHwCap(): UInt64; static;
+ class function GetHwCap2(): UInt64; static;
+{$IFEND}
+
+{$IF DEFINED(HASHLIB_MSWINDOWS)}
+ public
+ class function HasProcessorFeature(AFeature: UInt32): Boolean; static;
+{$IFEND}
+
+ end;
+
+{$IFEND} // HASHLIB_ARM
+
+implementation
+
+{$IF DEFINED(HASHLIB_ARM)}
+
+{ TArmHwCapProvider }
+
+{ ===== Linux / Android: getauxval ===== }
+
+{$IF DEFINED(HASHLIB_LINUX) OR DEFINED(HASHLIB_ANDROID)}
+
+class procedure TArmHwCapProvider.ResolveOnce();
+var
+ LHandle: Pointer;
+begin
+ if FResolved then
+ Exit;
+
+ FGetAuxVal := nil;
+ FResolved := True;
+
+ LHandle := dlopen(nil, RTLD_NOW);
+ if LHandle = nil then
+ Exit;
+
+ try
+ // getauxval is available in glibc (Linux) and Bionic (Android API 18+)
+ FGetAuxVal := TGetAuxValFunc(dlsym(LHandle, 'getauxval'));
+ finally
+ dlclose(LHandle);
+ end;
+end;
+
+class function TArmHwCapProvider.GetHwCap(): UInt64;
+begin
+ ResolveOnce();
+ if System.Assigned(FGetAuxVal) then
+ Result := FGetAuxVal(AT_HWCAP)
+ else
+ Result := 0;
+end;
+
+class function TArmHwCapProvider.GetHwCap2(): UInt64;
+begin
+ ResolveOnce();
+ if System.Assigned(FGetAuxVal) then
+ Result := FGetAuxVal(AT_HWCAP2)
+ else
+ Result := 0;
+end;
+
+{$IFEND} // HASHLIB_LINUX OR HASHLIB_ANDROID
+
+{ ===== BSD: elf_aux_info / _elf_aux_info ===== }
+
+{$IF DEFINED(HASHLIB_BSD)}
+
+class procedure TArmHwCapProvider.ResolveOnce();
+var
+ LHandle: Pointer;
+begin
+ if FResolved then
+ Exit;
+
+ FElfAuxInfo := nil;
+ FResolved := True;
+
+ LHandle := dlopen(nil, RTLD_NOW);
+ if LHandle = nil then
+ Exit;
+
+ try
+ // FreeBSD exposes elf_aux_info
+ FElfAuxInfo := TElfAuxInfoFunc(dlsym(LHandle, 'elf_aux_info'));
+ if not System.Assigned(FElfAuxInfo) then
+ begin
+ // NetBSD and DragonFlyBSD use the underscore-prefixed variant
+ FElfAuxInfo := TElfAuxInfoFunc(dlsym(LHandle, '_elf_aux_info'));
+ end;
+ finally
+ dlclose(LHandle);
+ end;
+end;
+
+class function TArmHwCapProvider.GetHwCap(): UInt64;
+var
+ LValue: UInt64;
+begin
+ ResolveOnce();
+ if System.Assigned(FElfAuxInfo) then
+ begin
+ LValue := 0;
+ if FElfAuxInfo(Int32(AT_HWCAP), @LValue, SizeOf(LValue)) = 0 then
+ Result := LValue
+ else
+ Result := 0;
+ end
+ else
+ Result := 0;
+end;
+
+class function TArmHwCapProvider.GetHwCap2(): UInt64;
+var
+ LValue: UInt64;
+begin
+ ResolveOnce();
+ if System.Assigned(FElfAuxInfo) then
+ begin
+ LValue := 0;
+ if FElfAuxInfo(Int32(AT_HWCAP2), @LValue, SizeOf(LValue)) = 0 then
+ Result := LValue
+ else
+ Result := 0;
+ end
+ else
+ Result := 0;
+end;
+
+{$IFEND} // HASHLIB_BSD
+
+{ ===== Windows: IsProcessorFeaturePresent ===== }
+
+{$IF DEFINED(HASHLIB_MSWINDOWS)}
+
+class function TArmHwCapProvider.HasProcessorFeature(AFeature: UInt32): Boolean;
+begin
+ Result := IsProcessorFeaturePresent(AFeature);
+end;
+
+{$IFEND} // HASHLIB_MSWINDOWS
+
+{$IFEND} // HASHLIB_ARM
+
+end.
diff --git a/HashLib/src/Utils/HlpArmSimdFeatures.pas b/HashLib/src/Utils/HlpArmSimdFeatures.pas
index 4dd61e1..6f8f3d2 100644
--- a/HashLib/src/Utils/HlpArmSimdFeatures.pas
+++ b/HashLib/src/Utils/HlpArmSimdFeatures.pas
@@ -5,18 +5,26 @@
interface
uses
- HlpSimdLevels;
+ HlpSimdLevels
+{$IF DEFINED(HASHLIB_ARM)}
+ , HlpArmHwCapProvider
+ {$IF DEFINED(HASHLIB_MACOS) OR DEFINED(HASHLIB_IOS)}
+ , HlpDarwinSysCtl
+ {$IFEND}
+{$IFEND}
+ ;
type
TArmSimdFeatures = class sealed
strict private
class var
- FSimdLevel: TArmSimdLevel;
+ FActiveSimdLevel: TArmSimdLevel;
FHasAES: Boolean;
FHasSHA1: Boolean;
FHasSHA256: Boolean;
FHasSHA512: Boolean;
FHasSHA3: Boolean;
+ FHasCRC32: Boolean;
FHasPMULL: Boolean;
strict private
@@ -28,6 +36,7 @@ TArmSimdFeatures = class sealed
class function CPUHasSHA256(): Boolean; static;
class function CPUHasSHA512(): Boolean; static;
class function CPUHasSHA3(): Boolean; static;
+ class function CPUHasCRC32(): Boolean; static;
class function CPUHasPMULL(): Boolean; static;
private
@@ -35,7 +44,7 @@ TArmSimdFeatures = class sealed
class procedure ApplyBuildOverrides(); static;
public
- class function GetSimdLevel(): TArmSimdLevel; static;
+ class function GetActiveSimdLevel(): TArmSimdLevel; static;
class function HasNEON(): Boolean; static;
class function HasSVE(): Boolean; static;
class function HasSVE2(): Boolean; static;
@@ -44,6 +53,7 @@ TArmSimdFeatures = class sealed
class function HasSHA256(): Boolean; static;
class function HasSHA512(): Boolean; static;
class function HasSHA3(): Boolean; static;
+ class function HasCRC32(): Boolean; static;
class function HasPMULL(): Boolean; static;
end;
@@ -51,86 +61,319 @@ implementation
{ TArmSimdFeatures }
+{ ========================= CPUHas* Detection Methods ======================== }
+
class function TArmSimdFeatures.CPUHasNEON(): Boolean;
begin
- // TODO: implement platform-specific NEON detection
+{$IF DEFINED(HASHLIB_ARM)}
+
+ {$IF DEFINED(HASHLIB_MSWINDOWS)}
+ // NEON is mandatory on Windows ARM64, but we verify for safety
+ Result := TArmHwCapProvider.HasProcessorFeature(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE);
+
+ {$ELSEIF DEFINED(HASHLIB_LINUX) OR DEFINED(HASHLIB_ANDROID) OR DEFINED(HASHLIB_BSD)}
+ {$IF DEFINED(HASHLIB_AARCH64)}
+ // NEON (ASIMD) is mandatory on AArch64, but we verify for safety
+ Result := TArmHwCapProvider.GetHwCap() and HWCAP_ASIMD <> 0;
+ {$ELSE}
+ Result := TArmHwCapProvider.GetHwCap() and HWCAP_NEON <> 0;
+ {$IFEND}
+
+ {$ELSEIF DEFINED(HASHLIB_MACOS) OR DEFINED(HASHLIB_IOS)}
+ // NEON is mandatory on AArch64 Apple Silicon, but we verify for safety
+ Result := TDarwinSysCtl.HasFeature('hw.optional.arm.FEAT_AdvSIMD', 'hw.optional.neon');
+
+ {$ELSE}
+ Result := False;
+ {$IFEND}
+
+{$ELSE}
Result := False;
+{$IFEND}
end;
class function TArmSimdFeatures.CPUHasSVE(): Boolean;
begin
- // TODO: implement platform-specific SVE detection
+{$IF DEFINED(HASHLIB_ARM)}
+ {$IF DEFINED(HASHLIB_AARCH64)}
+
+ {$IF DEFINED(HASHLIB_MSWINDOWS)}
+ // Windows ARM64 does not currently expose SVE detection
+ Result := False;
+
+ {$ELSEIF DEFINED(HASHLIB_LINUX) OR DEFINED(HASHLIB_ANDROID) OR DEFINED(HASHLIB_BSD)}
+ Result := TArmHwCapProvider.GetHwCap() and HWCAP_SVE <> 0;
+
+ {$ELSEIF DEFINED(HASHLIB_MACOS) OR DEFINED(HASHLIB_IOS)}
+ // Apple Silicon does not implement SVE, but we check anyway for future-proofing
+ Result := TDarwinSysCtl.HasFeature('hw.optional.arm.FEAT_SVE');
+
+ {$ELSE}
+ Result := False;
+ {$IFEND}
+
+ {$ELSE}
+ // SVE is AArch64-only
+ Result := False;
+ {$IFEND}
+{$ELSE}
Result := False;
+{$IFEND}
end;
class function TArmSimdFeatures.CPUHasSVE2(): Boolean;
begin
- // TODO: implement platform-specific SVE2 detection
+{$IF DEFINED(HASHLIB_ARM)}
+ {$IF DEFINED(HASHLIB_AARCH64)}
+
+ {$IF DEFINED(HASHLIB_MSWINDOWS)}
+ // Windows ARM64 does not currently expose SVE2 detection
+ Result := False;
+
+ {$ELSEIF DEFINED(HASHLIB_LINUX) OR DEFINED(HASHLIB_ANDROID) OR DEFINED(HASHLIB_BSD)}
+ Result := TArmHwCapProvider.GetHwCap2() and HWCAP2_SVE2 <> 0;
+
+ {$ELSEIF DEFINED(HASHLIB_MACOS) OR DEFINED(HASHLIB_IOS)}
+ // Apple Silicon does not implement SVE2, but we check anyway for future-proofing
+ Result := TDarwinSysCtl.HasFeature('hw.optional.arm.FEAT_SVE2');
+
+ {$ELSE}
+ Result := False;
+ {$IFEND}
+
+ {$ELSE}
+ // SVE2 is AArch64-only
+ Result := False;
+ {$IFEND}
+{$ELSE}
Result := False;
+{$IFEND}
end;
class function TArmSimdFeatures.CPUHasAES(): Boolean;
begin
- // TODO: implement platform-specific AES extension detection
+{$IF DEFINED(HASHLIB_ARM)}
+
+ {$IF DEFINED(HASHLIB_MSWINDOWS)}
+ // AES is bundled with crypto on Windows ARM64, but we verify for safety
+ Result := TArmHwCapProvider.HasProcessorFeature(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
+
+ {$ELSEIF DEFINED(HASHLIB_LINUX) OR DEFINED(HASHLIB_ANDROID) OR DEFINED(HASHLIB_BSD)}
+ {$IF DEFINED(HASHLIB_AARCH64)}
+ Result := TArmHwCapProvider.GetHwCap() and HWCAP_AES <> 0;
+ {$ELSE}
+ Result := TArmHwCapProvider.GetHwCap2() and HWCAP2_AES <> 0;
+ {$IFEND}
+
+ {$ELSEIF DEFINED(HASHLIB_MACOS) OR DEFINED(HASHLIB_IOS)}
+ // AES is present on all Apple Silicon, but we verify for safety
+ Result := TDarwinSysCtl.HasFeature('hw.optional.arm.FEAT_AES');
+
+ {$ELSE}
+ Result := False;
+ {$IFEND}
+
+{$ELSE}
Result := False;
+{$IFEND}
end;
class function TArmSimdFeatures.CPUHasSHA1(): Boolean;
begin
- // TODO: implement platform-specific SHA1 extension detection
+{$IF DEFINED(HASHLIB_ARM)}
+
+ {$IF DEFINED(HASHLIB_MSWINDOWS)}
+ // SHA1 is bundled with crypto on Windows ARM64, but we verify for safety
+ Result := TArmHwCapProvider.HasProcessorFeature(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
+
+ {$ELSEIF DEFINED(HASHLIB_LINUX) OR DEFINED(HASHLIB_ANDROID) OR DEFINED(HASHLIB_BSD)}
+ {$IF DEFINED(HASHLIB_AARCH64)}
+ Result := TArmHwCapProvider.GetHwCap() and HWCAP_SHA1 <> 0;
+ {$ELSE}
+ Result := TArmHwCapProvider.GetHwCap2() and HWCAP2_SHA1 <> 0;
+ {$IFEND}
+
+ {$ELSEIF DEFINED(HASHLIB_MACOS) OR DEFINED(HASHLIB_IOS)}
+ // SHA1 is present on all Apple Silicon, but we verify for safety
+ Result := TDarwinSysCtl.HasFeature('hw.optional.arm.FEAT_SHA1');
+
+ {$ELSE}
+ Result := False;
+ {$IFEND}
+
+{$ELSE}
Result := False;
+{$IFEND}
end;
class function TArmSimdFeatures.CPUHasSHA256(): Boolean;
begin
- // TODO: implement platform-specific SHA256 extension detection
+{$IF DEFINED(HASHLIB_ARM)}
+
+ {$IF DEFINED(HASHLIB_MSWINDOWS)}
+ // SHA256 is bundled with crypto on Windows ARM64, but we verify for safety
+ Result := TArmHwCapProvider.HasProcessorFeature(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
+
+ {$ELSEIF DEFINED(HASHLIB_LINUX) OR DEFINED(HASHLIB_ANDROID) OR DEFINED(HASHLIB_BSD)}
+ {$IF DEFINED(HASHLIB_AARCH64)}
+ Result := TArmHwCapProvider.GetHwCap() and HWCAP_SHA2 <> 0;
+ {$ELSE}
+ Result := TArmHwCapProvider.GetHwCap2() and HWCAP2_SHA2 <> 0;
+ {$IFEND}
+
+ {$ELSEIF DEFINED(HASHLIB_MACOS) OR DEFINED(HASHLIB_IOS)}
+ // SHA256 is present on all Apple Silicon, but we verify for safety
+ Result := TDarwinSysCtl.HasFeature('hw.optional.arm.FEAT_SHA256');
+
+ {$ELSE}
+ Result := False;
+ {$IFEND}
+
+{$ELSE}
Result := False;
+{$IFEND}
end;
class function TArmSimdFeatures.CPUHasSHA512(): Boolean;
begin
- // TODO: implement platform-specific SHA512 extension detection
+{$IF DEFINED(HASHLIB_ARM)}
+ {$IF DEFINED(HASHLIB_AARCH64)}
+
+ {$IF DEFINED(HASHLIB_MSWINDOWS)}
+ Result := TArmHwCapProvider.HasProcessorFeature(PF_ARM_V82_SHA512_INSTRUCTIONS_AVAILABLE);
+
+ {$ELSEIF DEFINED(HASHLIB_LINUX) OR DEFINED(HASHLIB_ANDROID) OR DEFINED(HASHLIB_BSD)}
+ Result := TArmHwCapProvider.GetHwCap() and HWCAP_SHA512 <> 0;
+
+ {$ELSEIF DEFINED(HASHLIB_MACOS) OR DEFINED(HASHLIB_IOS)}
+ Result := TDarwinSysCtl.HasFeature('hw.optional.arm.FEAT_SHA512', 'hw.optional.armv8_2_sha512');
+
+ {$ELSE}
+ Result := False;
+ {$IFEND}
+
+ {$ELSE}
+ // SHA512 acceleration is AArch64-only (ARMv8.2)
+ Result := False;
+ {$IFEND}
+{$ELSE}
Result := False;
+{$IFEND}
end;
class function TArmSimdFeatures.CPUHasSHA3(): Boolean;
begin
- // TODO: implement platform-specific SHA3 extension detection
+{$IF DEFINED(HASHLIB_ARM)}
+ {$IF DEFINED(HASHLIB_AARCH64)}
+
+ {$IF DEFINED(HASHLIB_MSWINDOWS)}
+ Result := TArmHwCapProvider.HasProcessorFeature(PF_ARM_V82_SHA3_INSTRUCTIONS_AVAILABLE);
+
+ {$ELSEIF DEFINED(HASHLIB_LINUX) OR DEFINED(HASHLIB_ANDROID) OR DEFINED(HASHLIB_BSD)}
+ Result := TArmHwCapProvider.GetHwCap() and HWCAP_SHA3 <> 0;
+
+ {$ELSEIF DEFINED(HASHLIB_MACOS) OR DEFINED(HASHLIB_IOS)}
+ Result := TDarwinSysCtl.HasFeature('hw.optional.arm.FEAT_SHA3', 'hw.optional.armv8_2_sha3');
+
+ {$ELSE}
+ Result := False;
+ {$IFEND}
+
+ {$ELSE}
+ // SHA3 acceleration is AArch64-only (ARMv8.2)
+ Result := False;
+ {$IFEND}
+{$ELSE}
Result := False;
+{$IFEND}
+end;
+
+class function TArmSimdFeatures.CPUHasCRC32(): Boolean;
+begin
+{$IF DEFINED(HASHLIB_ARM)}
+
+ {$IF DEFINED(HASHLIB_MSWINDOWS)}
+ // CRC32 is mandatory on Windows ARM64, but we verify for safety
+ Result := TArmHwCapProvider.HasProcessorFeature(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
+
+ {$ELSEIF DEFINED(HASHLIB_LINUX) OR DEFINED(HASHLIB_ANDROID) OR DEFINED(HASHLIB_BSD)}
+ {$IF DEFINED(HASHLIB_AARCH64)}
+ Result := TArmHwCapProvider.GetHwCap() and HWCAP_CRC32 <> 0;
+ {$ELSE}
+ Result := TArmHwCapProvider.GetHwCap2() and HWCAP2_CRC32 <> 0;
+ {$IFEND}
+
+ {$ELSEIF DEFINED(HASHLIB_MACOS) OR DEFINED(HASHLIB_IOS)}
+ // CRC32 is present on all Apple Silicon, but we verify for safety
+ Result := TDarwinSysCtl.HasFeature('hw.optional.armv8_crc32');
+
+ {$ELSE}
+ Result := False;
+ {$IFEND}
+
+{$ELSE}
+ Result := False;
+{$IFEND}
end;
class function TArmSimdFeatures.CPUHasPMULL(): Boolean;
begin
- // TODO: implement platform-specific PMULL extension detection
+{$IF DEFINED(HASHLIB_ARM)}
+
+ {$IF DEFINED(HASHLIB_MSWINDOWS)}
+ // PMULL is bundled with crypto on Windows ARM64, but we verify for safety
+ Result := TArmHwCapProvider.HasProcessorFeature(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
+
+ {$ELSEIF DEFINED(HASHLIB_LINUX) OR DEFINED(HASHLIB_ANDROID) OR DEFINED(HASHLIB_BSD)}
+ {$IF DEFINED(HASHLIB_AARCH64)}
+ Result := TArmHwCapProvider.GetHwCap() and HWCAP_PMULL <> 0;
+ {$ELSE}
+ Result := TArmHwCapProvider.GetHwCap2() and HWCAP2_PMULL <> 0;
+ {$IFEND}
+
+ {$ELSEIF DEFINED(HASHLIB_MACOS) OR DEFINED(HASHLIB_IOS)}
+ // PMULL is present on all Apple Silicon, but we verify for safety
+ Result := TDarwinSysCtl.HasFeature('hw.optional.arm.FEAT_PMULL');
+
+ {$ELSE}
+ Result := False;
+ {$IFEND}
+
+{$ELSE}
Result := False;
+{$IFEND}
end;
+{ ========================= Probe & Override ================================= }
+
class procedure TArmSimdFeatures.ProbeHardwareAndCache();
begin
- FSimdLevel := TArmSimdLevel.Scalar;
+ FActiveSimdLevel := TArmSimdLevel.Scalar;
FHasAES := False;
FHasSHA1 := False;
FHasSHA256 := False;
FHasSHA512 := False;
FHasSHA3 := False;
+ FHasCRC32 := False;
FHasPMULL := False;
if CPUHasNEON() then
begin
- FSimdLevel := TArmSimdLevel.NEON;
+ FActiveSimdLevel := TArmSimdLevel.NEON;
FHasAES := CPUHasAES();
FHasSHA1 := CPUHasSHA1();
FHasSHA256 := CPUHasSHA256();
FHasSHA512 := CPUHasSHA512();
FHasSHA3 := CPUHasSHA3();
+ FHasCRC32 := CPUHasCRC32();
FHasPMULL := CPUHasPMULL();
if CPUHasSVE() then
begin
- FSimdLevel := TArmSimdLevel.SVE;
+ FActiveSimdLevel := TArmSimdLevel.SVE;
if CPUHasSVE2() then
- FSimdLevel := TArmSimdLevel.SVE2;
+ FActiveSimdLevel := TArmSimdLevel.SVE2;
end;
end;
end;
@@ -138,40 +381,43 @@ class procedure TArmSimdFeatures.ProbeHardwareAndCache();
class procedure TArmSimdFeatures.ApplyBuildOverrides();
begin
{$IF DEFINED(HASHLIB_FORCE_SCALAR)}
- FSimdLevel := TArmSimdLevel.Scalar;
+ FActiveSimdLevel := TArmSimdLevel.Scalar;
FHasAES := False;
FHasSHA1 := False;
FHasSHA256 := False;
FHasSHA512 := False;
FHasSHA3 := False;
+ FHasCRC32 := False;
FHasPMULL := False;
{$ELSEIF DEFINED(HASHLIB_FORCE_NEON)}
- if FSimdLevel > TArmSimdLevel.NEON then
- FSimdLevel := TArmSimdLevel.NEON;
+ if FActiveSimdLevel > TArmSimdLevel.NEON then
+ FActiveSimdLevel := TArmSimdLevel.NEON;
{$ELSEIF DEFINED(HASHLIB_FORCE_SVE)}
- if FSimdLevel > TArmSimdLevel.SVE then
- FSimdLevel := TArmSimdLevel.SVE;
+ if FActiveSimdLevel > TArmSimdLevel.SVE then
+ FActiveSimdLevel := TArmSimdLevel.SVE;
{$IFEND}
end;
-class function TArmSimdFeatures.GetSimdLevel(): TArmSimdLevel;
+{ ========================= Public Accessors ================================= }
+
+class function TArmSimdFeatures.GetActiveSimdLevel(): TArmSimdLevel;
begin
- Result := FSimdLevel;
+ Result := FActiveSimdLevel;
end;
class function TArmSimdFeatures.HasNEON(): Boolean;
begin
- Result := FSimdLevel >= TArmSimdLevel.NEON;
+ Result := FActiveSimdLevel >= TArmSimdLevel.NEON;
end;
class function TArmSimdFeatures.HasSVE(): Boolean;
begin
- Result := FSimdLevel >= TArmSimdLevel.SVE;
+ Result := FActiveSimdLevel >= TArmSimdLevel.SVE;
end;
class function TArmSimdFeatures.HasSVE2(): Boolean;
begin
- Result := FSimdLevel >= TArmSimdLevel.SVE2;
+ Result := FActiveSimdLevel >= TArmSimdLevel.SVE2;
end;
class function TArmSimdFeatures.HasAES(): Boolean;
@@ -199,6 +445,11 @@ class function TArmSimdFeatures.HasSHA3(): Boolean;
Result := FHasSHA3;
end;
+class function TArmSimdFeatures.HasCRC32(): Boolean;
+begin
+ Result := FHasCRC32;
+end;
+
class function TArmSimdFeatures.HasPMULL(): Boolean;
begin
Result := FHasPMULL;
diff --git a/HashLib/src/Utils/HlpCpuFeatures.pas b/HashLib/src/Utils/HlpCpuFeatures.pas
index 4965630..510d3ac 100644
--- a/HashLib/src/Utils/HlpCpuFeatures.pas
+++ b/HashLib/src/Utils/HlpCpuFeatures.pas
@@ -5,36 +5,57 @@
interface
uses
- HlpSimdLevels,
- HlpX86SimdFeatures,
- HlpArmSimdFeatures;
+ HlpSimdLevels
+{$IF DEFINED(HASHLIB_X86)}
+ , HlpX86SimdFeatures
+{$IFEND}
+{$IF DEFINED(HASHLIB_ARM)}
+ , HlpArmSimdFeatures
+{$IFEND}
+ ;
type
+{$IF DEFINED(HASHLIB_X86)}
TCpuFeaturesX86 = class of TX86SimdFeatures;
+{$IFEND}
+{$IF DEFINED(HASHLIB_ARM)}
TCpuFeaturesArm = class of TArmSimdFeatures;
+{$IFEND}
TCpuFeatures = class sealed
strict private
+ {$IF DEFINED(HASHLIB_X86)}
class function GetX86(): TCpuFeaturesX86; static;
+ {$IFEND}
+ {$IF DEFINED(HASHLIB_ARM)}
class function GetArm(): TCpuFeaturesArm; static;
+ {$IFEND}
public
+ {$IF DEFINED(HASHLIB_X86)}
class property X86: TCpuFeaturesX86 read GetX86;
+ {$IFEND}
+ {$IF DEFINED(HASHLIB_ARM)}
class property Arm: TCpuFeaturesArm read GetArm;
+ {$IFEND}
end;
implementation
{ TCpuFeatures }
+{$IF DEFINED(HASHLIB_X86)}
class function TCpuFeatures.GetX86(): TCpuFeaturesX86;
begin
Result := TX86SimdFeatures;
end;
+{$IFEND}
+{$IF DEFINED(HASHLIB_ARM)}
class function TCpuFeatures.GetArm(): TCpuFeaturesArm;
begin
Result := TArmSimdFeatures;
end;
+{$IFEND}
end.
diff --git a/HashLib/src/Utils/HlpDarwinSysCtl.pas b/HashLib/src/Utils/HlpDarwinSysCtl.pas
new file mode 100644
index 0000000..e993588
--- /dev/null
+++ b/HashLib/src/Utils/HlpDarwinSysCtl.pas
@@ -0,0 +1,129 @@
+unit HlpDarwinSysCtl;
+
+{$I ..\Include\HashLib.inc}
+
+interface
+
+{$IF DEFINED(HASHLIB_ARM)}
+{$IF DEFINED(HASHLIB_MACOS) OR DEFINED(HASHLIB_IOS)}
+
+uses
+{$IFDEF FPC}
+ dl
+{$ELSE}
+ Posix.Dlfcn
+{$ENDIF}
+ ;
+
+type
+ ///
+ /// Resolves sysctlbyname from the already-loaded process image via
+ /// dlopen(nil) + dlsym, avoiding any static import of Posix.SysSysctl.
+ /// Provides a simple Boolean query for ARM feature detection on Darwin
+ /// (macOS and iOS).
+ ///
+ TDarwinSysCtl = class sealed
+ strict private
+ type
+ TSysCtlByNameFunc = function(AName: PAnsiChar; AOldP: Pointer;
+ AOldLenP: Pointer; ANewP: Pointer; ANewLen: NativeUInt): Int32; cdecl;
+
+ strict private
+ class var
+ FSysCtlByName: TSysCtlByNameFunc;
+ FResolved: Boolean;
+
+ strict private
+ class procedure ResolveOnce(); static;
+
+ ///
+ /// Queries a single sysctl key. Returns True if the key exists and
+ /// its integer value is >= 1.
+ ///
+ class function QueryKey(const AName: PAnsiChar): Boolean; static;
+
+ public
+ ///
+ /// Returns True if the named sysctl feature is available.
+ /// Tries AModernName first (macOS 12+ FEAT_* keys). If that key does
+ /// not exist or returns 0, falls back to ALegacyName (macOS 11 keys).
+ /// If ALegacyName is nil, no fallback is attempted.
+ ///
+ class function HasFeature(const AModernName: PAnsiChar;
+ const ALegacyName: PAnsiChar = nil): Boolean; static;
+ end;
+
+{$IFEND} // HASHLIB_MACOS OR HASHLIB_IOS
+{$IFEND} // HASHLIB_ARM
+
+implementation
+
+{$IF DEFINED(HASHLIB_ARM)}
+{$IF DEFINED(HASHLIB_MACOS) OR DEFINED(HASHLIB_IOS)}
+
+{ TDarwinSysCtl }
+
+class procedure TDarwinSysCtl.ResolveOnce();
+var
+ LHandle: Pointer;
+begin
+ if FResolved then
+ Exit;
+
+ FSysCtlByName := nil;
+ FResolved := True;
+
+ LHandle := dlopen(nil, RTLD_NOW);
+ if LHandle = nil then
+ Exit;
+
+ try
+ FSysCtlByName := TSysCtlByNameFunc(dlsym(LHandle, 'sysctlbyname'));
+ finally
+ dlclose(LHandle);
+ end;
+end;
+
+class function TDarwinSysCtl.QueryKey(const AName: PAnsiChar): Boolean;
+var
+ LValue: Int32;
+ LLen: NativeUInt;
+begin
+ if (AName = nil) or (not System.Assigned(FSysCtlByName)) then
+ begin
+ Result := False;
+ Exit;
+ end;
+
+ LValue := 0;
+ LLen := SizeOf(LValue);
+
+ if FSysCtlByName(AName, @LValue, @LLen, nil, 0) = 0 then
+ Result := LValue >= 1
+ else
+ Result := False;
+end;
+
+class function TDarwinSysCtl.HasFeature(const AModernName: PAnsiChar;
+ const ALegacyName: PAnsiChar): Boolean;
+begin
+ ResolveOnce();
+
+ if not System.Assigned(FSysCtlByName) then
+ begin
+ Result := False;
+ Exit;
+ end;
+
+ // Try the modern FEAT_* key first (available on macOS 12+)
+ Result := QueryKey(AModernName);
+
+ // If the modern key was not found or returned 0, try the legacy key
+ if (not Result) and (ALegacyName <> nil) then
+ Result := QueryKey(ALegacyName);
+end;
+
+{$IFEND} // HASHLIB_MACOS OR HASHLIB_IOS
+{$IFEND} // HASHLIB_ARM
+
+end.
diff --git a/HashLib/src/Utils/HlpX86SimdFeatures.pas b/HashLib/src/Utils/HlpX86SimdFeatures.pas
index 2eb7793..cbfcbce 100644
--- a/HashLib/src/Utils/HlpX86SimdFeatures.pas
+++ b/HashLib/src/Utils/HlpX86SimdFeatures.pas
@@ -17,7 +17,7 @@ TCpuIdResult = record
strict private
class var
- FSimdLevel: TX86SimdLevel;
+ FActiveSimdLevel: TX86SimdLevel;
FHasSHANI: Boolean;
FHasPCLMULQDQ: Boolean;
FHasVPCLMULQDQ: Boolean;
@@ -37,7 +37,7 @@ TCpuIdResult = record
class procedure ApplyBuildOverrides(); static;
public
- class function GetSimdLevel(): TX86SimdLevel; static;
+ class function GetActiveSimdLevel(): TX86SimdLevel; static;
class function HasSSE2(): Boolean; static;
class function HasSSSE3(): Boolean; static;
class function HasAVX2(): Boolean; static;
@@ -182,7 +182,7 @@ class function TX86SimdFeatures.CPUHasAESNI(): Boolean;
class procedure TX86SimdFeatures.ProbeHardwareAndCache();
begin
- FSimdLevel := TX86SimdLevel.Scalar;
+ FActiveSimdLevel := TX86SimdLevel.Scalar;
FHasSHANI := False;
FHasPCLMULQDQ := False;
FHasVPCLMULQDQ := False;
@@ -190,14 +190,14 @@ class procedure TX86SimdFeatures.ProbeHardwareAndCache();
if CPUHasSSE2() then
begin
- FSimdLevel := TX86SimdLevel.SSE2;
+ FActiveSimdLevel := TX86SimdLevel.SSE2;
FHasPCLMULQDQ := CPUHasPCLMULQDQ();
if CPUHasSSSE3() then
begin
- FSimdLevel := TX86SimdLevel.SSSE3;
+ FActiveSimdLevel := TX86SimdLevel.SSSE3;
if CPUHasAVX2() then
begin
- FSimdLevel := TX86SimdLevel.AVX2;
+ FActiveSimdLevel := TX86SimdLevel.AVX2;
FHasVPCLMULQDQ := CPUHasVPCLMULQDQ();
end;
end;
@@ -210,21 +210,21 @@ class procedure TX86SimdFeatures.ProbeHardwareAndCache();
class procedure TX86SimdFeatures.ApplyBuildOverrides();
begin
{$IF DEFINED(HASHLIB_FORCE_SCALAR)}
- FSimdLevel := TX86SimdLevel.Scalar;
+ FActiveSimdLevel := TX86SimdLevel.Scalar;
FHasSHANI := False;
FHasPCLMULQDQ := False;
FHasVPCLMULQDQ := False;
FHasAESNI := False;
{$ELSEIF DEFINED(HASHLIB_FORCE_SSE2)}
- if FSimdLevel > TX86SimdLevel.SSE2 then
- FSimdLevel := TX86SimdLevel.SSE2;
+ if FActiveSimdLevel > TX86SimdLevel.SSE2 then
+ FActiveSimdLevel := TX86SimdLevel.SSE2;
FHasSHANI := False;
FHasPCLMULQDQ := False;
FHasVPCLMULQDQ := False;
FHasAESNI := False;
{$ELSEIF DEFINED(HASHLIB_FORCE_SSSE3)}
- if FSimdLevel > TX86SimdLevel.SSSE3 then
- FSimdLevel := TX86SimdLevel.SSSE3;
+ if FActiveSimdLevel > TX86SimdLevel.SSSE3 then
+ FActiveSimdLevel := TX86SimdLevel.SSSE3;
FHasSHANI := False;
FHasPCLMULQDQ := False;
FHasVPCLMULQDQ := False;
@@ -232,24 +232,24 @@ class procedure TX86SimdFeatures.ApplyBuildOverrides();
{$IFEND}
end;
-class function TX86SimdFeatures.GetSimdLevel(): TX86SimdLevel;
+class function TX86SimdFeatures.GetActiveSimdLevel(): TX86SimdLevel;
begin
- Result := FSimdLevel;
+ Result := FActiveSimdLevel;
end;
class function TX86SimdFeatures.HasSSE2(): Boolean;
begin
- Result := FSimdLevel >= TX86SimdLevel.SSE2;
+ Result := FActiveSimdLevel >= TX86SimdLevel.SSE2;
end;
class function TX86SimdFeatures.HasSSSE3(): Boolean;
begin
- Result := FSimdLevel >= TX86SimdLevel.SSSE3;
+ Result := FActiveSimdLevel >= TX86SimdLevel.SSSE3;
end;
class function TX86SimdFeatures.HasAVX2(): Boolean;
begin
- Result := FSimdLevel >= TX86SimdLevel.AVX2;
+ Result := FActiveSimdLevel >= TX86SimdLevel.AVX2;
end;
class function TX86SimdFeatures.HasSHANI(): Boolean;