Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
fail-fast: false
matrix:
compiler: [clang, gcc, msvc]
os: [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-latest, macos-latest, windows-latest, windows-11-arm]
optimized: [true, false]
shared_lib: [true, false]
use_glog: [true, false]
Expand All @@ -38,16 +38,26 @@ jobs:
# Not testing with GCC on macOS.
- os: macos-latest
compiler: gcc
# Only testing with MSVC on Windows.
# Only testing with MSVC on Windows x64.
- os: windows-latest
compiler: clang
- os: windows-latest
compiler: gcc
# Not testing fringe configurations (glog, shared libraries) on Windows.
# Only testing with MSVC on Windows arm64.
- os: windows-11-arm
compiler: clang
- os: windows-11-arm
compiler: gcc
# Not testing fringe configurations (glog, shared libraries) on Windows x64.
- os: windows-latest
use_glog: true
- os: windows-latest
shared_lib: true
# Not testing fringe configurations (glog, shared libraries) on Windows arm64.
- os: windows-11-arm
use_glog: true
- os: windows-11-arm
shared_lib: true
include:
- compiler: clang
CC: clang
Expand Down Expand Up @@ -79,6 +89,7 @@ jobs:
- name: Generate build config
run: >-
cmake -S "${{ github.workspace }}" -B "${{ env.CMAKE_BUILD_DIR }}"
${{ matrix.os == 'windows-11-arm' && '-A ARM64' || '' }}
-DCMAKE_BUILD_TYPE=${{ env.CMAKE_BUILD_TYPE }}
-DCMAKE_INSTALL_PREFIX=${{ runner.temp }}/install_test/
-DBUILD_SHARED_LIBS=${{ matrix.shared_lib && '1' || '0' }}
Expand Down
30 changes: 25 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,19 +139,35 @@ set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQURED_FLAGS})
# Check for ARMv8 w/ CRC and CRYPTO extensions support in the compiler.
set(OLD_CMAKE_REQURED_FLAGS ${CMAKE_REQUIRED_FLAGS})
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# TODO(pwnall): Insert correct flag when VS gets ARM CRC32C support.
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} /arch:NOTYET")
# MSVC ARM64 builds have intrinsics available without special flags when
# targeting ARM64. For cross-compilation or emulation, use /arch:armv8.0
if(NOT (CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|arm64|aarch64" OR
CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64"))
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} /arch:armv8.0")
endif()
else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -march=armv8-a+crc+crypto")
endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
check_cxx_source_compiles("
#if defined(_MSC_VER)
#include <intrin.h>
#include <arm64_neon.h>
#else // !defined(_MSC_VER)
#include <arm_acle.h>
#include <arm_neon.h>
#endif // defined(_MSC_VER)

int main() {
__crc32cb(0, 0); __crc32ch(0, 0); __crc32cw(0, 0); __crc32cd(0, 0);
#if defined(_MSC_VER)
__n64 na, nb;
na.n64_u64[0] = 0;
nb.n64_u64[0] = 0;
neon_pmull_64(na, nb);
#else // !defined(_MSC_VER)
vmull_p64(0, 0);
return 0;
#endif // defined(_MSC_VER)
return 0;
}
" HAVE_ARM64_CRC32C)
set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQURED_FLAGS})
Expand Down Expand Up @@ -228,8 +244,12 @@ target_sources(crc32c_arm64
)
if(HAVE_ARM64_CRC32C)
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# TODO(pwnall): Insert correct flag when VS gets ARM64 CRC32C support.
target_compile_options(crc32c_arm64 PRIVATE "/arch:NOTYET")
# MSVC ARM64 builds have intrinsics available without special flags when
# targeting ARM64. For cross-compilation or emulation, use /arch:armv8.0
if(NOT (CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|arm64|aarch64" OR
CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64"))
target_compile_options(crc32c_arm64 PRIVATE "/arch:armv8.0")
endif()
else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(crc32c_arm64 PRIVATE "-march=armv8-a+crc+crypto")
endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
Expand Down
32 changes: 28 additions & 4 deletions src/crc32c_arm64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,33 @@

#if HAVE_ARM64_CRC32C

#if defined(_MSC_VER)

#include <intrin.h>
#include <arm64_neon.h>

// MSVC ARM64 vmull_p64 wrapper - handles polynomial multiplication
inline uint64_t Arm64_Vmull_P64(uint64_t a, uint64_t b) {
__n64 na, nb;
na.n64_u64[0] = a;
nb.n64_u64[0] = b;
__n128 result = neon_pmull_64(na, nb);
return result.n128_u64[0];
}

#else

#include <arm_acle.h>
#include <arm_neon.h>

// GCC/Clang version - handles polynomial multiplication
inline uint64_t Arm64_Vmull_P64(uint64_t a, uint64_t b) {
poly128_t result = vmull_p64(a, b);
return vgetq_lane_u64(vreinterpretq_u64_p128(result), 0);
}

#endif

#define KBYTES 1032
#define SEGMENTBYTES 256

Expand Down Expand Up @@ -67,7 +91,7 @@ uint32_t ExtendArm64(uint32_t crc, const uint8_t *data, size_t size) {

// k0=CRC(x^(3*SEGMENTBYTES*8)), k1=CRC(x^(2*SEGMENTBYTES*8)),
// k2=CRC(x^(SEGMENTBYTES*8))
const poly64_t k0 = 0x8d96551c, k1 = 0xbd6f81f8, k2 = 0xdcb17aa4;
const uint64_t k0 = 0x8d96551c, k1 = 0xbd6f81f8, k2 = 0xdcb17aa4;

crc = crc ^ kCRC32Xor;

Expand All @@ -81,9 +105,9 @@ uint32_t ExtendArm64(uint32_t crc, const uint8_t *data, size_t size) {
CRC32C1024BYTES(data);

// Merge the 4 partial CRC32C values.
t2 = (uint64_t)vmull_p64(crc2, k2);
t1 = (uint64_t)vmull_p64(crc1, k1);
t0 = (uint64_t)vmull_p64(crc0, k0);
t2 = Arm64_Vmull_P64(crc2, k2);
t1 = Arm64_Vmull_P64(crc1, k1);
t0 = Arm64_Vmull_P64(crc0, k0);
crc = __crc32cd(crc3, ReadUint64LE(data));
data += sizeof(uint64_t);
crc ^= __crc32cd(0, t2);
Expand Down
10 changes: 10 additions & 0 deletions src/crc32c_arm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@

#if HAVE_ARM64_CRC32C

#if defined(_MSC_VER)
// MSVC ARM64: arm64_neon.h includes both NEON and ACLE intrinsics
#include <intrin.h>
#include <arm64_neon.h>
#else
// GCC/Clang: separate headers
#include <arm_acle.h>
#include <arm_neon.h>
#endif

namespace crc32c {

uint32_t ExtendArm64(uint32_t crc, const uint8_t* data, size_t count);
Expand Down
9 changes: 9 additions & 0 deletions src/crc32c_arm64_check.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ extern "C" unsigned long getauxval(unsigned long type) __attribute__((weak));
#include <sys/sysctl.h>
#endif // defined (__APPLE__)

#if defined(_WIN32)
#include <windows.h>
#endif

namespace crc32c {

inline bool CanUseArm64Crc32() {
Expand All @@ -54,6 +58,11 @@ inline bool CanUseArm64Crc32() {
size_t len = sizeof(val);
return sysctlbyname("hw.optional.armv8_crc32", &val, &len, nullptr, 0) == 0
&& val != 0;
#elif defined(_WIN32) && (defined(_M_ARM64) || defined(_M_ARM64EC))
// On Windows ARM64, CRC32 and Crypto extensions are always available
// PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE = 31
// PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE = 30
return IsProcessorFeaturePresent(31) && IsProcessorFeaturePresent(30);
#else
return false;
#endif // HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL
Expand Down
Loading