chromium/third_party/abseil-cpp/absl/crc/internal/cpu_detect.cc

// Copyright 2022 The Abseil Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "absl/crc/internal/cpu_detect.h"

#include <cstdint>
#include <string>

#include "absl/base/config.h"

#if defined(__aarch64__) && defined(__linux__)
#include <asm/hwcap.h>
#include <sys/auxv.h>
#endif

#if defined(_WIN32) || defined(_WIN64)
#include <intrin.h>
#endif

#if defined(__x86_64__) || defined(_M_X64)
#if ABSL_HAVE_BUILTIN(__cpuid)
// MSVC-equivalent __cpuid intrinsic declaration for clang-like compilers
// for non-Windows build environments.
extern void __cpuid(int[4], int);
#elif !defined(_WIN32) && !defined(_WIN64)
// MSVC defines this function for us.
// https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex
static void __cpuid(int cpu_info[4], int info_type) {}
#endif  // !defined(_WIN32) && !defined(_WIN64)
#endif  // defined(__x86_64__) || defined(_M_X64)

namespace absl {
ABSL_NAMESPACE_BEGIN
namespace crc_internal {

#if defined(__x86_64__) || defined(_M_X64)

namespace {

enum class Vendor {};

Vendor GetVendor() {}

CpuType GetIntelCpuType() {}

CpuType GetAmdCpuType() {}

}  // namespace

CpuType GetCpuType() {}

bool SupportsArmCRC32PMULL() {}

#elif defined(__aarch64__) && defined(__linux__)

#ifndef HWCAP_CPUID
#define HWCAP_CPUID
#endif

#define ABSL_INTERNAL_AARCH64_ID_REG_READ

CpuType GetCpuType() {
  // MIDR_EL1 is not visible to EL0, however the access will be emulated by
  // linux if AT_HWCAP has HWCAP_CPUID set.
  //
  // This method will be unreliable on heterogeneous computing systems (ex:
  // big.LITTLE) since the value of MIDR_EL1 will change based on the calling
  // thread.
  uint64_t hwcaps = getauxval(AT_HWCAP);
  if (hwcaps & HWCAP_CPUID) {
    uint64_t midr = 0;
    ABSL_INTERNAL_AARCH64_ID_REG_READ(MIDR_EL1, midr);
    uint32_t implementer = (midr >> 24) & 0xff;
    uint32_t part_number = (midr >> 4) & 0xfff;
    switch (implementer) {
      case 0x41:
        switch (part_number) {
          case 0xd0c: return CpuType::kArmNeoverseN1;
          case 0xd40: return CpuType::kArmNeoverseV1;
          case 0xd49: return CpuType::kArmNeoverseN2;
          case 0xd4f: return CpuType::kArmNeoverseV2;
          default:
            return CpuType::kUnknown;
        }
        break;
      case 0xc0:
        switch (part_number) {
          case 0xac3: return CpuType::kAmpereSiryn;
          default:
            return CpuType::kUnknown;
        }
        break;
      default:
        return CpuType::kUnknown;
    }
  }
  return CpuType::kUnknown;
}

bool SupportsArmCRC32PMULL() {
  uint64_t hwcaps = getauxval(AT_HWCAP);
  return (hwcaps & HWCAP_CRC32) && (hwcaps & HWCAP_PMULL);
}

#else

CpuType GetCpuType() { return CpuType::kUnknown; }

bool SupportsArmCRC32PMULL() { return false; }

#endif

}  // namespace crc_internal
ABSL_NAMESPACE_END
}  // namespace absl