/ src / crc32c / src / crc32c_arm64_check.h
crc32c_arm64_check.h
 1  // Copyright 2017 The CRC32C Authors. All rights reserved.
 2  // Use of this source code is governed by a BSD-style license that can be
 3  // found in the LICENSE file. See the AUTHORS file for names of contributors.
 4  
 5  // ARM-specific code checking for the availability of CRC32C instructions.
 6  
 7  #ifndef CRC32C_CRC32C_ARM_CHECK_H_
 8  #define CRC32C_CRC32C_ARM_CHECK_H_
 9  
10  #include <cstddef>
11  #include <cstdint>
12  
13  #ifdef CRC32C_HAVE_CONFIG_H
14  #include "crc32c/crc32c_config.h"
15  #endif
16  
17  #if HAVE_ARM64_CRC32C
18  
19  #ifdef __linux__
20  #if HAVE_STRONG_GETAUXVAL
21  #include <sys/auxv.h>
22  #elif HAVE_WEAK_GETAUXVAL
23  // getauxval() is not available on Android until API level 20. Link it as a weak
24  // symbol.
25  extern "C" unsigned long getauxval(unsigned long type) __attribute__((weak));
26  
27  #define AT_HWCAP 16
28  #endif  // HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL
29  #endif  // defined (__linux__)
30  
31  #ifdef __APPLE__
32  #include <sys/types.h>
33  #include <sys/sysctl.h>
34  #endif  // defined (__APPLE__)
35  
36  namespace crc32c {
37  
38  inline bool CanUseArm64Crc32() {
39  #if defined (__linux__) && (HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL)
40    // From 'arch/arm64/include/uapi/asm/hwcap.h' in Linux kernel source code.
41    constexpr unsigned long kHWCAP_PMULL = 1 << 4;
42    constexpr unsigned long kHWCAP_CRC32 = 1 << 7;
43    unsigned long hwcap =
44  #if HAVE_STRONG_GETAUXVAL
45        // Some compilers warn on (&getauxval != nullptr) in the block below.
46        getauxval(AT_HWCAP);
47  #elif HAVE_WEAK_GETAUXVAL
48        (&getauxval != nullptr) ? getauxval(AT_HWCAP) : 0;
49  #else
50  #error This is supposed to be nested inside a check for HAVE_*_GETAUXVAL.
51  #endif  // HAVE_STRONG_GETAUXVAL
52    return (hwcap & (kHWCAP_PMULL | kHWCAP_CRC32)) ==
53           (kHWCAP_PMULL | kHWCAP_CRC32);
54  #elif defined(__APPLE__)
55    int val = 0;
56    size_t len = sizeof(val);
57    return sysctlbyname("hw.optional.armv8_crc32", &val, &len, nullptr, 0) == 0
58               && val != 0;
59  #else
60    return false;
61  #endif  // HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL
62  }
63  
64  }  // namespace crc32c
65  
66  #endif  // HAVE_ARM64_CRC32C
67  
68  #endif  // CRC32C_CRC32C_ARM_CHECK_H_