llvm/llvm/lib/TargetParser/Host.cpp

//===-- Host.cpp - Implement OS Host Detection ------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//  This file implements the operating system Host detection.
//
//===----------------------------------------------------------------------===//

#include "llvm/TargetParser/Host.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/TargetParser/X86TargetParser.h"
#include <string.h>

// Include the platform-specific parts of this class.
#ifdef LLVM_ON_UNIX
#include "Unix/Host.inc"
#include <sched.h>
#endif
#ifdef _WIN32
#include "Windows/Host.inc"
#endif
#ifdef _MSC_VER
#include <intrin.h>
#endif
#ifdef __MVS__
#include "llvm/Support/BCD.h"
#endif
#if defined(__APPLE__)
#include <mach/host_info.h>
#include <mach/mach.h>
#include <mach/mach_host.h>
#include <mach/machine.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#endif
#ifdef _AIX
#include <sys/systemcfg.h>
#endif
#if defined(__sun__) && defined(__svr4__)
#include <kstat.h>
#endif
#if defined(__GNUC__) || defined(__clang__)
#if (defined(__i386__) || defined(__x86_64__)) && !defined(_MSC_VER)
#include <cpuid.h>
#endif
#endif

#define DEBUG_TYPE

//===----------------------------------------------------------------------===//
//
//  Implementations of the CPU detection routines
//
//===----------------------------------------------------------------------===//

usingnamespacellvm;

static std::unique_ptr<llvm::MemoryBuffer>
    LLVM_ATTRIBUTE_UNUSED getProcCpuinfoContent() {}

StringRef sys::detail::getHostCPUNameForPowerPC(StringRef ProcCpuinfoContent) {}

StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) {}

namespace {
StringRef getCPUNameFromS390Model(unsigned int Id, bool HaveVectorSupport) {}
} // end anonymous namespace

StringRef sys::detail::getHostCPUNameForS390x(StringRef ProcCpuinfoContent) {}

StringRef sys::detail::getHostCPUNameForRISCV(StringRef ProcCpuinfoContent) {}

StringRef sys::detail::getHostCPUNameForBPF() {}

#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) ||            \
    defined(_M_X64)

/// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in
/// the specified arguments.  If we can't run cpuid on the host, return true.
static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
                               unsigned *rECX, unsigned *rEDX) {}

namespace llvm {
namespace sys {
namespace detail {
namespace x86 {

VendorSignatures getVendorSignature(unsigned *MaxLeaf) {}

} // namespace x86
} // namespace detail
} // namespace sys
} // namespace llvm

usingnamespacellvm::sys::detail::x86;

/// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return
/// the 4 values in the specified arguments.  If we can't run cpuid on the host,
/// return true.
static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
                                 unsigned *rEAX, unsigned *rEBX, unsigned *rECX,
                                 unsigned *rEDX) {}

// Read control register 0 (XCR0). Used to detect features such as AVX.
static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) {}

static void detectX86FamilyModel(unsigned EAX, unsigned *Family,
                                 unsigned *Model) {}

#define testFeature

static StringRef getIntelProcessorTypeAndSubtype(unsigned Family,
                                                 unsigned Model,
                                                 const unsigned *Features,
                                                 unsigned *Type,
                                                 unsigned *Subtype) {}

static const char *getAMDProcessorTypeAndSubtype(unsigned Family,
                                                 unsigned Model,
                                                 const unsigned *Features,
                                                 unsigned *Type,
                                                 unsigned *Subtype) {}

#undef testFeature

static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
                                 unsigned *Features) {}

StringRef sys::getHostCPUName() {}

#elif defined(__APPLE__) && defined(__powerpc__)
StringRef sys::getHostCPUName() {
  host_basic_info_data_t hostInfo;
  mach_msg_type_number_t infoCount;

  infoCount = HOST_BASIC_INFO_COUNT;
  mach_port_t hostPort = mach_host_self();
  host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&hostInfo,
            &infoCount);
  mach_port_deallocate(mach_task_self(), hostPort);

  if (hostInfo.cpu_type != CPU_TYPE_POWERPC)
    return "generic";

  switch (hostInfo.cpu_subtype) {
  case CPU_SUBTYPE_POWERPC_601:
    return "601";
  case CPU_SUBTYPE_POWERPC_602:
    return "602";
  case CPU_SUBTYPE_POWERPC_603:
    return "603";
  case CPU_SUBTYPE_POWERPC_603e:
    return "603e";
  case CPU_SUBTYPE_POWERPC_603ev:
    return "603ev";
  case CPU_SUBTYPE_POWERPC_604:
    return "604";
  case CPU_SUBTYPE_POWERPC_604e:
    return "604e";
  case CPU_SUBTYPE_POWERPC_620:
    return "620";
  case CPU_SUBTYPE_POWERPC_750:
    return "750";
  case CPU_SUBTYPE_POWERPC_7400:
    return "7400";
  case CPU_SUBTYPE_POWERPC_7450:
    return "7450";
  case CPU_SUBTYPE_POWERPC_970:
    return "970";
  default:;
  }

  return "generic";
}
#elif defined(__linux__) && defined(__powerpc__)
StringRef sys::getHostCPUName() {
  std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent();
  StringRef Content = P ? P->getBuffer() : "";
  return detail::getHostCPUNameForPowerPC(Content);
}
#elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__))
StringRef sys::getHostCPUName() {
  std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent();
  StringRef Content = P ? P->getBuffer() : "";
  return detail::getHostCPUNameForARM(Content);
}
#elif defined(__linux__) && defined(__s390x__)
StringRef sys::getHostCPUName() {
  std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent();
  StringRef Content = P ? P->getBuffer() : "";
  return detail::getHostCPUNameForS390x(Content);
}
#elif defined(__MVS__)
StringRef sys::getHostCPUName() {
  // Get pointer to Communications Vector Table (CVT).
  // The pointer is located at offset 16 of the Prefixed Save Area (PSA).
  // It is stored as 31 bit pointer and will be zero-extended to 64 bit.
  int *StartToCVTOffset = reinterpret_cast<int *>(0x10);
  // Since its stored as a 31-bit pointer, get the 4 bytes from the start
  // of address.
  int ReadValue = *StartToCVTOffset;
  // Explicitly clear the high order bit.
  ReadValue = (ReadValue & 0x7FFFFFFF);
  char *CVT = reinterpret_cast<char *>(ReadValue);
  // The model number is located in the CVT prefix at offset -6 and stored as
  // signless packed decimal.
  uint16_t Id = *(uint16_t *)&CVT[-6];
  // Convert number to integer.
  Id = decodePackedBCD<uint16_t>(Id, false);
  // Check for vector support. It's stored in field CVTFLAG5 (offset 244),
  // bit CVTVEF (X'80'). The facilities list is part of the PSA but the vector
  // extension can only be used if bit CVTVEF is on.
  bool HaveVectorSupport = CVT[244] & 0x80;
  return getCPUNameFromS390Model(Id, HaveVectorSupport);
}
#elif defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__))
#define CPUFAMILY_ARM_SWIFT
#define CPUFAMILY_ARM_CYCLONE
#define CPUFAMILY_ARM_TYPHOON
#define CPUFAMILY_ARM_TWISTER
#define CPUFAMILY_ARM_HURRICANE
#define CPUFAMILY_ARM_MONSOON_MISTRAL
#define CPUFAMILY_ARM_VORTEX_TEMPEST
#define CPUFAMILY_ARM_LIGHTNING_THUNDER
#define CPUFAMILY_ARM_FIRESTORM_ICESTORM
#define CPUFAMILY_ARM_BLIZZARD_AVALANCHE
#define CPUFAMILY_ARM_EVEREST_SAWTOOTH

StringRef sys::getHostCPUName() {
  uint32_t Family;
  size_t Length = sizeof(Family);
  sysctlbyname("hw.cpufamily", &Family, &Length, NULL, 0);

  switch (Family) {
  case CPUFAMILY_ARM_SWIFT:
    return "swift";
  case CPUFAMILY_ARM_CYCLONE:
    return "apple-a7";
  case CPUFAMILY_ARM_TYPHOON:
    return "apple-a8";
  case CPUFAMILY_ARM_TWISTER:
    return "apple-a9";
  case CPUFAMILY_ARM_HURRICANE:
    return "apple-a10";
  case CPUFAMILY_ARM_MONSOON_MISTRAL:
    return "apple-a11";
  case CPUFAMILY_ARM_VORTEX_TEMPEST:
    return "apple-a12";
  case CPUFAMILY_ARM_LIGHTNING_THUNDER:
    return "apple-a13";
  case CPUFAMILY_ARM_FIRESTORM_ICESTORM:
    return "apple-m1";
  case CPUFAMILY_ARM_BLIZZARD_AVALANCHE:
    return "apple-m2";
  case CPUFAMILY_ARM_EVEREST_SAWTOOTH:
    return "apple-m3";
  default:
    // Default to the newest CPU we know about.
    return "apple-m3";
  }
}
#elif defined(_AIX)
StringRef sys::getHostCPUName() {
  switch (_system_configuration.implementation) {
  case POWER_4:
    if (_system_configuration.version == PV_4_3)
      return "970";
    return "pwr4";
  case POWER_5:
    if (_system_configuration.version == PV_5)
      return "pwr5";
    return "pwr5x";
  case POWER_6:
    if (_system_configuration.version == PV_6_Compat)
      return "pwr6";
    return "pwr6x";
  case POWER_7:
    return "pwr7";
  case POWER_8:
    return "pwr8";
  case POWER_9:
    return "pwr9";
// TODO: simplify this once the macro is available in all OS levels.
#ifdef POWER_10
  case POWER_10:
#else
  case 0x40000:
#endif
    return "pwr10";
#ifdef POWER_11
  case POWER_11:
#else
  case 0x80000:
#endif
    return "pwr11";
  default:
    return "generic";
  }
}
#elif defined(__loongarch__)
StringRef sys::getHostCPUName() {
  // Use processor id to detect cpu name.
  uint32_t processor_id;
  __asm__("cpucfg %[prid], $zero\n\t" : [prid] "=r"(processor_id));
  // Refer PRID_SERIES_MASK in linux kernel: arch/loongarch/include/asm/cpu.h.
  switch (processor_id & 0xf000) {
  case 0xc000: // Loongson 64bit, 4-issue
    return "la464";
  case 0xd000: // Loongson 64bit, 6-issue
    return "la664";
  // TODO: Others.
  default:
    break;
  }
  return "generic";
}
#elif defined(__riscv)
StringRef sys::getHostCPUName() {
#if defined(__linux__)
  std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent();
  StringRef Content = P ? P->getBuffer() : "";
  StringRef Name = detail::getHostCPUNameForRISCV(Content);
  if (!Name.empty())
    return Name;
#endif
#if __riscv_xlen == 64
  return "generic-rv64";
#elif __riscv_xlen == 32
  return "generic-rv32";
#else
#error "Unhandled value of __riscv_xlen"
#endif
}
#elif defined(__sparc__)
#if defined(__linux__)
StringRef sys::detail::getHostCPUNameForSPARC(StringRef ProcCpuinfoContent) {
  SmallVector<StringRef> Lines;
  ProcCpuinfoContent.split(Lines, "\n");

  // Look for cpu line to determine cpu name
  StringRef Cpu;
  for (unsigned I = 0, E = Lines.size(); I != E; ++I) {
    if (Lines[I].starts_with("cpu")) {
      Cpu = Lines[I].substr(5).ltrim("\t :");
      break;
    }
  }

  return StringSwitch<const char *>(Cpu)
      .StartsWith("SuperSparc", "supersparc")
      .StartsWith("HyperSparc", "hypersparc")
      .StartsWith("SpitFire", "ultrasparc")
      .StartsWith("BlackBird", "ultrasparc")
      .StartsWith("Sabre", " ultrasparc")
      .StartsWith("Hummingbird", "ultrasparc")
      .StartsWith("Cheetah", "ultrasparc3")
      .StartsWith("Jalapeno", "ultrasparc3")
      .StartsWith("Jaguar", "ultrasparc3")
      .StartsWith("Panther", "ultrasparc3")
      .StartsWith("Serrano", "ultrasparc3")
      .StartsWith("UltraSparc T1", "niagara")
      .StartsWith("UltraSparc T2", "niagara2")
      .StartsWith("UltraSparc T3", "niagara3")
      .StartsWith("UltraSparc T4", "niagara4")
      .StartsWith("UltraSparc T5", "niagara4")
      .StartsWith("LEON", "leon3")
      // niagara7/m8 not supported by LLVM yet.
      .StartsWith("SPARC-M7", "niagara4" /* "niagara7" */)
      .StartsWith("SPARC-S7", "niagara4" /* "niagara7" */)
      .StartsWith("SPARC-M8", "niagara4" /* "m8" */)
      .Default("generic");
}
#endif

StringRef sys::getHostCPUName() {
#if defined(__linux__)
  std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent();
  StringRef Content = P ? P->getBuffer() : "";
  return detail::getHostCPUNameForSPARC(Content);
#elif defined(__sun__) && defined(__svr4__)
  char *buf = NULL;
  kstat_ctl_t *kc;
  kstat_t *ksp;
  kstat_named_t *brand = NULL;

  kc = kstat_open();
  if (kc != NULL) {
    ksp = kstat_lookup(kc, const_cast<char *>("cpu_info"), -1, NULL);
    if (ksp != NULL && kstat_read(kc, ksp, NULL) != -1 &&
        ksp->ks_type == KSTAT_TYPE_NAMED)
      brand =
          (kstat_named_t *)kstat_data_lookup(ksp, const_cast<char *>("brand"));
    if (brand != NULL && brand->data_type == KSTAT_DATA_STRING)
      buf = KSTAT_NAMED_STR_PTR(brand);
  }
  kstat_close(kc);

  return StringSwitch<const char *>(buf)
      .Case("TMS390S10", "supersparc") // Texas Instruments microSPARC I
      .Case("TMS390Z50", "supersparc") // Texas Instruments SuperSPARC I
      .Case("TMS390Z55",
            "supersparc") // Texas Instruments SuperSPARC I with SuperCache
      .Case("MB86904", "supersparc") // Fujitsu microSPARC II
      .Case("MB86907", "supersparc") // Fujitsu TurboSPARC
      .Case("RT623", "hypersparc")   // Ross hyperSPARC
      .Case("RT625", "hypersparc")
      .Case("RT626", "hypersparc")
      .Case("UltraSPARC-I", "ultrasparc")
      .Case("UltraSPARC-II", "ultrasparc")
      .Case("UltraSPARC-IIe", "ultrasparc")
      .Case("UltraSPARC-IIi", "ultrasparc")
      .Case("SPARC64-III", "ultrasparc")
      .Case("SPARC64-IV", "ultrasparc")
      .Case("UltraSPARC-III", "ultrasparc3")
      .Case("UltraSPARC-III+", "ultrasparc3")
      .Case("UltraSPARC-IIIi", "ultrasparc3")
      .Case("UltraSPARC-IIIi+", "ultrasparc3")
      .Case("UltraSPARC-IV", "ultrasparc3")
      .Case("UltraSPARC-IV+", "ultrasparc3")
      .Case("SPARC64-V", "ultrasparc3")
      .Case("SPARC64-VI", "ultrasparc3")
      .Case("SPARC64-VII", "ultrasparc3")
      .Case("UltraSPARC-T1", "niagara")
      .Case("UltraSPARC-T2", "niagara2")
      .Case("UltraSPARC-T2", "niagara2")
      .Case("UltraSPARC-T2+", "niagara2")
      .Case("SPARC-T3", "niagara3")
      .Case("SPARC-T4", "niagara4")
      .Case("SPARC-T5", "niagara4")
      // niagara7/m8 not supported by LLVM yet.
      .Case("SPARC-M7", "niagara4" /* "niagara7" */)
      .Case("SPARC-S7", "niagara4" /* "niagara7" */)
      .Case("SPARC-M8", "niagara4" /* "m8" */)
      .Default("generic");
#else
  return "generic";
#endif
}
#else
StringRef sys::getHostCPUName() { return "generic"; }
namespace llvm {
namespace sys {
namespace detail {
namespace x86 {

VendorSignatures getVendorSignature(unsigned *MaxLeaf) {
  return VendorSignatures::UNKNOWN;
}

} // namespace x86
} // namespace detail
} // namespace sys
} // namespace llvm
#endif

#if defined(__i386__) || defined(_M_IX86) || \
    defined(__x86_64__) || defined(_M_X64)
const StringMap<bool> sys::getHostCPUFeatures() {}
#elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__))
const StringMap<bool> sys::getHostCPUFeatures() {
  StringMap<bool> Features;
  std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent();
  if (!P)
    return Features;

  SmallVector<StringRef, 32> Lines;
  P->getBuffer().split(Lines, "\n");

  SmallVector<StringRef, 32> CPUFeatures;

  // Look for the CPU features.
  for (unsigned I = 0, E = Lines.size(); I != E; ++I)
    if (Lines[I].starts_with("Features")) {
      Lines[I].split(CPUFeatures, ' ');
      break;
    }

#if defined(__aarch64__)
  // All of these are "crypto" features, but we must sift out actual features
  // as the former meaning of "crypto" as a single feature is no more.
  enum { CAP_AES = 0x1, CAP_PMULL = 0x2, CAP_SHA1 = 0x4, CAP_SHA2 = 0x8 };
  uint32_t crypto = 0;
#endif

  for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) {
    StringRef LLVMFeatureStr = StringSwitch<StringRef>(CPUFeatures[I])
#if defined(__aarch64__)
                                   .Case("asimd", "neon")
                                   .Case("fp", "fp-armv8")
                                   .Case("crc32", "crc")
                                   .Case("atomics", "lse")
                                   .Case("sve", "sve")
                                   .Case("sve2", "sve2")
#else
                                   .Case("half", "fp16")
                                   .Case("neon", "neon")
                                   .Case("vfpv3", "vfp3")
                                   .Case("vfpv3d16", "vfp3d16")
                                   .Case("vfpv4", "vfp4")
                                   .Case("idiva", "hwdiv-arm")
                                   .Case("idivt", "hwdiv")
#endif
                                   .Default("");

#if defined(__aarch64__)
    // We need to check crypto separately since we need all of the crypto
    // extensions to enable the subtarget feature
    if (CPUFeatures[I] == "aes")
      crypto |= CAP_AES;
    else if (CPUFeatures[I] == "pmull")
      crypto |= CAP_PMULL;
    else if (CPUFeatures[I] == "sha1")
      crypto |= CAP_SHA1;
    else if (CPUFeatures[I] == "sha2")
      crypto |= CAP_SHA2;
#endif

    if (LLVMFeatureStr != "")
      Features[LLVMFeatureStr] = true;
  }

#if defined(__aarch64__)
  // LLVM has decided some AArch64 CPUs have all the instructions they _may_
  // have, as opposed to all the instructions they _must_ have, so allow runtime
  // information to correct us on that.
  uint32_t Aes = CAP_AES | CAP_PMULL;
  uint32_t Sha2 = CAP_SHA1 | CAP_SHA2;
  Features["aes"] = (crypto & Aes) == Aes;
  Features["sha2"] = (crypto & Sha2) == Sha2;
#endif

  return Features;
}
#elif defined(_WIN32) && (defined(__aarch64__) || defined(_M_ARM64))
const StringMap<bool> sys::getHostCPUFeatures() {
  StringMap<bool> Features;

  // If we're asking the OS at runtime, believe what the OS says
  Features["neon"] =
      IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE);
  Features["crc"] =
      IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);

  // Avoid inferring "crypto" means more than the traditional AES + SHA2
  bool TradCrypto =
      IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
  Features["aes"] = TradCrypto;
  Features["sha2"] = TradCrypto;

  return Features;
}
#elif defined(__linux__) && defined(__loongarch__)
#include <sys/auxv.h>
const StringMap<bool> sys::getHostCPUFeatures() {
  unsigned long hwcap = getauxval(AT_HWCAP);
  bool HasFPU = hwcap & (1UL << 3); // HWCAP_LOONGARCH_FPU
  uint32_t cpucfg2 = 0x2;
  __asm__("cpucfg %[cpucfg2], %[cpucfg2]\n\t" : [cpucfg2] "+r"(cpucfg2));

  StringMap<bool> Features;

  Features["f"] = HasFPU && (cpucfg2 & (1U << 1)); // CPUCFG.2.FP_SP
  Features["d"] = HasFPU && (cpucfg2 & (1U << 2)); // CPUCFG.2.FP_DP

  Features["lsx"] = hwcap & (1UL << 4);  // HWCAP_LOONGARCH_LSX
  Features["lasx"] = hwcap & (1UL << 5); // HWCAP_LOONGARCH_LASX
  Features["lvz"] = hwcap & (1UL << 9);  // HWCAP_LOONGARCH_LVZ

  return Features;
}
#elif defined(__linux__) && defined(__riscv)
// struct riscv_hwprobe
struct RISCVHwProbe {
  int64_t Key;
  uint64_t Value;
};
const StringMap<bool> sys::getHostCPUFeatures() {
  RISCVHwProbe Query[]{{/*RISCV_HWPROBE_KEY_BASE_BEHAVIOR=*/3, 0},
                       {/*RISCV_HWPROBE_KEY_IMA_EXT_0=*/4, 0}};
  int Ret = syscall(/*__NR_riscv_hwprobe=*/258, /*pairs=*/Query,
                    /*pair_count=*/std::size(Query), /*cpu_count=*/0,
                    /*cpus=*/0, /*flags=*/0);
  if (Ret != 0)
    return {};

  StringMap<bool> Features;
  uint64_t BaseMask = Query[0].Value;
  // Check whether RISCV_HWPROBE_BASE_BEHAVIOR_IMA is set.
  if (BaseMask & 1) {
    Features["i"] = true;
    Features["m"] = true;
    Features["a"] = true;
  }

  uint64_t ExtMask = Query[1].Value;
  Features["f"] = ExtMask & (1 << 0);           // RISCV_HWPROBE_IMA_FD
  Features["d"] = ExtMask & (1 << 0);           // RISCV_HWPROBE_IMA_FD
  Features["c"] = ExtMask & (1 << 1);           // RISCV_HWPROBE_IMA_C
  Features["v"] = ExtMask & (1 << 2);           // RISCV_HWPROBE_IMA_V
  Features["zba"] = ExtMask & (1 << 3);         // RISCV_HWPROBE_EXT_ZBA
  Features["zbb"] = ExtMask & (1 << 4);         // RISCV_HWPROBE_EXT_ZBB
  Features["zbs"] = ExtMask & (1 << 5);         // RISCV_HWPROBE_EXT_ZBS
  Features["zicboz"] = ExtMask & (1 << 6);      // RISCV_HWPROBE_EXT_ZICBOZ
  Features["zbc"] = ExtMask & (1 << 7);         // RISCV_HWPROBE_EXT_ZBC
  Features["zbkb"] = ExtMask & (1 << 8);        // RISCV_HWPROBE_EXT_ZBKB
  Features["zbkc"] = ExtMask & (1 << 9);        // RISCV_HWPROBE_EXT_ZBKC
  Features["zbkx"] = ExtMask & (1 << 10);       // RISCV_HWPROBE_EXT_ZBKX
  Features["zknd"] = ExtMask & (1 << 11);       // RISCV_HWPROBE_EXT_ZKND
  Features["zkne"] = ExtMask & (1 << 12);       // RISCV_HWPROBE_EXT_ZKNE
  Features["zknh"] = ExtMask & (1 << 13);       // RISCV_HWPROBE_EXT_ZKNH
  Features["zksed"] = ExtMask & (1 << 14);      // RISCV_HWPROBE_EXT_ZKSED
  Features["zksh"] = ExtMask & (1 << 15);       // RISCV_HWPROBE_EXT_ZKSH
  Features["zkt"] = ExtMask & (1 << 16);        // RISCV_HWPROBE_EXT_ZKT
  Features["zvbb"] = ExtMask & (1 << 17);       // RISCV_HWPROBE_EXT_ZVBB
  Features["zvbc"] = ExtMask & (1 << 18);       // RISCV_HWPROBE_EXT_ZVBC
  Features["zvkb"] = ExtMask & (1 << 19);       // RISCV_HWPROBE_EXT_ZVKB
  Features["zvkg"] = ExtMask & (1 << 20);       // RISCV_HWPROBE_EXT_ZVKG
  Features["zvkned"] = ExtMask & (1 << 21);     // RISCV_HWPROBE_EXT_ZVKNED
  Features["zvknha"] = ExtMask & (1 << 22);     // RISCV_HWPROBE_EXT_ZVKNHA
  Features["zvknhb"] = ExtMask & (1 << 23);     // RISCV_HWPROBE_EXT_ZVKNHB
  Features["zvksed"] = ExtMask & (1 << 24);     // RISCV_HWPROBE_EXT_ZVKSED
  Features["zvksh"] = ExtMask & (1 << 25);      // RISCV_HWPROBE_EXT_ZVKSH
  Features["zvkt"] = ExtMask & (1 << 26);       // RISCV_HWPROBE_EXT_ZVKT
  Features["zfh"] = ExtMask & (1 << 27);        // RISCV_HWPROBE_EXT_ZFH
  Features["zfhmin"] = ExtMask & (1 << 28);     // RISCV_HWPROBE_EXT_ZFHMIN
  Features["zihintntl"] = ExtMask & (1 << 29);  // RISCV_HWPROBE_EXT_ZIHINTNTL
  Features["zvfh"] = ExtMask & (1 << 30);       // RISCV_HWPROBE_EXT_ZVFH
  Features["zvfhmin"] = ExtMask & (1ULL << 31); // RISCV_HWPROBE_EXT_ZVFHMIN
  Features["zfa"] = ExtMask & (1ULL << 32);     // RISCV_HWPROBE_EXT_ZFA
  Features["ztso"] = ExtMask & (1ULL << 33);    // RISCV_HWPROBE_EXT_ZTSO
  Features["zacas"] = ExtMask & (1ULL << 34);   // RISCV_HWPROBE_EXT_ZACAS
  Features["zicond"] = ExtMask & (1ULL << 35);  // RISCV_HWPROBE_EXT_ZICOND
  Features["zihintpause"] =
      ExtMask & (1ULL << 36); // RISCV_HWPROBE_EXT_ZIHINTPAUSE

  // TODO: set unaligned-scalar-mem if RISCV_HWPROBE_KEY_MISALIGNED_PERF returns
  // RISCV_HWPROBE_MISALIGNED_FAST.

  return Features;
}
#else
const StringMap<bool> sys::getHostCPUFeatures() { return {}; }
#endif

#if __APPLE__
/// \returns the \p triple, but with the Host's arch spliced in.
static Triple withHostArch(Triple T) {
#if defined(__arm__)
  T.setArch(Triple::arm);
  T.setArchName("arm");
#elif defined(__arm64e__)
  T.setArch(Triple::aarch64, Triple::AArch64SubArch_arm64e);
  T.setArchName("arm64e");
#elif defined(__aarch64__)
  T.setArch(Triple::aarch64);
  T.setArchName("arm64");
#elif defined(__x86_64h__)
  T.setArch(Triple::x86_64);
  T.setArchName("x86_64h");
#elif defined(__x86_64__)
  T.setArch(Triple::x86_64);
  T.setArchName("x86_64");
#elif defined(__i386__)
  T.setArch(Triple::x86);
  T.setArchName("i386");
#elif defined(__powerpc__)
  T.setArch(Triple::ppc);
  T.setArchName("powerpc");
#else
#  error "Unimplemented host arch fixup"
#endif
  return T;
}
#endif

std::string sys::getProcessTriple() {}

void sys::printDefaultTargetAndDetectedCPU(raw_ostream &OS) {}