diff options
Diffstat (limited to 'third_party/llvm-project/include/llvm/Support')
76 files changed, 20090 insertions, 0 deletions
diff --git a/third_party/llvm-project/include/llvm/Support/AArch64TargetParser.def b/third_party/llvm-project/include/llvm/Support/AArch64TargetParser.def new file mode 100644 index 000000000..7e8ba9122 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/AArch64TargetParser.def @@ -0,0 +1,151 @@ +//===- AARCH64TargetParser.def - AARCH64 target parsing defines ---------*- 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 provides defines to build up the AARCH64 target parser's logic. +// +//===----------------------------------------------------------------------===// + +// NOTE: NO INCLUDE GUARD DESIRED! + +#ifndef AARCH64_ARCH +#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) +#endif +AARCH64_ARCH("invalid", INVALID, "", "", + ARMBuildAttrs::CPUArch::v8_A, FK_NONE, AArch64::AEK_NONE) +AARCH64_ARCH("armv8-a", ARMV8A, "8-A", "v8", ARMBuildAttrs::CPUArch::v8_A, + FK_CRYPTO_NEON_FP_ARMV8, + (AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_SIMD)) +AARCH64_ARCH("armv8.1-a", ARMV8_1A, "8.1-A", "v8.1a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | + AArch64::AEK_SIMD | AArch64::AEK_LSE | AArch64::AEK_RDM)) +AARCH64_ARCH("armv8.2-a", ARMV8_2A, "8.2-A", "v8.2a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | + AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE | + AArch64::AEK_RDM)) +AARCH64_ARCH("armv8.3-a", ARMV8_3A, "8.3-A", "v8.3a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | + AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE | + AArch64::AEK_RDM | AArch64::AEK_RCPC)) +AARCH64_ARCH("armv8.4-a", ARMV8_4A, "8.4-A", "v8.4a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | + AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE | + AArch64::AEK_RDM | AArch64::AEK_RCPC | AArch64::AEK_DOTPROD)) +AARCH64_ARCH("armv8.5-a", ARMV8_5A, "8.5-A", "v8.5a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | + AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE | + AArch64::AEK_RDM | AArch64::AEK_RCPC | AArch64::AEK_DOTPROD)) +#undef AARCH64_ARCH + +#ifndef AARCH64_ARCH_EXT_NAME +#define AARCH64_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE) +#endif +// FIXME: This would be nicer were it tablegen +AARCH64_ARCH_EXT_NAME("invalid", AArch64::AEK_INVALID, nullptr, nullptr) +AARCH64_ARCH_EXT_NAME("none", AArch64::AEK_NONE, nullptr, nullptr) +AARCH64_ARCH_EXT_NAME("crc", AArch64::AEK_CRC, "+crc", "-crc") +AARCH64_ARCH_EXT_NAME("lse", AArch64::AEK_LSE, "+lse", "-lse") +AARCH64_ARCH_EXT_NAME("rdm", AArch64::AEK_RDM, "+rdm", "-rdm") +AARCH64_ARCH_EXT_NAME("crypto", AArch64::AEK_CRYPTO, "+crypto","-crypto") +AARCH64_ARCH_EXT_NAME("sm4", AArch64::AEK_SM4, "+sm4", "-sm4") +AARCH64_ARCH_EXT_NAME("sha3", AArch64::AEK_SHA3, "+sha3", "-sha3") +AARCH64_ARCH_EXT_NAME("sha2", AArch64::AEK_SHA2, "+sha2", "-sha2") +AARCH64_ARCH_EXT_NAME("aes", AArch64::AEK_AES, "+aes", "-aes") +AARCH64_ARCH_EXT_NAME("dotprod", AArch64::AEK_DOTPROD, "+dotprod","-dotprod") +AARCH64_ARCH_EXT_NAME("fp", AArch64::AEK_FP, "+fp-armv8", "-fp-armv8") +AARCH64_ARCH_EXT_NAME("simd", AArch64::AEK_SIMD, "+neon", "-neon") +AARCH64_ARCH_EXT_NAME("fp16", AArch64::AEK_FP16, "+fullfp16", "-fullfp16") +AARCH64_ARCH_EXT_NAME("fp16fml", AArch64::AEK_FP16FML, "+fp16fml", "-fp16fml") +AARCH64_ARCH_EXT_NAME("profile", AArch64::AEK_PROFILE, "+spe", "-spe") +AARCH64_ARCH_EXT_NAME("ras", AArch64::AEK_RAS, "+ras", "-ras") +AARCH64_ARCH_EXT_NAME("sve", AArch64::AEK_SVE, "+sve", "-sve") +AARCH64_ARCH_EXT_NAME("sve2", AArch64::AEK_SVE2, "+sve2", "-sve2") +AARCH64_ARCH_EXT_NAME("sve2-aes", AArch64::AEK_SVE2AES, "+sve2-aes", "-sve2-aes") +AARCH64_ARCH_EXT_NAME("sve2-sm4", AArch64::AEK_SVE2SM4, "+sve2-sm4", "-sve2-sm4") +AARCH64_ARCH_EXT_NAME("sve2-sha3", AArch64::AEK_SVE2SHA3, "+sve2-sha3", "-sve2-sha3") +AARCH64_ARCH_EXT_NAME("sve2-bitperm", AArch64::AEK_SVE2BITPERM, "+sve2-bitperm", "-sve2-bitperm") +AARCH64_ARCH_EXT_NAME("rcpc", AArch64::AEK_RCPC, "+rcpc", "-rcpc") +AARCH64_ARCH_EXT_NAME("rng", AArch64::AEK_RAND, "+rand", "-rand") +AARCH64_ARCH_EXT_NAME("memtag", AArch64::AEK_MTE, "+mte", "-mte") +AARCH64_ARCH_EXT_NAME("ssbs", AArch64::AEK_SSBS, "+ssbs", "-ssbs") +AARCH64_ARCH_EXT_NAME("sb", AArch64::AEK_SB, "+sb", "-sb") +AARCH64_ARCH_EXT_NAME("predres", AArch64::AEK_PREDRES, "+predres", "-predres") +AARCH64_ARCH_EXT_NAME("tme", AArch64::AEK_TME, "+tme", "-tme") +#undef AARCH64_ARCH_EXT_NAME + +#ifndef AARCH64_CPU_NAME +#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) +#endif +AARCH64_CPU_NAME("cortex-a35", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_CRC)) +AARCH64_CPU_NAME("cortex-a53", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, true, + (AArch64::AEK_CRC)) +AARCH64_CPU_NAME("cortex-a55", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC)) +AARCH64_CPU_NAME("cortex-a57", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_CRC)) +AARCH64_CPU_NAME("cortex-a65", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_DOTPROD | AArch64::AEK_FP16 | AArch64::AEK_RAS | + AArch64::AEK_RCPC | AArch64::AEK_SSBS)) +AARCH64_CPU_NAME("cortex-a65ae", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_DOTPROD | AArch64::AEK_FP16 | AArch64::AEK_RAS | + AArch64::AEK_RCPC | AArch64::AEK_SSBS)) +AARCH64_CPU_NAME("cortex-a72", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_CRC)) +AARCH64_CPU_NAME("cortex-a73", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_CRC)) +AARCH64_CPU_NAME("cortex-a75", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC)) +AARCH64_CPU_NAME("cortex-a76", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC | + AArch64::AEK_SSBS)) +AARCH64_CPU_NAME("cortex-a76ae", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC | + AArch64::AEK_SSBS)) +AARCH64_CPU_NAME("neoverse-e1", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_DOTPROD | AArch64::AEK_FP16 | AArch64::AEK_RAS | + AArch64::AEK_RCPC | AArch64::AEK_SSBS)) +AARCH64_CPU_NAME("neoverse-n1", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_DOTPROD | AArch64::AEK_FP16 | + AArch64::AEK_PROFILE | AArch64::AEK_RAS | AArch64::AEK_RCPC | + AArch64::AEK_SSBS)) +AARCH64_CPU_NAME("cyclone", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_NONE)) +AARCH64_CPU_NAME("exynos-m3", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_CRC)) +AARCH64_CPU_NAME("exynos-m4", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_DOTPROD | AArch64::AEK_FP16)) +AARCH64_CPU_NAME("exynos-m5", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_DOTPROD | AArch64::AEK_FP16)) +AARCH64_CPU_NAME("falkor", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_CRC | AArch64::AEK_RDM)) +AARCH64_CPU_NAME("saphira", ARMV8_3A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_PROFILE)) +AARCH64_CPU_NAME("kryo", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_CRC)) +AARCH64_CPU_NAME("thunderx2t99", ARMV8_1A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_NONE)) +AARCH64_CPU_NAME("thunderx", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_CRC | AArch64::AEK_PROFILE)) +AARCH64_CPU_NAME("thunderxt88", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_CRC | AArch64::AEK_PROFILE)) +AARCH64_CPU_NAME("thunderxt81", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_CRC | AArch64::AEK_PROFILE)) +AARCH64_CPU_NAME("thunderxt83", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_CRC | AArch64::AEK_PROFILE)) +AARCH64_CPU_NAME("tsv110", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_DOTPROD | + AArch64::AEK_FP16 | AArch64::AEK_FP16FML | + AArch64::AEK_PROFILE)) +// Invalid CPU +AARCH64_CPU_NAME("invalid", INVALID, FK_INVALID, true, AArch64::AEK_INVALID) +#undef AARCH64_CPU_NAME diff --git a/third_party/llvm-project/include/llvm/Support/AArch64TargetParser.h b/third_party/llvm-project/include/llvm/Support/AArch64TargetParser.h new file mode 100644 index 000000000..94f341c83 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/AArch64TargetParser.h @@ -0,0 +1,129 @@ +//===-- AArch64TargetParser - Parser for AArch64 features -------*- 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 a target parser to recognise AArch64 hardware features +// such as FPU/CPU/ARCH and extension names. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_AARCH64TARGETPARSERCOMMON_H +#define LLVM_SUPPORT_AARCH64TARGETPARSERCOMMON_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/ARMTargetParser.h" +#include <vector> + +// FIXME:This should be made into class design,to avoid dupplication. +namespace llvm { +namespace AArch64 { + +// Arch extension modifiers for CPUs. +enum ArchExtKind : unsigned { + AEK_INVALID = 0, + AEK_NONE = 1, + AEK_CRC = 1 << 1, + AEK_CRYPTO = 1 << 2, + AEK_FP = 1 << 3, + AEK_SIMD = 1 << 4, + AEK_FP16 = 1 << 5, + AEK_PROFILE = 1 << 6, + AEK_RAS = 1 << 7, + AEK_LSE = 1 << 8, + AEK_SVE = 1 << 9, + AEK_DOTPROD = 1 << 10, + AEK_RCPC = 1 << 11, + AEK_RDM = 1 << 12, + AEK_SM4 = 1 << 13, + AEK_SHA3 = 1 << 14, + AEK_SHA2 = 1 << 15, + AEK_AES = 1 << 16, + AEK_FP16FML = 1 << 17, + AEK_RAND = 1 << 18, + AEK_MTE = 1 << 19, + AEK_SSBS = 1 << 20, + AEK_SB = 1 << 21, + AEK_PREDRES = 1 << 22, + AEK_SVE2 = 1 << 23, + AEK_SVE2AES = 1 << 24, + AEK_SVE2SM4 = 1 << 25, + AEK_SVE2SHA3 = 1 << 26, + AEK_SVE2BITPERM = 1 << 27, + AEK_TME = 1 << 28, +}; + +enum class ArchKind { +#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) ID, +#include "AArch64TargetParser.def" +}; + +const ARM::ArchNames<ArchKind> AArch64ARCHNames[] = { +#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, \ + ARCH_BASE_EXT) \ + {NAME, \ + sizeof(NAME) - 1, \ + CPU_ATTR, \ + sizeof(CPU_ATTR) - 1, \ + SUB_ARCH, \ + sizeof(SUB_ARCH) - 1, \ + ARM::FPUKind::ARCH_FPU, \ + ARCH_BASE_EXT, \ + AArch64::ArchKind::ID, \ + ARCH_ATTR}, +#include "AArch64TargetParser.def" +}; + +const ARM::ExtName AArch64ARCHExtNames[] = { +#define AARCH64_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE) \ + {NAME, sizeof(NAME) - 1, ID, FEATURE, NEGFEATURE}, +#include "AArch64TargetParser.def" +}; + +const ARM::CpuNames<ArchKind> AArch64CPUNames[] = { +#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ + {NAME, sizeof(NAME) - 1, AArch64::ArchKind::ID, IS_DEFAULT, DEFAULT_EXT}, +#include "AArch64TargetParser.def" +}; + +const ArchKind ArchKinds[] = { +#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) \ + ArchKind::ID, +#include "AArch64TargetParser.def" +}; + +// FIXME: These should be moved to TargetTuple once it exists +bool getExtensionFeatures(unsigned Extensions, + std::vector<StringRef> &Features); +bool getArchFeatures(ArchKind AK, std::vector<StringRef> &Features); + +StringRef getArchName(ArchKind AK); +unsigned getArchAttr(ArchKind AK); +StringRef getCPUAttr(ArchKind AK); +StringRef getSubArch(ArchKind AK); +StringRef getArchExtName(unsigned ArchExtKind); +StringRef getArchExtFeature(StringRef ArchExt); + +// Information by Name +unsigned getDefaultFPU(StringRef CPU, ArchKind AK); +unsigned getDefaultExtensions(StringRef CPU, ArchKind AK); +StringRef getDefaultCPU(StringRef Arch); +ArchKind getCPUArchKind(StringRef CPU); + +// Parser +ArchKind parseArch(StringRef Arch); +ArchExtKind parseArchExt(StringRef ArchExt); +ArchKind parseCPUArch(StringRef CPU); +// Used by target parser tests +void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values); + +bool isX18ReservedByDefault(const Triple &TT); + +} // namespace AArch64 +} // namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/ARMAttributeParser.h b/third_party/llvm-project/include/llvm/Support/ARMAttributeParser.h new file mode 100644 index 000000000..f6c39abb4 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/ARMAttributeParser.h @@ -0,0 +1,141 @@ +//===--- ARMAttributeParser.h - ARM Attribute Information Printer ---------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ARMATTRIBUTEPARSER_H +#define LLVM_SUPPORT_ARMATTRIBUTEPARSER_H + +#include "ARMBuildAttributes.h" +#include "ScopedPrinter.h" + +#include <map> + +namespace llvm { +class StringRef; + +class ARMAttributeParser { + ScopedPrinter *SW; + + std::map<unsigned, unsigned> Attributes; + + struct DisplayHandler { + ARMBuildAttrs::AttrType Attribute; + void (ARMAttributeParser::*Routine)(ARMBuildAttrs::AttrType, + const uint8_t *, uint32_t &); + }; + static const DisplayHandler DisplayRoutines[]; + + uint64_t ParseInteger(const uint8_t *Data, uint32_t &Offset); + StringRef ParseString(const uint8_t *Data, uint32_t &Offset); + + void IntegerAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void StringAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + + void PrintAttribute(unsigned Tag, unsigned Value, StringRef ValueDesc); + + void CPU_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void CPU_arch_profile(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ARM_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void THUMB_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void FP_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void WMMX_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void Advanced_SIMD_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void MVE_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void PCS_config(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_R9_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_RW_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_RO_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_GOT_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_wchar_t(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_rounding(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_denormal(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_user_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_number_model(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_align_needed(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_align_preserved(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_enum_size(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_HardFP_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_VFP_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_WMMX_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_optimization_goals(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_optimization_goals(ARMBuildAttrs::AttrType Tag, + const uint8_t *Data, uint32_t &Offset); + void compatibility(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void CPU_unaligned_access(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void FP_HP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_16bit_format(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void MPextension_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void DIV_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void DSP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void T2EE_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void Virtualization_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void nodefaults(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + + void ParseAttributeList(const uint8_t *Data, uint32_t &Offset, + uint32_t Length); + void ParseIndexList(const uint8_t *Data, uint32_t &Offset, + SmallVectorImpl<uint8_t> &IndexList); + void ParseSubsection(const uint8_t *Data, uint32_t Length); +public: + ARMAttributeParser(ScopedPrinter *SW) : SW(SW) {} + + ARMAttributeParser() : SW(nullptr) { } + + void Parse(ArrayRef<uint8_t> Section, bool isLittle); + + bool hasAttribute(unsigned Tag) const { + return Attributes.count(Tag); + } + + unsigned getAttributeValue(unsigned Tag) const { + return Attributes.find(Tag)->second; + } +}; + +} + +#endif + diff --git a/third_party/llvm-project/include/llvm/Support/ARMBuildAttributes.h b/third_party/llvm-project/include/llvm/Support/ARMBuildAttributes.h new file mode 100644 index 000000000..90481eaa1 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/ARMBuildAttributes.h @@ -0,0 +1,253 @@ +//===-- ARMBuildAttributes.h - ARM Build Attributes -------------*- 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 contains enumerations and support routines for ARM build attributes +// as defined in ARM ABI addenda document (ABI release 2.08). +// +// ELF for the ARM Architecture r2.09 - November 30, 2012 +// +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044e/IHI0044E_aaelf.pdf +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ARMBUILDATTRIBUTES_H +#define LLVM_SUPPORT_ARMBUILDATTRIBUTES_H + +namespace llvm { +class StringRef; + +namespace ARMBuildAttrs { + +enum SpecialAttr { + // This is for the .cpu asm attr. It translates into one or more + // AttrType (below) entries in the .ARM.attributes section in the ELF. + SEL_CPU +}; + +enum AttrType { + // Rest correspond to ELF/.ARM.attributes + File = 1, + CPU_raw_name = 4, + CPU_name = 5, + CPU_arch = 6, + CPU_arch_profile = 7, + ARM_ISA_use = 8, + THUMB_ISA_use = 9, + FP_arch = 10, + WMMX_arch = 11, + Advanced_SIMD_arch = 12, + PCS_config = 13, + ABI_PCS_R9_use = 14, + ABI_PCS_RW_data = 15, + ABI_PCS_RO_data = 16, + ABI_PCS_GOT_use = 17, + ABI_PCS_wchar_t = 18, + ABI_FP_rounding = 19, + ABI_FP_denormal = 20, + ABI_FP_exceptions = 21, + ABI_FP_user_exceptions = 22, + ABI_FP_number_model = 23, + ABI_align_needed = 24, + ABI_align_preserved = 25, + ABI_enum_size = 26, + ABI_HardFP_use = 27, + ABI_VFP_args = 28, + ABI_WMMX_args = 29, + ABI_optimization_goals = 30, + ABI_FP_optimization_goals = 31, + compatibility = 32, + CPU_unaligned_access = 34, + FP_HP_extension = 36, + ABI_FP_16bit_format = 38, + MPextension_use = 42, // recoded from 70 (ABI r2.08) + DIV_use = 44, + DSP_extension = 46, + MVE_arch = 48, + also_compatible_with = 65, + conformance = 67, + Virtualization_use = 68, + + /// Legacy Tags + Section = 2, // deprecated (ABI r2.09) + Symbol = 3, // deprecated (ABI r2.09) + ABI_align8_needed = 24, // renamed to ABI_align_needed (ABI r2.09) + ABI_align8_preserved = 25, // renamed to ABI_align_preserved (ABI r2.09) + nodefaults = 64, // deprecated (ABI r2.09) + T2EE_use = 66, // deprecated (ABI r2.09) + MPextension_use_old = 70 // recoded to MPextension_use (ABI r2.08) +}; + +StringRef AttrTypeAsString(unsigned Attr, bool HasTagPrefix = true); +StringRef AttrTypeAsString(AttrType Attr, bool HasTagPrefix = true); +int AttrTypeFromString(StringRef Tag); + +// Magic numbers for .ARM.attributes +enum AttrMagic { + Format_Version = 0x41 +}; + +// Legal Values for CPU_arch, (=6), uleb128 +enum CPUArch { + Pre_v4 = 0, + v4 = 1, // e.g. SA110 + v4T = 2, // e.g. ARM7TDMI + v5T = 3, // e.g. ARM9TDMI + v5TE = 4, // e.g. ARM946E_S + v5TEJ = 5, // e.g. ARM926EJ_S + v6 = 6, // e.g. ARM1136J_S + v6KZ = 7, // e.g. ARM1176JZ_S + v6T2 = 8, // e.g. ARM1156T2_S + v6K = 9, // e.g. ARM1176JZ_S + v7 = 10, // e.g. Cortex A8, Cortex M3 + v6_M = 11, // e.g. Cortex M1 + v6S_M = 12, // v6_M with the System extensions + v7E_M = 13, // v7_M with DSP extensions + v8_A = 14, // v8_A AArch32 + v8_R = 15, // e.g. Cortex R52 + v8_M_Base= 16, // v8_M_Base AArch32 + v8_M_Main= 17, // v8_M_Main AArch32 + v8_1_M_Main=21, // v8_1_M_Main AArch32 +}; + +enum CPUArchProfile { // (=7), uleb128 + Not_Applicable = 0, // pre v7, or cross-profile code + ApplicationProfile = (0x41), // 'A' (e.g. for Cortex A8) + RealTimeProfile = (0x52), // 'R' (e.g. for Cortex R4) + MicroControllerProfile = (0x4D), // 'M' (e.g. for Cortex M3) + SystemProfile = (0x53) // 'S' Application or real-time profile +}; + +// The following have a lot of common use cases +enum { + Not_Allowed = 0, + Allowed = 1, + + // Tag_ARM_ISA_use (=8), uleb128 + + // Tag_THUMB_ISA_use, (=9), uleb128 + AllowThumb32 = 2, // 32-bit Thumb (implies 16-bit instructions) + AllowThumbDerived = 3, // Thumb allowed, derived from arch/profile + + // Tag_FP_arch (=10), uleb128 (formerly Tag_VFP_arch = 10) + AllowFPv2 = 2, // v2 FP ISA permitted (implies use of the v1 FP ISA) + AllowFPv3A = 3, // v3 FP ISA permitted (implies use of the v2 FP ISA) + AllowFPv3B = 4, // v3 FP ISA permitted, but only D0-D15, S0-S31 + AllowFPv4A = 5, // v4 FP ISA permitted (implies use of v3 FP ISA) + AllowFPv4B = 6, // v4 FP ISA was permitted, but only D0-D15, S0-S31 + AllowFPARMv8A = 7, // Use of the ARM v8-A FP ISA was permitted + AllowFPARMv8B = 8, // Use of the ARM v8-A FP ISA was permitted, but only + // D0-D15, S0-S31 + + // Tag_WMMX_arch, (=11), uleb128 + AllowWMMXv1 = 1, // The user permitted this entity to use WMMX v1 + AllowWMMXv2 = 2, // The user permitted this entity to use WMMX v2 + + // Tag_Advanced_SIMD_arch, (=12), uleb128 + AllowNeon = 1, // SIMDv1 was permitted + AllowNeon2 = 2, // SIMDv2 was permitted (Half-precision FP, MAC operations) + AllowNeonARMv8 = 3, // ARM v8-A SIMD was permitted + AllowNeonARMv8_1a = 4,// ARM v8.1-A SIMD was permitted (RDMA) + + // Tag_MVE_arch, (=48), uleb128 + AllowMVEInteger = 1, // integer-only MVE was permitted + AllowMVEIntegerAndFloat = 2, // both integer and floating point MVE were permitted + + // Tag_ABI_PCS_R9_use, (=14), uleb128 + R9IsGPR = 0, // R9 used as v6 (just another callee-saved register) + R9IsSB = 1, // R9 used as a global static base rgister + R9IsTLSPointer = 2, // R9 used as a thread local storage pointer + R9Reserved = 3, // R9 not used by code associated with attributed entity + + // Tag_ABI_PCS_RW_data, (=15), uleb128 + AddressRWPCRel = 1, // Address RW static data PC-relative + AddressRWSBRel = 2, // Address RW static data SB-relative + AddressRWNone = 3, // No RW static data permitted + + // Tag_ABI_PCS_RO_data, (=14), uleb128 + AddressROPCRel = 1, // Address RO static data PC-relative + AddressRONone = 2, // No RO static data permitted + + // Tag_ABI_PCS_GOT_use, (=17), uleb128 + AddressDirect = 1, // Address imported data directly + AddressGOT = 2, // Address imported data indirectly (via GOT) + + // Tag_ABI_PCS_wchar_t, (=18), uleb128 + WCharProhibited = 0, // wchar_t is not used + WCharWidth2Bytes = 2, // sizeof(wchar_t) == 2 + WCharWidth4Bytes = 4, // sizeof(wchar_t) == 4 + + // Tag_ABI_align_needed, (=24), uleb128 + Align8Byte = 1, + Align4Byte = 2, + AlignReserved = 3, + + // Tag_ABI_align_needed, (=25), uleb128 + AlignNotPreserved = 0, + AlignPreserve8Byte = 1, + AlignPreserveAll = 2, + + // Tag_ABI_FP_denormal, (=20), uleb128 + PositiveZero = 0, + IEEEDenormals = 1, + PreserveFPSign = 2, // sign when flushed-to-zero is preserved + + // Tag_ABI_FP_number_model, (=23), uleb128 + AllowIEEENormal = 1, + AllowRTABI = 2, // numbers, infinities, and one quiet NaN (see [RTABI]) + AllowIEEE754 = 3, // this code to use all the IEEE 754-defined FP encodings + + // Tag_ABI_enum_size, (=26), uleb128 + EnumProhibited = 0, // The user prohibited the use of enums when building + // this entity. + EnumSmallest = 1, // Enum is smallest container big enough to hold all + // values. + Enum32Bit = 2, // Enum is at least 32 bits. + Enum32BitABI = 3, // Every enumeration visible across an ABI-complying + // interface contains a value needing 32 bits to encode + // it; other enums can be containerized. + + // Tag_ABI_HardFP_use, (=27), uleb128 + HardFPImplied = 0, // FP use should be implied by Tag_FP_arch + HardFPSinglePrecision = 1, // Single-precision only + + // Tag_ABI_VFP_args, (=28), uleb128 + BaseAAPCS = 0, + HardFPAAPCS = 1, + ToolChainFPPCS = 2, + CompatibleFPAAPCS = 3, + + // Tag_FP_HP_extension, (=36), uleb128 + AllowHPFP = 1, // Allow use of Half Precision FP + + // Tag_FP_16bit_format, (=38), uleb128 + FP16FormatIEEE = 1, + FP16VFP3 = 2, + + // Tag_MPextension_use, (=42), uleb128 + AllowMP = 1, // Allow use of MP extensions + + // Tag_DIV_use, (=44), uleb128 + // Note: AllowDIVExt must be emitted if and only if the permission to use + // hardware divide cannot be conveyed using AllowDIVIfExists or DisallowDIV + AllowDIVIfExists = 0, // Allow hardware divide if available in arch, or no + // info exists. + DisallowDIV = 1, // Hardware divide explicitly disallowed. + AllowDIVExt = 2, // Allow hardware divide as optional architecture + // extension above the base arch specified by + // Tag_CPU_arch and Tag_CPU_arch_profile. + + // Tag_Virtualization_use, (=68), uleb128 + AllowTZ = 1, + AllowVirtualization = 2, + AllowTZVirtualization = 3 +}; + +} // namespace ARMBuildAttrs +} // namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/ARMTargetParser.def b/third_party/llvm-project/include/llvm/Support/ARMTargetParser.def new file mode 100644 index 000000000..7f03d9a13 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/ARMTargetParser.def @@ -0,0 +1,293 @@ +//===- ARMTargetParser.def - ARM target parsing defines ---------*- 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 provides defines to build up the ARM target parser's logic. +// +//===----------------------------------------------------------------------===// + +// NOTE: NO INCLUDE GUARD DESIRED! + +#ifndef ARM_FPU +#define ARM_FPU(NAME, KIND, VERSION, NEON_SUPPORT, RESTRICTION) +#endif +ARM_FPU("invalid", FK_INVALID, FPUVersion::NONE, NeonSupportLevel::None, FPURestriction::None) +ARM_FPU("none", FK_NONE, FPUVersion::NONE, NeonSupportLevel::None, FPURestriction::None) +ARM_FPU("vfp", FK_VFP, FPUVersion::VFPV2, NeonSupportLevel::None, FPURestriction::None) +ARM_FPU("vfpv2", FK_VFPV2, FPUVersion::VFPV2, NeonSupportLevel::None, FPURestriction::None) +ARM_FPU("vfpv3", FK_VFPV3, FPUVersion::VFPV3, NeonSupportLevel::None, FPURestriction::None) +ARM_FPU("vfpv3-fp16", FK_VFPV3_FP16, FPUVersion::VFPV3_FP16, NeonSupportLevel::None, FPURestriction::None) +ARM_FPU("vfpv3-d16", FK_VFPV3_D16, FPUVersion::VFPV3, NeonSupportLevel::None, FPURestriction::D16) +ARM_FPU("vfpv3-d16-fp16", FK_VFPV3_D16_FP16, FPUVersion::VFPV3_FP16, NeonSupportLevel::None, FPURestriction::D16) +ARM_FPU("vfpv3xd", FK_VFPV3XD, FPUVersion::VFPV3, NeonSupportLevel::None, FPURestriction::SP_D16) +ARM_FPU("vfpv3xd-fp16", FK_VFPV3XD_FP16, FPUVersion::VFPV3_FP16, NeonSupportLevel::None, FPURestriction::SP_D16) +ARM_FPU("vfpv4", FK_VFPV4, FPUVersion::VFPV4, NeonSupportLevel::None, FPURestriction::None) +ARM_FPU("vfpv4-d16", FK_VFPV4_D16, FPUVersion::VFPV4, NeonSupportLevel::None, FPURestriction::D16) +ARM_FPU("fpv4-sp-d16", FK_FPV4_SP_D16, FPUVersion::VFPV4, NeonSupportLevel::None, FPURestriction::SP_D16) +ARM_FPU("fpv5-d16", FK_FPV5_D16, FPUVersion::VFPV5, NeonSupportLevel::None, FPURestriction::D16) +ARM_FPU("fpv5-sp-d16", FK_FPV5_SP_D16, FPUVersion::VFPV5, NeonSupportLevel::None, FPURestriction::SP_D16) +ARM_FPU("fp-armv8", FK_FP_ARMV8, FPUVersion::VFPV5, NeonSupportLevel::None, FPURestriction::None) +ARM_FPU("fp-armv8-fullfp16-d16", FK_FP_ARMV8_FULLFP16_D16, FPUVersion::VFPV5_FULLFP16, NeonSupportLevel::None, FPURestriction::D16) +ARM_FPU("fp-armv8-fullfp16-sp-d16", FK_FP_ARMV8_FULLFP16_SP_D16, FPUVersion::VFPV5_FULLFP16, NeonSupportLevel::None, FPURestriction::SP_D16) +ARM_FPU("neon", FK_NEON, FPUVersion::VFPV3, NeonSupportLevel::Neon, FPURestriction::None) +ARM_FPU("neon-fp16", FK_NEON_FP16, FPUVersion::VFPV3_FP16, NeonSupportLevel::Neon, FPURestriction::None) +ARM_FPU("neon-vfpv4", FK_NEON_VFPV4, FPUVersion::VFPV4, NeonSupportLevel::Neon, FPURestriction::None) +ARM_FPU("neon-fp-armv8", FK_NEON_FP_ARMV8, FPUVersion::VFPV5, NeonSupportLevel::Neon, FPURestriction::None) +ARM_FPU("crypto-neon-fp-armv8", FK_CRYPTO_NEON_FP_ARMV8, FPUVersion::VFPV5, NeonSupportLevel::Crypto, + FPURestriction::None) +ARM_FPU("softvfp", FK_SOFTVFP, FPUVersion::NONE, NeonSupportLevel::None, FPURestriction::None) +#undef ARM_FPU + +#ifndef ARM_ARCH +#define ARM_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) +#endif +ARM_ARCH("invalid", INVALID, "", "", + ARMBuildAttrs::CPUArch::Pre_v4, FK_NONE, ARM::AEK_NONE) +ARM_ARCH("armv2", ARMV2, "2", "v2", ARMBuildAttrs::CPUArch::Pre_v4, + FK_NONE, ARM::AEK_NONE) +ARM_ARCH("armv2a", ARMV2A, "2A", "v2a", ARMBuildAttrs::CPUArch::Pre_v4, + FK_NONE, ARM::AEK_NONE) +ARM_ARCH("armv3", ARMV3, "3", "v3", ARMBuildAttrs::CPUArch::Pre_v4, + FK_NONE, ARM::AEK_NONE) +ARM_ARCH("armv3m", ARMV3M, "3M", "v3m", ARMBuildAttrs::CPUArch::Pre_v4, + FK_NONE, ARM::AEK_NONE) +ARM_ARCH("armv4", ARMV4, "4", "v4", ARMBuildAttrs::CPUArch::v4, + FK_NONE, ARM::AEK_NONE) +ARM_ARCH("armv4t", ARMV4T, "4T", "v4t", ARMBuildAttrs::CPUArch::v4T, + FK_NONE, ARM::AEK_NONE) +ARM_ARCH("armv5t", ARMV5T, "5T", "v5", ARMBuildAttrs::CPUArch::v5T, + FK_NONE, ARM::AEK_NONE) +ARM_ARCH("armv5te", ARMV5TE, "5TE", "v5e", ARMBuildAttrs::CPUArch::v5TE, + FK_NONE, ARM::AEK_DSP) +ARM_ARCH("armv5tej", ARMV5TEJ, "5TEJ", "v5e", ARMBuildAttrs::CPUArch::v5TEJ, + FK_NONE, ARM::AEK_DSP) +ARM_ARCH("armv6", ARMV6, "6", "v6", ARMBuildAttrs::CPUArch::v6, + FK_VFPV2, ARM::AEK_DSP) +ARM_ARCH("armv6k", ARMV6K, "6K", "v6k", ARMBuildAttrs::CPUArch::v6K, + FK_VFPV2, ARM::AEK_DSP) +ARM_ARCH("armv6t2", ARMV6T2, "6T2", "v6t2", ARMBuildAttrs::CPUArch::v6T2, + FK_NONE, ARM::AEK_DSP) +ARM_ARCH("armv6kz", ARMV6KZ, "6KZ", "v6kz", ARMBuildAttrs::CPUArch::v6KZ, + FK_VFPV2, (ARM::AEK_SEC | ARM::AEK_DSP)) +ARM_ARCH("armv6-m", ARMV6M, "6-M", "v6m", ARMBuildAttrs::CPUArch::v6_M, + FK_NONE, ARM::AEK_NONE) +ARM_ARCH("armv7-a", ARMV7A, "7-A", "v7", ARMBuildAttrs::CPUArch::v7, + FK_NEON, ARM::AEK_DSP) +ARM_ARCH("armv7ve", ARMV7VE, "7VE", "v7ve", ARMBuildAttrs::CPUArch::v7, + FK_NEON, (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | + ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP)) +ARM_ARCH("armv7-r", ARMV7R, "7-R", "v7r", ARMBuildAttrs::CPUArch::v7, + FK_NONE, (ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP)) +ARM_ARCH("armv7-m", ARMV7M, "7-M", "v7m", ARMBuildAttrs::CPUArch::v7, + FK_NONE, ARM::AEK_HWDIVTHUMB) +ARM_ARCH("armv7e-m", ARMV7EM, "7E-M", "v7em", ARMBuildAttrs::CPUArch::v7E_M, + FK_NONE, (ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP)) +ARM_ARCH("armv8-a", ARMV8A, "8-A", "v8", ARMBuildAttrs::CPUArch::v8_A, + FK_CRYPTO_NEON_FP_ARMV8, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC)) +ARM_ARCH("armv8.1-a", ARMV8_1A, "8.1-A", "v8.1a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC)) +ARM_ARCH("armv8.2-a", ARMV8_2A, "8.2-A", "v8.2a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS)) +ARM_ARCH("armv8.3-a", ARMV8_3A, "8.3-A", "v8.3a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS)) +ARM_ARCH("armv8.4-a", ARMV8_4A, "8.4-A", "v8.4a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS | + ARM::AEK_DOTPROD)) +ARM_ARCH("armv8.5-a", ARMV8_5A, "8.5-A", "v8.5a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS | + ARM::AEK_DOTPROD)) +ARM_ARCH("armv8-r", ARMV8R, "8-R", "v8r", ARMBuildAttrs::CPUArch::v8_R, + FK_NEON_FP_ARMV8, + (ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB | + ARM::AEK_DSP | ARM::AEK_CRC)) +ARM_ARCH("armv8-m.base", ARMV8MBaseline, "8-M.Baseline", "v8m.base", + ARMBuildAttrs::CPUArch::v8_M_Base, FK_NONE, ARM::AEK_HWDIVTHUMB) +ARM_ARCH("armv8-m.main", ARMV8MMainline, "8-M.Mainline", "v8m.main", + ARMBuildAttrs::CPUArch::v8_M_Main, FK_FPV5_D16, ARM::AEK_HWDIVTHUMB) +ARM_ARCH("armv8.1-m.main", ARMV8_1MMainline, "8.1-M.Mainline", "v8.1m.main", + ARMBuildAttrs::CPUArch::v8_1_M_Main, FK_FP_ARMV8_FULLFP16_SP_D16, ARM::AEK_HWDIVTHUMB | ARM::AEK_RAS | ARM::AEK_LOB) +// Non-standard Arch names. +ARM_ARCH("iwmmxt", IWMMXT, "iwmmxt", "", ARMBuildAttrs::CPUArch::v5TE, + FK_NONE, ARM::AEK_NONE) +ARM_ARCH("iwmmxt2", IWMMXT2, "iwmmxt2", "", ARMBuildAttrs::CPUArch::v5TE, + FK_NONE, ARM::AEK_NONE) +ARM_ARCH("xscale", XSCALE, "xscale", "v5e", ARMBuildAttrs::CPUArch::v5TE, + FK_NONE, ARM::AEK_NONE) +ARM_ARCH("armv7s", ARMV7S, "7-S", "v7s", ARMBuildAttrs::CPUArch::v7, + FK_NEON_VFPV4, ARM::AEK_DSP) +ARM_ARCH("armv7k", ARMV7K, "7-K", "v7k", ARMBuildAttrs::CPUArch::v7, + FK_NONE, ARM::AEK_DSP) +#undef ARM_ARCH + +#ifndef ARM_ARCH_EXT_NAME +#define ARM_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE) +#endif +// FIXME: This would be nicer were it tablegen +ARM_ARCH_EXT_NAME("invalid", ARM::AEK_INVALID, nullptr, nullptr) +ARM_ARCH_EXT_NAME("none", ARM::AEK_NONE, nullptr, nullptr) +ARM_ARCH_EXT_NAME("crc", ARM::AEK_CRC, "+crc", "-crc") +ARM_ARCH_EXT_NAME("crypto", ARM::AEK_CRYPTO, "+crypto","-crypto") +ARM_ARCH_EXT_NAME("sha2", ARM::AEK_SHA2, "+sha2", "-sha2") +ARM_ARCH_EXT_NAME("aes", ARM::AEK_AES, "+aes", "-aes") +ARM_ARCH_EXT_NAME("dotprod", ARM::AEK_DOTPROD, "+dotprod","-dotprod") +ARM_ARCH_EXT_NAME("dsp", ARM::AEK_DSP, "+dsp", "-dsp") +ARM_ARCH_EXT_NAME("fp", ARM::AEK_FP, nullptr, nullptr) +ARM_ARCH_EXT_NAME("fp.dp", ARM::AEK_FP_DP, nullptr, nullptr) +ARM_ARCH_EXT_NAME("mve", (ARM::AEK_DSP | ARM::AEK_SIMD), "+mve", "-mve") +ARM_ARCH_EXT_NAME("mve.fp", (ARM::AEK_DSP | ARM::AEK_SIMD | ARM::AEK_FP), "+mve.fp", "-mve.fp") +ARM_ARCH_EXT_NAME("idiv", (ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB), nullptr, nullptr) +ARM_ARCH_EXT_NAME("mp", ARM::AEK_MP, nullptr, nullptr) +ARM_ARCH_EXT_NAME("simd", ARM::AEK_SIMD, nullptr, nullptr) +ARM_ARCH_EXT_NAME("sec", ARM::AEK_SEC, nullptr, nullptr) +ARM_ARCH_EXT_NAME("virt", ARM::AEK_VIRT, nullptr, nullptr) +ARM_ARCH_EXT_NAME("fp16", ARM::AEK_FP16, "+fullfp16", "-fullfp16") +ARM_ARCH_EXT_NAME("ras", ARM::AEK_RAS, "+ras", "-ras") +ARM_ARCH_EXT_NAME("os", ARM::AEK_OS, nullptr, nullptr) +ARM_ARCH_EXT_NAME("iwmmxt", ARM::AEK_IWMMXT, nullptr, nullptr) +ARM_ARCH_EXT_NAME("iwmmxt2", ARM::AEK_IWMMXT2, nullptr, nullptr) +ARM_ARCH_EXT_NAME("maverick", ARM::AEK_MAVERICK, nullptr, nullptr) +ARM_ARCH_EXT_NAME("xscale", ARM::AEK_XSCALE, nullptr, nullptr) +ARM_ARCH_EXT_NAME("fp16fml", ARM::AEK_FP16FML, "+fp16fml", "-fp16fml") +ARM_ARCH_EXT_NAME("sb", ARM::AEK_SB, "+sb", "-sb") +ARM_ARCH_EXT_NAME("lob", ARM::AEK_LOB, "+lob", "-lob") +#undef ARM_ARCH_EXT_NAME + +#ifndef ARM_HW_DIV_NAME +#define ARM_HW_DIV_NAME(NAME, ID) +#endif +ARM_HW_DIV_NAME("invalid", ARM::AEK_INVALID) +ARM_HW_DIV_NAME("none", ARM::AEK_NONE) +ARM_HW_DIV_NAME("thumb", ARM::AEK_HWDIVTHUMB) +ARM_HW_DIV_NAME("arm", ARM::AEK_HWDIVARM) +ARM_HW_DIV_NAME("arm,thumb", (ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB)) +#undef ARM_HW_DIV_NAME + +#ifndef ARM_CPU_NAME +#define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) +#endif +ARM_CPU_NAME("arm2", ARMV2, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm3", ARMV2A, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm6", ARMV3, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm7m", ARMV3M, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm8", ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm810", ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("strongarm", ARMV4, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("strongarm110", ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("strongarm1100", ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("strongarm1110", ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm7tdmi", ARMV4T, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm7tdmi-s", ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm710t", ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm720t", ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm9", ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm9tdmi", ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm920", ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm920t", ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm922t", ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm9312", ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm940t", ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("ep9312", ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm10tdmi", ARMV5T, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1020t", ARMV5T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm9e", ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm946e-s", ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm966e-s", ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm968e-s", ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm10e", ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1020e", ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1022e", ARMV5TE, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm926ej-s", ARMV5TEJ, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1136j-s", ARMV6, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1136jf-s", ARMV6, FK_VFPV2, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1136jz-s", ARMV6, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("mpcore", ARMV6K, FK_VFPV2, true, ARM::AEK_NONE) +ARM_CPU_NAME("mpcorenovfp", ARMV6K, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1176jz-s", ARMV6KZ, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1176jzf-s", ARMV6KZ, FK_VFPV2, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1156t2-s", ARMV6T2, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1156t2f-s", ARMV6T2, FK_VFPV2, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m0", ARMV6M, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m0plus", ARMV6M, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m1", ARMV6M, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("sc000", ARMV6M, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-a5", ARMV7A, FK_NEON_VFPV4, false, + (ARM::AEK_SEC | ARM::AEK_MP)) +ARM_CPU_NAME("cortex-a7", ARMV7A, FK_NEON_VFPV4, false, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIVTHUMB)) +ARM_CPU_NAME("cortex-a8", ARMV7A, FK_NEON, false, ARM::AEK_SEC) +ARM_CPU_NAME("cortex-a9", ARMV7A, FK_NEON_FP16, false, (ARM::AEK_SEC | ARM::AEK_MP)) +ARM_CPU_NAME("cortex-a12", ARMV7A, FK_NEON_VFPV4, false, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIVTHUMB)) +ARM_CPU_NAME("cortex-a15", ARMV7A, FK_NEON_VFPV4, false, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIVTHUMB)) +ARM_CPU_NAME("cortex-a17", ARMV7A, FK_NEON_VFPV4, false, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIVTHUMB)) +ARM_CPU_NAME("krait", ARMV7A, FK_NEON_VFPV4, false, + (ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB)) +ARM_CPU_NAME("cortex-r4", ARMV7R, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-r4f", ARMV7R, FK_VFPV3_D16, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-r5", ARMV7R, FK_VFPV3_D16, false, + (ARM::AEK_MP | ARM::AEK_HWDIVARM)) +ARM_CPU_NAME("cortex-r7", ARMV7R, FK_VFPV3_D16_FP16, false, + (ARM::AEK_MP | ARM::AEK_HWDIVARM)) +ARM_CPU_NAME("cortex-r8", ARMV7R, FK_VFPV3_D16_FP16, false, + (ARM::AEK_MP | ARM::AEK_HWDIVARM)) +ARM_CPU_NAME("cortex-r52", ARMV8R, FK_NEON_FP_ARMV8, true, ARM::AEK_NONE) +ARM_CPU_NAME("sc300", ARMV7M, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m3", ARMV7M, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m4", ARMV7EM, FK_FPV4_SP_D16, true, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m7", ARMV7EM, FK_FPV5_D16, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m23", ARMV8MBaseline, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m33", ARMV8MMainline, FK_FPV5_SP_D16, false, ARM::AEK_DSP) +ARM_CPU_NAME("cortex-m35p", ARMV8MMainline, FK_FPV5_SP_D16, false, ARM::AEK_DSP) +ARM_CPU_NAME("cortex-a32", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a35", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a53", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a55", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) +ARM_CPU_NAME("cortex-a57", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a72", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a73", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a75", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) +ARM_CPU_NAME("cortex-a76", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) +ARM_CPU_NAME("cortex-a76ae", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) +ARM_CPU_NAME("neoverse-n1", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) +ARM_CPU_NAME("cyclone", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("exynos-m3", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("exynos-m4", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) +ARM_CPU_NAME("exynos-m5", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) +ARM_CPU_NAME("kryo", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +// Non-standard Arch names. +ARM_CPU_NAME("iwmmxt", IWMMXT, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("xscale", XSCALE, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("swift", ARMV7S, FK_NEON_VFPV4, true, + (ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB)) +// Invalid CPU +ARM_CPU_NAME("invalid", INVALID, FK_INVALID, true, ARM::AEK_INVALID) +#undef ARM_CPU_NAME diff --git a/third_party/llvm-project/include/llvm/Support/ARMTargetParser.h b/third_party/llvm-project/include/llvm/Support/ARMTargetParser.h new file mode 100644 index 000000000..02d4c9751 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/ARMTargetParser.h @@ -0,0 +1,267 @@ +//===-- ARMTargetParser - Parser for ARM target features --------*- 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 a target parser to recognise ARM hardware features +// such as FPU/CPU/ARCH/extensions and specific support such as HWDIV. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ARMTARGETPARSER_H +#define LLVM_SUPPORT_ARMTARGETPARSER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/ARMBuildAttributes.h" +#include <vector> + +namespace llvm { +namespace ARM { + +// Arch extension modifiers for CPUs. +// Note that this is not the same as the AArch64 list +enum ArchExtKind : unsigned { + AEK_INVALID = 0, + AEK_NONE = 1, + AEK_CRC = 1 << 1, + AEK_CRYPTO = 1 << 2, + AEK_FP = 1 << 3, + AEK_HWDIVTHUMB = 1 << 4, + AEK_HWDIVARM = 1 << 5, + AEK_MP = 1 << 6, + AEK_SIMD = 1 << 7, + AEK_SEC = 1 << 8, + AEK_VIRT = 1 << 9, + AEK_DSP = 1 << 10, + AEK_FP16 = 1 << 11, + AEK_RAS = 1 << 12, + AEK_DOTPROD = 1 << 13, + AEK_SHA2 = 1 << 14, + AEK_AES = 1 << 15, + AEK_FP16FML = 1 << 16, + AEK_SB = 1 << 17, + AEK_FP_DP = 1 << 18, + AEK_LOB = 1 << 19, + // Unsupported extensions. + AEK_OS = 0x8000000, + AEK_IWMMXT = 0x10000000, + AEK_IWMMXT2 = 0x20000000, + AEK_MAVERICK = 0x40000000, + AEK_XSCALE = 0x80000000, +}; + +// List of Arch Extension names. +// FIXME: TableGen this. +struct ExtName { + const char *NameCStr; + size_t NameLength; + unsigned ID; + const char *Feature; + const char *NegFeature; + + StringRef getName() const { return StringRef(NameCStr, NameLength); } +}; + +const ExtName ARCHExtNames[] = { +#define ARM_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE) \ + {NAME, sizeof(NAME) - 1, ID, FEATURE, NEGFEATURE}, +#include "ARMTargetParser.def" +}; + +// List of HWDiv names (use getHWDivSynonym) and which architectural +// features they correspond to (use getHWDivFeatures). +// FIXME: TableGen this. +const struct { + const char *NameCStr; + size_t NameLength; + unsigned ID; + + StringRef getName() const { return StringRef(NameCStr, NameLength); } +} HWDivNames[] = { +#define ARM_HW_DIV_NAME(NAME, ID) {NAME, sizeof(NAME) - 1, ID}, +#include "ARMTargetParser.def" +}; + +// Arch names. +enum class ArchKind { +#define ARM_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) ID, +#include "ARMTargetParser.def" +}; + +// List of CPU names and their arches. +// The same CPU can have multiple arches and can be default on multiple arches. +// When finding the Arch for a CPU, first-found prevails. Sort them accordingly. +// When this becomes table-generated, we'd probably need two tables. +// FIXME: TableGen this. +template <typename T> struct CpuNames { + const char *NameCStr; + size_t NameLength; + T ArchID; + bool Default; // is $Name the default CPU for $ArchID ? + unsigned DefaultExtensions; + + StringRef getName() const { return StringRef(NameCStr, NameLength); } +}; + +const CpuNames<ArchKind> CPUNames[] = { +#define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ + {NAME, sizeof(NAME) - 1, ARM::ArchKind::ID, IS_DEFAULT, DEFAULT_EXT}, +#include "ARMTargetParser.def" +}; + +// FPU names. +enum FPUKind { +#define ARM_FPU(NAME, KIND, VERSION, NEON_SUPPORT, RESTRICTION) KIND, +#include "ARMTargetParser.def" + FK_LAST +}; + +// FPU Version +enum class FPUVersion { + NONE, + VFPV2, + VFPV3, + VFPV3_FP16, + VFPV4, + VFPV5, + VFPV5_FULLFP16, +}; + +// An FPU name restricts the FPU in one of three ways: +enum class FPURestriction { + None = 0, ///< No restriction + D16, ///< Only 16 D registers + SP_D16 ///< Only single-precision instructions, with 16 D registers +}; + +// An FPU name implies one of three levels of Neon support: +enum class NeonSupportLevel { + None = 0, ///< No Neon + Neon, ///< Neon + Crypto ///< Neon with Crypto +}; + +// ISA kinds. +enum class ISAKind { INVALID = 0, ARM, THUMB, AARCH64 }; + +// Endianness +// FIXME: BE8 vs. BE32? +enum class EndianKind { INVALID = 0, LITTLE, BIG }; + +// v6/v7/v8 Profile +enum class ProfileKind { INVALID = 0, A, R, M }; + +// List of canonical FPU names (use getFPUSynonym) and which architectural +// features they correspond to (use getFPUFeatures). +// FIXME: TableGen this. +// The entries must appear in the order listed in ARM::FPUKind for correct +// indexing +struct FPUName { + const char *NameCStr; + size_t NameLength; + FPUKind ID; + FPUVersion FPUVer; + NeonSupportLevel NeonSupport; + FPURestriction Restriction; + + StringRef getName() const { return StringRef(NameCStr, NameLength); } +}; + +static const FPUName FPUNames[] = { +#define ARM_FPU(NAME, KIND, VERSION, NEON_SUPPORT, RESTRICTION) \ + {NAME, sizeof(NAME) - 1, KIND, VERSION, NEON_SUPPORT, RESTRICTION}, +#include "llvm/Support/ARMTargetParser.def" +}; + +// List of canonical arch names (use getArchSynonym). +// This table also provides the build attribute fields for CPU arch +// and Arch ID, according to the Addenda to the ARM ABI, chapters +// 2.4 and 2.3.5.2 respectively. +// FIXME: SubArch values were simplified to fit into the expectations +// of the triples and are not conforming with their official names. +// Check to see if the expectation should be changed. +// FIXME: TableGen this. +template <typename T> struct ArchNames { + const char *NameCStr; + size_t NameLength; + const char *CPUAttrCStr; + size_t CPUAttrLength; + const char *SubArchCStr; + size_t SubArchLength; + unsigned DefaultFPU; + unsigned ArchBaseExtensions; + T ID; + ARMBuildAttrs::CPUArch ArchAttr; // Arch ID in build attributes. + + StringRef getName() const { return StringRef(NameCStr, NameLength); } + + // CPU class in build attributes. + StringRef getCPUAttr() const { return StringRef(CPUAttrCStr, CPUAttrLength); } + + // Sub-Arch name. + StringRef getSubArch() const { return StringRef(SubArchCStr, SubArchLength); } +}; + +static const ArchNames<ArchKind> ARCHNames[] = { +#define ARM_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, \ + ARCH_BASE_EXT) \ + {NAME, sizeof(NAME) - 1, \ + CPU_ATTR, sizeof(CPU_ATTR) - 1, \ + SUB_ARCH, sizeof(SUB_ARCH) - 1, \ + ARCH_FPU, ARCH_BASE_EXT, \ + ArchKind::ID, ARCH_ATTR}, +#include "llvm/Support/ARMTargetParser.def" +}; + +// Information by ID +StringRef getFPUName(unsigned FPUKind); +FPUVersion getFPUVersion(unsigned FPUKind); +NeonSupportLevel getFPUNeonSupportLevel(unsigned FPUKind); +FPURestriction getFPURestriction(unsigned FPUKind); + +// FIXME: These should be moved to TargetTuple once it exists +bool getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features); +bool getHWDivFeatures(unsigned HWDivKind, std::vector<StringRef> &Features); +bool getExtensionFeatures(unsigned Extensions, + std::vector<StringRef> &Features); + +StringRef getArchName(ArchKind AK); +unsigned getArchAttr(ArchKind AK); +StringRef getCPUAttr(ArchKind AK); +StringRef getSubArch(ArchKind AK); +StringRef getArchExtName(unsigned ArchExtKind); +StringRef getArchExtFeature(StringRef ArchExt); +bool appendArchExtFeatures(StringRef CPU, ARM::ArchKind AK, StringRef ArchExt, + std::vector<StringRef> &Features); +StringRef getHWDivName(unsigned HWDivKind); + +// Information by Name +unsigned getDefaultFPU(StringRef CPU, ArchKind AK); +unsigned getDefaultExtensions(StringRef CPU, ArchKind AK); +StringRef getDefaultCPU(StringRef Arch); +StringRef getCanonicalArchName(StringRef Arch); +StringRef getFPUSynonym(StringRef FPU); +StringRef getArchSynonym(StringRef Arch); + +// Parser +unsigned parseHWDiv(StringRef HWDiv); +unsigned parseFPU(StringRef FPU); +ArchKind parseArch(StringRef Arch); +unsigned parseArchExt(StringRef ArchExt); +ArchKind parseCPUArch(StringRef CPU); +ISAKind parseArchISA(StringRef Arch); +EndianKind parseArchEndian(StringRef Arch); +ProfileKind parseArchProfile(StringRef Arch); +unsigned parseArchVersion(StringRef Arch); + +void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values); +StringRef computeDefaultTargetABI(const Triple &TT, StringRef CPU); + +} // namespace ARM +} // namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/AlignOf.h b/third_party/llvm-project/include/llvm/Support/AlignOf.h new file mode 100644 index 000000000..eb42542b7 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/AlignOf.h @@ -0,0 +1,55 @@ +//===--- AlignOf.h - Portable calculation of type alignment -----*- 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 defines the AlignedCharArrayUnion class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ALIGNOF_H +#define LLVM_SUPPORT_ALIGNOF_H + +#include "llvm/Support/Compiler.h" +#include <cstddef> + +namespace llvm { + +namespace detail { + +template <typename T, typename... Ts> class AlignerImpl { + T t; + AlignerImpl<Ts...> rest; + AlignerImpl() = delete; +}; + +template <typename T> class AlignerImpl<T> { + T t; + AlignerImpl() = delete; +}; + +template <typename T, typename... Ts> union SizerImpl { + char arr[sizeof(T)]; + SizerImpl<Ts...> rest; +}; + +template <typename T> union SizerImpl<T> { char arr[sizeof(T)]; }; +} // end namespace detail + +/// A suitably aligned and sized character array member which can hold elements +/// of any type. +/// +/// These types may be arrays, structs, or any other types. This exposes a +/// `buffer` member which can be used as suitable storage for a placement new of +/// any of these types. +template <typename T, typename... Ts> struct AlignedCharArrayUnion { + alignas(::llvm::detail::AlignerImpl<T, Ts...>) char buffer[sizeof( + llvm::detail::SizerImpl<T, Ts...>)]; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_ALIGNOF_H diff --git a/third_party/llvm-project/include/llvm/Support/Alignment.h b/third_party/llvm-project/include/llvm/Support/Alignment.h new file mode 100644 index 000000000..72fad87dd --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Alignment.h @@ -0,0 +1,403 @@ +//===-- llvm/Support/Alignment.h - Useful alignment functions ---*- 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 contains types to represent alignments. +// They are instrumented to guarantee some invariants are preserved and prevent +// invalid manipulations. +// +// - Align represents an alignment in bytes, it is always set and always a valid +// power of two, its minimum value is 1 which means no alignment requirements. +// +// - MaybeAlign is an optional type, it may be undefined or set. When it's set +// you can get the underlying Align type by using the getValue() method. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ALIGNMENT_H_ +#define LLVM_SUPPORT_ALIGNMENT_H_ + +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MathExtras.h" +#include <cassert> +#include <limits> + +namespace llvm { + +#define ALIGN_CHECK_ISPOSITIVE(decl) \ + assert(decl > 0 && (#decl " should be defined")) +#define ALIGN_CHECK_ISSET(decl) \ + assert(decl.hasValue() && (#decl " should be defined")) + +/// This struct is a compact representation of a valid (non-zero power of two) +/// alignment. +/// It is suitable for use as static global constants. +struct Align { +private: + uint8_t ShiftValue = 0; /// The log2 of the required alignment. + /// ShiftValue is less than 64 by construction. + + friend struct MaybeAlign; + friend unsigned Log2(Align); + friend bool operator==(Align Lhs, Align Rhs); + friend bool operator!=(Align Lhs, Align Rhs); + friend bool operator<=(Align Lhs, Align Rhs); + friend bool operator>=(Align Lhs, Align Rhs); + friend bool operator<(Align Lhs, Align Rhs); + friend bool operator>(Align Lhs, Align Rhs); + friend unsigned encode(struct MaybeAlign A); + friend struct MaybeAlign decodeMaybeAlign(unsigned Value); + + /// A trivial type to allow construction of constexpr Align. + /// This is currently needed to workaround a bug in GCC 5.3 which prevents + /// definition of constexpr assign operators. + /// https://stackoverflow.com/questions/46756288/explicitly-defaulted-function-cannot-be-declared-as-constexpr-because-the-implic + /// FIXME: Remove this, make all assign operators constexpr and introduce user + /// defined literals when we don't have to support GCC 5.3 anymore. + /// https://llvm.org/docs/GettingStarted.html#getting-a-modern-host-c-toolchain + struct LogValue { + uint8_t Log; + }; + +public: + /// Default is byte-aligned. + constexpr Align() = default; + /// Do not perform checks in case of copy/move construct/assign, because the + /// checks have been performed when building `Other`. + constexpr Align(const Align &Other) = default; + constexpr Align(Align &&Other) = default; + Align &operator=(const Align &Other) = default; + Align &operator=(Align &&Other) = default; + + explicit Align(uint64_t Value) { + assert(Value > 0 && "Value must not be 0"); + assert(llvm::isPowerOf2_64(Value) && "Alignment is not a power of 2"); + ShiftValue = Log2_64(Value); + assert(ShiftValue < 64 && "Broken invariant"); + } + + /// This is a hole in the type system and should not be abused. + /// Needed to interact with C for instance. + uint64_t value() const { return uint64_t(1) << ShiftValue; } + + /// Returns a default constructed Align which corresponds to no alignment. + /// This is useful to test for unalignment as it conveys clear semantic. + /// `if (A != Align::None())` + /// would be better than + /// `if (A > Align(1))` + constexpr static const Align None() { return Align(); } + + /// Allow constructions of constexpr Align. + template <size_t kValue> constexpr static LogValue Constant() { + return LogValue{static_cast<uint8_t>(CTLog2<kValue>())}; + } + + /// Allow constructions of constexpr Align from types. + /// Compile time equivalent to Align(alignof(T)). + template <typename T> constexpr static LogValue Of() { + return Constant<std::alignment_of<T>::value>(); + } + + /// Constexpr constructor from LogValue type. + constexpr Align(LogValue CA) : ShiftValue(CA.Log) {} +}; + +/// Treats the value 0 as a 1, so Align is always at least 1. +inline Align assumeAligned(uint64_t Value) { + return Value ? Align(Value) : Align(); +} + +/// This struct is a compact representation of a valid (power of two) or +/// undefined (0) alignment. +struct MaybeAlign : public llvm::Optional<Align> { +private: + using UP = llvm::Optional<Align>; + +public: + /// Default is undefined. + MaybeAlign() = default; + /// Do not perform checks in case of copy/move construct/assign, because the + /// checks have been performed when building `Other`. + MaybeAlign(const MaybeAlign &Other) = default; + MaybeAlign &operator=(const MaybeAlign &Other) = default; + MaybeAlign(MaybeAlign &&Other) = default; + MaybeAlign &operator=(MaybeAlign &&Other) = default; + + /// Use llvm::Optional<Align> constructor. + using UP::UP; + + explicit MaybeAlign(uint64_t Value) { + assert((Value == 0 || llvm::isPowerOf2_64(Value)) && + "Alignment is neither 0 nor a power of 2"); + if (Value) + emplace(Value); + } + + /// For convenience, returns a valid alignment or 1 if undefined. + Align valueOrOne() const { return hasValue() ? getValue() : Align(); } +}; + +/// Checks that SizeInBytes is a multiple of the alignment. +inline bool isAligned(Align Lhs, uint64_t SizeInBytes) { + return SizeInBytes % Lhs.value() == 0; +} + +/// Checks that SizeInBytes is a multiple of the alignment. +/// Returns false if the alignment is undefined. +inline bool isAligned(MaybeAlign Lhs, uint64_t SizeInBytes) { + ALIGN_CHECK_ISSET(Lhs); + return SizeInBytes % (*Lhs).value() == 0; +} + +/// Checks that Addr is a multiple of the alignment. +inline bool isAddrAligned(Align Lhs, const void *Addr) { + return isAligned(Lhs, reinterpret_cast<uintptr_t>(Addr)); +} + +/// Returns a multiple of A needed to store `Size` bytes. +inline uint64_t alignTo(uint64_t Size, Align A) { + const uint64_t value = A.value(); + // The following line is equivalent to `(Size + value - 1) / value * value`. + + // The division followed by a multiplication can be thought of as a right + // shift followed by a left shift which zeros out the extra bits produced in + // the bump; `~(value - 1)` is a mask where all those bits being zeroed out + // are just zero. + + // Most compilers can generate this code but the pattern may be missed when + // multiple functions gets inlined. + return (Size + value - 1) & ~(value - 1); +} + +/// Returns a multiple of A needed to store `Size` bytes. +/// Returns `Size` if current alignment is undefined. +inline uint64_t alignTo(uint64_t Size, MaybeAlign A) { + return A ? alignTo(Size, A.getValue()) : Size; +} + +/// Aligns `Addr` to `Alignment` bytes, rounding up. +inline uintptr_t alignAddr(const void *Addr, Align Alignment) { + uintptr_t ArithAddr = reinterpret_cast<uintptr_t>(Addr); + assert(static_cast<uintptr_t>(ArithAddr + Alignment.value() - 1) >= + ArithAddr && "Overflow"); + return alignTo(ArithAddr, Alignment); +} + +/// Returns the offset to the next integer (mod 2**64) that is greater than +/// or equal to \p Value and is a multiple of \p Align. +inline uint64_t offsetToAlignment(uint64_t Value, Align Alignment) { + return alignTo(Value, Alignment) - Value; +} + +/// Returns the necessary adjustment for aligning `Addr` to `Alignment` +/// bytes, rounding up. +inline uint64_t offsetToAlignedAddr(const void *Addr, Align Alignment) { + return offsetToAlignment(reinterpret_cast<uintptr_t>(Addr), Alignment); +} + +/// Returns the log2 of the alignment. +inline unsigned Log2(Align A) { return A.ShiftValue; } + +/// Returns the log2 of the alignment. +/// \pre A must be defined. +inline unsigned Log2(MaybeAlign A) { + ALIGN_CHECK_ISSET(A); + return Log2(A.getValue()); +} + +/// Returns the alignment that satisfies both alignments. +/// Same semantic as MinAlign. +inline Align commonAlignment(Align A, Align B) { return std::min(A, B); } + +/// Returns the alignment that satisfies both alignments. +/// Same semantic as MinAlign. +inline Align commonAlignment(Align A, uint64_t Offset) { + return Align(MinAlign(A.value(), Offset)); +} + +/// Returns the alignment that satisfies both alignments. +/// Same semantic as MinAlign. +inline MaybeAlign commonAlignment(MaybeAlign A, MaybeAlign B) { + return A && B ? commonAlignment(*A, *B) : A ? A : B; +} + +/// Returns the alignment that satisfies both alignments. +/// Same semantic as MinAlign. +inline MaybeAlign commonAlignment(MaybeAlign A, uint64_t Offset) { + return MaybeAlign(MinAlign((*A).value(), Offset)); +} + +/// Returns a representation of the alignment that encodes undefined as 0. +inline unsigned encode(MaybeAlign A) { return A ? A->ShiftValue + 1 : 0; } + +/// Dual operation of the encode function above. +inline MaybeAlign decodeMaybeAlign(unsigned Value) { + if (Value == 0) + return MaybeAlign(); + Align Out; + Out.ShiftValue = Value - 1; + return Out; +} + +/// Returns a representation of the alignment, the encoded value is positive by +/// definition. +inline unsigned encode(Align A) { return encode(MaybeAlign(A)); } + +/// Comparisons between Align and scalars. Rhs must be positive. +inline bool operator==(Align Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISPOSITIVE(Rhs); + return Lhs.value() == Rhs; +} +inline bool operator!=(Align Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISPOSITIVE(Rhs); + return Lhs.value() != Rhs; +} +inline bool operator<=(Align Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISPOSITIVE(Rhs); + return Lhs.value() <= Rhs; +} +inline bool operator>=(Align Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISPOSITIVE(Rhs); + return Lhs.value() >= Rhs; +} +inline bool operator<(Align Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISPOSITIVE(Rhs); + return Lhs.value() < Rhs; +} +inline bool operator>(Align Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISPOSITIVE(Rhs); + return Lhs.value() > Rhs; +} + +/// Comparisons between MaybeAlign and scalars. +inline bool operator==(MaybeAlign Lhs, uint64_t Rhs) { + return Lhs ? (*Lhs).value() == Rhs : Rhs == 0; +} +inline bool operator!=(MaybeAlign Lhs, uint64_t Rhs) { + return Lhs ? (*Lhs).value() != Rhs : Rhs != 0; +} +inline bool operator<=(MaybeAlign Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISSET(Lhs); + ALIGN_CHECK_ISPOSITIVE(Rhs); + return (*Lhs).value() <= Rhs; +} +inline bool operator>=(MaybeAlign Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISSET(Lhs); + ALIGN_CHECK_ISPOSITIVE(Rhs); + return (*Lhs).value() >= Rhs; +} +inline bool operator<(MaybeAlign Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISSET(Lhs); + ALIGN_CHECK_ISPOSITIVE(Rhs); + return (*Lhs).value() < Rhs; +} +inline bool operator>(MaybeAlign Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISSET(Lhs); + ALIGN_CHECK_ISPOSITIVE(Rhs); + return (*Lhs).value() > Rhs; +} + +/// Comparisons operators between Align. +inline bool operator==(Align Lhs, Align Rhs) { + return Lhs.ShiftValue == Rhs.ShiftValue; +} +inline bool operator!=(Align Lhs, Align Rhs) { + return Lhs.ShiftValue != Rhs.ShiftValue; +} +inline bool operator<=(Align Lhs, Align Rhs) { + return Lhs.ShiftValue <= Rhs.ShiftValue; +} +inline bool operator>=(Align Lhs, Align Rhs) { + return Lhs.ShiftValue >= Rhs.ShiftValue; +} +inline bool operator<(Align Lhs, Align Rhs) { + return Lhs.ShiftValue < Rhs.ShiftValue; +} +inline bool operator>(Align Lhs, Align Rhs) { + return Lhs.ShiftValue > Rhs.ShiftValue; +} + +/// Comparisons operators between Align and MaybeAlign. +inline bool operator==(Align Lhs, MaybeAlign Rhs) { + ALIGN_CHECK_ISSET(Rhs); + return Lhs.value() == (*Rhs).value(); +} +inline bool operator!=(Align Lhs, MaybeAlign Rhs) { + ALIGN_CHECK_ISSET(Rhs); + return Lhs.value() != (*Rhs).value(); +} +inline bool operator<=(Align Lhs, MaybeAlign Rhs) { + ALIGN_CHECK_ISSET(Rhs); + return Lhs.value() <= (*Rhs).value(); +} +inline bool operator>=(Align Lhs, MaybeAlign Rhs) { + ALIGN_CHECK_ISSET(Rhs); + return Lhs.value() >= (*Rhs).value(); +} +inline bool operator<(Align Lhs, MaybeAlign Rhs) { + ALIGN_CHECK_ISSET(Rhs); + return Lhs.value() < (*Rhs).value(); +} +inline bool operator>(Align Lhs, MaybeAlign Rhs) { + ALIGN_CHECK_ISSET(Rhs); + return Lhs.value() > (*Rhs).value(); +} + +/// Comparisons operators between MaybeAlign and Align. +inline bool operator==(MaybeAlign Lhs, Align Rhs) { + ALIGN_CHECK_ISSET(Lhs); + return Lhs && (*Lhs).value() == Rhs.value(); +} +inline bool operator!=(MaybeAlign Lhs, Align Rhs) { + ALIGN_CHECK_ISSET(Lhs); + return Lhs && (*Lhs).value() != Rhs.value(); +} +inline bool operator<=(MaybeAlign Lhs, Align Rhs) { + ALIGN_CHECK_ISSET(Lhs); + return Lhs && (*Lhs).value() <= Rhs.value(); +} +inline bool operator>=(MaybeAlign Lhs, Align Rhs) { + ALIGN_CHECK_ISSET(Lhs); + return Lhs && (*Lhs).value() >= Rhs.value(); +} +inline bool operator<(MaybeAlign Lhs, Align Rhs) { + ALIGN_CHECK_ISSET(Lhs); + return Lhs && (*Lhs).value() < Rhs.value(); +} +inline bool operator>(MaybeAlign Lhs, Align Rhs) { + ALIGN_CHECK_ISSET(Lhs); + return Lhs && (*Lhs).value() > Rhs.value(); +} + +inline Align operator/(Align Lhs, uint64_t Divisor) { + assert(llvm::isPowerOf2_64(Divisor) && + "Divisor must be positive and a power of 2"); + assert(Lhs != 1 && "Can't halve byte alignment"); + return Align(Lhs.value() / Divisor); +} + +inline MaybeAlign operator/(MaybeAlign Lhs, uint64_t Divisor) { + assert(llvm::isPowerOf2_64(Divisor) && + "Divisor must be positive and a power of 2"); + return Lhs ? Lhs.getValue() / Divisor : MaybeAlign(); +} + +inline Align max(MaybeAlign Lhs, Align Rhs) { + return Lhs && *Lhs > Rhs ? *Lhs : Rhs; +} + +inline Align max(Align Lhs, MaybeAlign Rhs) { + return Rhs && *Rhs > Lhs ? *Rhs : Lhs; +} + +#undef ALIGN_CHECK_ISPOSITIVE +#undef ALIGN_CHECK_ISSET + +} // namespace llvm + +#endif // LLVM_SUPPORT_ALIGNMENT_H_ diff --git a/third_party/llvm-project/include/llvm/Support/Allocator.h b/third_party/llvm-project/include/llvm/Support/Allocator.h new file mode 100644 index 000000000..106b90c35 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Allocator.h @@ -0,0 +1,523 @@ +//===- Allocator.h - Simple memory allocation abstraction -------*- 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 +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines the MallocAllocator and BumpPtrAllocator interfaces. Both +/// of these conform to an LLVM "Allocator" concept which consists of an +/// Allocate method accepting a size and alignment, and a Deallocate accepting +/// a pointer and size. Further, the LLVM "Allocator" concept has overloads of +/// Allocate and Deallocate for setting size and alignment based on the final +/// type. These overloads are typically provided by a base class template \c +/// AllocatorBase. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ALLOCATOR_H +#define LLVM_SUPPORT_ALLOCATOR_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Alignment.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemAlloc.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <iterator> +#include <type_traits> +#include <utility> + +namespace llvm { + +/// CRTP base class providing obvious overloads for the core \c +/// Allocate() methods of LLVM-style allocators. +/// +/// This base class both documents the full public interface exposed by all +/// LLVM-style allocators, and redirects all of the overloads to a single core +/// set of methods which the derived class must define. +template <typename DerivedT> class AllocatorBase { +public: + /// Allocate \a Size bytes of \a Alignment aligned memory. This method + /// must be implemented by \c DerivedT. + void *Allocate(size_t Size, size_t Alignment) { +#ifdef __clang__ + static_assert(static_cast<void *(AllocatorBase::*)(size_t, size_t)>( + &AllocatorBase::Allocate) != + static_cast<void *(DerivedT::*)(size_t, size_t)>( + &DerivedT::Allocate), + "Class derives from AllocatorBase without implementing the " + "core Allocate(size_t, size_t) overload!"); +#endif + return static_cast<DerivedT *>(this)->Allocate(Size, Alignment); + } + + /// Deallocate \a Ptr to \a Size bytes of memory allocated by this + /// allocator. + void Deallocate(const void *Ptr, size_t Size) { +#ifdef __clang__ + static_assert(static_cast<void (AllocatorBase::*)(const void *, size_t)>( + &AllocatorBase::Deallocate) != + static_cast<void (DerivedT::*)(const void *, size_t)>( + &DerivedT::Deallocate), + "Class derives from AllocatorBase without implementing the " + "core Deallocate(void *) overload!"); +#endif + return static_cast<DerivedT *>(this)->Deallocate(Ptr, Size); + } + + // The rest of these methods are helpers that redirect to one of the above + // core methods. + + /// Allocate space for a sequence of objects without constructing them. + template <typename T> T *Allocate(size_t Num = 1) { + return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T))); + } + + /// Deallocate space for a sequence of objects without constructing them. + template <typename T> + typename std::enable_if< + !std::is_same<typename std::remove_cv<T>::type, void>::value, void>::type + Deallocate(T *Ptr, size_t Num = 1) { + Deallocate(static_cast<const void *>(Ptr), Num * sizeof(T)); + } +}; + +class MallocAllocator : public AllocatorBase<MallocAllocator> { +public: + void Reset() {} + + LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, + size_t /*Alignment*/) { + return safe_malloc(Size); + } + + // Pull in base class overloads. + using AllocatorBase<MallocAllocator>::Allocate; + + void Deallocate(const void *Ptr, size_t /*Size*/) { + free(const_cast<void *>(Ptr)); + } + + // Pull in base class overloads. + using AllocatorBase<MallocAllocator>::Deallocate; + + void PrintStats() const {} +}; + +namespace detail { + +// We call out to an external function to actually print the message as the +// printing code uses Allocator.h in its implementation. +void printBumpPtrAllocatorStats(unsigned NumSlabs, size_t BytesAllocated, + size_t TotalMemory); + +} // end namespace detail + +/// Allocate memory in an ever growing pool, as if by bump-pointer. +/// +/// This isn't strictly a bump-pointer allocator as it uses backing slabs of +/// memory rather than relying on a boundless contiguous heap. However, it has +/// bump-pointer semantics in that it is a monotonically growing pool of memory +/// where every allocation is found by merely allocating the next N bytes in +/// the slab, or the next N bytes in the next slab. +/// +/// Note that this also has a threshold for forcing allocations above a certain +/// size into their own slab. +/// +/// The BumpPtrAllocatorImpl template defaults to using a MallocAllocator +/// object, which wraps malloc, to allocate memory, but it can be changed to +/// use a custom allocator. +template <typename AllocatorT = MallocAllocator, size_t SlabSize = 4096, + size_t SizeThreshold = SlabSize> +class BumpPtrAllocatorImpl + : public AllocatorBase< + BumpPtrAllocatorImpl<AllocatorT, SlabSize, SizeThreshold>> { +public: + static_assert(SizeThreshold <= SlabSize, + "The SizeThreshold must be at most the SlabSize to ensure " + "that objects larger than a slab go into their own memory " + "allocation."); + + BumpPtrAllocatorImpl() = default; + + template <typename T> + BumpPtrAllocatorImpl(T &&Allocator) + : Allocator(std::forward<T &&>(Allocator)) {} + + // Manually implement a move constructor as we must clear the old allocator's + // slabs as a matter of correctness. + BumpPtrAllocatorImpl(BumpPtrAllocatorImpl &&Old) + : CurPtr(Old.CurPtr), End(Old.End), Slabs(std::move(Old.Slabs)), + CustomSizedSlabs(std::move(Old.CustomSizedSlabs)), + BytesAllocated(Old.BytesAllocated), RedZoneSize(Old.RedZoneSize), + Allocator(std::move(Old.Allocator)) { + Old.CurPtr = Old.End = nullptr; + Old.BytesAllocated = 0; + Old.Slabs.clear(); + Old.CustomSizedSlabs.clear(); + } + + ~BumpPtrAllocatorImpl() { + DeallocateSlabs(Slabs.begin(), Slabs.end()); + DeallocateCustomSizedSlabs(); + } + + BumpPtrAllocatorImpl &operator=(BumpPtrAllocatorImpl &&RHS) { + DeallocateSlabs(Slabs.begin(), Slabs.end()); + DeallocateCustomSizedSlabs(); + + CurPtr = RHS.CurPtr; + End = RHS.End; + BytesAllocated = RHS.BytesAllocated; + RedZoneSize = RHS.RedZoneSize; + Slabs = std::move(RHS.Slabs); + CustomSizedSlabs = std::move(RHS.CustomSizedSlabs); + Allocator = std::move(RHS.Allocator); + + RHS.CurPtr = RHS.End = nullptr; + RHS.BytesAllocated = 0; + RHS.Slabs.clear(); + RHS.CustomSizedSlabs.clear(); + return *this; + } + + /// Deallocate all but the current slab and reset the current pointer + /// to the beginning of it, freeing all memory allocated so far. + void Reset() { + // Deallocate all but the first slab, and deallocate all custom-sized slabs. + DeallocateCustomSizedSlabs(); + CustomSizedSlabs.clear(); + + if (Slabs.empty()) + return; + + // Reset the state. + BytesAllocated = 0; + CurPtr = (char *)Slabs.front(); + End = CurPtr + SlabSize; + + __asan_poison_memory_region(*Slabs.begin(), computeSlabSize(0)); + DeallocateSlabs(std::next(Slabs.begin()), Slabs.end()); + Slabs.erase(std::next(Slabs.begin()), Slabs.end()); + } + + /// Allocate space at the specified alignment. + LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void * + Allocate(size_t Size, Align Alignment) { + // Keep track of how many bytes we've allocated. + BytesAllocated += Size; + + size_t Adjustment = offsetToAlignedAddr(CurPtr, Alignment); + assert(Adjustment + Size >= Size && "Adjustment + Size must not overflow"); + + size_t SizeToAllocate = Size; +#if LLVM_ADDRESS_SANITIZER_BUILD + // Add trailing bytes as a "red zone" under ASan. + SizeToAllocate += RedZoneSize; +#endif + + // Check if we have enough space. + if (Adjustment + SizeToAllocate <= size_t(End - CurPtr)) { + char *AlignedPtr = CurPtr + Adjustment; + CurPtr = AlignedPtr + SizeToAllocate; + // Update the allocation point of this memory block in MemorySanitizer. + // Without this, MemorySanitizer messages for values originated from here + // will point to the allocation of the entire slab. + __msan_allocated_memory(AlignedPtr, Size); + // Similarly, tell ASan about this space. + __asan_unpoison_memory_region(AlignedPtr, Size); + return AlignedPtr; + } + + // If Size is really big, allocate a separate slab for it. + size_t PaddedSize = SizeToAllocate + Alignment.value() - 1; + if (PaddedSize > SizeThreshold) { + void *NewSlab = Allocator.Allocate(PaddedSize, 0); + // We own the new slab and don't want anyone reading anyting other than + // pieces returned from this method. So poison the whole slab. + __asan_poison_memory_region(NewSlab, PaddedSize); + CustomSizedSlabs.push_back(std::make_pair(NewSlab, PaddedSize)); + + uintptr_t AlignedAddr = alignAddr(NewSlab, Alignment); + assert(AlignedAddr + Size <= (uintptr_t)NewSlab + PaddedSize); + char *AlignedPtr = (char*)AlignedAddr; + __msan_allocated_memory(AlignedPtr, Size); + __asan_unpoison_memory_region(AlignedPtr, Size); + return AlignedPtr; + } + + // Otherwise, start a new slab and try again. + StartNewSlab(); + uintptr_t AlignedAddr = alignAddr(CurPtr, Alignment); + assert(AlignedAddr + SizeToAllocate <= (uintptr_t)End && + "Unable to allocate memory!"); + char *AlignedPtr = (char*)AlignedAddr; + CurPtr = AlignedPtr + SizeToAllocate; + __msan_allocated_memory(AlignedPtr, Size); + __asan_unpoison_memory_region(AlignedPtr, Size); + return AlignedPtr; + } + + inline LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void * + Allocate(size_t Size, size_t Alignment) { + assert(Alignment > 0 && "0-byte alignnment is not allowed. Use 1 instead."); + return Allocate(Size, Align(Alignment)); + } + + // Pull in base class overloads. + using AllocatorBase<BumpPtrAllocatorImpl>::Allocate; + + // Bump pointer allocators are expected to never free their storage; and + // clients expect pointers to remain valid for non-dereferencing uses even + // after deallocation. + void Deallocate(const void *Ptr, size_t Size) { + __asan_poison_memory_region(Ptr, Size); + } + + // Pull in base class overloads. + using AllocatorBase<BumpPtrAllocatorImpl>::Deallocate; + + size_t GetNumSlabs() const { return Slabs.size() + CustomSizedSlabs.size(); } + + /// \return An index uniquely and reproducibly identifying + /// an input pointer \p Ptr in the given allocator. + /// The returned value is negative iff the object is inside a custom-size + /// slab. + /// Returns an empty optional if the pointer is not found in the allocator. + llvm::Optional<int64_t> identifyObject(const void *Ptr) { + const char *P = static_cast<const char *>(Ptr); + int64_t InSlabIdx = 0; + for (size_t Idx = 0, E = Slabs.size(); Idx < E; Idx++) { + const char *S = static_cast<const char *>(Slabs[Idx]); + if (P >= S && P < S + computeSlabSize(Idx)) + return InSlabIdx + static_cast<int64_t>(P - S); + InSlabIdx += static_cast<int64_t>(computeSlabSize(Idx)); + } + + // Use negative index to denote custom sized slabs. + int64_t InCustomSizedSlabIdx = -1; + for (size_t Idx = 0, E = CustomSizedSlabs.size(); Idx < E; Idx++) { + const char *S = static_cast<const char *>(CustomSizedSlabs[Idx].first); + size_t Size = CustomSizedSlabs[Idx].second; + if (P >= S && P < S + Size) + return InCustomSizedSlabIdx - static_cast<int64_t>(P - S); + InCustomSizedSlabIdx -= static_cast<int64_t>(Size); + } + return None; + } + + /// A wrapper around identifyObject that additionally asserts that + /// the object is indeed within the allocator. + /// \return An index uniquely and reproducibly identifying + /// an input pointer \p Ptr in the given allocator. + int64_t identifyKnownObject(const void *Ptr) { + Optional<int64_t> Out = identifyObject(Ptr); + assert(Out && "Wrong allocator used"); + return *Out; + } + + /// A wrapper around identifyKnownObject. Accepts type information + /// about the object and produces a smaller identifier by relying on + /// the alignment information. Note that sub-classes may have different + /// alignment, so the most base class should be passed as template parameter + /// in order to obtain correct results. For that reason automatic template + /// parameter deduction is disabled. + /// \return An index uniquely and reproducibly identifying + /// an input pointer \p Ptr in the given allocator. This identifier is + /// different from the ones produced by identifyObject and + /// identifyAlignedObject. + template <typename T> + int64_t identifyKnownAlignedObject(const void *Ptr) { + int64_t Out = identifyKnownObject(Ptr); + assert(Out % alignof(T) == 0 && "Wrong alignment information"); + return Out / alignof(T); + } + + size_t getTotalMemory() const { + size_t TotalMemory = 0; + for (auto I = Slabs.begin(), E = Slabs.end(); I != E; ++I) + TotalMemory += computeSlabSize(std::distance(Slabs.begin(), I)); + for (auto &PtrAndSize : CustomSizedSlabs) + TotalMemory += PtrAndSize.second; + return TotalMemory; + } + + size_t getBytesAllocated() const { return BytesAllocated; } + + void setRedZoneSize(size_t NewSize) { + RedZoneSize = NewSize; + } + + void PrintStats() const { + detail::printBumpPtrAllocatorStats(Slabs.size(), BytesAllocated, + getTotalMemory()); + } + +private: + /// The current pointer into the current slab. + /// + /// This points to the next free byte in the slab. + char *CurPtr = nullptr; + + /// The end of the current slab. + char *End = nullptr; + + /// The slabs allocated so far. + SmallVector<void *, 4> Slabs; + + /// Custom-sized slabs allocated for too-large allocation requests. + SmallVector<std::pair<void *, size_t>, 0> CustomSizedSlabs; + + /// How many bytes we've allocated. + /// + /// Used so that we can compute how much space was wasted. + size_t BytesAllocated = 0; + + /// The number of bytes to put between allocations when running under + /// a sanitizer. + size_t RedZoneSize = 1; + + /// The allocator instance we use to get slabs of memory. + AllocatorT Allocator; + + static size_t computeSlabSize(unsigned SlabIdx) { + // Scale the actual allocated slab size based on the number of slabs + // allocated. Every 128 slabs allocated, we double the allocated size to + // reduce allocation frequency, but saturate at multiplying the slab size by + // 2^30. + return SlabSize * ((size_t)1 << std::min<size_t>(30, SlabIdx / 128)); + } + + /// Allocate a new slab and move the bump pointers over into the new + /// slab, modifying CurPtr and End. + void StartNewSlab() { + size_t AllocatedSlabSize = computeSlabSize(Slabs.size()); + + void *NewSlab = Allocator.Allocate(AllocatedSlabSize, 0); + // We own the new slab and don't want anyone reading anything other than + // pieces returned from this method. So poison the whole slab. + __asan_poison_memory_region(NewSlab, AllocatedSlabSize); + + Slabs.push_back(NewSlab); + CurPtr = (char *)(NewSlab); + End = ((char *)NewSlab) + AllocatedSlabSize; + } + + /// Deallocate a sequence of slabs. + void DeallocateSlabs(SmallVectorImpl<void *>::iterator I, + SmallVectorImpl<void *>::iterator E) { + for (; I != E; ++I) { + size_t AllocatedSlabSize = + computeSlabSize(std::distance(Slabs.begin(), I)); + Allocator.Deallocate(*I, AllocatedSlabSize); + } + } + + /// Deallocate all memory for custom sized slabs. + void DeallocateCustomSizedSlabs() { + for (auto &PtrAndSize : CustomSizedSlabs) { + void *Ptr = PtrAndSize.first; + size_t Size = PtrAndSize.second; + Allocator.Deallocate(Ptr, Size); + } + } + + template <typename T> friend class SpecificBumpPtrAllocator; +}; + +/// The standard BumpPtrAllocator which just uses the default template +/// parameters. +typedef BumpPtrAllocatorImpl<> BumpPtrAllocator; + +/// A BumpPtrAllocator that allows only elements of a specific type to be +/// allocated. +/// +/// This allows calling the destructor in DestroyAll() and when the allocator is +/// destroyed. +template <typename T> class SpecificBumpPtrAllocator { + BumpPtrAllocator Allocator; + +public: + SpecificBumpPtrAllocator() { + // Because SpecificBumpPtrAllocator walks the memory to call destructors, + // it can't have red zones between allocations. + Allocator.setRedZoneSize(0); + } + SpecificBumpPtrAllocator(SpecificBumpPtrAllocator &&Old) + : Allocator(std::move(Old.Allocator)) {} + ~SpecificBumpPtrAllocator() { DestroyAll(); } + + SpecificBumpPtrAllocator &operator=(SpecificBumpPtrAllocator &&RHS) { + Allocator = std::move(RHS.Allocator); + return *this; + } + + /// Call the destructor of each allocated object and deallocate all but the + /// current slab and reset the current pointer to the beginning of it, freeing + /// all memory allocated so far. + void DestroyAll() { + auto DestroyElements = [](char *Begin, char *End) { + assert(Begin == (char *)alignAddr(Begin, Align::Of<T>())); + for (char *Ptr = Begin; Ptr + sizeof(T) <= End; Ptr += sizeof(T)) + reinterpret_cast<T *>(Ptr)->~T(); + }; + + for (auto I = Allocator.Slabs.begin(), E = Allocator.Slabs.end(); I != E; + ++I) { + size_t AllocatedSlabSize = BumpPtrAllocator::computeSlabSize( + std::distance(Allocator.Slabs.begin(), I)); + char *Begin = (char *)alignAddr(*I, Align::Of<T>()); + char *End = *I == Allocator.Slabs.back() ? Allocator.CurPtr + : (char *)*I + AllocatedSlabSize; + + DestroyElements(Begin, End); + } + + for (auto &PtrAndSize : Allocator.CustomSizedSlabs) { + void *Ptr = PtrAndSize.first; + size_t Size = PtrAndSize.second; + DestroyElements((char *)alignAddr(Ptr, Align::Of<T>()), + (char *)Ptr + Size); + } + + Allocator.Reset(); + } + + /// Allocate space for an array of objects without constructing them. + T *Allocate(size_t num = 1) { return Allocator.Allocate<T>(num); } +}; + +} // end namespace llvm + +template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold> +void *operator new(size_t Size, + llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize, + SizeThreshold> &Allocator) { + struct S { + char c; + union { + double D; + long double LD; + long long L; + void *P; + } x; + }; + return Allocator.Allocate( + Size, std::min((size_t)llvm::NextPowerOf2(Size), offsetof(S, x))); +} + +template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold> +void operator delete( + void *, llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize, SizeThreshold> &) { +} + +#endif // LLVM_SUPPORT_ALLOCATOR_H diff --git a/third_party/llvm-project/include/llvm/Support/BinaryByteStream.h b/third_party/llvm-project/include/llvm/Support/BinaryByteStream.h new file mode 100644 index 000000000..7acce9a03 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/BinaryByteStream.h @@ -0,0 +1,273 @@ +//===- BinaryByteStream.h ---------------------------------------*- 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 +//===----------------------------------------------------------------------===// +// A BinaryStream which stores data in a single continguous memory buffer. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H +#define LLVM_SUPPORT_BINARYBYTESTREAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/MemoryBuffer.h" +#include <algorithm> +#include <cstdint> +#include <cstring> +#include <memory> + +namespace llvm { + +/// An implementation of BinaryStream which holds its entire data set +/// in a single contiguous buffer. BinaryByteStream guarantees that no read +/// operation will ever incur a copy. Note that BinaryByteStream does not +/// own the underlying buffer. +class BinaryByteStream : public BinaryStream { +public: + BinaryByteStream() = default; + BinaryByteStream(ArrayRef<uint8_t> Data, llvm::support::endianness Endian) + : Endian(Endian), Data(Data) {} + BinaryByteStream(StringRef Data, llvm::support::endianness Endian) + : Endian(Endian), Data(Data.bytes_begin(), Data.bytes_end()) {} + + llvm::support::endianness getEndian() const override { return Endian; } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override { + if (auto EC = checkOffsetForRead(Offset, Size)) + return EC; + Buffer = Data.slice(Offset, Size); + return Error::success(); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override { + if (auto EC = checkOffsetForRead(Offset, 1)) + return EC; + Buffer = Data.slice(Offset); + return Error::success(); + } + + uint32_t getLength() override { return Data.size(); } + + ArrayRef<uint8_t> data() const { return Data; } + + StringRef str() const { + const char *CharData = reinterpret_cast<const char *>(Data.data()); + return StringRef(CharData, Data.size()); + } + +protected: + llvm::support::endianness Endian; + ArrayRef<uint8_t> Data; +}; + +/// An implementation of BinaryStream whose data is backed by an llvm +/// MemoryBuffer object. MemoryBufferByteStream owns the MemoryBuffer in +/// question. As with BinaryByteStream, reading from a MemoryBufferByteStream +/// will never cause a copy. +class MemoryBufferByteStream : public BinaryByteStream { +public: + MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer, + llvm::support::endianness Endian) + : BinaryByteStream(Buffer->getBuffer(), Endian), + MemBuffer(std::move(Buffer)) {} + + std::unique_ptr<MemoryBuffer> MemBuffer; +}; + +/// An implementation of BinaryStream which holds its entire data set +/// in a single contiguous buffer. As with BinaryByteStream, the mutable +/// version also guarantees that no read operation will ever incur a copy, +/// and similarly it does not own the underlying buffer. +class MutableBinaryByteStream : public WritableBinaryStream { +public: + MutableBinaryByteStream() = default; + MutableBinaryByteStream(MutableArrayRef<uint8_t> Data, + llvm::support::endianness Endian) + : Data(Data), ImmutableStream(Data, Endian) {} + + llvm::support::endianness getEndian() const override { + return ImmutableStream.getEndian(); + } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override { + return ImmutableStream.readBytes(Offset, Size, Buffer); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override { + return ImmutableStream.readLongestContiguousChunk(Offset, Buffer); + } + + uint32_t getLength() override { return ImmutableStream.getLength(); } + + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override { + if (Buffer.empty()) + return Error::success(); + + if (auto EC = checkOffsetForWrite(Offset, Buffer.size())) + return EC; + + uint8_t *DataPtr = const_cast<uint8_t *>(Data.data()); + ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size()); + return Error::success(); + } + + Error commit() override { return Error::success(); } + + MutableArrayRef<uint8_t> data() const { return Data; } + +private: + MutableArrayRef<uint8_t> Data; + BinaryByteStream ImmutableStream; +}; + +/// An implementation of WritableBinaryStream which can write at its end +/// causing the underlying data to grow. This class owns the underlying data. +class AppendingBinaryByteStream : public WritableBinaryStream { + std::vector<uint8_t> Data; + llvm::support::endianness Endian = llvm::support::little; + +public: + AppendingBinaryByteStream() = default; + AppendingBinaryByteStream(llvm::support::endianness Endian) + : Endian(Endian) {} + + void clear() { Data.clear(); } + + llvm::support::endianness getEndian() const override { return Endian; } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override { + if (auto EC = checkOffsetForWrite(Offset, Buffer.size())) + return EC; + + Buffer = makeArrayRef(Data).slice(Offset, Size); + return Error::success(); + } + + void insert(uint32_t Offset, ArrayRef<uint8_t> Bytes) { + Data.insert(Data.begin() + Offset, Bytes.begin(), Bytes.end()); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override { + if (auto EC = checkOffsetForWrite(Offset, 1)) + return EC; + + Buffer = makeArrayRef(Data).slice(Offset); + return Error::success(); + } + + uint32_t getLength() override { return Data.size(); } + + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override { + if (Buffer.empty()) + return Error::success(); + + // This is well-defined for any case except where offset is strictly + // greater than the current length. If offset is equal to the current + // length, we can still grow. If offset is beyond the current length, we + // would have to decide how to deal with the intermediate uninitialized + // bytes. So we punt on that case for simplicity and just say it's an + // error. + if (Offset > getLength()) + return make_error<BinaryStreamError>(stream_error_code::invalid_offset); + + uint32_t RequiredSize = Offset + Buffer.size(); + if (RequiredSize > Data.size()) + Data.resize(RequiredSize); + + ::memcpy(Data.data() + Offset, Buffer.data(), Buffer.size()); + return Error::success(); + } + + Error commit() override { return Error::success(); } + + /// Return the properties of this stream. + virtual BinaryStreamFlags getFlags() const override { + return BSF_Write | BSF_Append; + } + + MutableArrayRef<uint8_t> data() { return Data; } +}; + +/// An implementation of WritableBinaryStream backed by an llvm +/// FileOutputBuffer. +class FileBufferByteStream : public WritableBinaryStream { +private: + class StreamImpl : public MutableBinaryByteStream { + public: + StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer, + llvm::support::endianness Endian) + : MutableBinaryByteStream( + MutableArrayRef<uint8_t>(Buffer->getBufferStart(), + Buffer->getBufferEnd()), + Endian), + FileBuffer(std::move(Buffer)) {} + + Error commit() override { + if (FileBuffer->commit()) + return make_error<BinaryStreamError>( + stream_error_code::filesystem_error); + return Error::success(); + } + + /// Returns a pointer to the start of the buffer. + uint8_t *getBufferStart() const { return FileBuffer->getBufferStart(); } + + /// Returns a pointer to the end of the buffer. + uint8_t *getBufferEnd() const { return FileBuffer->getBufferEnd(); } + + private: + std::unique_ptr<FileOutputBuffer> FileBuffer; + }; + +public: + FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer, + llvm::support::endianness Endian) + : Impl(std::move(Buffer), Endian) {} + + llvm::support::endianness getEndian() const override { + return Impl.getEndian(); + } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override { + return Impl.readBytes(Offset, Size, Buffer); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override { + return Impl.readLongestContiguousChunk(Offset, Buffer); + } + + uint32_t getLength() override { return Impl.getLength(); } + + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) override { + return Impl.writeBytes(Offset, Data); + } + + Error commit() override { return Impl.commit(); } + + /// Returns a pointer to the start of the buffer. + uint8_t *getBufferStart() const { return Impl.getBufferStart(); } + + /// Returns a pointer to the end of the buffer. + uint8_t *getBufferEnd() const { return Impl.getBufferEnd(); } + +private: + StreamImpl Impl; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BYTESTREAM_H diff --git a/third_party/llvm-project/include/llvm/Support/BinaryStream.h b/third_party/llvm-project/include/llvm/Support/BinaryStream.h new file mode 100644 index 000000000..fcf439855 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/BinaryStream.h @@ -0,0 +1,101 @@ +//===- BinaryStream.h - Base interface for a stream of data -----*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BINARYSTREAM_H +#define LLVM_SUPPORT_BINARYSTREAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitmaskEnum.h" +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <cstdint> + +namespace llvm { + +enum BinaryStreamFlags { + BSF_None = 0, + BSF_Write = 1, // Stream supports writing. + BSF_Append = 2, // Writing can occur at offset == length. + LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ BSF_Append) +}; + +/// An interface for accessing data in a stream-like format, but which +/// discourages copying. Instead of specifying a buffer in which to copy +/// data on a read, the API returns an ArrayRef to data owned by the stream's +/// implementation. Since implementations may not necessarily store data in a +/// single contiguous buffer (or even in memory at all), in such cases a it may +/// be necessary for an implementation to cache such a buffer so that it can +/// return it. +class BinaryStream { +public: + virtual ~BinaryStream() = default; + + virtual llvm::support::endianness getEndian() const = 0; + + /// Given an offset into the stream and a number of bytes, attempt to + /// read the bytes and set the output ArrayRef to point to data owned by the + /// stream. + virtual Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) = 0; + + /// Given an offset into the stream, read as much as possible without + /// copying any data. + virtual Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) = 0; + + /// Return the number of bytes of data in this stream. + virtual uint32_t getLength() = 0; + + /// Return the properties of this stream. + virtual BinaryStreamFlags getFlags() const { return BSF_None; } + +protected: + Error checkOffsetForRead(uint32_t Offset, uint32_t DataSize) { + if (Offset > getLength()) + return make_error<BinaryStreamError>(stream_error_code::invalid_offset); + if (getLength() < DataSize + Offset) + return make_error<BinaryStreamError>(stream_error_code::stream_too_short); + return Error::success(); + } +}; + +/// A BinaryStream which can be read from as well as written to. Note +/// that writing to a BinaryStream always necessitates copying from the input +/// buffer to the stream's backing store. Streams are assumed to be buffered +/// so that to be portable it is necessary to call commit() on the stream when +/// all data has been written. +class WritableBinaryStream : public BinaryStream { +public: + ~WritableBinaryStream() override = default; + + /// Attempt to write the given bytes into the stream at the desired + /// offset. This will always necessitate a copy. Cannot shrink or grow the + /// stream, only writes into existing allocated space. + virtual Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) = 0; + + /// For buffered streams, commits changes to the backing store. + virtual Error commit() = 0; + + /// Return the properties of this stream. + BinaryStreamFlags getFlags() const override { return BSF_Write; } + +protected: + Error checkOffsetForWrite(uint32_t Offset, uint32_t DataSize) { + if (!(getFlags() & BSF_Append)) + return checkOffsetForRead(Offset, DataSize); + + if (Offset > getLength()) + return make_error<BinaryStreamError>(stream_error_code::invalid_offset); + return Error::success(); + } +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAM_H diff --git a/third_party/llvm-project/include/llvm/Support/BinaryStreamError.h b/third_party/llvm-project/include/llvm/Support/BinaryStreamError.h new file mode 100644 index 000000000..cf6e034ff --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/BinaryStreamError.h @@ -0,0 +1,47 @@ +//===- BinaryStreamError.h - Error extensions for Binary Streams *- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BINARYSTREAMERROR_H +#define LLVM_SUPPORT_BINARYSTREAMERROR_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + +#include <string> + +namespace llvm { +enum class stream_error_code { + unspecified, + stream_too_short, + invalid_array_size, + invalid_offset, + filesystem_error +}; + +/// Base class for errors originating when parsing raw PDB files +class BinaryStreamError : public ErrorInfo<BinaryStreamError> { +public: + static char ID; + explicit BinaryStreamError(stream_error_code C); + explicit BinaryStreamError(StringRef Context); + BinaryStreamError(stream_error_code C, StringRef Context); + + void log(raw_ostream &OS) const override; + std::error_code convertToErrorCode() const override; + + StringRef getErrorMessage() const; + + stream_error_code getErrorCode() const { return Code; } + +private: + std::string ErrMsg; + stream_error_code Code; +}; +} // namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAMERROR_H diff --git a/third_party/llvm-project/include/llvm/Support/CBindingWrapping.h b/third_party/llvm-project/include/llvm/Support/CBindingWrapping.h new file mode 100644 index 000000000..46d6b4e3f --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/CBindingWrapping.h @@ -0,0 +1,46 @@ +//===- llvm/Support/CBindingWrapping.h - C Interface Wrapping ---*- 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 declares the wrapping macros for the C interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CBINDINGWRAPPING_H +#define LLVM_SUPPORT_CBINDINGWRAPPING_H + +#include "llvm-c/Types.h" +#include "llvm/Support/Casting.h" + +#define DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref) \ + inline ty *unwrap(ref P) { \ + return reinterpret_cast<ty*>(P); \ + } \ + \ + inline ref wrap(const ty *P) { \ + return reinterpret_cast<ref>(const_cast<ty*>(P)); \ + } + +#define DEFINE_ISA_CONVERSION_FUNCTIONS(ty, ref) \ + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref) \ + \ + template<typename T> \ + inline T *unwrap(ref P) { \ + return cast<T>(unwrap(P)); \ + } + +#define DEFINE_STDCXX_CONVERSION_FUNCTIONS(ty, ref) \ + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref) \ + \ + template<typename T> \ + inline T *unwrap(ref P) { \ + T *Q = (T*)unwrap(P); \ + assert(Q && "Invalid cast!"); \ + return Q; \ + } + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/Casting.h b/third_party/llvm-project/include/llvm/Support/Casting.h new file mode 100644 index 000000000..46bdedb04 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Casting.h @@ -0,0 +1,408 @@ +//===- llvm/Support/Casting.h - Allow flexible, checked, casts --*- 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 defines the isa<X>(), cast<X>(), dyn_cast<X>(), cast_or_null<X>(), +// and dyn_cast_or_null<X>() templates. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CASTING_H +#define LLVM_SUPPORT_CASTING_H + +#include "llvm/Support/Compiler.h" +#include "llvm/Support/type_traits.h" +#include <cassert> +#include <memory> +#include <type_traits> + +namespace llvm { + +//===----------------------------------------------------------------------===// +// isa<x> Support Templates +//===----------------------------------------------------------------------===// + +// Define a template that can be specialized by smart pointers to reflect the +// fact that they are automatically dereferenced, and are not involved with the +// template selection process... the default implementation is a noop. +// +template<typename From> struct simplify_type { + using SimpleType = From; // The real type this represents... + + // An accessor to get the real value... + static SimpleType &getSimplifiedValue(From &Val) { return Val; } +}; + +template<typename From> struct simplify_type<const From> { + using NonConstSimpleType = typename simplify_type<From>::SimpleType; + using SimpleType = + typename add_const_past_pointer<NonConstSimpleType>::type; + using RetType = + typename add_lvalue_reference_if_not_pointer<SimpleType>::type; + + static RetType getSimplifiedValue(const From& Val) { + return simplify_type<From>::getSimplifiedValue(const_cast<From&>(Val)); + } +}; + +// The core of the implementation of isa<X> is here; To and From should be +// the names of classes. This template can be specialized to customize the +// implementation of isa<> without rewriting it from scratch. +template <typename To, typename From, typename Enabler = void> +struct isa_impl { + static inline bool doit(const From &Val) { + return To::classof(&Val); + } +}; + +/// Always allow upcasts, and perform no dynamic check for them. +template <typename To, typename From> +struct isa_impl< + To, From, typename std::enable_if<std::is_base_of<To, From>::value>::type> { + static inline bool doit(const From &) { return true; } +}; + +template <typename To, typename From> struct isa_impl_cl { + static inline bool doit(const From &Val) { + return isa_impl<To, From>::doit(Val); + } +}; + +template <typename To, typename From> struct isa_impl_cl<To, const From> { + static inline bool doit(const From &Val) { + return isa_impl<To, From>::doit(Val); + } +}; + +template <typename To, typename From> +struct isa_impl_cl<To, const std::unique_ptr<From>> { + static inline bool doit(const std::unique_ptr<From> &Val) { + assert(Val && "isa<> used on a null pointer"); + return isa_impl_cl<To, From>::doit(*Val); + } +}; + +template <typename To, typename From> struct isa_impl_cl<To, From*> { + static inline bool doit(const From *Val) { + assert(Val && "isa<> used on a null pointer"); + return isa_impl<To, From>::doit(*Val); + } +}; + +template <typename To, typename From> struct isa_impl_cl<To, From*const> { + static inline bool doit(const From *Val) { + assert(Val && "isa<> used on a null pointer"); + return isa_impl<To, From>::doit(*Val); + } +}; + +template <typename To, typename From> struct isa_impl_cl<To, const From*> { + static inline bool doit(const From *Val) { + assert(Val && "isa<> used on a null pointer"); + return isa_impl<To, From>::doit(*Val); + } +}; + +template <typename To, typename From> struct isa_impl_cl<To, const From*const> { + static inline bool doit(const From *Val) { + assert(Val && "isa<> used on a null pointer"); + return isa_impl<To, From>::doit(*Val); + } +}; + +template<typename To, typename From, typename SimpleFrom> +struct isa_impl_wrap { + // When From != SimplifiedType, we can simplify the type some more by using + // the simplify_type template. + static bool doit(const From &Val) { + return isa_impl_wrap<To, SimpleFrom, + typename simplify_type<SimpleFrom>::SimpleType>::doit( + simplify_type<const From>::getSimplifiedValue(Val)); + } +}; + +template<typename To, typename FromTy> +struct isa_impl_wrap<To, FromTy, FromTy> { + // When From == SimpleType, we are as simple as we are going to get. + static bool doit(const FromTy &Val) { + return isa_impl_cl<To,FromTy>::doit(Val); + } +}; + +// isa<X> - Return true if the parameter to the template is an instance of the +// template type argument. Used like this: +// +// if (isa<Type>(myVal)) { ... } +// +template <class X, class Y> LLVM_NODISCARD inline bool isa(const Y &Val) { + return isa_impl_wrap<X, const Y, + typename simplify_type<const Y>::SimpleType>::doit(Val); +} + +// isa_and_nonnull<X> - Functionally identical to isa, except that a null value +// is accepted. +// +template <class X, class Y> +LLVM_NODISCARD inline bool isa_and_nonnull(const Y &Val) { + if (!Val) + return false; + return isa<X>(Val); +} + +//===----------------------------------------------------------------------===// +// cast<x> Support Templates +//===----------------------------------------------------------------------===// + +template<class To, class From> struct cast_retty; + +// Calculate what type the 'cast' function should return, based on a requested +// type of To and a source type of From. +template<class To, class From> struct cast_retty_impl { + using ret_type = To &; // Normal case, return Ty& +}; +template<class To, class From> struct cast_retty_impl<To, const From> { + using ret_type = const To &; // Normal case, return Ty& +}; + +template<class To, class From> struct cast_retty_impl<To, From*> { + using ret_type = To *; // Pointer arg case, return Ty* +}; + +template<class To, class From> struct cast_retty_impl<To, const From*> { + using ret_type = const To *; // Constant pointer arg case, return const Ty* +}; + +template<class To, class From> struct cast_retty_impl<To, const From*const> { + using ret_type = const To *; // Constant pointer arg case, return const Ty* +}; + +template <class To, class From> +struct cast_retty_impl<To, std::unique_ptr<From>> { +private: + using PointerType = typename cast_retty_impl<To, From *>::ret_type; + using ResultType = typename std::remove_pointer<PointerType>::type; + +public: + using ret_type = std::unique_ptr<ResultType>; +}; + +template<class To, class From, class SimpleFrom> +struct cast_retty_wrap { + // When the simplified type and the from type are not the same, use the type + // simplifier to reduce the type, then reuse cast_retty_impl to get the + // resultant type. + using ret_type = typename cast_retty<To, SimpleFrom>::ret_type; +}; + +template<class To, class FromTy> +struct cast_retty_wrap<To, FromTy, FromTy> { + // When the simplified type is equal to the from type, use it directly. + using ret_type = typename cast_retty_impl<To,FromTy>::ret_type; +}; + +template<class To, class From> +struct cast_retty { + using ret_type = typename cast_retty_wrap< + To, From, typename simplify_type<From>::SimpleType>::ret_type; +}; + +// Ensure the non-simple values are converted using the simplify_type template +// that may be specialized by smart pointers... +// +template<class To, class From, class SimpleFrom> struct cast_convert_val { + // This is not a simple type, use the template to simplify it... + static typename cast_retty<To, From>::ret_type doit(From &Val) { + return cast_convert_val<To, SimpleFrom, + typename simplify_type<SimpleFrom>::SimpleType>::doit( + simplify_type<From>::getSimplifiedValue(Val)); + } +}; + +template<class To, class FromTy> struct cast_convert_val<To,FromTy,FromTy> { + // This _is_ a simple type, just cast it. + static typename cast_retty<To, FromTy>::ret_type doit(const FromTy &Val) { + typename cast_retty<To, FromTy>::ret_type Res2 + = (typename cast_retty<To, FromTy>::ret_type)const_cast<FromTy&>(Val); + return Res2; + } +}; + +template <class X> struct is_simple_type { + static const bool value = + std::is_same<X, typename simplify_type<X>::SimpleType>::value; +}; + +// cast<X> - Return the argument parameter cast to the specified type. This +// casting operator asserts that the type is correct, so it does not return null +// on failure. It does not allow a null argument (use cast_or_null for that). +// It is typically used like this: +// +// cast<Instruction>(myVal)->getParent() +// +template <class X, class Y> +inline typename std::enable_if<!is_simple_type<Y>::value, + typename cast_retty<X, const Y>::ret_type>::type +cast(const Y &Val) { + assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!"); + return cast_convert_val< + X, const Y, typename simplify_type<const Y>::SimpleType>::doit(Val); +} + +template <class X, class Y> +inline typename cast_retty<X, Y>::ret_type cast(Y &Val) { + assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!"); + return cast_convert_val<X, Y, + typename simplify_type<Y>::SimpleType>::doit(Val); +} + +template <class X, class Y> +inline typename cast_retty<X, Y *>::ret_type cast(Y *Val) { + assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!"); + return cast_convert_val<X, Y*, + typename simplify_type<Y*>::SimpleType>::doit(Val); +} + +template <class X, class Y> +inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type +cast(std::unique_ptr<Y> &&Val) { + assert(isa<X>(Val.get()) && "cast<Ty>() argument of incompatible type!"); + using ret_type = typename cast_retty<X, std::unique_ptr<Y>>::ret_type; + return ret_type( + cast_convert_val<X, Y *, typename simplify_type<Y *>::SimpleType>::doit( + Val.release())); +} + +// cast_or_null<X> - Functionally identical to cast, except that a null value is +// accepted. +// +template <class X, class Y> +LLVM_NODISCARD inline + typename std::enable_if<!is_simple_type<Y>::value, + typename cast_retty<X, const Y>::ret_type>::type + cast_or_null(const Y &Val) { + if (!Val) + return nullptr; + assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!"); + return cast<X>(Val); +} + +template <class X, class Y> +LLVM_NODISCARD inline + typename std::enable_if<!is_simple_type<Y>::value, + typename cast_retty<X, Y>::ret_type>::type + cast_or_null(Y &Val) { + if (!Val) + return nullptr; + assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!"); + return cast<X>(Val); +} + +template <class X, class Y> +LLVM_NODISCARD inline typename cast_retty<X, Y *>::ret_type +cast_or_null(Y *Val) { + if (!Val) return nullptr; + assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!"); + return cast<X>(Val); +} + +template <class X, class Y> +inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type +cast_or_null(std::unique_ptr<Y> &&Val) { + if (!Val) + return nullptr; + return cast<X>(std::move(Val)); +} + +// dyn_cast<X> - Return the argument parameter cast to the specified type. This +// casting operator returns null if the argument is of the wrong type, so it can +// be used to test for a type as well as cast if successful. This should be +// used in the context of an if statement like this: +// +// if (const Instruction *I = dyn_cast<Instruction>(myVal)) { ... } +// + +template <class X, class Y> +LLVM_NODISCARD inline + typename std::enable_if<!is_simple_type<Y>::value, + typename cast_retty<X, const Y>::ret_type>::type + dyn_cast(const Y &Val) { + return isa<X>(Val) ? cast<X>(Val) : nullptr; +} + +template <class X, class Y> +LLVM_NODISCARD inline typename cast_retty<X, Y>::ret_type dyn_cast(Y &Val) { + return isa<X>(Val) ? cast<X>(Val) : nullptr; +} + +template <class X, class Y> +LLVM_NODISCARD inline typename cast_retty<X, Y *>::ret_type dyn_cast(Y *Val) { + return isa<X>(Val) ? cast<X>(Val) : nullptr; +} + +// dyn_cast_or_null<X> - Functionally identical to dyn_cast, except that a null +// value is accepted. +// +template <class X, class Y> +LLVM_NODISCARD inline + typename std::enable_if<!is_simple_type<Y>::value, + typename cast_retty<X, const Y>::ret_type>::type + dyn_cast_or_null(const Y &Val) { + return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr; +} + +template <class X, class Y> +LLVM_NODISCARD inline + typename std::enable_if<!is_simple_type<Y>::value, + typename cast_retty<X, Y>::ret_type>::type + dyn_cast_or_null(Y &Val) { + return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr; +} + +template <class X, class Y> +LLVM_NODISCARD inline typename cast_retty<X, Y *>::ret_type +dyn_cast_or_null(Y *Val) { + return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr; +} + +// unique_dyn_cast<X> - Given a unique_ptr<Y>, try to return a unique_ptr<X>, +// taking ownership of the input pointer iff isa<X>(Val) is true. If the +// cast is successful, From refers to nullptr on exit and the casted value +// is returned. If the cast is unsuccessful, the function returns nullptr +// and From is unchanged. +template <class X, class Y> +LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &Val) + -> decltype(cast<X>(Val)) { + if (!isa<X>(Val)) + return nullptr; + return cast<X>(std::move(Val)); +} + +template <class X, class Y> +LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &&Val) + -> decltype(cast<X>(Val)) { + return unique_dyn_cast<X, Y>(Val); +} + +// dyn_cast_or_null<X> - Functionally identical to unique_dyn_cast, except that +// a null value is accepted. +template <class X, class Y> +LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &Val) + -> decltype(cast<X>(Val)) { + if (!Val) + return nullptr; + return unique_dyn_cast<X, Y>(Val); +} + +template <class X, class Y> +LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &&Val) + -> decltype(cast<X>(Val)) { + return unique_dyn_cast_or_null<X, Y>(Val); +} + +} // end namespace llvm + +#endif // LLVM_SUPPORT_CASTING_H diff --git a/third_party/llvm-project/include/llvm/Support/Chrono.h b/third_party/llvm-project/include/llvm/Support/Chrono.h new file mode 100644 index 000000000..334ab6083 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Chrono.h @@ -0,0 +1,171 @@ +//===- llvm/Support/Chrono.h - Utilities for Timing Manipulation-*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CHRONO_H +#define LLVM_SUPPORT_CHRONO_H + +#include "llvm/Support/Compiler.h" +#include "llvm/Support/FormatProviders.h" + +#include <chrono> +#include <ctime> + +namespace llvm { + +class raw_ostream; + +namespace sys { + +/// A time point on the system clock. This is provided for two reasons: +/// - to insulate us agains subtle differences in behavoir to differences in +/// system clock precision (which is implementation-defined and differs between +/// platforms). +/// - to shorten the type name +/// The default precision is nanoseconds. If need a specific precision specify +/// it explicitly. If unsure, use the default. If you need a time point on a +/// clock other than the system_clock, use std::chrono directly. +template <typename D = std::chrono::nanoseconds> +using TimePoint = std::chrono::time_point<std::chrono::system_clock, D>; + +/// Convert a TimePoint to std::time_t +inline std::time_t toTimeT(TimePoint<> TP) { + using namespace std::chrono; + return system_clock::to_time_t( + time_point_cast<system_clock::time_point::duration>(TP)); +} + +/// Convert a std::time_t to a TimePoint +inline TimePoint<std::chrono::seconds> +toTimePoint(std::time_t T) { + using namespace std::chrono; + return time_point_cast<seconds>(system_clock::from_time_t(T)); +} + +/// Convert a std::time_t + nanoseconds to a TimePoint +inline TimePoint<> +toTimePoint(std::time_t T, uint32_t nsec) { + using namespace std::chrono; + return time_point_cast<nanoseconds>(system_clock::from_time_t(T)) + + nanoseconds(nsec); +} + +} // namespace sys + +raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP); + +/// Format provider for TimePoint<> +/// +/// The options string is a strftime format string, with extensions: +/// - %L is millis: 000-999 +/// - %f is micros: 000000-999999 +/// - %N is nanos: 000000000 - 999999999 +/// +/// If no options are given, the default format is "%Y-%m-%d %H:%M:%S.%N". +template <> +struct format_provider<sys::TimePoint<>> { + static void format(const sys::TimePoint<> &TP, llvm::raw_ostream &OS, + StringRef Style); +}; + +/// Implementation of format_provider<T> for duration types. +/// +/// The options string of a duration type has the grammar: +/// +/// duration_options ::= [unit][show_unit [number_options]] +/// unit ::= `h`|`m`|`s`|`ms|`us`|`ns` +/// show_unit ::= `+` | `-` +/// number_options ::= options string for a integral or floating point type +/// +/// Examples +/// ================================= +/// | options | Input | Output | +/// ================================= +/// | "" | 1s | 1 s | +/// | "ms" | 1s | 1000 ms | +/// | "ms-" | 1s | 1000 | +/// | "ms-n" | 1s | 1,000 | +/// | "" | 1.0s | 1.00 s | +/// ================================= +/// +/// If the unit of the duration type is not one of the units specified above, +/// it is still possible to format it, provided you explicitly request a +/// display unit or you request that the unit is not displayed. + +namespace detail { +template <typename Period> struct unit { static const char value[]; }; +template <typename Period> const char unit<Period>::value[] = ""; + +template <> struct unit<std::ratio<3600>> { static const char value[]; }; +template <> struct unit<std::ratio<60>> { static const char value[]; }; +template <> struct unit<std::ratio<1>> { static const char value[]; }; +template <> struct unit<std::milli> { static const char value[]; }; +template <> struct unit<std::micro> { static const char value[]; }; +template <> struct unit<std::nano> { static const char value[]; }; +} // namespace detail + +template <typename Rep, typename Period> +struct format_provider<std::chrono::duration<Rep, Period>> { +private: + typedef std::chrono::duration<Rep, Period> Dur; + typedef typename std::conditional< + std::chrono::treat_as_floating_point<Rep>::value, double, intmax_t>::type + InternalRep; + + template <typename AsPeriod> static InternalRep getAs(const Dur &D) { + using namespace std::chrono; + return duration_cast<duration<InternalRep, AsPeriod>>(D).count(); + } + + static std::pair<InternalRep, StringRef> consumeUnit(StringRef &Style, + const Dur &D) { + using namespace std::chrono; + if (Style.consume_front("ns")) + return {getAs<std::nano>(D), "ns"}; + if (Style.consume_front("us")) + return {getAs<std::micro>(D), "us"}; + if (Style.consume_front("ms")) + return {getAs<std::milli>(D), "ms"}; + if (Style.consume_front("s")) + return {getAs<std::ratio<1>>(D), "s"}; + if (Style.consume_front("m")) + return {getAs<std::ratio<60>>(D), "m"}; + if (Style.consume_front("h")) + return {getAs<std::ratio<3600>>(D), "h"}; + return {D.count(), detail::unit<Period>::value}; + } + + static bool consumeShowUnit(StringRef &Style) { + if (Style.empty()) + return true; + if (Style.consume_front("-")) + return false; + if (Style.consume_front("+")) + return true; + assert(0 && "Unrecognised duration format"); + return true; + } + +public: + static void format(const Dur &D, llvm::raw_ostream &Stream, StringRef Style) { + InternalRep count; + StringRef unit; + std::tie(count, unit) = consumeUnit(Style, D); + bool show_unit = consumeShowUnit(Style); + + format_provider<InternalRep>::format(count, Stream, Style); + + if (show_unit) { + assert(!unit.empty()); + Stream << " " << unit; + } + } +}; + +} // namespace llvm + +#endif // LLVM_SUPPORT_CHRONO_H diff --git a/third_party/llvm-project/include/llvm/Support/CodeGen.h b/third_party/llvm-project/include/llvm/Support/CodeGen.h new file mode 100644 index 000000000..a3f423e55 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/CodeGen.h @@ -0,0 +1,67 @@ +//===-- llvm/Support/CodeGen.h - CodeGen Concepts ---------------*- 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 define some types which define code generation concepts. For +// example, relocation model. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CODEGEN_H +#define LLVM_SUPPORT_CODEGEN_H + +namespace llvm { + + // Relocation model types. + namespace Reloc { + // Cannot be named PIC due to collision with -DPIC + enum Model { Static, PIC_, DynamicNoPIC, ROPI, RWPI, ROPI_RWPI }; + } + + // Code model types. + namespace CodeModel { + // Sync changes with CodeGenCWrappers.h. + enum Model { Tiny, Small, Kernel, Medium, Large }; + } + + namespace PICLevel { + // This is used to map -fpic/-fPIC. + enum Level { NotPIC=0, SmallPIC=1, BigPIC=2 }; + } + + namespace PIELevel { + enum Level { Default=0, Small=1, Large=2 }; + } + + // TLS models. + namespace TLSModel { + enum Model { + GeneralDynamic, + LocalDynamic, + InitialExec, + LocalExec + }; + } + + // Code generation optimization level. + namespace CodeGenOpt { + enum Level { + None = 0, // -O0 + Less = 1, // -O1 + Default = 2, // -O2, -Os + Aggressive = 3 // -O3 + }; + } + + // Specify effect of frame pointer elimination optimization. + namespace FramePointer { + enum FP {All, NonLeaf, None}; + } + +} // end llvm namespace + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/CommandLine.h b/third_party/llvm-project/include/llvm/Support/CommandLine.h new file mode 100644 index 000000000..4eb30f548 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/CommandLine.h @@ -0,0 +1 @@ +// XXX BINARYEN - we don't need this, but stuff imports it diff --git a/third_party/llvm-project/include/llvm/Support/Compiler.h b/third_party/llvm-project/include/llvm/Support/Compiler.h new file mode 100644 index 000000000..cb7e57d4c --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Compiler.h @@ -0,0 +1,585 @@ +//===-- llvm/Support/Compiler.h - Compiler abstraction support --*- 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 defines several macros, based on the current compiler. This allows +// use of compiler-specific features in a way that remains portable. This header +// can be included from either C or C++. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_COMPILER_H +#define LLVM_SUPPORT_COMPILER_H + +#include "llvm/Config/llvm-config.h" + +#ifdef __cplusplus +#include <new> +#endif +#include <stddef.h> + +#if defined(_MSC_VER) +#include <sal.h> +#endif + +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +#ifndef __has_extension +# define __has_extension(x) 0 +#endif + +#ifndef __has_attribute +# define __has_attribute(x) 0 +#endif + +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +// Only use __has_cpp_attribute in C++ mode. GCC defines __has_cpp_attribute in +// C mode, but the :: in __has_cpp_attribute(scoped::attribute) is invalid. +#ifndef LLVM_HAS_CPP_ATTRIBUTE +#if defined(__cplusplus) && defined(__has_cpp_attribute) +# define LLVM_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define LLVM_HAS_CPP_ATTRIBUTE(x) 0 +#endif +#endif + +/// \macro LLVM_GNUC_PREREQ +/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't +/// available. +#ifndef LLVM_GNUC_PREREQ +# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +# define LLVM_GNUC_PREREQ(maj, min, patch) \ + ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \ + ((maj) << 20) + ((min) << 10) + (patch)) +# elif defined(__GNUC__) && defined(__GNUC_MINOR__) +# define LLVM_GNUC_PREREQ(maj, min, patch) \ + ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10)) +# else +# define LLVM_GNUC_PREREQ(maj, min, patch) 0 +# endif +#endif + +/// \macro LLVM_MSC_PREREQ +/// Is the compiler MSVC of at least the specified version? +/// The common \param version values to check for are: +/// * 1910: VS2017, version 15.1 & 15.2 +/// * 1911: VS2017, version 15.3 & 15.4 +/// * 1912: VS2017, version 15.5 +/// * 1913: VS2017, version 15.6 +/// * 1914: VS2017, version 15.7 +/// * 1915: VS2017, version 15.8 +/// * 1916: VS2017, version 15.9 +/// * 1920: VS2019, version 16.0 +/// * 1921: VS2019, version 16.1 +#ifdef _MSC_VER +#define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version)) + +// We require at least MSVC 2017. +#if !LLVM_MSC_PREREQ(1910) +#error LLVM requires at least MSVC 2017. +#endif + +#else +#define LLVM_MSC_PREREQ(version) 0 +#endif + +/// Does the compiler support ref-qualifiers for *this? +/// +/// Sadly, this is separate from just rvalue reference support because GCC +/// and MSVC implemented this later than everything else. +#if __has_feature(cxx_rvalue_references) || LLVM_GNUC_PREREQ(4, 8, 1) +#define LLVM_HAS_RVALUE_REFERENCE_THIS 1 +#else +#define LLVM_HAS_RVALUE_REFERENCE_THIS 0 +#endif + +/// Expands to '&' if ref-qualifiers for *this are supported. +/// +/// This can be used to provide lvalue/rvalue overrides of member functions. +/// The rvalue override should be guarded by LLVM_HAS_RVALUE_REFERENCE_THIS +#if LLVM_HAS_RVALUE_REFERENCE_THIS +#define LLVM_LVALUE_FUNCTION & +#else +#define LLVM_LVALUE_FUNCTION +#endif + +/// LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked +/// into a shared library, then the class should be private to the library and +/// not accessible from outside it. Can also be used to mark variables and +/// functions, making them private to any shared library they are linked into. +/// On PE/COFF targets, library visibility is the default, so this isn't needed. +#if (__has_attribute(visibility) || LLVM_GNUC_PREREQ(4, 0, 0)) && \ + !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32) +#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden"))) +#else +#define LLVM_LIBRARY_VISIBILITY +#endif + +#if defined(__GNUC__) +#define LLVM_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality) +#else +#define LLVM_PREFETCH(addr, rw, locality) +#endif + +#if __has_attribute(used) || LLVM_GNUC_PREREQ(3, 1, 0) +#define LLVM_ATTRIBUTE_USED __attribute__((__used__)) +#else +#define LLVM_ATTRIBUTE_USED +#endif + +/// LLVM_NODISCARD - Warn if a type or return value is discarded. + +// Use the 'nodiscard' attribute in C++17 or newer mode. +#if __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(nodiscard) +#define LLVM_NODISCARD [[nodiscard]] +#elif LLVM_HAS_CPP_ATTRIBUTE(clang::warn_unused_result) +#define LLVM_NODISCARD [[clang::warn_unused_result]] +// Clang in C++14 mode claims that it has the 'nodiscard' attribute, but also +// warns in the pedantic mode that 'nodiscard' is a C++17 extension (PR33518). +// Use the 'nodiscard' attribute in C++14 mode only with GCC. +// TODO: remove this workaround when PR33518 is resolved. +#elif defined(__GNUC__) && LLVM_HAS_CPP_ATTRIBUTE(nodiscard) +#define LLVM_NODISCARD [[nodiscard]] +#else +#define LLVM_NODISCARD +#endif + +// Indicate that a non-static, non-const C++ member function reinitializes +// the entire object to a known state, independent of the previous state of +// the object. +// +// The clang-tidy check bugprone-use-after-move recognizes this attribute as a +// marker that a moved-from object has left the indeterminate state and can be +// reused. +#if LLVM_HAS_CPP_ATTRIBUTE(clang::reinitializes) +#define LLVM_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]] +#else +#define LLVM_ATTRIBUTE_REINITIALIZES +#endif + +// Some compilers warn about unused functions. When a function is sometimes +// used or not depending on build settings (e.g. a function only called from +// within "assert"), this attribute can be used to suppress such warnings. +// +// However, it shouldn't be used for unused *variables*, as those have a much +// more portable solution: +// (void)unused_var_name; +// Prefer cast-to-void wherever it is sufficient. +#if __has_attribute(unused) || LLVM_GNUC_PREREQ(3, 1, 0) +#define LLVM_ATTRIBUTE_UNUSED __attribute__((__unused__)) +#else +#define LLVM_ATTRIBUTE_UNUSED +#endif + +// FIXME: Provide this for PE/COFF targets. +#if (__has_attribute(weak) || LLVM_GNUC_PREREQ(4, 0, 0)) && \ + (!defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32)) +#define LLVM_ATTRIBUTE_WEAK __attribute__((__weak__)) +#else +#define LLVM_ATTRIBUTE_WEAK +#endif + +// Prior to clang 3.2, clang did not accept any spelling of +// __has_attribute(const), so assume it is supported. +#if defined(__clang__) || defined(__GNUC__) +// aka 'CONST' but following LLVM Conventions. +#define LLVM_READNONE __attribute__((__const__)) +#else +#define LLVM_READNONE +#endif + +#if __has_attribute(pure) || defined(__GNUC__) +// aka 'PURE' but following LLVM Conventions. +#define LLVM_READONLY __attribute__((__pure__)) +#else +#define LLVM_READONLY +#endif + +#if __has_builtin(__builtin_expect) || LLVM_GNUC_PREREQ(4, 0, 0) +#define LLVM_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true) +#define LLVM_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false) +#else +#define LLVM_LIKELY(EXPR) (EXPR) +#define LLVM_UNLIKELY(EXPR) (EXPR) +#endif + +/// LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so, +/// mark a method "not for inlining". +#if __has_attribute(noinline) || LLVM_GNUC_PREREQ(3, 4, 0) +#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline) +#else +#define LLVM_ATTRIBUTE_NOINLINE +#endif + +/// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do +/// so, mark a method "always inline" because it is performance sensitive. GCC +/// 3.4 supported this but is buggy in various cases and produces unimplemented +/// errors, just use it in GCC 4.0 and later. +#if __has_attribute(always_inline) || LLVM_GNUC_PREREQ(4, 0, 0) +#define LLVM_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline +#else +#define LLVM_ATTRIBUTE_ALWAYS_INLINE +#endif + +#ifdef __GNUC__ +#define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn) +#else +#define LLVM_ATTRIBUTE_NORETURN +#endif + +#if __has_attribute(returns_nonnull) || LLVM_GNUC_PREREQ(4, 9, 0) +#define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_ +#else +#define LLVM_ATTRIBUTE_RETURNS_NONNULL +#endif + +/// \macro LLVM_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a +/// pointer that does not alias any other valid pointer. +#ifdef __GNUC__ +#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict) +#else +#define LLVM_ATTRIBUTE_RETURNS_NOALIAS +#endif + +/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements. +#if __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(fallthrough) +#define LLVM_FALLTHROUGH [[fallthrough]] +#elif LLVM_HAS_CPP_ATTRIBUTE(gnu::fallthrough) +#define LLVM_FALLTHROUGH [[gnu::fallthrough]] +#elif __has_attribute(fallthrough) +#define LLVM_FALLTHROUGH __attribute__((fallthrough)) +#elif LLVM_HAS_CPP_ATTRIBUTE(clang::fallthrough) +#define LLVM_FALLTHROUGH [[clang::fallthrough]] +#else +#define LLVM_FALLTHROUGH +#endif + +/// LLVM_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that +/// they are constant initialized. +#if LLVM_HAS_CPP_ATTRIBUTE(clang::require_constant_initialization) +#define LLVM_REQUIRE_CONSTANT_INITIALIZATION \ + [[clang::require_constant_initialization]] +#else +#define LLVM_REQUIRE_CONSTANT_INITIALIZATION +#endif + +/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress +/// pedantic diagnostics. +#ifdef __GNUC__ +#define LLVM_EXTENSION __extension__ +#else +#define LLVM_EXTENSION +#endif + +// LLVM_ATTRIBUTE_DEPRECATED(decl, "message") +#if __has_feature(attribute_deprecated_with_message) +# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \ + decl __attribute__((deprecated(message))) +#elif defined(__GNUC__) +# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \ + decl __attribute__((deprecated)) +#elif defined(_MSC_VER) +# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \ + __declspec(deprecated(message)) decl +#else +# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \ + decl +#endif + +/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands +/// to an expression which states that it is undefined behavior for the +/// compiler to reach this point. Otherwise is not defined. +#if __has_builtin(__builtin_unreachable) || LLVM_GNUC_PREREQ(4, 5, 0) +# define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable() +#elif defined(_MSC_VER) +# define LLVM_BUILTIN_UNREACHABLE __assume(false) +#endif + +/// LLVM_BUILTIN_TRAP - On compilers which support it, expands to an expression +/// which causes the program to exit abnormally. +#if __has_builtin(__builtin_trap) || LLVM_GNUC_PREREQ(4, 3, 0) +# define LLVM_BUILTIN_TRAP __builtin_trap() +#elif defined(_MSC_VER) +// The __debugbreak intrinsic is supported by MSVC, does not require forward +// declarations involving platform-specific typedefs (unlike RaiseException), +// results in a call to vectored exception handlers, and encodes to a short +// instruction that still causes the trapping behavior we want. +# define LLVM_BUILTIN_TRAP __debugbreak() +#else +# define LLVM_BUILTIN_TRAP *(volatile int*)0x11 = 0 +#endif + +/// LLVM_BUILTIN_DEBUGTRAP - On compilers which support it, expands to +/// an expression which causes the program to break while running +/// under a debugger. +#if __has_builtin(__builtin_debugtrap) +# define LLVM_BUILTIN_DEBUGTRAP __builtin_debugtrap() +#elif defined(_MSC_VER) +// The __debugbreak intrinsic is supported by MSVC and breaks while +// running under the debugger, and also supports invoking a debugger +// when the OS is configured appropriately. +# define LLVM_BUILTIN_DEBUGTRAP __debugbreak() +#else +// Just continue execution when built with compilers that have no +// support. This is a debugging aid and not intended to force the +// program to abort if encountered. +# define LLVM_BUILTIN_DEBUGTRAP +#endif + +/// \macro LLVM_ASSUME_ALIGNED +/// Returns a pointer with an assumed alignment. +#if __has_builtin(__builtin_assume_aligned) || LLVM_GNUC_PREREQ(4, 7, 0) +# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a) +#elif defined(LLVM_BUILTIN_UNREACHABLE) +// As of today, clang does not support __builtin_assume_aligned. +# define LLVM_ASSUME_ALIGNED(p, a) \ + (((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p))) +#else +# define LLVM_ASSUME_ALIGNED(p, a) (p) +#endif + +/// \macro LLVM_PACKED +/// Used to specify a packed structure. +/// LLVM_PACKED( +/// struct A { +/// int i; +/// int j; +/// int k; +/// long long l; +/// }); +/// +/// LLVM_PACKED_START +/// struct B { +/// int i; +/// int j; +/// int k; +/// long long l; +/// }; +/// LLVM_PACKED_END +#ifdef _MSC_VER +# define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop)) +# define LLVM_PACKED_START __pragma(pack(push, 1)) +# define LLVM_PACKED_END __pragma(pack(pop)) +#else +# define LLVM_PACKED(d) d __attribute__((packed)) +# define LLVM_PACKED_START _Pragma("pack(push, 1)") +# define LLVM_PACKED_END _Pragma("pack(pop)") +#endif + +/// \macro LLVM_PTR_SIZE +/// A constant integer equivalent to the value of sizeof(void*). +/// Generally used in combination with alignas or when doing computation in the +/// preprocessor. +#ifdef __SIZEOF_POINTER__ +# define LLVM_PTR_SIZE __SIZEOF_POINTER__ +#elif defined(_WIN64) +# define LLVM_PTR_SIZE 8 +#elif defined(_WIN32) +# define LLVM_PTR_SIZE 4 +#elif defined(_MSC_VER) +# error "could not determine LLVM_PTR_SIZE as a constant int for MSVC" +#else +# define LLVM_PTR_SIZE sizeof(void *) +#endif + +/// \macro LLVM_MEMORY_SANITIZER_BUILD +/// Whether LLVM itself is built with MemorySanitizer instrumentation. +#if __has_feature(memory_sanitizer) +# define LLVM_MEMORY_SANITIZER_BUILD 1 +# include <sanitizer/msan_interface.h> +#else +# define LLVM_MEMORY_SANITIZER_BUILD 0 +# define __msan_allocated_memory(p, size) +# define __msan_unpoison(p, size) +#endif + +/// \macro LLVM_ADDRESS_SANITIZER_BUILD +/// Whether LLVM itself is built with AddressSanitizer instrumentation. +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +# define LLVM_ADDRESS_SANITIZER_BUILD 1 +# include <sanitizer/asan_interface.h> +#else +# define LLVM_ADDRESS_SANITIZER_BUILD 0 +# define __asan_poison_memory_region(p, size) +# define __asan_unpoison_memory_region(p, size) +#endif + +/// \macro LLVM_THREAD_SANITIZER_BUILD +/// Whether LLVM itself is built with ThreadSanitizer instrumentation. +#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__) +# define LLVM_THREAD_SANITIZER_BUILD 1 +#else +# define LLVM_THREAD_SANITIZER_BUILD 0 +#endif + +#if LLVM_THREAD_SANITIZER_BUILD +// Thread Sanitizer is a tool that finds races in code. +// See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations . +// tsan detects these exact functions by name. +#ifdef __cplusplus +extern "C" { +#endif +void AnnotateHappensAfter(const char *file, int line, const volatile void *cv); +void AnnotateHappensBefore(const char *file, int line, const volatile void *cv); +void AnnotateIgnoreWritesBegin(const char *file, int line); +void AnnotateIgnoreWritesEnd(const char *file, int line); +#ifdef __cplusplus +} +#endif + +// This marker is used to define a happens-before arc. The race detector will +// infer an arc from the begin to the end when they share the same pointer +// argument. +# define TsanHappensBefore(cv) AnnotateHappensBefore(__FILE__, __LINE__, cv) + +// This marker defines the destination of a happens-before arc. +# define TsanHappensAfter(cv) AnnotateHappensAfter(__FILE__, __LINE__, cv) + +// Ignore any races on writes between here and the next TsanIgnoreWritesEnd. +# define TsanIgnoreWritesBegin() AnnotateIgnoreWritesBegin(__FILE__, __LINE__) + +// Resume checking for racy writes. +# define TsanIgnoreWritesEnd() AnnotateIgnoreWritesEnd(__FILE__, __LINE__) +#else +# define TsanHappensBefore(cv) +# define TsanHappensAfter(cv) +# define TsanIgnoreWritesBegin() +# define TsanIgnoreWritesEnd() +#endif + +/// \macro LLVM_NO_SANITIZE +/// Disable a particular sanitizer for a function. +#if __has_attribute(no_sanitize) +#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND))) +#else +#define LLVM_NO_SANITIZE(KIND) +#endif + +/// Mark debug helper function definitions like dump() that should not be +/// stripped from debug builds. +/// Note that you should also surround dump() functions with +/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always +/// get stripped in release builds. +// FIXME: Move this to a private config.h as it's not usable in public headers. +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED +#else +#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE +#endif + +/// \macro LLVM_PRETTY_FUNCTION +/// Gets a user-friendly looking function signature for the current scope +/// using the best available method on each platform. The exact format of the +/// resulting string is implementation specific and non-portable, so this should +/// only be used, for example, for logging or diagnostics. +#if defined(_MSC_VER) +#define LLVM_PRETTY_FUNCTION __FUNCSIG__ +#elif defined(__GNUC__) || defined(__clang__) +#define LLVM_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#else +#define LLVM_PRETTY_FUNCTION __func__ +#endif + +/// \macro LLVM_THREAD_LOCAL +/// A thread-local storage specifier which can be used with globals, +/// extern globals, and static globals. +/// +/// This is essentially an extremely restricted analog to C++11's thread_local +/// support, and uses that when available. However, it falls back on +/// platform-specific or vendor-provided extensions when necessary. These +/// extensions don't support many of the C++11 thread_local's features. You +/// should only use this for PODs that you can statically initialize to +/// some constant value. In almost all circumstances this is most appropriate +/// for use with a pointer, integer, or small aggregation of pointers and +/// integers. +#if LLVM_ENABLE_THREADS +#if __has_feature(cxx_thread_local) +#define LLVM_THREAD_LOCAL thread_local +#elif defined(_MSC_VER) +// MSVC supports this with a __declspec. +#define LLVM_THREAD_LOCAL __declspec(thread) +#else +// Clang, GCC, and other compatible compilers used __thread prior to C++11 and +// we only need the restricted functionality that provides. +#define LLVM_THREAD_LOCAL __thread +#endif +#else // !LLVM_ENABLE_THREADS +// If threading is disabled entirely, this compiles to nothing and you get +// a normal global variable. +#define LLVM_THREAD_LOCAL +#endif + +/// \macro LLVM_ENABLE_EXCEPTIONS +/// Whether LLVM is built with exception support. +#if __has_feature(cxx_exceptions) +#define LLVM_ENABLE_EXCEPTIONS 1 +#elif defined(__GNUC__) && defined(__EXCEPTIONS) +#define LLVM_ENABLE_EXCEPTIONS 1 +#elif defined(_MSC_VER) && defined(_CPPUNWIND) +#define LLVM_ENABLE_EXCEPTIONS 1 +#endif + +#ifdef __cplusplus +namespace llvm { + +/// Allocate a buffer of memory with the given size and alignment. +/// +/// When the compiler supports aligned operator new, this will use it to to +/// handle even over-aligned allocations. +/// +/// However, this doesn't make any attempt to leverage the fancier techniques +/// like posix_memalign due to portability. It is mostly intended to allow +/// compatibility with platforms that, after aligned allocation was added, use +/// reduced default alignment. +inline void *allocate_buffer(size_t Size, size_t Alignment) { + return ::operator new(Size +#ifdef __cpp_aligned_new + , + std::align_val_t(Alignment) +#endif + ); +} + +/// Deallocate a buffer of memory with the given size and alignment. +/// +/// If supported, this will used the sized delete operator. Also if supported, +/// this will pass the alignment to the delete operator. +/// +/// The pointer must have been allocated with the corresponding new operator, +/// most likely using the above helper. +inline void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment) { + ::operator delete(Ptr +#ifdef __cpp_sized_deallocation + , + Size +#endif +#ifdef __cpp_aligned_new + , + std::align_val_t(Alignment) +#endif + ); +} + +} // End namespace llvm + +#endif // __cplusplus +#endif diff --git a/third_party/llvm-project/include/llvm/Support/ConvertUTF.h b/third_party/llvm-project/include/llvm/Support/ConvertUTF.h new file mode 100644 index 000000000..1add18533 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/ConvertUTF.h @@ -0,0 +1,306 @@ +/*===--- ConvertUTF.h - Universal Character Names conversions ---------------=== + * + * 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 + * + *==------------------------------------------------------------------------==*/ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Header file. + + Several funtions are included here, forming a complete set of + conversions between the three formats. UTF-7 is not included + here, but is handled in a separate source file. + + Each of these routines takes pointers to input buffers and output + buffers. The input buffers are const. + + Each routine converts the text between *sourceStart and sourceEnd, + putting the result into the buffer between *targetStart and + targetEnd. Note: the end pointers are *after* the last item: e.g. + *(sourceEnd - 1) is the last item. + + The return result indicates whether the conversion was successful, + and if not, whether the problem was in the source or target buffers. + (Only the first encountered problem is indicated.) + + After the conversion, *sourceStart and *targetStart are both + updated to point to the end of last text successfully converted in + the respective buffers. + + Input parameters: + sourceStart - pointer to a pointer to the source buffer. + The contents of this are modified on return so that + it points at the next thing to be converted. + targetStart - similarly, pointer to pointer to the target buffer. + sourceEnd, targetEnd - respectively pointers to the ends of the + two buffers, for overflow checking only. + + These conversion functions take a ConversionFlags argument. When this + flag is set to strict, both irregular sequences and isolated surrogates + will cause an error. When the flag is set to lenient, both irregular + sequences and isolated surrogates are converted. + + Whether the flag is strict or lenient, all illegal sequences will cause + an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>, + or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code + must check for illegal sequences. + + When the flag is set to lenient, characters over 0x10FFFF are converted + to the replacement character; otherwise (when the flag is set to strict) + they constitute an error. + + Output parameters: + The value "sourceIllegal" is returned from some routines if the input + sequence is malformed. When "sourceIllegal" is returned, the source + value will point to the illegal value that caused the problem. E.g., + in UTF-8 when a sequence is malformed, it points to the start of the + malformed sequence. + + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Fixes & updates, Sept 2001. + +------------------------------------------------------------------------ */ + +#ifndef LLVM_SUPPORT_CONVERTUTF_H +#define LLVM_SUPPORT_CONVERTUTF_H + +#include <cstddef> +#include <string> +#include <system_error> + +// Wrap everything in namespace llvm so that programs can link with llvm and +// their own version of the unicode libraries. + +namespace llvm { + +/* --------------------------------------------------------------------- + The following 4 definitions are compiler-specific. + The C standard does not guarantee that wchar_t has at least + 16 bits, so wchar_t is no less portable than unsigned short! + All should be unsigned values to avoid sign extension during + bit mask & shift operations. +------------------------------------------------------------------------ */ + +typedef unsigned int UTF32; /* at least 32 bits */ +typedef unsigned short UTF16; /* at least 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ +typedef unsigned char Boolean; /* 0 or 1 */ + +/* Some fundamental constants */ +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD +#define UNI_MAX_BMP (UTF32)0x0000FFFF +#define UNI_MAX_UTF16 (UTF32)0x0010FFFF +#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF +#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF + +#define UNI_MAX_UTF8_BYTES_PER_CODE_POINT 4 + +#define UNI_UTF16_BYTE_ORDER_MARK_NATIVE 0xFEFF +#define UNI_UTF16_BYTE_ORDER_MARK_SWAPPED 0xFFFE + +typedef enum { + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ +} ConversionResult; + +typedef enum { + strictConversion = 0, + lenientConversion +} ConversionFlags; + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +/** + * Convert a partial UTF8 sequence to UTF32. If the sequence ends in an + * incomplete code unit sequence, returns \c sourceExhausted. + */ +ConversionResult ConvertUTF8toUTF32Partial( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +/** + * Convert a partial UTF8 sequence to UTF32. If the sequence ends in an + * incomplete code unit sequence, returns \c sourceIllegal. + */ +ConversionResult ConvertUTF8toUTF32( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); + +Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd); + +unsigned getNumBytesForUTF8(UTF8 firstByte); + +/*************************************************************************/ +/* Below are LLVM-specific wrappers of the functions above. */ + +template <typename T> class ArrayRef; +template <typename T> class SmallVectorImpl; +class StringRef; + +/** + * Convert an UTF8 StringRef to UTF8, UTF16, or UTF32 depending on + * WideCharWidth. The converted data is written to ResultPtr, which needs to + * point to at least WideCharWidth * (Source.Size() + 1) bytes. On success, + * ResultPtr will point one after the end of the copied string. On failure, + * ResultPtr will not be changed, and ErrorPtr will be set to the location of + * the first character which could not be converted. + * \return true on success. + */ +bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source, + char *&ResultPtr, const UTF8 *&ErrorPtr); + +/** +* Converts a UTF-8 StringRef to a std::wstring. +* \return true on success. +*/ +bool ConvertUTF8toWide(llvm::StringRef Source, std::wstring &Result); + +/** +* Converts a UTF-8 C-string to a std::wstring. +* \return true on success. +*/ +bool ConvertUTF8toWide(const char *Source, std::wstring &Result); + +/** +* Converts a std::wstring to a UTF-8 encoded std::string. +* \return true on success. +*/ +bool convertWideToUTF8(const std::wstring &Source, std::string &Result); + + +/** + * Convert an Unicode code point to UTF8 sequence. + * + * \param Source a Unicode code point. + * \param [in,out] ResultPtr pointer to the output buffer, needs to be at least + * \c UNI_MAX_UTF8_BYTES_PER_CODE_POINT bytes. On success \c ResultPtr is + * updated one past end of the converted sequence. + * + * \returns true on success. + */ +bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr); + +/** + * Convert the first UTF8 sequence in the given source buffer to a UTF32 + * code point. + * + * \param [in,out] source A pointer to the source buffer. If the conversion + * succeeds, this pointer will be updated to point to the byte just past the + * end of the converted sequence. + * \param sourceEnd A pointer just past the end of the source buffer. + * \param [out] target The converted code + * \param flags Whether the conversion is strict or lenient. + * + * \returns conversionOK on success + * + * \sa ConvertUTF8toUTF32 + */ +inline ConversionResult convertUTF8Sequence(const UTF8 **source, + const UTF8 *sourceEnd, + UTF32 *target, + ConversionFlags flags) { + if (*source == sourceEnd) + return sourceExhausted; + unsigned size = getNumBytesForUTF8(**source); + if ((ptrdiff_t)size > sourceEnd - *source) + return sourceExhausted; + return ConvertUTF8toUTF32(source, *source + size, &target, target + 1, flags); +} + +/** + * Returns true if a blob of text starts with a UTF-16 big or little endian byte + * order mark. + */ +bool hasUTF16ByteOrderMark(ArrayRef<char> SrcBytes); + +/** + * Converts a stream of raw bytes assumed to be UTF16 into a UTF8 std::string. + * + * \param [in] SrcBytes A buffer of what is assumed to be UTF-16 encoded text. + * \param [out] Out Converted UTF-8 is stored here on success. + * \returns true on success + */ +bool convertUTF16ToUTF8String(ArrayRef<char> SrcBytes, std::string &Out); + +/** +* Converts a UTF16 string into a UTF8 std::string. +* +* \param [in] Src A buffer of UTF-16 encoded text. +* \param [out] Out Converted UTF-8 is stored here on success. +* \returns true on success +*/ +bool convertUTF16ToUTF8String(ArrayRef<UTF16> Src, std::string &Out); + +/** + * Converts a UTF-8 string into a UTF-16 string with native endianness. + * + * \returns true on success + */ +bool convertUTF8ToUTF16String(StringRef SrcUTF8, + SmallVectorImpl<UTF16> &DstUTF16); + +#if defined(_WIN32) +namespace sys { +namespace windows { +std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16); +/// Convert to UTF16 from the current code page used in the system +std::error_code CurCPToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16); +std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, + SmallVectorImpl<char> &utf8); +/// Convert from UTF16 to the current code page used in the system +std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, + SmallVectorImpl<char> &utf8); +} // namespace windows +} // namespace sys +#endif + +} /* end namespace llvm */ + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/DJB.h b/third_party/llvm-project/include/llvm/Support/DJB.h new file mode 100644 index 000000000..8a04a324a --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/DJB.h @@ -0,0 +1,32 @@ +//===-- llvm/Support/DJB.h ---DJB Hash --------------------------*- 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 contains support for the DJ Bernstein hash function. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_DJB_H +#define LLVM_SUPPORT_DJB_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { + +/// The Bernstein hash function used by the DWARF accelerator tables. +inline uint32_t djbHash(StringRef Buffer, uint32_t H = 5381) { + for (unsigned char C : Buffer.bytes()) + H = (H << 5) + H + C; + return H; +} + +/// Computes the Bernstein hash after folding the input according to the Dwarf 5 +/// standard case folding rules. +uint32_t caseFoldingDjbHash(StringRef Buffer, uint32_t H = 5381); +} // namespace llvm + +#endif // LLVM_SUPPORT_DJB_H diff --git a/third_party/llvm-project/include/llvm/Support/DataExtractor.h b/third_party/llvm-project/include/llvm/Support/DataExtractor.h new file mode 100644 index 000000000..f590a1e10 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/DataExtractor.h @@ -0,0 +1,575 @@ +//===-- DataExtractor.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_DATAEXTRACTOR_H +#define LLVM_SUPPORT_DATAEXTRACTOR_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Error.h" + +namespace llvm { + +/// An auxiliary type to facilitate extraction of 3-byte entities. +struct Uint24 { + uint8_t Bytes[3]; + Uint24(uint8_t U) { + Bytes[0] = Bytes[1] = Bytes[2] = U; + } + Uint24(uint8_t U0, uint8_t U1, uint8_t U2) { + Bytes[0] = U0; Bytes[1] = U1; Bytes[2] = U2; + } + uint32_t getAsUint32(bool IsLittleEndian) const { + int LoIx = IsLittleEndian ? 0 : 2; + return Bytes[LoIx] + (Bytes[1] << 8) + (Bytes[2-LoIx] << 16); + } +}; + +using uint24_t = Uint24; +static_assert(sizeof(uint24_t) == 3, "sizeof(uint24_t) != 3"); + +/// Needed by swapByteOrder(). +inline uint24_t getSwappedBytes(uint24_t C) { + return uint24_t(C.Bytes[2], C.Bytes[1], C.Bytes[0]); +} + +class DataExtractor { + StringRef Data; + uint8_t IsLittleEndian; + uint8_t AddressSize; +public: + /// A class representing a position in a DataExtractor, as well as any error + /// encountered during extraction. It enables one to extract a sequence of + /// values without error-checking and then checking for errors in bulk at the + /// end. The class holds an Error object, so failing to check the result of + /// the parse will result in a runtime error. The error flag is sticky and + /// will cause all subsequent extraction functions to fail without even + /// attempting to parse and without updating the Cursor offset. After clearing + /// the error flag, one can again use the Cursor object for parsing. + class Cursor { + uint64_t Offset; + Error Err; + + friend class DataExtractor; + + public: + /// Construct a cursor for extraction from the given offset. + explicit Cursor(uint64_t Offset) : Offset(Offset), Err(Error::success()) {} + + /// Checks whether the cursor is valid (i.e. no errors were encountered). In + /// case of errors, this does not clear the error flag -- one must call + /// takeError() instead. + explicit operator bool() { return !Err; } + + /// Return the current position of this Cursor. In the error state this is + /// the position of the Cursor before the first error was encountered. + uint64_t tell() const { return Offset; } + + /// Return error contained inside this Cursor, if any. Clears the internal + /// Cursor state. + Error takeError() { return std::move(Err); } + }; + + /// Construct with a buffer that is owned by the caller. + /// + /// This constructor allows us to use data that is owned by the + /// caller. The data must stay around as long as this object is + /// valid. + DataExtractor(StringRef Data, bool IsLittleEndian, uint8_t AddressSize) + : Data(Data), IsLittleEndian(IsLittleEndian), AddressSize(AddressSize) {} + DataExtractor(ArrayRef<uint8_t> Data, bool IsLittleEndian, + uint8_t AddressSize) + : Data(StringRef(reinterpret_cast<const char *>(Data.data()), + Data.size())), + IsLittleEndian(IsLittleEndian), AddressSize(AddressSize) {} + + /// Get the data pointed to by this extractor. + StringRef getData() const { return Data; } + /// Get the endianness for this extractor. + bool isLittleEndian() const { return IsLittleEndian; } + /// Get the address size for this extractor. + uint8_t getAddressSize() const { return AddressSize; } + /// Set the address size for this extractor. + void setAddressSize(uint8_t Size) { AddressSize = Size; } + + /// Extract a C string from \a *offset_ptr. + /// + /// Returns a pointer to a C String from the data at the offset + /// pointed to by \a offset_ptr. A variable length NULL terminated C + /// string will be extracted and the \a offset_ptr will be + /// updated with the offset of the byte that follows the NULL + /// terminator byte. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// @return + /// A pointer to the C string value in the data. If the offset + /// pointed to by \a offset_ptr is out of bounds, or if the + /// offset plus the length of the C string is out of bounds, + /// NULL will be returned. + const char *getCStr(uint64_t *offset_ptr) const; + + /// Extract a C string from \a *offset_ptr. + /// + /// Returns a StringRef for the C String from the data at the offset + /// pointed to by \a offset_ptr. A variable length NULL terminated C + /// string will be extracted and the \a offset_ptr will be + /// updated with the offset of the byte that follows the NULL + /// terminator byte. + /// + /// \param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// \return + /// A StringRef for the C string value in the data. If the offset + /// pointed to by \a offset_ptr is out of bounds, or if the + /// offset plus the length of the C string is out of bounds, + /// a default-initialized StringRef will be returned. + StringRef getCStrRef(uint64_t *offset_ptr) const; + + /// Extract an unsigned integer of size \a byte_size from \a + /// *offset_ptr. + /// + /// Extract a single unsigned integer value and update the offset + /// pointed to by \a offset_ptr. The size of the extracted integer + /// is specified by the \a byte_size argument. \a byte_size should + /// have a value greater than or equal to one and less than or equal + /// to eight since the return value is 64 bits wide. Any + /// \a byte_size values less than 1 or greater than 8 will result in + /// nothing being extracted, and zero being returned. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// @param[in] byte_size + /// The size in byte of the integer to extract. + /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// + /// @return + /// The unsigned integer value that was extracted, or zero on + /// failure. + uint64_t getUnsigned(uint64_t *offset_ptr, uint32_t byte_size, + Error *Err = nullptr) const; + + /// Extract an unsigned integer of the given size from the location given by + /// the cursor. In case of an extraction error, or if the cursor is already in + /// an error state, zero is returned. + uint64_t getUnsigned(Cursor &C, uint32_t Size) const { + return getUnsigned(&C.Offset, Size, &C.Err); + } + + /// Extract an signed integer of size \a byte_size from \a *offset_ptr. + /// + /// Extract a single signed integer value (sign extending if required) + /// and update the offset pointed to by \a offset_ptr. The size of + /// the extracted integer is specified by the \a byte_size argument. + /// \a byte_size should have a value greater than or equal to one + /// and less than or equal to eight since the return value is 64 + /// bits wide. Any \a byte_size values less than 1 or greater than + /// 8 will result in nothing being extracted, and zero being returned. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// @param[in] size + /// The size in bytes of the integer to extract. + /// + /// @return + /// The sign extended signed integer value that was extracted, + /// or zero on failure. + int64_t getSigned(uint64_t *offset_ptr, uint32_t size) const; + + //------------------------------------------------------------------ + /// Extract an pointer from \a *offset_ptr. + /// + /// Extract a single pointer from the data and update the offset + /// pointed to by \a offset_ptr. The size of the extracted pointer + /// is \a getAddressSize(), so the address size has to be + /// set correctly prior to extracting any pointer values. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// @return + /// The extracted pointer value as a 64 integer. + uint64_t getAddress(uint64_t *offset_ptr) const { + return getUnsigned(offset_ptr, AddressSize); + } + + /// Extract a pointer-sized unsigned integer from the location given by the + /// cursor. In case of an extraction error, or if the cursor is already in + /// an error state, zero is returned. + uint64_t getAddress(Cursor &C) const { return getUnsigned(C, AddressSize); } + + /// Extract a uint8_t value from \a *offset_ptr. + /// + /// Extract a single uint8_t from the binary data at the offset + /// pointed to by \a offset_ptr, and advance the offset on success. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// + /// @return + /// The extracted uint8_t value. + uint8_t getU8(uint64_t *offset_ptr, Error *Err = nullptr) const; + + /// Extract a single uint8_t value from the location given by the cursor. In + /// case of an extraction error, or if the cursor is already in an error + /// state, zero is returned. + uint8_t getU8(Cursor &C) const { return getU8(&C.Offset, &C.Err); } + + /// Extract \a count uint8_t values from \a *offset_ptr. + /// + /// Extract \a count uint8_t values from the binary data at the + /// offset pointed to by \a offset_ptr, and advance the offset on + /// success. The extracted values are copied into \a dst. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// @param[out] dst + /// A buffer to copy \a count uint8_t values into. \a dst must + /// be large enough to hold all requested data. + /// + /// @param[in] count + /// The number of uint8_t values to extract. + /// + /// @return + /// \a dst if all values were properly extracted and copied, + /// NULL otherise. + uint8_t *getU8(uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const; + + /// Extract \a Count uint8_t values from the location given by the cursor and + /// store them into the destination buffer. In case of an extraction error, or + /// if the cursor is already in an error state, a nullptr is returned and the + /// destination buffer is left unchanged. + uint8_t *getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const; + + /// Extract \a Count uint8_t values from the location given by the cursor and + /// store them into the destination vector. The vector is resized to fit the + /// extracted data. In case of an extraction error, or if the cursor is + /// already in an error state, the destination vector is left unchanged and + /// cursor is placed into an error state. + void getU8(Cursor &C, SmallVectorImpl<uint8_t> &Dst, uint32_t Count) const { + if (isValidOffsetForDataOfSize(C.Offset, Count)) + Dst.resize(Count); + + // This relies on the fact that getU8 will not attempt to write to the + // buffer if isValidOffsetForDataOfSize(C.Offset, Count) is false. + getU8(C, Dst.data(), Count); + } + + //------------------------------------------------------------------ + /// Extract a uint16_t value from \a *offset_ptr. + /// + /// Extract a single uint16_t from the binary data at the offset + /// pointed to by \a offset_ptr, and update the offset on success. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// + /// @return + /// The extracted uint16_t value. + //------------------------------------------------------------------ + uint16_t getU16(uint64_t *offset_ptr, Error *Err = nullptr) const; + + /// Extract a single uint16_t value from the location given by the cursor. In + /// case of an extraction error, or if the cursor is already in an error + /// state, zero is returned. + uint16_t getU16(Cursor &C) const { return getU16(&C.Offset, &C.Err); } + + /// Extract \a count uint16_t values from \a *offset_ptr. + /// + /// Extract \a count uint16_t values from the binary data at the + /// offset pointed to by \a offset_ptr, and advance the offset on + /// success. The extracted values are copied into \a dst. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// @param[out] dst + /// A buffer to copy \a count uint16_t values into. \a dst must + /// be large enough to hold all requested data. + /// + /// @param[in] count + /// The number of uint16_t values to extract. + /// + /// @return + /// \a dst if all values were properly extracted and copied, + /// NULL otherise. + uint16_t *getU16(uint64_t *offset_ptr, uint16_t *dst, uint32_t count) const; + + /// Extract a 24-bit unsigned value from \a *offset_ptr and return it + /// in a uint32_t. + /// + /// Extract 3 bytes from the binary data at the offset pointed to by + /// \a offset_ptr, construct a uint32_t from them and update the offset + /// on success. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the 3 bytes if the value is extracted correctly. If the offset + /// is out of bounds or there are not enough bytes to extract this value, + /// the offset will be left unmodified. + /// + /// @return + /// The extracted 24-bit value represented in a uint32_t. + uint32_t getU24(uint64_t *offset_ptr) const; + + /// Extract a uint32_t value from \a *offset_ptr. + /// + /// Extract a single uint32_t from the binary data at the offset + /// pointed to by \a offset_ptr, and update the offset on success. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// + /// @return + /// The extracted uint32_t value. + uint32_t getU32(uint64_t *offset_ptr, Error *Err = nullptr) const; + + /// Extract a single uint32_t value from the location given by the cursor. In + /// case of an extraction error, or if the cursor is already in an error + /// state, zero is returned. + uint32_t getU32(Cursor &C) const { return getU32(&C.Offset, &C.Err); } + + /// Extract \a count uint32_t values from \a *offset_ptr. + /// + /// Extract \a count uint32_t values from the binary data at the + /// offset pointed to by \a offset_ptr, and advance the offset on + /// success. The extracted values are copied into \a dst. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// @param[out] dst + /// A buffer to copy \a count uint32_t values into. \a dst must + /// be large enough to hold all requested data. + /// + /// @param[in] count + /// The number of uint32_t values to extract. + /// + /// @return + /// \a dst if all values were properly extracted and copied, + /// NULL otherise. + uint32_t *getU32(uint64_t *offset_ptr, uint32_t *dst, uint32_t count) const; + + /// Extract a uint64_t value from \a *offset_ptr. + /// + /// Extract a single uint64_t from the binary data at the offset + /// pointed to by \a offset_ptr, and update the offset on success. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// + /// @return + /// The extracted uint64_t value. + uint64_t getU64(uint64_t *offset_ptr, Error *Err = nullptr) const; + + /// Extract a single uint64_t value from the location given by the cursor. In + /// case of an extraction error, or if the cursor is already in an error + /// state, zero is returned. + uint64_t getU64(Cursor &C) const { return getU64(&C.Offset, &C.Err); } + + /// Extract \a count uint64_t values from \a *offset_ptr. + /// + /// Extract \a count uint64_t values from the binary data at the + /// offset pointed to by \a offset_ptr, and advance the offset on + /// success. The extracted values are copied into \a dst. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// @param[out] dst + /// A buffer to copy \a count uint64_t values into. \a dst must + /// be large enough to hold all requested data. + /// + /// @param[in] count + /// The number of uint64_t values to extract. + /// + /// @return + /// \a dst if all values were properly extracted and copied, + /// NULL otherise. + uint64_t *getU64(uint64_t *offset_ptr, uint64_t *dst, uint32_t count) const; + + /// Extract a signed LEB128 value from \a *offset_ptr. + /// + /// Extracts an signed LEB128 number from this object's data + /// starting at the offset pointed to by \a offset_ptr. The offset + /// pointed to by \a offset_ptr will be updated with the offset of + /// the byte following the last extracted byte. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// @return + /// The extracted signed integer value. + int64_t getSLEB128(uint64_t *offset_ptr) const; + + /// Extract a unsigned LEB128 value from \a *offset_ptr. + /// + /// Extracts an unsigned LEB128 number from this object's data + /// starting at the offset pointed to by \a offset_ptr. The offset + /// pointed to by \a offset_ptr will be updated with the offset of + /// the byte following the last extracted byte. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// + /// @return + /// The extracted unsigned integer value. + uint64_t getULEB128(uint64_t *offset_ptr, llvm::Error *Err = nullptr) const; + + /// Extract an unsigned ULEB128 value from the location given by the cursor. + /// In case of an extraction error, or if the cursor is already in an error + /// state, zero is returned. + uint64_t getULEB128(Cursor &C) const { return getULEB128(&C.Offset, &C.Err); } + + /// Advance the Cursor position by the given number of bytes. No-op if the + /// cursor is in an error state. + void skip(Cursor &C, uint64_t Length) const; + + /// Return true iff the cursor is at the end of the buffer, regardless of the + /// error state of the cursor. The only way both eof and error states can be + /// true is if one attempts a read while the cursor is at the very end of the + /// data buffer. + bool eof(const Cursor &C) const { return Data.size() == C.Offset; } + + /// Test the validity of \a offset. + /// + /// @return + /// \b true if \a offset is a valid offset into the data in this + /// object, \b false otherwise. + bool isValidOffset(uint64_t offset) const { return Data.size() > offset; } + + /// Test the availability of \a length bytes of data from \a offset. + /// + /// @return + /// \b true if \a offset is a valid offset and there are \a + /// length bytes available at that offset, \b false otherwise. + bool isValidOffsetForDataOfSize(uint64_t offset, uint64_t length) const { + return offset + length >= offset && isValidOffset(offset + length - 1); + } + + /// Test the availability of enough bytes of data for a pointer from + /// \a offset. The size of a pointer is \a getAddressSize(). + /// + /// @return + /// \b true if \a offset is a valid offset and there are enough + /// bytes for a pointer available at that offset, \b false + /// otherwise. + bool isValidOffsetForAddress(uint64_t offset) const { + return isValidOffsetForDataOfSize(offset, AddressSize); + } + +protected: + // Make it possible for subclasses to access these fields without making them + // public. + static uint64_t &getOffset(Cursor &C) { return C.Offset; } + static Error &getError(Cursor &C) { return C.Err; } +}; + +} // namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/DataTypes.h b/third_party/llvm-project/include/llvm/Support/DataTypes.h new file mode 100644 index 000000000..a3fcc8253 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/DataTypes.h @@ -0,0 +1,16 @@ +//===-- llvm/Support/DataTypes.h - Define fixed size types ------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Due to layering constraints (Support depends on llvm-c) this is a thin +// wrapper around the implementation that lives in llvm-c, though most clients +// can/should think of this as being provided by Support for simplicity (not +// many clients are aware of their dependency on llvm-c). +// +//===----------------------------------------------------------------------===// + +#include "llvm-c/DataTypes.h" diff --git a/third_party/llvm-project/include/llvm/Support/Debug.h b/third_party/llvm-project/include/llvm/Support/Debug.h new file mode 100644 index 000000000..64b730951 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Debug.h @@ -0,0 +1,126 @@ +//===- llvm/Support/Debug.h - Easy way to add debug output ------*- 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 a handy way of adding debugging information to your +// code, without it being enabled all of the time, and without having to add +// command line options to enable it. +// +// In particular, just wrap your code with the LLVM_DEBUG() macro, and it will +// be enabled automatically if you specify '-debug' on the command-line. +// LLVM_DEBUG() requires the DEBUG_TYPE macro to be defined. Set it to "foo" +// specify that your debug code belongs to class "foo". Be careful that you only +// do this after including Debug.h and not around any #include of headers. +// Headers should define and undef the macro acround the code that needs to use +// the LLVM_DEBUG() macro. Then, on the command line, you can specify +// '-debug-only=foo' to enable JUST the debug information for the foo class. +// +// When compiling without assertions, the -debug-* options and all code in +// LLVM_DEBUG() statements disappears, so it does not affect the runtime of the +// code. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_DEBUG_H +#define LLVM_SUPPORT_DEBUG_H + +namespace llvm { + +class raw_ostream; + +#ifndef NDEBUG + +/// isCurrentDebugType - Return true if the specified string is the debug type +/// specified on the command line, or if none was specified on the command line +/// with the -debug-only=X option. +/// +bool isCurrentDebugType(const char *Type); + +/// setCurrentDebugType - Set the current debug type, as if the -debug-only=X +/// option were specified. Note that DebugFlag also needs to be set to true for +/// debug output to be produced. +/// +void setCurrentDebugType(const char *Type); + +/// setCurrentDebugTypes - Set the current debug type, as if the +/// -debug-only=X,Y,Z option were specified. Note that DebugFlag +/// also needs to be set to true for debug output to be produced. +/// +void setCurrentDebugTypes(const char **Types, unsigned Count); + +/// DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug +/// information. In the '-debug' option is specified on the commandline, and if +/// this is a debug build, then the code specified as the option to the macro +/// will be executed. Otherwise it will not be. Example: +/// +/// DEBUG_WITH_TYPE("bitset", dbgs() << "Bitset contains: " << Bitset << "\n"); +/// +/// This will emit the debug information if -debug is present, and -debug-only +/// is not specified, or is specified as "bitset". +#define DEBUG_WITH_TYPE(TYPE, X) \ + do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType(TYPE)) { X; } \ + } while (false) + +#else +#define isCurrentDebugType(X) (false) +#define setCurrentDebugType(X) +#define setCurrentDebugTypes(X, N) +#define DEBUG_WITH_TYPE(TYPE, X) do { } while (false) +#endif + +/// This boolean is set to true if the '-debug' command line option +/// is specified. This should probably not be referenced directly, instead, use +/// the DEBUG macro below. +/// +extern bool DebugFlag; + +/// \name Verification flags. +/// +/// These flags turns on/off that are expensive and are turned off by default, +/// unless macro EXPENSIVE_CHECKS is defined. The flags allow selectively +/// turning the checks on without need to recompile. +/// \{ + +/// Enables verification of dominator trees. +/// +extern bool VerifyDomInfo; + +/// Enables verification of loop info. +/// +extern bool VerifyLoopInfo; + +/// Enables verification of MemorySSA. +/// +extern bool VerifyMemorySSA; + +///\} + +/// EnableDebugBuffering - This defaults to false. If true, the debug +/// stream will install signal handlers to dump any buffered debug +/// output. It allows clients to selectively allow the debug stream +/// to install signal handlers if they are certain there will be no +/// conflict. +/// +extern bool EnableDebugBuffering; + +/// dbgs() - This returns a reference to a raw_ostream for debugging +/// messages. If debugging is disabled it returns errs(). Use it +/// like: dbgs() << "foo" << "bar"; +raw_ostream &dbgs(); + +// DEBUG macro - This macro should be used by passes to emit debug information. +// In the '-debug' option is specified on the commandline, and if this is a +// debug build, then the code specified as the option to the macro will be +// executed. Otherwise it will not be. Example: +// +// LLVM_DEBUG(dbgs() << "Bitset contains: " << Bitset << "\n"); +// +#define LLVM_DEBUG(X) DEBUG_WITH_TYPE(DEBUG_TYPE, X) + +} // end namespace llvm + +#endif // LLVM_SUPPORT_DEBUG_H diff --git a/third_party/llvm-project/include/llvm/Support/Endian.h b/third_party/llvm-project/include/llvm/Support/Endian.h new file mode 100644 index 000000000..87aecedd3 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Endian.h @@ -0,0 +1,429 @@ +//===- Endian.h - Utilities for IO with endian specific data ----*- 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 declares generic functions to read and write endian specific data. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ENDIAN_H +#define LLVM_SUPPORT_ENDIAN_H + +#include "llvm/Support/AlignOf.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/SwapByteOrder.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <type_traits> + +namespace llvm { +namespace support { + +enum endianness {big, little, native}; + +// These are named values for common alignments. +enum {aligned = 0, unaligned = 1}; + +namespace detail { + +/// ::value is either alignment, or alignof(T) if alignment is 0. +template<class T, int alignment> +struct PickAlignment { + enum { value = alignment == 0 ? alignof(T) : alignment }; +}; + +} // end namespace detail + +namespace endian { + +constexpr endianness system_endianness() { + return sys::IsBigEndianHost ? big : little; +} + +template <typename value_type> +inline value_type byte_swap(value_type value, endianness endian) { + if ((endian != native) && (endian != system_endianness())) + sys::swapByteOrder(value); + return value; +} + +/// Swap the bytes of value to match the given endianness. +template<typename value_type, endianness endian> +inline value_type byte_swap(value_type value) { + return byte_swap(value, endian); +} + +/// Read a value of a particular endianness from memory. +template <typename value_type, std::size_t alignment> +inline value_type read(const void *memory, endianness endian) { + value_type ret; + + memcpy(&ret, + LLVM_ASSUME_ALIGNED( + memory, (detail::PickAlignment<value_type, alignment>::value)), + sizeof(value_type)); + return byte_swap<value_type>(ret, endian); +} + +template<typename value_type, + endianness endian, + std::size_t alignment> +inline value_type read(const void *memory) { + return read<value_type, alignment>(memory, endian); +} + +/// Read a value of a particular endianness from a buffer, and increment the +/// buffer past that value. +template <typename value_type, std::size_t alignment, typename CharT> +inline value_type readNext(const CharT *&memory, endianness endian) { + value_type ret = read<value_type, alignment>(memory, endian); + memory += sizeof(value_type); + return ret; +} + +template<typename value_type, endianness endian, std::size_t alignment, + typename CharT> +inline value_type readNext(const CharT *&memory) { + return readNext<value_type, alignment, CharT>(memory, endian); +} + +/// Write a value to memory with a particular endianness. +template <typename value_type, std::size_t alignment> +inline void write(void *memory, value_type value, endianness endian) { + value = byte_swap<value_type>(value, endian); + memcpy(LLVM_ASSUME_ALIGNED( + memory, (detail::PickAlignment<value_type, alignment>::value)), + &value, sizeof(value_type)); +} + +template<typename value_type, + endianness endian, + std::size_t alignment> +inline void write(void *memory, value_type value) { + write<value_type, alignment>(memory, value, endian); +} + +template <typename value_type> +using make_unsigned_t = typename std::make_unsigned<value_type>::type; + +/// Read a value of a particular endianness from memory, for a location +/// that starts at the given bit offset within the first byte. +template <typename value_type, endianness endian, std::size_t alignment> +inline value_type readAtBitAlignment(const void *memory, uint64_t startBit) { + assert(startBit < 8); + if (startBit == 0) + return read<value_type, endian, alignment>(memory); + else { + // Read two values and compose the result from them. + value_type val[2]; + memcpy(&val[0], + LLVM_ASSUME_ALIGNED( + memory, (detail::PickAlignment<value_type, alignment>::value)), + sizeof(value_type) * 2); + val[0] = byte_swap<value_type, endian>(val[0]); + val[1] = byte_swap<value_type, endian>(val[1]); + + // Shift bits from the lower value into place. + make_unsigned_t<value_type> lowerVal = val[0] >> startBit; + // Mask off upper bits after right shift in case of signed type. + make_unsigned_t<value_type> numBitsFirstVal = + (sizeof(value_type) * 8) - startBit; + lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1; + + // Get the bits from the upper value. + make_unsigned_t<value_type> upperVal = + val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1); + // Shift them in to place. + upperVal <<= numBitsFirstVal; + + return lowerVal | upperVal; + } +} + +/// Write a value to memory with a particular endianness, for a location +/// that starts at the given bit offset within the first byte. +template <typename value_type, endianness endian, std::size_t alignment> +inline void writeAtBitAlignment(void *memory, value_type value, + uint64_t startBit) { + assert(startBit < 8); + if (startBit == 0) + write<value_type, endian, alignment>(memory, value); + else { + // Read two values and shift the result into them. + value_type val[2]; + memcpy(&val[0], + LLVM_ASSUME_ALIGNED( + memory, (detail::PickAlignment<value_type, alignment>::value)), + sizeof(value_type) * 2); + val[0] = byte_swap<value_type, endian>(val[0]); + val[1] = byte_swap<value_type, endian>(val[1]); + + // Mask off any existing bits in the upper part of the lower value that + // we want to replace. + val[0] &= ((make_unsigned_t<value_type>)1 << startBit) - 1; + make_unsigned_t<value_type> numBitsFirstVal = + (sizeof(value_type) * 8) - startBit; + make_unsigned_t<value_type> lowerVal = value; + if (startBit > 0) { + // Mask off the upper bits in the new value that are not going to go into + // the lower value. This avoids a left shift of a negative value, which + // is undefined behavior. + lowerVal &= (((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1); + // Now shift the new bits into place + lowerVal <<= startBit; + } + val[0] |= lowerVal; + + // Mask off any existing bits in the lower part of the upper value that + // we want to replace. + val[1] &= ~(((make_unsigned_t<value_type>)1 << startBit) - 1); + // Next shift the bits that go into the upper value into position. + make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal; + // Mask off upper bits after right shift in case of signed type. + upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1; + val[1] |= upperVal; + + // Finally, rewrite values. + val[0] = byte_swap<value_type, endian>(val[0]); + val[1] = byte_swap<value_type, endian>(val[1]); + memcpy(LLVM_ASSUME_ALIGNED( + memory, (detail::PickAlignment<value_type, alignment>::value)), + &val[0], sizeof(value_type) * 2); + } +} + +} // end namespace endian + +namespace detail { + +template <typename ValueType, endianness Endian, std::size_t Alignment, + std::size_t ALIGN = PickAlignment<ValueType, Alignment>::value> +struct packed_endian_specific_integral { + using value_type = ValueType; + static constexpr endianness endian = Endian; + static constexpr std::size_t alignment = Alignment; + + packed_endian_specific_integral() = default; + + explicit packed_endian_specific_integral(value_type val) { *this = val; } + + operator value_type() const { + return endian::read<value_type, endian, alignment>( + (const void*)Value.buffer); + } + + void operator=(value_type newValue) { + endian::write<value_type, endian, alignment>( + (void*)Value.buffer, newValue); + } + + packed_endian_specific_integral &operator+=(value_type newValue) { + *this = *this + newValue; + return *this; + } + + packed_endian_specific_integral &operator-=(value_type newValue) { + *this = *this - newValue; + return *this; + } + + packed_endian_specific_integral &operator|=(value_type newValue) { + *this = *this | newValue; + return *this; + } + + packed_endian_specific_integral &operator&=(value_type newValue) { + *this = *this & newValue; + return *this; + } + +private: + struct { + alignas(ALIGN) char buffer[sizeof(value_type)]; + } Value; + +public: + struct ref { + explicit ref(void *Ptr) : Ptr(Ptr) {} + + operator value_type() const { + return endian::read<value_type, endian, alignment>(Ptr); + } + + void operator=(value_type NewValue) { + endian::write<value_type, endian, alignment>(Ptr, NewValue); + } + + private: + void *Ptr; + }; +}; + +} // end namespace detail + +using ulittle16_t = + detail::packed_endian_specific_integral<uint16_t, little, unaligned>; +using ulittle32_t = + detail::packed_endian_specific_integral<uint32_t, little, unaligned>; +using ulittle64_t = + detail::packed_endian_specific_integral<uint64_t, little, unaligned>; + +using little16_t = + detail::packed_endian_specific_integral<int16_t, little, unaligned>; +using little32_t = + detail::packed_endian_specific_integral<int32_t, little, unaligned>; +using little64_t = + detail::packed_endian_specific_integral<int64_t, little, unaligned>; + +using aligned_ulittle16_t = + detail::packed_endian_specific_integral<uint16_t, little, aligned>; +using aligned_ulittle32_t = + detail::packed_endian_specific_integral<uint32_t, little, aligned>; +using aligned_ulittle64_t = + detail::packed_endian_specific_integral<uint64_t, little, aligned>; + +using aligned_little16_t = + detail::packed_endian_specific_integral<int16_t, little, aligned>; +using aligned_little32_t = + detail::packed_endian_specific_integral<int32_t, little, aligned>; +using aligned_little64_t = + detail::packed_endian_specific_integral<int64_t, little, aligned>; + +using ubig16_t = + detail::packed_endian_specific_integral<uint16_t, big, unaligned>; +using ubig32_t = + detail::packed_endian_specific_integral<uint32_t, big, unaligned>; +using ubig64_t = + detail::packed_endian_specific_integral<uint64_t, big, unaligned>; + +using big16_t = + detail::packed_endian_specific_integral<int16_t, big, unaligned>; +using big32_t = + detail::packed_endian_specific_integral<int32_t, big, unaligned>; +using big64_t = + detail::packed_endian_specific_integral<int64_t, big, unaligned>; + +using aligned_ubig16_t = + detail::packed_endian_specific_integral<uint16_t, big, aligned>; +using aligned_ubig32_t = + detail::packed_endian_specific_integral<uint32_t, big, aligned>; +using aligned_ubig64_t = + detail::packed_endian_specific_integral<uint64_t, big, aligned>; + +using aligned_big16_t = + detail::packed_endian_specific_integral<int16_t, big, aligned>; +using aligned_big32_t = + detail::packed_endian_specific_integral<int32_t, big, aligned>; +using aligned_big64_t = + detail::packed_endian_specific_integral<int64_t, big, aligned>; + +using unaligned_uint16_t = + detail::packed_endian_specific_integral<uint16_t, native, unaligned>; +using unaligned_uint32_t = + detail::packed_endian_specific_integral<uint32_t, native, unaligned>; +using unaligned_uint64_t = + detail::packed_endian_specific_integral<uint64_t, native, unaligned>; + +using unaligned_int16_t = + detail::packed_endian_specific_integral<int16_t, native, unaligned>; +using unaligned_int32_t = + detail::packed_endian_specific_integral<int32_t, native, unaligned>; +using unaligned_int64_t = + detail::packed_endian_specific_integral<int64_t, native, unaligned>; + +template <typename T> +using little_t = detail::packed_endian_specific_integral<T, little, unaligned>; +template <typename T> +using big_t = detail::packed_endian_specific_integral<T, big, unaligned>; + +template <typename T> +using aligned_little_t = + detail::packed_endian_specific_integral<T, little, aligned>; +template <typename T> +using aligned_big_t = detail::packed_endian_specific_integral<T, big, aligned>; + +namespace endian { + +template <typename T> inline T read(const void *P, endianness E) { + return read<T, unaligned>(P, E); +} + +template <typename T, endianness E> inline T read(const void *P) { + return *(const detail::packed_endian_specific_integral<T, E, unaligned> *)P; +} + +inline uint16_t read16(const void *P, endianness E) { + return read<uint16_t>(P, E); +} +inline uint32_t read32(const void *P, endianness E) { + return read<uint32_t>(P, E); +} +inline uint64_t read64(const void *P, endianness E) { + return read<uint64_t>(P, E); +} + +template <endianness E> inline uint16_t read16(const void *P) { + return read<uint16_t, E>(P); +} +template <endianness E> inline uint32_t read32(const void *P) { + return read<uint32_t, E>(P); +} +template <endianness E> inline uint64_t read64(const void *P) { + return read<uint64_t, E>(P); +} + +inline uint16_t read16le(const void *P) { return read16<little>(P); } +inline uint32_t read32le(const void *P) { return read32<little>(P); } +inline uint64_t read64le(const void *P) { return read64<little>(P); } +inline uint16_t read16be(const void *P) { return read16<big>(P); } +inline uint32_t read32be(const void *P) { return read32<big>(P); } +inline uint64_t read64be(const void *P) { return read64<big>(P); } + +template <typename T> inline void write(void *P, T V, endianness E) { + write<T, unaligned>(P, V, E); +} + +template <typename T, endianness E> inline void write(void *P, T V) { + *(detail::packed_endian_specific_integral<T, E, unaligned> *)P = V; +} + +inline void write16(void *P, uint16_t V, endianness E) { + write<uint16_t>(P, V, E); +} +inline void write32(void *P, uint32_t V, endianness E) { + write<uint32_t>(P, V, E); +} +inline void write64(void *P, uint64_t V, endianness E) { + write<uint64_t>(P, V, E); +} + +template <endianness E> inline void write16(void *P, uint16_t V) { + write<uint16_t, E>(P, V); +} +template <endianness E> inline void write32(void *P, uint32_t V) { + write<uint32_t, E>(P, V); +} +template <endianness E> inline void write64(void *P, uint64_t V) { + write<uint64_t, E>(P, V); +} + +inline void write16le(void *P, uint16_t V) { write16<little>(P, V); } +inline void write32le(void *P, uint32_t V) { write32<little>(P, V); } +inline void write64le(void *P, uint64_t V) { write64<little>(P, V); } +inline void write16be(void *P, uint16_t V) { write16<big>(P, V); } +inline void write32be(void *P, uint32_t V) { write32<big>(P, V); } +inline void write64be(void *P, uint64_t V) { write64<big>(P, V); } + +} // end namespace endian + +} // end namespace support +} // end namespace llvm + +#endif // LLVM_SUPPORT_ENDIAN_H diff --git a/third_party/llvm-project/include/llvm/Support/Errc.h b/third_party/llvm-project/include/llvm/Support/Errc.h new file mode 100644 index 000000000..9be8e5705 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Errc.h @@ -0,0 +1,86 @@ +//===- llvm/Support/Errc.h - Defines the llvm::errc enum --------*- 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 +// +//===----------------------------------------------------------------------===// +// +// While std::error_code works OK on all platforms we use, there are some +// some problems with std::errc that can be avoided by using our own +// enumeration: +// +// * std::errc is a namespace in some implementations. That meas that ADL +// doesn't work and it is sometimes necessary to write std::make_error_code +// or in templates: +// using std::make_error_code; +// make_error_code(...); +// +// with this enum it is safe to always just use make_error_code. +// +// * Some implementations define fewer names than others. This header has +// the intersection of all the ones we support. +// +// * std::errc is just marked with is_error_condition_enum. This means that +// common patters like AnErrorCode == errc::no_such_file_or_directory take +// 4 virtual calls instead of two comparisons. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ERRC_H +#define LLVM_SUPPORT_ERRC_H + +#include <system_error> + +namespace llvm { +enum class errc { + argument_list_too_long = int(std::errc::argument_list_too_long), + argument_out_of_domain = int(std::errc::argument_out_of_domain), + bad_address = int(std::errc::bad_address), + bad_file_descriptor = int(std::errc::bad_file_descriptor), + broken_pipe = int(std::errc::broken_pipe), + device_or_resource_busy = int(std::errc::device_or_resource_busy), + directory_not_empty = int(std::errc::directory_not_empty), + executable_format_error = int(std::errc::executable_format_error), + file_exists = int(std::errc::file_exists), + file_too_large = int(std::errc::file_too_large), + filename_too_long = int(std::errc::filename_too_long), + function_not_supported = int(std::errc::function_not_supported), + illegal_byte_sequence = int(std::errc::illegal_byte_sequence), + inappropriate_io_control_operation = + int(std::errc::inappropriate_io_control_operation), + interrupted = int(std::errc::interrupted), + invalid_argument = int(std::errc::invalid_argument), + invalid_seek = int(std::errc::invalid_seek), + io_error = int(std::errc::io_error), + is_a_directory = int(std::errc::is_a_directory), + no_child_process = int(std::errc::no_child_process), + no_lock_available = int(std::errc::no_lock_available), + no_space_on_device = int(std::errc::no_space_on_device), + no_such_device_or_address = int(std::errc::no_such_device_or_address), + no_such_device = int(std::errc::no_such_device), + no_such_file_or_directory = int(std::errc::no_such_file_or_directory), + no_such_process = int(std::errc::no_such_process), + not_a_directory = int(std::errc::not_a_directory), + not_enough_memory = int(std::errc::not_enough_memory), + not_supported = int(std::errc::not_supported), + operation_not_permitted = int(std::errc::operation_not_permitted), + permission_denied = int(std::errc::permission_denied), + read_only_file_system = int(std::errc::read_only_file_system), + resource_deadlock_would_occur = int(std::errc::resource_deadlock_would_occur), + resource_unavailable_try_again = + int(std::errc::resource_unavailable_try_again), + result_out_of_range = int(std::errc::result_out_of_range), + too_many_files_open_in_system = int(std::errc::too_many_files_open_in_system), + too_many_files_open = int(std::errc::too_many_files_open), + too_many_links = int(std::errc::too_many_links) +}; + +inline std::error_code make_error_code(errc E) { + return std::error_code(static_cast<int>(E), std::generic_category()); +} +} + +namespace std { +template <> struct is_error_code_enum<llvm::errc> : std::true_type {}; +} +#endif diff --git a/third_party/llvm-project/include/llvm/Support/Errno.h b/third_party/llvm-project/include/llvm/Support/Errno.h new file mode 100644 index 000000000..aedb5fb29 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Errno.h @@ -0,0 +1,46 @@ +//===- llvm/Support/Errno.h - Portable+convenient errno handling -*- 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 declares some portable and convenient functions to deal with errno. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ERRNO_H +#define LLVM_SUPPORT_ERRNO_H + +#include <cerrno> +#include <string> +#include <type_traits> + +namespace llvm { +namespace sys { + +/// Returns a string representation of the errno value, using whatever +/// thread-safe variant of strerror() is available. Be sure to call this +/// immediately after the function that set errno, or errno may have been +/// overwritten by an intervening call. +std::string StrError(); + +/// Like the no-argument version above, but uses \p errnum instead of errno. +std::string StrError(int errnum); + +template <typename FailT, typename Fun, typename... Args> +inline auto RetryAfterSignal(const FailT &Fail, const Fun &F, + const Args &... As) -> decltype(F(As...)) { + decltype(F(As...)) Res; + do { + errno = 0; + Res = F(As...); + } while (Res == Fail && errno == EINTR); + return Res; +} + +} // namespace sys +} // namespace llvm + +#endif // LLVM_SYSTEM_ERRNO_H diff --git a/third_party/llvm-project/include/llvm/Support/Error.h b/third_party/llvm-project/include/llvm/Support/Error.h new file mode 100644 index 000000000..350877a21 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Error.h @@ -0,0 +1,1351 @@ +//===- llvm/Support/Error.h - Recoverable error handling --------*- 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 defines an API used to report recoverable errors. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ERROR_H +#define LLVM_SUPPORT_ERROR_H + +#include "llvm-c/Error.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Config/abi-breaking.h" +#include "llvm/Support/AlignOf.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstdlib> +#include <functional> +#include <memory> +#include <new> +#include <string> +#include <system_error> +#include <type_traits> +#include <utility> +#include <vector> + +namespace llvm { + +class ErrorSuccess; + +/// Base class for error info classes. Do not extend this directly: Extend +/// the ErrorInfo template subclass instead. +class ErrorInfoBase { +public: + virtual ~ErrorInfoBase() = default; + + /// Print an error message to an output stream. + virtual void log(raw_ostream &OS) const = 0; + + /// Return the error message as a string. + virtual std::string message() const { + std::string Msg; + raw_string_ostream OS(Msg); + log(OS); + return OS.str(); + } + + /// Convert this error to a std::error_code. + /// + /// This is a temporary crutch to enable interaction with code still + /// using std::error_code. It will be removed in the future. + virtual std::error_code convertToErrorCode() const = 0; + + // Returns the class ID for this type. + static const void *classID() { return &ID; } + + // Returns the class ID for the dynamic type of this ErrorInfoBase instance. + virtual const void *dynamicClassID() const = 0; + + // Check whether this instance is a subclass of the class identified by + // ClassID. + virtual bool isA(const void *const ClassID) const { + return ClassID == classID(); + } + + // Check whether this instance is a subclass of ErrorInfoT. + template <typename ErrorInfoT> bool isA() const { + return isA(ErrorInfoT::classID()); + } + +private: + virtual void anchor(); + + static char ID; +}; + +/// Lightweight error class with error context and mandatory checking. +/// +/// Instances of this class wrap a ErrorInfoBase pointer. Failure states +/// are represented by setting the pointer to a ErrorInfoBase subclass +/// instance containing information describing the failure. Success is +/// represented by a null pointer value. +/// +/// Instances of Error also contains a 'Checked' flag, which must be set +/// before the destructor is called, otherwise the destructor will trigger a +/// runtime error. This enforces at runtime the requirement that all Error +/// instances be checked or returned to the caller. +/// +/// There are two ways to set the checked flag, depending on what state the +/// Error instance is in. For Error instances indicating success, it +/// is sufficient to invoke the boolean conversion operator. E.g.: +/// +/// @code{.cpp} +/// Error foo(<...>); +/// +/// if (auto E = foo(<...>)) +/// return E; // <- Return E if it is in the error state. +/// // We have verified that E was in the success state. It can now be safely +/// // destroyed. +/// @endcode +/// +/// A success value *can not* be dropped. For example, just calling 'foo(<...>)' +/// without testing the return value will raise a runtime error, even if foo +/// returns success. +/// +/// For Error instances representing failure, you must use either the +/// handleErrors or handleAllErrors function with a typed handler. E.g.: +/// +/// @code{.cpp} +/// class MyErrorInfo : public ErrorInfo<MyErrorInfo> { +/// // Custom error info. +/// }; +/// +/// Error foo(<...>) { return make_error<MyErrorInfo>(...); } +/// +/// auto E = foo(<...>); // <- foo returns failure with MyErrorInfo. +/// auto NewE = +/// handleErrors(E, +/// [](const MyErrorInfo &M) { +/// // Deal with the error. +/// }, +/// [](std::unique_ptr<OtherError> M) -> Error { +/// if (canHandle(*M)) { +/// // handle error. +/// return Error::success(); +/// } +/// // Couldn't handle this error instance. Pass it up the stack. +/// return Error(std::move(M)); +/// ); +/// // Note - we must check or return NewE in case any of the handlers +/// // returned a new error. +/// @endcode +/// +/// The handleAllErrors function is identical to handleErrors, except +/// that it has a void return type, and requires all errors to be handled and +/// no new errors be returned. It prevents errors (assuming they can all be +/// handled) from having to be bubbled all the way to the top-level. +/// +/// *All* Error instances must be checked before destruction, even if +/// they're moved-assigned or constructed from Success values that have already +/// been checked. This enforces checking through all levels of the call stack. +class LLVM_NODISCARD Error { + // Both ErrorList and FileError need to be able to yank ErrorInfoBase + // pointers out of this class to add to the error list. + friend class ErrorList; + friend class FileError; + + // handleErrors needs to be able to set the Checked flag. + template <typename... HandlerTs> + friend Error handleErrors(Error E, HandlerTs &&... Handlers); + + // Expected<T> needs to be able to steal the payload when constructed from an + // error. + template <typename T> friend class Expected; + + // wrap needs to be able to steal the payload. + friend LLVMErrorRef wrap(Error); + +protected: + /// Create a success value. Prefer using 'Error::success()' for readability + Error() { + setPtr(nullptr); + setChecked(false); + } + +public: + /// Create a success value. + static ErrorSuccess success(); + + // Errors are not copy-constructable. + Error(const Error &Other) = delete; + + /// Move-construct an error value. The newly constructed error is considered + /// unchecked, even if the source error had been checked. The original error + /// becomes a checked Success value, regardless of its original state. + Error(Error &&Other) { + setChecked(true); + *this = std::move(Other); + } + + /// Create an error value. Prefer using the 'make_error' function, but + /// this constructor can be useful when "re-throwing" errors from handlers. + Error(std::unique_ptr<ErrorInfoBase> Payload) { + setPtr(Payload.release()); + setChecked(false); + } + + // Errors are not copy-assignable. + Error &operator=(const Error &Other) = delete; + + /// Move-assign an error value. The current error must represent success, you + /// you cannot overwrite an unhandled error. The current error is then + /// considered unchecked. The source error becomes a checked success value, + /// regardless of its original state. + Error &operator=(Error &&Other) { + // Don't allow overwriting of unchecked values. + assertIsChecked(); + setPtr(Other.getPtr()); + + // This Error is unchecked, even if the source error was checked. + setChecked(false); + + // Null out Other's payload and set its checked bit. + Other.setPtr(nullptr); + Other.setChecked(true); + + return *this; + } + + /// Destroy a Error. Fails with a call to abort() if the error is + /// unchecked. + ~Error() { + assertIsChecked(); + delete getPtr(); + } + + /// Bool conversion. Returns true if this Error is in a failure state, + /// and false if it is in an accept state. If the error is in a Success state + /// it will be considered checked. + explicit operator bool() { + setChecked(getPtr() == nullptr); + return getPtr() != nullptr; + } + + /// Check whether one error is a subclass of another. + template <typename ErrT> bool isA() const { + return getPtr() && getPtr()->isA(ErrT::classID()); + } + + /// Returns the dynamic class id of this error, or null if this is a success + /// value. + const void* dynamicClassID() const { + if (!getPtr()) + return nullptr; + return getPtr()->dynamicClassID(); + } + +private: +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + // assertIsChecked() happens very frequently, but under normal circumstances + // is supposed to be a no-op. So we want it to be inlined, but having a bunch + // of debug prints can cause the function to be too large for inlining. So + // it's important that we define this function out of line so that it can't be + // inlined. + LLVM_ATTRIBUTE_NORETURN + void fatalUncheckedError() const; +#endif + + void assertIsChecked() { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (LLVM_UNLIKELY(!getChecked() || getPtr())) + fatalUncheckedError(); +#endif + } + + ErrorInfoBase *getPtr() const { + return reinterpret_cast<ErrorInfoBase*>( + reinterpret_cast<uintptr_t>(Payload) & + ~static_cast<uintptr_t>(0x1)); + } + + void setPtr(ErrorInfoBase *EI) { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + Payload = reinterpret_cast<ErrorInfoBase*>( + (reinterpret_cast<uintptr_t>(EI) & + ~static_cast<uintptr_t>(0x1)) | + (reinterpret_cast<uintptr_t>(Payload) & 0x1)); +#else + Payload = EI; +#endif + } + + bool getChecked() const { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + return (reinterpret_cast<uintptr_t>(Payload) & 0x1) == 0; +#else + return true; +#endif + } + + void setChecked(bool V) { + Payload = reinterpret_cast<ErrorInfoBase*>( + (reinterpret_cast<uintptr_t>(Payload) & + ~static_cast<uintptr_t>(0x1)) | + (V ? 0 : 1)); + } + + std::unique_ptr<ErrorInfoBase> takePayload() { + std::unique_ptr<ErrorInfoBase> Tmp(getPtr()); + setPtr(nullptr); + setChecked(true); + return Tmp; + } + + friend raw_ostream &operator<<(raw_ostream &OS, const Error &E) { + if (auto P = E.getPtr()) + P->log(OS); + else + OS << "success"; + return OS; + } + + ErrorInfoBase *Payload = nullptr; +}; + +/// Subclass of Error for the sole purpose of identifying the success path in +/// the type system. This allows to catch invalid conversion to Expected<T> at +/// compile time. +class ErrorSuccess final : public Error {}; + +inline ErrorSuccess Error::success() { return ErrorSuccess(); } + +/// Make a Error instance representing failure using the given error info +/// type. +template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) { + return Error(std::make_unique<ErrT>(std::forward<ArgTs>(Args)...)); +} + +/// Base class for user error types. Users should declare their error types +/// like: +/// +/// class MyError : public ErrorInfo<MyError> { +/// .... +/// }; +/// +/// This class provides an implementation of the ErrorInfoBase::kind +/// method, which is used by the Error RTTI system. +template <typename ThisErrT, typename ParentErrT = ErrorInfoBase> +class ErrorInfo : public ParentErrT { +public: + using ParentErrT::ParentErrT; // inherit constructors + + static const void *classID() { return &ThisErrT::ID; } + + const void *dynamicClassID() const override { return &ThisErrT::ID; } + + bool isA(const void *const ClassID) const override { + return ClassID == classID() || ParentErrT::isA(ClassID); + } +}; + +/// Special ErrorInfo subclass representing a list of ErrorInfos. +/// Instances of this class are constructed by joinError. +class ErrorList final : public ErrorInfo<ErrorList> { + // handleErrors needs to be able to iterate the payload list of an + // ErrorList. + template <typename... HandlerTs> + friend Error handleErrors(Error E, HandlerTs &&... Handlers); + + // joinErrors is implemented in terms of join. + friend Error joinErrors(Error, Error); + +public: + void log(raw_ostream &OS) const override { + OS << "Multiple errors:\n"; + for (auto &ErrPayload : Payloads) { + ErrPayload->log(OS); + OS << "\n"; + } + } + + std::error_code convertToErrorCode() const override; + + // Used by ErrorInfo::classID. + static char ID; + +private: + ErrorList(std::unique_ptr<ErrorInfoBase> Payload1, + std::unique_ptr<ErrorInfoBase> Payload2) { + assert(!Payload1->isA<ErrorList>() && !Payload2->isA<ErrorList>() && + "ErrorList constructor payloads should be singleton errors"); + Payloads.push_back(std::move(Payload1)); + Payloads.push_back(std::move(Payload2)); + } + + static Error join(Error E1, Error E2) { + if (!E1) + return E2; + if (!E2) + return E1; + if (E1.isA<ErrorList>()) { + auto &E1List = static_cast<ErrorList &>(*E1.getPtr()); + if (E2.isA<ErrorList>()) { + auto E2Payload = E2.takePayload(); + auto &E2List = static_cast<ErrorList &>(*E2Payload); + for (auto &Payload : E2List.Payloads) + E1List.Payloads.push_back(std::move(Payload)); + } else + E1List.Payloads.push_back(E2.takePayload()); + + return E1; + } + if (E2.isA<ErrorList>()) { + auto &E2List = static_cast<ErrorList &>(*E2.getPtr()); + E2List.Payloads.insert(E2List.Payloads.begin(), E1.takePayload()); + return E2; + } + return Error(std::unique_ptr<ErrorList>( + new ErrorList(E1.takePayload(), E2.takePayload()))); + } + + std::vector<std::unique_ptr<ErrorInfoBase>> Payloads; +}; + +/// Concatenate errors. The resulting Error is unchecked, and contains the +/// ErrorInfo(s), if any, contained in E1, followed by the +/// ErrorInfo(s), if any, contained in E2. +inline Error joinErrors(Error E1, Error E2) { + return ErrorList::join(std::move(E1), std::move(E2)); +} + +/// Tagged union holding either a T or a Error. +/// +/// This class parallels ErrorOr, but replaces error_code with Error. Since +/// Error cannot be copied, this class replaces getError() with +/// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the +/// error class type. +template <class T> class LLVM_NODISCARD Expected { + template <class T1> friend class ExpectedAsOutParameter; + template <class OtherT> friend class Expected; + + static const bool isRef = std::is_reference<T>::value; + + using wrap = std::reference_wrapper<typename std::remove_reference<T>::type>; + + using error_type = std::unique_ptr<ErrorInfoBase>; + +public: + using storage_type = typename std::conditional<isRef, wrap, T>::type; + using value_type = T; + +private: + using reference = typename std::remove_reference<T>::type &; + using const_reference = const typename std::remove_reference<T>::type &; + using pointer = typename std::remove_reference<T>::type *; + using const_pointer = const typename std::remove_reference<T>::type *; + +public: + /// Create an Expected<T> error value from the given Error. + Expected(Error Err) + : HasError(true) +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + // Expected is unchecked upon construction in Debug builds. + , Unchecked(true) +#endif + { + assert(Err && "Cannot create Expected<T> from Error success value."); + new (getErrorStorage()) error_type(Err.takePayload()); + } + + /// Forbid to convert from Error::success() implicitly, this avoids having + /// Expected<T> foo() { return Error::success(); } which compiles otherwise + /// but triggers the assertion above. + Expected(ErrorSuccess) = delete; + + /// Create an Expected<T> success value from the given OtherT value, which + /// must be convertible to T. + template <typename OtherT> + Expected(OtherT &&Val, + typename std::enable_if<std::is_convertible<OtherT, T>::value>::type + * = nullptr) + : HasError(false) +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + // Expected is unchecked upon construction in Debug builds. + , Unchecked(true) +#endif + { + new (getStorage()) storage_type(std::forward<OtherT>(Val)); + } + + /// Move construct an Expected<T> value. + Expected(Expected &&Other) { moveConstruct(std::move(Other)); } + + /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT + /// must be convertible to T. + template <class OtherT> + Expected(Expected<OtherT> &&Other, + typename std::enable_if<std::is_convertible<OtherT, T>::value>::type + * = nullptr) { + moveConstruct(std::move(Other)); + } + + /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT + /// isn't convertible to T. + template <class OtherT> + explicit Expected( + Expected<OtherT> &&Other, + typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * = + nullptr) { + moveConstruct(std::move(Other)); + } + + /// Move-assign from another Expected<T>. + Expected &operator=(Expected &&Other) { + moveAssign(std::move(Other)); + return *this; + } + + /// Destroy an Expected<T>. + ~Expected() { + assertIsChecked(); + if (!HasError) + getStorage()->~storage_type(); + else + getErrorStorage()->~error_type(); + } + + /// Return false if there is an error. + explicit operator bool() { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + Unchecked = HasError; +#endif + return !HasError; + } + + /// Returns a reference to the stored T value. + reference get() { + assertIsChecked(); + return *getStorage(); + } + + /// Returns a const reference to the stored T value. + const_reference get() const { + assertIsChecked(); + return const_cast<Expected<T> *>(this)->get(); + } + + /// Check that this Expected<T> is an error of type ErrT. + template <typename ErrT> bool errorIsA() const { + return HasError && (*getErrorStorage())->template isA<ErrT>(); + } + + /// Take ownership of the stored error. + /// After calling this the Expected<T> is in an indeterminate state that can + /// only be safely destructed. No further calls (beside the destructor) should + /// be made on the Expected<T> value. + Error takeError() { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + Unchecked = false; +#endif + return HasError ? Error(std::move(*getErrorStorage())) : Error::success(); + } + + /// Returns a pointer to the stored T value. + pointer operator->() { + assertIsChecked(); + return toPointer(getStorage()); + } + + /// Returns a const pointer to the stored T value. + const_pointer operator->() const { + assertIsChecked(); + return toPointer(getStorage()); + } + + /// Returns a reference to the stored T value. + reference operator*() { + assertIsChecked(); + return *getStorage(); + } + + /// Returns a const reference to the stored T value. + const_reference operator*() const { + assertIsChecked(); + return *getStorage(); + } + +private: + template <class T1> + static bool compareThisIfSameType(const T1 &a, const T1 &b) { + return &a == &b; + } + + template <class T1, class T2> + static bool compareThisIfSameType(const T1 &a, const T2 &b) { + return false; + } + + template <class OtherT> void moveConstruct(Expected<OtherT> &&Other) { + HasError = Other.HasError; +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + Unchecked = true; + Other.Unchecked = false; +#endif + + if (!HasError) + new (getStorage()) storage_type(std::move(*Other.getStorage())); + else + new (getErrorStorage()) error_type(std::move(*Other.getErrorStorage())); + } + + template <class OtherT> void moveAssign(Expected<OtherT> &&Other) { + assertIsChecked(); + + if (compareThisIfSameType(*this, Other)) + return; + + this->~Expected(); + new (this) Expected(std::move(Other)); + } + + pointer toPointer(pointer Val) { return Val; } + + const_pointer toPointer(const_pointer Val) const { return Val; } + + pointer toPointer(wrap *Val) { return &Val->get(); } + + const_pointer toPointer(const wrap *Val) const { return &Val->get(); } + + storage_type *getStorage() { + assert(!HasError && "Cannot get value when an error exists!"); + return reinterpret_cast<storage_type *>(TStorage.buffer); + } + + const storage_type *getStorage() const { + assert(!HasError && "Cannot get value when an error exists!"); + return reinterpret_cast<const storage_type *>(TStorage.buffer); + } + + error_type *getErrorStorage() { + assert(HasError && "Cannot get error when a value exists!"); + return reinterpret_cast<error_type *>(ErrorStorage.buffer); + } + + const error_type *getErrorStorage() const { + assert(HasError && "Cannot get error when a value exists!"); + return reinterpret_cast<const error_type *>(ErrorStorage.buffer); + } + + // Used by ExpectedAsOutParameter to reset the checked flag. + void setUnchecked() { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + Unchecked = true; +#endif + } + +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + LLVM_ATTRIBUTE_NORETURN + LLVM_ATTRIBUTE_NOINLINE + void fatalUncheckedExpected() const { + dbgs() << "Expected<T> must be checked before access or destruction.\n"; + if (HasError) { + dbgs() << "Unchecked Expected<T> contained error:\n"; + (*getErrorStorage())->log(dbgs()); + } else + dbgs() << "Expected<T> value was in success state. (Note: Expected<T> " + "values in success mode must still be checked prior to being " + "destroyed).\n"; + abort(); + } +#endif + + void assertIsChecked() { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (LLVM_UNLIKELY(Unchecked)) + fatalUncheckedExpected(); +#endif + } + + union { + AlignedCharArrayUnion<storage_type> TStorage; + AlignedCharArrayUnion<error_type> ErrorStorage; + }; + bool HasError : 1; +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + bool Unchecked : 1; +#endif +}; + +/// Report a serious error, calling any installed error handler. See +/// ErrorHandling.h. +LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, + bool gen_crash_diag = true); + +/// Report a fatal error if Err is a failure value. +/// +/// This function can be used to wrap calls to fallible functions ONLY when it +/// is known that the Error will always be a success value. E.g. +/// +/// @code{.cpp} +/// // foo only attempts the fallible operation if DoFallibleOperation is +/// // true. If DoFallibleOperation is false then foo always returns +/// // Error::success(). +/// Error foo(bool DoFallibleOperation); +/// +/// cantFail(foo(false)); +/// @endcode +inline void cantFail(Error Err, const char *Msg = nullptr) { + if (Err) { + if (!Msg) + Msg = "Failure value returned from cantFail wrapped call"; +#ifndef NDEBUG + std::string Str; + raw_string_ostream OS(Str); + OS << Msg << "\n" << Err; + Msg = OS.str().c_str(); +#endif + llvm_unreachable(Msg); + } +} + +/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and +/// returns the contained value. +/// +/// This function can be used to wrap calls to fallible functions ONLY when it +/// is known that the Error will always be a success value. E.g. +/// +/// @code{.cpp} +/// // foo only attempts the fallible operation if DoFallibleOperation is +/// // true. If DoFallibleOperation is false then foo always returns an int. +/// Expected<int> foo(bool DoFallibleOperation); +/// +/// int X = cantFail(foo(false)); +/// @endcode +template <typename T> +T cantFail(Expected<T> ValOrErr, const char *Msg = nullptr) { + if (ValOrErr) + return std::move(*ValOrErr); + else { + if (!Msg) + Msg = "Failure value returned from cantFail wrapped call"; +#ifndef NDEBUG + std::string Str; + raw_string_ostream OS(Str); + auto E = ValOrErr.takeError(); + OS << Msg << "\n" << E; + Msg = OS.str().c_str(); +#endif + llvm_unreachable(Msg); + } +} + +/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and +/// returns the contained reference. +/// +/// This function can be used to wrap calls to fallible functions ONLY when it +/// is known that the Error will always be a success value. E.g. +/// +/// @code{.cpp} +/// // foo only attempts the fallible operation if DoFallibleOperation is +/// // true. If DoFallibleOperation is false then foo always returns a Bar&. +/// Expected<Bar&> foo(bool DoFallibleOperation); +/// +/// Bar &X = cantFail(foo(false)); +/// @endcode +template <typename T> +T& cantFail(Expected<T&> ValOrErr, const char *Msg = nullptr) { + if (ValOrErr) + return *ValOrErr; + else { + if (!Msg) + Msg = "Failure value returned from cantFail wrapped call"; +#ifndef NDEBUG + std::string Str; + raw_string_ostream OS(Str); + auto E = ValOrErr.takeError(); + OS << Msg << "\n" << E; + Msg = OS.str().c_str(); +#endif + llvm_unreachable(Msg); + } +} + +/// Helper for testing applicability of, and applying, handlers for +/// ErrorInfo types. +template <typename HandlerT> +class ErrorHandlerTraits + : public ErrorHandlerTraits<decltype( + &std::remove_reference<HandlerT>::type::operator())> {}; + +// Specialization functions of the form 'Error (const ErrT&)'. +template <typename ErrT> class ErrorHandlerTraits<Error (&)(ErrT &)> { +public: + static bool appliesTo(const ErrorInfoBase &E) { + return E.template isA<ErrT>(); + } + + template <typename HandlerT> + static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { + assert(appliesTo(*E) && "Applying incorrect handler"); + return H(static_cast<ErrT &>(*E)); + } +}; + +// Specialization functions of the form 'void (const ErrT&)'. +template <typename ErrT> class ErrorHandlerTraits<void (&)(ErrT &)> { +public: + static bool appliesTo(const ErrorInfoBase &E) { + return E.template isA<ErrT>(); + } + + template <typename HandlerT> + static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { + assert(appliesTo(*E) && "Applying incorrect handler"); + H(static_cast<ErrT &>(*E)); + return Error::success(); + } +}; + +/// Specialization for functions of the form 'Error (std::unique_ptr<ErrT>)'. +template <typename ErrT> +class ErrorHandlerTraits<Error (&)(std::unique_ptr<ErrT>)> { +public: + static bool appliesTo(const ErrorInfoBase &E) { + return E.template isA<ErrT>(); + } + + template <typename HandlerT> + static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { + assert(appliesTo(*E) && "Applying incorrect handler"); + std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release())); + return H(std::move(SubE)); + } +}; + +/// Specialization for functions of the form 'void (std::unique_ptr<ErrT>)'. +template <typename ErrT> +class ErrorHandlerTraits<void (&)(std::unique_ptr<ErrT>)> { +public: + static bool appliesTo(const ErrorInfoBase &E) { + return E.template isA<ErrT>(); + } + + template <typename HandlerT> + static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { + assert(appliesTo(*E) && "Applying incorrect handler"); + std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release())); + H(std::move(SubE)); + return Error::success(); + } +}; + +// Specialization for member functions of the form 'RetT (const ErrT&)'. +template <typename C, typename RetT, typename ErrT> +class ErrorHandlerTraits<RetT (C::*)(ErrT &)> + : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; + +// Specialization for member functions of the form 'RetT (const ErrT&) const'. +template <typename C, typename RetT, typename ErrT> +class ErrorHandlerTraits<RetT (C::*)(ErrT &) const> + : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; + +// Specialization for member functions of the form 'RetT (const ErrT&)'. +template <typename C, typename RetT, typename ErrT> +class ErrorHandlerTraits<RetT (C::*)(const ErrT &)> + : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; + +// Specialization for member functions of the form 'RetT (const ErrT&) const'. +template <typename C, typename RetT, typename ErrT> +class ErrorHandlerTraits<RetT (C::*)(const ErrT &) const> + : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; + +/// Specialization for member functions of the form +/// 'RetT (std::unique_ptr<ErrT>)'. +template <typename C, typename RetT, typename ErrT> +class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>)> + : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {}; + +/// Specialization for member functions of the form +/// 'RetT (std::unique_ptr<ErrT>) const'. +template <typename C, typename RetT, typename ErrT> +class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>) const> + : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {}; + +inline Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload) { + return Error(std::move(Payload)); +} + +template <typename HandlerT, typename... HandlerTs> +Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload, + HandlerT &&Handler, HandlerTs &&... Handlers) { + if (ErrorHandlerTraits<HandlerT>::appliesTo(*Payload)) + return ErrorHandlerTraits<HandlerT>::apply(std::forward<HandlerT>(Handler), + std::move(Payload)); + return handleErrorImpl(std::move(Payload), + std::forward<HandlerTs>(Handlers)...); +} + +/// Pass the ErrorInfo(s) contained in E to their respective handlers. Any +/// unhandled errors (or Errors returned by handlers) are re-concatenated and +/// returned. +/// Because this function returns an error, its result must also be checked +/// or returned. If you intend to handle all errors use handleAllErrors +/// (which returns void, and will abort() on unhandled errors) instead. +template <typename... HandlerTs> +Error handleErrors(Error E, HandlerTs &&... Hs) { + if (!E) + return Error::success(); + + std::unique_ptr<ErrorInfoBase> Payload = E.takePayload(); + + if (Payload->isA<ErrorList>()) { + ErrorList &List = static_cast<ErrorList &>(*Payload); + Error R; + for (auto &P : List.Payloads) + R = ErrorList::join( + std::move(R), + handleErrorImpl(std::move(P), std::forward<HandlerTs>(Hs)...)); + return R; + } + + return handleErrorImpl(std::move(Payload), std::forward<HandlerTs>(Hs)...); +} + +/// Behaves the same as handleErrors, except that by contract all errors +/// *must* be handled by the given handlers (i.e. there must be no remaining +/// errors after running the handlers, or llvm_unreachable is called). +template <typename... HandlerTs> +void handleAllErrors(Error E, HandlerTs &&... Handlers) { + cantFail(handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...)); +} + +/// Check that E is a non-error, then drop it. +/// If E is an error, llvm_unreachable will be called. +inline void handleAllErrors(Error E) { + cantFail(std::move(E)); +} + +/// Handle any errors (if present) in an Expected<T>, then try a recovery path. +/// +/// If the incoming value is a success value it is returned unmodified. If it +/// is a failure value then it the contained error is passed to handleErrors. +/// If handleErrors is able to handle the error then the RecoveryPath functor +/// is called to supply the final result. If handleErrors is not able to +/// handle all errors then the unhandled errors are returned. +/// +/// This utility enables the follow pattern: +/// +/// @code{.cpp} +/// enum FooStrategy { Aggressive, Conservative }; +/// Expected<Foo> foo(FooStrategy S); +/// +/// auto ResultOrErr = +/// handleExpected( +/// foo(Aggressive), +/// []() { return foo(Conservative); }, +/// [](AggressiveStrategyError&) { +/// // Implicitly conusme this - we'll recover by using a conservative +/// // strategy. +/// }); +/// +/// @endcode +template <typename T, typename RecoveryFtor, typename... HandlerTs> +Expected<T> handleExpected(Expected<T> ValOrErr, RecoveryFtor &&RecoveryPath, + HandlerTs &&... Handlers) { + if (ValOrErr) + return ValOrErr; + + if (auto Err = handleErrors(ValOrErr.takeError(), + std::forward<HandlerTs>(Handlers)...)) + return std::move(Err); + + return RecoveryPath(); +} + +/// Log all errors (if any) in E to OS. If there are any errors, ErrorBanner +/// will be printed before the first one is logged. A newline will be printed +/// after each error. +/// +/// This function is compatible with the helpers from Support/WithColor.h. You +/// can pass any of them as the OS. Please consider using them instead of +/// including 'error: ' in the ErrorBanner. +/// +/// This is useful in the base level of your program to allow clean termination +/// (allowing clean deallocation of resources, etc.), while reporting error +/// information to the user. +void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner = {}); + +/// Write all error messages (if any) in E to a string. The newline character +/// is used to separate error messages. +inline std::string toString(Error E) { + SmallVector<std::string, 2> Errors; + handleAllErrors(std::move(E), [&Errors](const ErrorInfoBase &EI) { + Errors.push_back(EI.message()); + }); + return join(Errors.begin(), Errors.end(), "\n"); +} + +/// Consume a Error without doing anything. This method should be used +/// only where an error can be considered a reasonable and expected return +/// value. +/// +/// Uses of this method are potentially indicative of design problems: If it's +/// legitimate to do nothing while processing an "error", the error-producer +/// might be more clearly refactored to return an Optional<T>. +inline void consumeError(Error Err) { + handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {}); +} + +/// Convert an Expected to an Optional without doing anything. This method +/// should be used only where an error can be considered a reasonable and +/// expected return value. +/// +/// Uses of this method are potentially indicative of problems: perhaps the +/// error should be propagated further, or the error-producer should just +/// return an Optional in the first place. +template <typename T> Optional<T> expectedToOptional(Expected<T> &&E) { + if (E) + return std::move(*E); + consumeError(E.takeError()); + return None; +} + +/// Helper for converting an Error to a bool. +/// +/// This method returns true if Err is in an error state, or false if it is +/// in a success state. Puts Err in a checked state in both cases (unlike +/// Error::operator bool(), which only does this for success states). +inline bool errorToBool(Error Err) { + bool IsError = static_cast<bool>(Err); + if (IsError) + consumeError(std::move(Err)); + return IsError; +} + +/// Helper for Errors used as out-parameters. +/// +/// This helper is for use with the Error-as-out-parameter idiom, where an error +/// is passed to a function or method by reference, rather than being returned. +/// In such cases it is helpful to set the checked bit on entry to the function +/// so that the error can be written to (unchecked Errors abort on assignment) +/// and clear the checked bit on exit so that clients cannot accidentally forget +/// to check the result. This helper performs these actions automatically using +/// RAII: +/// +/// @code{.cpp} +/// Result foo(Error &Err) { +/// ErrorAsOutParameter ErrAsOutParam(&Err); // 'Checked' flag set +/// // <body of foo> +/// // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed. +/// } +/// @endcode +/// +/// ErrorAsOutParameter takes an Error* rather than Error& so that it can be +/// used with optional Errors (Error pointers that are allowed to be null). If +/// ErrorAsOutParameter took an Error reference, an instance would have to be +/// created inside every condition that verified that Error was non-null. By +/// taking an Error pointer we can just create one instance at the top of the +/// function. +class ErrorAsOutParameter { +public: + ErrorAsOutParameter(Error *Err) : Err(Err) { + // Raise the checked bit if Err is success. + if (Err) + (void)!!*Err; + } + + ~ErrorAsOutParameter() { + // Clear the checked bit. + if (Err && !*Err) + *Err = Error::success(); + } + +private: + Error *Err; +}; + +/// Helper for Expected<T>s used as out-parameters. +/// +/// See ErrorAsOutParameter. +template <typename T> +class ExpectedAsOutParameter { +public: + ExpectedAsOutParameter(Expected<T> *ValOrErr) + : ValOrErr(ValOrErr) { + if (ValOrErr) + (void)!!*ValOrErr; + } + + ~ExpectedAsOutParameter() { + if (ValOrErr) + ValOrErr->setUnchecked(); + } + +private: + Expected<T> *ValOrErr; +}; + +/// This class wraps a std::error_code in a Error. +/// +/// This is useful if you're writing an interface that returns a Error +/// (or Expected) and you want to call code that still returns +/// std::error_codes. +class ECError : public ErrorInfo<ECError> { + friend Error errorCodeToError(std::error_code); + + virtual void anchor() override; + +public: + void setErrorCode(std::error_code EC) { this->EC = EC; } + std::error_code convertToErrorCode() const override { return EC; } + void log(raw_ostream &OS) const override { OS << EC.message(); } + + // Used by ErrorInfo::classID. + static char ID; + +protected: + ECError() = default; + ECError(std::error_code EC) : EC(EC) {} + + std::error_code EC; +}; + +/// The value returned by this function can be returned from convertToErrorCode +/// for Error values where no sensible translation to std::error_code exists. +/// It should only be used in this situation, and should never be used where a +/// sensible conversion to std::error_code is available, as attempts to convert +/// to/from this error will result in a fatal error. (i.e. it is a programmatic +///error to try to convert such a value). +std::error_code inconvertibleErrorCode(); + +/// Helper for converting an std::error_code to a Error. +Error errorCodeToError(std::error_code EC); + +/// Helper for converting an ECError to a std::error_code. +/// +/// This method requires that Err be Error() or an ECError, otherwise it +/// will trigger a call to abort(). +std::error_code errorToErrorCode(Error Err); + +/// Convert an ErrorOr<T> to an Expected<T>. +template <typename T> Expected<T> errorOrToExpected(ErrorOr<T> &&EO) { + if (auto EC = EO.getError()) + return errorCodeToError(EC); + return std::move(*EO); +} + +/// Convert an Expected<T> to an ErrorOr<T>. +template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> &&E) { + if (auto Err = E.takeError()) + return errorToErrorCode(std::move(Err)); + return std::move(*E); +} + +/// This class wraps a string in an Error. +/// +/// StringError is useful in cases where the client is not expected to be able +/// to consume the specific error message programmatically (for example, if the +/// error message is to be presented to the user). +/// +/// StringError can also be used when additional information is to be printed +/// along with a error_code message. Depending on the constructor called, this +/// class can either display: +/// 1. the error_code message (ECError behavior) +/// 2. a string +/// 3. the error_code message and a string +/// +/// These behaviors are useful when subtyping is required; for example, when a +/// specific library needs an explicit error type. In the example below, +/// PDBError is derived from StringError: +/// +/// @code{.cpp} +/// Expected<int> foo() { +/// return llvm::make_error<PDBError>(pdb_error_code::dia_failed_loading, +/// "Additional information"); +/// } +/// @endcode +/// +class StringError : public ErrorInfo<StringError> { +public: + static char ID; + + // Prints EC + S and converts to EC + StringError(std::error_code EC, const Twine &S = Twine()); + + // Prints S and converts to EC + StringError(const Twine &S, std::error_code EC); + + void log(raw_ostream &OS) const override; + std::error_code convertToErrorCode() const override; + + const std::string &getMessage() const { return Msg; } + +private: + std::string Msg; + std::error_code EC; + const bool PrintMsgOnly = false; +}; + +/// Create formatted StringError object. +template <typename... Ts> +inline Error createStringError(std::error_code EC, char const *Fmt, + const Ts &... Vals) { + std::string Buffer; + raw_string_ostream Stream(Buffer); + Stream << format(Fmt, Vals...); + return make_error<StringError>(Stream.str(), EC); +} + +Error createStringError(std::error_code EC, char const *Msg); + +inline Error createStringError(std::error_code EC, const Twine &S) { + return createStringError(EC, S.str().c_str()); +} + +template <typename... Ts> +inline Error createStringError(std::errc EC, char const *Fmt, + const Ts &... Vals) { + return createStringError(std::make_error_code(EC), Fmt, Vals...); +} + +/// This class wraps a filename and another Error. +/// +/// In some cases, an error needs to live along a 'source' name, in order to +/// show more detailed information to the user. +class FileError final : public ErrorInfo<FileError> { + + friend Error createFileError(const Twine &, Error); + friend Error createFileError(const Twine &, size_t, Error); + +public: + void log(raw_ostream &OS) const override { + assert(Err && !FileName.empty() && "Trying to log after takeError()."); + OS << "'" << FileName << "': "; + if (Line.hasValue()) + OS << "line " << Line.getValue() << ": "; + Err->log(OS); + } + + Error takeError() { return Error(std::move(Err)); } + + std::error_code convertToErrorCode() const override; + + // Used by ErrorInfo::classID. + static char ID; + +private: + FileError(const Twine &F, Optional<size_t> LineNum, + std::unique_ptr<ErrorInfoBase> E) { + assert(E && "Cannot create FileError from Error success value."); + assert(!F.isTriviallyEmpty() && + "The file name provided to FileError must not be empty."); + FileName = F.str(); + Err = std::move(E); + Line = std::move(LineNum); + } + + static Error build(const Twine &F, Optional<size_t> Line, Error E) { + return Error( + std::unique_ptr<FileError>(new FileError(F, Line, E.takePayload()))); + } + + std::string FileName; + Optional<size_t> Line; + std::unique_ptr<ErrorInfoBase> Err; +}; + +/// Concatenate a source file path and/or name with an Error. The resulting +/// Error is unchecked. +inline Error createFileError(const Twine &F, Error E) { + return FileError::build(F, Optional<size_t>(), std::move(E)); +} + +/// Concatenate a source file path and/or name with line number and an Error. +/// The resulting Error is unchecked. +inline Error createFileError(const Twine &F, size_t Line, Error E) { + return FileError::build(F, Optional<size_t>(Line), std::move(E)); +} + +/// Concatenate a source file path and/or name with a std::error_code +/// to form an Error object. +inline Error createFileError(const Twine &F, std::error_code EC) { + return createFileError(F, errorCodeToError(EC)); +} + +/// Concatenate a source file path and/or name with line number and +/// std::error_code to form an Error object. +inline Error createFileError(const Twine &F, size_t Line, std::error_code EC) { + return createFileError(F, Line, errorCodeToError(EC)); +} + +Error createFileError(const Twine &F, ErrorSuccess) = delete; + +/// Helper for check-and-exit error handling. +/// +/// For tool use only. NOT FOR USE IN LIBRARY CODE. +/// +class ExitOnError { +public: + /// Create an error on exit helper. + ExitOnError(std::string Banner = "", int DefaultErrorExitCode = 1) + : Banner(std::move(Banner)), + GetExitCode([=](const Error &) { return DefaultErrorExitCode; }) {} + + /// Set the banner string for any errors caught by operator(). + void setBanner(std::string Banner) { this->Banner = std::move(Banner); } + + /// Set the exit-code mapper function. + void setExitCodeMapper(std::function<int(const Error &)> GetExitCode) { + this->GetExitCode = std::move(GetExitCode); + } + + /// Check Err. If it's in a failure state log the error(s) and exit. + void operator()(Error Err) const { checkError(std::move(Err)); } + + /// Check E. If it's in a success state then return the contained value. If + /// it's in a failure state log the error(s) and exit. + template <typename T> T operator()(Expected<T> &&E) const { + checkError(E.takeError()); + return std::move(*E); + } + + /// Check E. If it's in a success state then return the contained reference. If + /// it's in a failure state log the error(s) and exit. + template <typename T> T& operator()(Expected<T&> &&E) const { + checkError(E.takeError()); + return *E; + } + +private: + void checkError(Error Err) const { + if (Err) { + int ExitCode = GetExitCode(Err); + logAllUnhandledErrors(std::move(Err), errs(), Banner); + exit(ExitCode); + } + } + + std::string Banner; + std::function<int(const Error &)> GetExitCode; +}; + +/// Conversion from Error to LLVMErrorRef for C error bindings. +inline LLVMErrorRef wrap(Error Err) { + return reinterpret_cast<LLVMErrorRef>(Err.takePayload().release()); +} + +/// Conversion from LLVMErrorRef to Error for C error bindings. +inline Error unwrap(LLVMErrorRef ErrRef) { + return Error(std::unique_ptr<ErrorInfoBase>( + reinterpret_cast<ErrorInfoBase *>(ErrRef))); +} + +} // end namespace llvm + +#endif // LLVM_SUPPORT_ERROR_H diff --git a/third_party/llvm-project/include/llvm/Support/ErrorHandling.h b/third_party/llvm-project/include/llvm/Support/ErrorHandling.h new file mode 100644 index 000000000..f75c2984a --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/ErrorHandling.h @@ -0,0 +1,143 @@ +//===- llvm/Support/ErrorHandling.h - Fatal error handling ------*- 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 defines an API used to indicate fatal error conditions. Non-fatal +// errors (most of them) should be handled through LLVMContext. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ERRORHANDLING_H +#define LLVM_SUPPORT_ERRORHANDLING_H + +#include "llvm/Support/Compiler.h" +#include <string> + +namespace llvm { +class StringRef; + class Twine; + + /// An error handler callback. + typedef void (*fatal_error_handler_t)(void *user_data, + const std::string& reason, + bool gen_crash_diag); + + /// install_fatal_error_handler - Installs a new error handler to be used + /// whenever a serious (non-recoverable) error is encountered by LLVM. + /// + /// If no error handler is installed the default is to print the error message + /// to stderr, and call exit(1). If an error handler is installed then it is + /// the handler's responsibility to log the message, it will no longer be + /// printed to stderr. If the error handler returns, then exit(1) will be + /// called. + /// + /// It is dangerous to naively use an error handler which throws an exception. + /// Even though some applications desire to gracefully recover from arbitrary + /// faults, blindly throwing exceptions through unfamiliar code isn't a way to + /// achieve this. + /// + /// \param user_data - An argument which will be passed to the install error + /// handler. + void install_fatal_error_handler(fatal_error_handler_t handler, + void *user_data = nullptr); + + /// Restores default error handling behaviour. + void remove_fatal_error_handler(); + + /// ScopedFatalErrorHandler - This is a simple helper class which just + /// calls install_fatal_error_handler in its constructor and + /// remove_fatal_error_handler in its destructor. + struct ScopedFatalErrorHandler { + explicit ScopedFatalErrorHandler(fatal_error_handler_t handler, + void *user_data = nullptr) { + install_fatal_error_handler(handler, user_data); + } + + ~ScopedFatalErrorHandler() { remove_fatal_error_handler(); } + }; + +/// Reports a serious error, calling any installed error handler. These +/// functions are intended to be used for error conditions which are outside +/// the control of the compiler (I/O errors, invalid user input, etc.) +/// +/// If no error handler is installed the default is to print the message to +/// standard error, followed by a newline. +/// After the error handler is called this function will call exit(1), it +/// does not return. +LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason, + bool gen_crash_diag = true); +LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const std::string &reason, + bool gen_crash_diag = true); +LLVM_ATTRIBUTE_NORETURN void report_fatal_error(StringRef reason, + bool gen_crash_diag = true); +LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const Twine &reason, + bool gen_crash_diag = true); + +/// Installs a new bad alloc error handler that should be used whenever a +/// bad alloc error, e.g. failing malloc/calloc, is encountered by LLVM. +/// +/// The user can install a bad alloc handler, in order to define the behavior +/// in case of failing allocations, e.g. throwing an exception. Note that this +/// handler must not trigger any additional allocations itself. +/// +/// If no error handler is installed the default is to print the error message +/// to stderr, and call exit(1). If an error handler is installed then it is +/// the handler's responsibility to log the message, it will no longer be +/// printed to stderr. If the error handler returns, then exit(1) will be +/// called. +/// +/// +/// \param user_data - An argument which will be passed to the installed error +/// handler. +void install_bad_alloc_error_handler(fatal_error_handler_t handler, + void *user_data = nullptr); + +/// Restores default bad alloc error handling behavior. +void remove_bad_alloc_error_handler(); + +void install_out_of_memory_new_handler(); + +/// Reports a bad alloc error, calling any user defined bad alloc +/// error handler. In contrast to the generic 'report_fatal_error' +/// functions, this function is expected to return, e.g. the user +/// defined error handler throws an exception. +/// +/// Note: When throwing an exception in the bad alloc handler, make sure that +/// the following unwind succeeds, e.g. do not trigger additional allocations +/// in the unwind chain. +/// +/// If no error handler is installed (default), then a bad_alloc exception +/// is thrown, if LLVM is compiled with exception support, otherwise an +/// assertion is called. +void report_bad_alloc_error(const char *Reason, bool GenCrashDiag = true); + +/// This function calls abort(), and prints the optional message to stderr. +/// Use the llvm_unreachable macro (that adds location info), instead of +/// calling this function directly. +LLVM_ATTRIBUTE_NORETURN void +llvm_unreachable_internal(const char *msg = nullptr, const char *file = nullptr, + unsigned line = 0); +} + +/// Marks that the current location is not supposed to be reachable. +/// In !NDEBUG builds, prints the message and location info to stderr. +/// In NDEBUG builds, becomes an optimizer hint that the current location +/// is not supposed to be reachable. On compilers that don't support +/// such hints, prints a reduced message instead. +/// +/// Use this instead of assert(0). It conveys intent more clearly and +/// allows compilers to omit some unnecessary code. +#ifndef NDEBUG +#define llvm_unreachable(msg) \ + ::llvm::llvm_unreachable_internal(msg, __FILE__, __LINE__) +#elif defined(LLVM_BUILTIN_UNREACHABLE) +#define llvm_unreachable(msg) LLVM_BUILTIN_UNREACHABLE +#else +#define llvm_unreachable(msg) ::llvm::llvm_unreachable_internal() +#endif + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/ErrorOr.h b/third_party/llvm-project/include/llvm/Support/ErrorOr.h new file mode 100644 index 000000000..8211f4d8a --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/ErrorOr.h @@ -0,0 +1,278 @@ +//===- llvm/Support/ErrorOr.h - Error Smart Pointer -------------*- 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Provides ErrorOr<T> smart pointer. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ERROROR_H +#define LLVM_SUPPORT_ERROROR_H + +#include "llvm/Support/AlignOf.h" +#include <cassert> +#include <system_error> +#include <type_traits> +#include <utility> + +namespace llvm { + +/// Represents either an error or a value T. +/// +/// ErrorOr<T> is a pointer-like class that represents the result of an +/// operation. The result is either an error, or a value of type T. This is +/// designed to emulate the usage of returning a pointer where nullptr indicates +/// failure. However instead of just knowing that the operation failed, we also +/// have an error_code and optional user data that describes why it failed. +/// +/// It is used like the following. +/// \code +/// ErrorOr<Buffer> getBuffer(); +/// +/// auto buffer = getBuffer(); +/// if (error_code ec = buffer.getError()) +/// return ec; +/// buffer->write("adena"); +/// \endcode +/// +/// +/// Implicit conversion to bool returns true if there is a usable value. The +/// unary * and -> operators provide pointer like access to the value. Accessing +/// the value when there is an error has undefined behavior. +/// +/// When T is a reference type the behavior is slightly different. The reference +/// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and +/// there is special handling to make operator -> work as if T was not a +/// reference. +/// +/// T cannot be a rvalue reference. +template<class T> +class ErrorOr { + template <class OtherT> friend class ErrorOr; + + static const bool isRef = std::is_reference<T>::value; + + using wrap = std::reference_wrapper<typename std::remove_reference<T>::type>; + +public: + using storage_type = typename std::conditional<isRef, wrap, T>::type; + +private: + using reference = typename std::remove_reference<T>::type &; + using const_reference = const typename std::remove_reference<T>::type &; + using pointer = typename std::remove_reference<T>::type *; + using const_pointer = const typename std::remove_reference<T>::type *; + +public: + template <class E> + ErrorOr(E ErrorCode, + typename std::enable_if<std::is_error_code_enum<E>::value || + std::is_error_condition_enum<E>::value, + void *>::type = nullptr) + : HasError(true) { + new (getErrorStorage()) std::error_code(make_error_code(ErrorCode)); + } + + ErrorOr(std::error_code EC) : HasError(true) { + new (getErrorStorage()) std::error_code(EC); + } + + template <class OtherT> + ErrorOr(OtherT &&Val, + typename std::enable_if<std::is_convertible<OtherT, T>::value>::type + * = nullptr) + : HasError(false) { + new (getStorage()) storage_type(std::forward<OtherT>(Val)); + } + + ErrorOr(const ErrorOr &Other) { + copyConstruct(Other); + } + + template <class OtherT> + ErrorOr( + const ErrorOr<OtherT> &Other, + typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * = + nullptr) { + copyConstruct(Other); + } + + template <class OtherT> + explicit ErrorOr( + const ErrorOr<OtherT> &Other, + typename std::enable_if< + !std::is_convertible<OtherT, const T &>::value>::type * = nullptr) { + copyConstruct(Other); + } + + ErrorOr(ErrorOr &&Other) { + moveConstruct(std::move(Other)); + } + + template <class OtherT> + ErrorOr( + ErrorOr<OtherT> &&Other, + typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * = + nullptr) { + moveConstruct(std::move(Other)); + } + + // This might eventually need SFINAE but it's more complex than is_convertible + // & I'm too lazy to write it right now. + template <class OtherT> + explicit ErrorOr( + ErrorOr<OtherT> &&Other, + typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * = + nullptr) { + moveConstruct(std::move(Other)); + } + + ErrorOr &operator=(const ErrorOr &Other) { + copyAssign(Other); + return *this; + } + + ErrorOr &operator=(ErrorOr &&Other) { + moveAssign(std::move(Other)); + return *this; + } + + ~ErrorOr() { + if (!HasError) + getStorage()->~storage_type(); + } + + /// Return false if there is an error. + explicit operator bool() const { + return !HasError; + } + + reference get() { return *getStorage(); } + const_reference get() const { return const_cast<ErrorOr<T> *>(this)->get(); } + + std::error_code getError() const { + return HasError ? *getErrorStorage() : std::error_code(); + } + + pointer operator ->() { + return toPointer(getStorage()); + } + + const_pointer operator->() const { return toPointer(getStorage()); } + + reference operator *() { + return *getStorage(); + } + + const_reference operator*() const { return *getStorage(); } + +private: + template <class OtherT> + void copyConstruct(const ErrorOr<OtherT> &Other) { + if (!Other.HasError) { + // Get the other value. + HasError = false; + new (getStorage()) storage_type(*Other.getStorage()); + } else { + // Get other's error. + HasError = true; + new (getErrorStorage()) std::error_code(Other.getError()); + } + } + + template <class T1> + static bool compareThisIfSameType(const T1 &a, const T1 &b) { + return &a == &b; + } + + template <class T1, class T2> + static bool compareThisIfSameType(const T1 &a, const T2 &b) { + return false; + } + + template <class OtherT> + void copyAssign(const ErrorOr<OtherT> &Other) { + if (compareThisIfSameType(*this, Other)) + return; + + this->~ErrorOr(); + new (this) ErrorOr(Other); + } + + template <class OtherT> + void moveConstruct(ErrorOr<OtherT> &&Other) { + if (!Other.HasError) { + // Get the other value. + HasError = false; + new (getStorage()) storage_type(std::move(*Other.getStorage())); + } else { + // Get other's error. + HasError = true; + new (getErrorStorage()) std::error_code(Other.getError()); + } + } + + template <class OtherT> + void moveAssign(ErrorOr<OtherT> &&Other) { + if (compareThisIfSameType(*this, Other)) + return; + + this->~ErrorOr(); + new (this) ErrorOr(std::move(Other)); + } + + pointer toPointer(pointer Val) { + return Val; + } + + const_pointer toPointer(const_pointer Val) const { return Val; } + + pointer toPointer(wrap *Val) { + return &Val->get(); + } + + const_pointer toPointer(const wrap *Val) const { return &Val->get(); } + + storage_type *getStorage() { + assert(!HasError && "Cannot get value when an error exists!"); + return reinterpret_cast<storage_type*>(TStorage.buffer); + } + + const storage_type *getStorage() const { + assert(!HasError && "Cannot get value when an error exists!"); + return reinterpret_cast<const storage_type*>(TStorage.buffer); + } + + std::error_code *getErrorStorage() { + assert(HasError && "Cannot get error when a value exists!"); + return reinterpret_cast<std::error_code *>(ErrorStorage.buffer); + } + + const std::error_code *getErrorStorage() const { + return const_cast<ErrorOr<T> *>(this)->getErrorStorage(); + } + + union { + AlignedCharArrayUnion<storage_type> TStorage; + AlignedCharArrayUnion<std::error_code> ErrorStorage; + }; + bool HasError : 1; +}; + +template <class T, class E> +typename std::enable_if<std::is_error_code_enum<E>::value || + std::is_error_condition_enum<E>::value, + bool>::type +operator==(const ErrorOr<T> &Err, E Code) { + return Err.getError() == Code; +} + +} // end namespace llvm + +#endif // LLVM_SUPPORT_ERROROR_H diff --git a/third_party/llvm-project/include/llvm/Support/FileOutputBuffer.h b/third_party/llvm-project/include/llvm/Support/FileOutputBuffer.h new file mode 100644 index 000000000..bdc1425d4 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/FileOutputBuffer.h @@ -0,0 +1,88 @@ +//=== FileOutputBuffer.h - File Output Buffer -------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Utility for creating a in-memory buffer that will be written to a file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_FILEOUTPUTBUFFER_H +#define LLVM_SUPPORT_FILEOUTPUTBUFFER_H + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" + +namespace llvm { +/// FileOutputBuffer - This interface provides simple way to create an in-memory +/// buffer which will be written to a file. During the lifetime of these +/// objects, the content or existence of the specified file is undefined. That +/// is, creating an OutputBuffer for a file may immediately remove the file. +/// If the FileOutputBuffer is committed, the target file's content will become +/// the buffer content at the time of the commit. If the FileOutputBuffer is +/// not committed, the file will be deleted in the FileOutputBuffer destructor. +class FileOutputBuffer { +public: + enum { + /// set the 'x' bit on the resulting file + F_executable = 1, + + /// Don't use mmap and instead write an in-memory buffer to a file when this + /// buffer is closed. + F_no_mmap = 2, + }; + + /// Factory method to create an OutputBuffer object which manages a read/write + /// buffer of the specified size. When committed, the buffer will be written + /// to the file at the specified path. + /// + /// When F_modify is specified and \p FilePath refers to an existing on-disk + /// file \p Size may be set to -1, in which case the entire file is used. + /// Otherwise, the file shrinks or grows as necessary based on the value of + /// \p Size. It is an error to specify F_modify and Size=-1 if \p FilePath + /// does not exist. + static Expected<std::unique_ptr<FileOutputBuffer>> + create(StringRef FilePath, size_t Size, unsigned Flags = 0); + + /// Returns a pointer to the start of the buffer. + virtual uint8_t *getBufferStart() const = 0; + + /// Returns a pointer to the end of the buffer. + virtual uint8_t *getBufferEnd() const = 0; + + /// Returns size of the buffer. + virtual size_t getBufferSize() const = 0; + + /// Returns path where file will show up if buffer is committed. + StringRef getPath() const { return FinalPath; } + + /// Flushes the content of the buffer to its file and deallocates the + /// buffer. If commit() is not called before this object's destructor + /// is called, the file is deleted in the destructor. The optional parameter + /// is used if it turns out you want the file size to be smaller than + /// initially requested. + virtual Error commit() = 0; + + /// If this object was previously committed, the destructor just deletes + /// this object. If this object was not committed, the destructor + /// deallocates the buffer and the target file is never written. + virtual ~FileOutputBuffer() {} + + /// This removes the temporary file (unless it already was committed) + /// but keeps the memory mapping alive. + virtual void discard() {} + +protected: + FileOutputBuffer(StringRef Path) : FinalPath(Path) {} + + std::string FinalPath; +}; +} // end namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/FileSystem.h b/third_party/llvm-project/include/llvm/Support/FileSystem.h new file mode 100644 index 000000000..a29a9d787 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/FileSystem.h @@ -0,0 +1,1444 @@ +//===- llvm/Support/FileSystem.h - File System OS Concept -------*- 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 declares the llvm::sys::fs namespace. It is designed after +// TR2/boost filesystem (v3), but modified to remove exception handling and the +// path class. +// +// All functions return an error_code and their actual work via the last out +// argument. The out argument is defined if and only if errc::success is +// returned. A function may return any error code in the generic or system +// category. However, they shall be equivalent to any error conditions listed +// in each functions respective documentation if the condition applies. [ note: +// this does not guarantee that error_code will be in the set of explicitly +// listed codes, but it does guarantee that if any of the explicitly listed +// errors occur, the correct error_code will be used ]. All functions may +// return errc::not_enough_memory if there is not enough memory to complete the +// operation. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_FILESYSTEM_H +#define LLVM_SUPPORT_FILESYSTEM_H + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MD5.h" +#include <cassert> +#include <cstdint> +#include <ctime> +#include <memory> +#include <stack> +#include <string> +#include <system_error> +#include <tuple> +#include <vector> + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +namespace llvm { +namespace sys { +namespace fs { + +#if defined(_WIN32) +// A Win32 HANDLE is a typedef of void* +using file_t = void *; +#else +using file_t = int; +#endif + +extern const file_t kInvalidFile; + +/// An enumeration for the file system's view of the type. +enum class file_type { + status_error, + file_not_found, + regular_file, + directory_file, + symlink_file, + block_file, + character_file, + fifo_file, + socket_file, + type_unknown +}; + +/// space_info - Self explanatory. +struct space_info { + uint64_t capacity; + uint64_t free; + uint64_t available; +}; + +enum perms { + no_perms = 0, + owner_read = 0400, + owner_write = 0200, + owner_exe = 0100, + owner_all = owner_read | owner_write | owner_exe, + group_read = 040, + group_write = 020, + group_exe = 010, + group_all = group_read | group_write | group_exe, + others_read = 04, + others_write = 02, + others_exe = 01, + others_all = others_read | others_write | others_exe, + all_read = owner_read | group_read | others_read, + all_write = owner_write | group_write | others_write, + all_exe = owner_exe | group_exe | others_exe, + all_all = owner_all | group_all | others_all, + set_uid_on_exe = 04000, + set_gid_on_exe = 02000, + sticky_bit = 01000, + all_perms = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit, + perms_not_known = 0xFFFF +}; + +// Helper functions so that you can use & and | to manipulate perms bits: +inline perms operator|(perms l, perms r) { + return static_cast<perms>(static_cast<unsigned short>(l) | + static_cast<unsigned short>(r)); +} +inline perms operator&(perms l, perms r) { + return static_cast<perms>(static_cast<unsigned short>(l) & + static_cast<unsigned short>(r)); +} +inline perms &operator|=(perms &l, perms r) { + l = l | r; + return l; +} +inline perms &operator&=(perms &l, perms r) { + l = l & r; + return l; +} +inline perms operator~(perms x) { + // Avoid UB by explicitly truncating the (unsigned) ~ result. + return static_cast<perms>( + static_cast<unsigned short>(~static_cast<unsigned short>(x))); +} + +class UniqueID { + uint64_t Device; + uint64_t File; + +public: + UniqueID() = default; + UniqueID(uint64_t Device, uint64_t File) : Device(Device), File(File) {} + + bool operator==(const UniqueID &Other) const { + return Device == Other.Device && File == Other.File; + } + bool operator!=(const UniqueID &Other) const { return !(*this == Other); } + bool operator<(const UniqueID &Other) const { + return std::tie(Device, File) < std::tie(Other.Device, Other.File); + } + + uint64_t getDevice() const { return Device; } + uint64_t getFile() const { return File; } +}; + +/// Represents the result of a call to directory_iterator::status(). This is a +/// subset of the information returned by a regular sys::fs::status() call, and +/// represents the information provided by Windows FileFirstFile/FindNextFile. +class basic_file_status { +protected: + #if defined(LLVM_ON_UNIX) + time_t fs_st_atime = 0; + time_t fs_st_mtime = 0; + uint32_t fs_st_atime_nsec = 0; + uint32_t fs_st_mtime_nsec = 0; + uid_t fs_st_uid = 0; + gid_t fs_st_gid = 0; + off_t fs_st_size = 0; + #elif defined (_WIN32) + uint32_t LastAccessedTimeHigh = 0; + uint32_t LastAccessedTimeLow = 0; + uint32_t LastWriteTimeHigh = 0; + uint32_t LastWriteTimeLow = 0; + uint32_t FileSizeHigh = 0; + uint32_t FileSizeLow = 0; + #endif + file_type Type = file_type::status_error; + perms Perms = perms_not_known; + +public: + basic_file_status() = default; + + explicit basic_file_status(file_type Type) : Type(Type) {} + + #if defined(LLVM_ON_UNIX) + basic_file_status(file_type Type, perms Perms, time_t ATime, + uint32_t ATimeNSec, time_t MTime, uint32_t MTimeNSec, + uid_t UID, gid_t GID, off_t Size) + : fs_st_atime(ATime), fs_st_mtime(MTime), + fs_st_atime_nsec(ATimeNSec), fs_st_mtime_nsec(MTimeNSec), + fs_st_uid(UID), fs_st_gid(GID), + fs_st_size(Size), Type(Type), Perms(Perms) {} +#elif defined(_WIN32) + basic_file_status(file_type Type, perms Perms, uint32_t LastAccessTimeHigh, + uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh, + uint32_t LastWriteTimeLow, uint32_t FileSizeHigh, + uint32_t FileSizeLow) + : LastAccessedTimeHigh(LastAccessTimeHigh), + LastAccessedTimeLow(LastAccessTimeLow), + LastWriteTimeHigh(LastWriteTimeHigh), + LastWriteTimeLow(LastWriteTimeLow), FileSizeHigh(FileSizeHigh), + FileSizeLow(FileSizeLow), Type(Type), Perms(Perms) {} + #endif + + // getters + file_type type() const { return Type; } + perms permissions() const { return Perms; } + + /// The file access time as reported from the underlying file system. + /// + /// Also see comments on \c getLastModificationTime() related to the precision + /// of the returned value. + TimePoint<> getLastAccessedTime() const; + + /// The file modification time as reported from the underlying file system. + /// + /// The returned value allows for nanosecond precision but the actual + /// resolution is an implementation detail of the underlying file system. + /// There is no guarantee for what kind of resolution you can expect, the + /// resolution can differ across platforms and even across mountpoints on the + /// same machine. + TimePoint<> getLastModificationTime() const; + + #if defined(LLVM_ON_UNIX) + uint32_t getUser() const { return fs_st_uid; } + uint32_t getGroup() const { return fs_st_gid; } + uint64_t getSize() const { return fs_st_size; } + #elif defined (_WIN32) + uint32_t getUser() const { + return 9999; // Not applicable to Windows, so... + } + + uint32_t getGroup() const { + return 9999; // Not applicable to Windows, so... + } + + uint64_t getSize() const { + return (uint64_t(FileSizeHigh) << 32) + FileSizeLow; + } + #endif + + // setters + void type(file_type v) { Type = v; } + void permissions(perms p) { Perms = p; } +}; + +/// Represents the result of a call to sys::fs::status(). +class file_status : public basic_file_status { + friend bool equivalent(file_status A, file_status B); + + #if defined(LLVM_ON_UNIX) + dev_t fs_st_dev = 0; + nlink_t fs_st_nlinks = 0; + ino_t fs_st_ino = 0; + #elif defined (_WIN32) + uint32_t NumLinks = 0; + uint32_t VolumeSerialNumber = 0; + uint32_t FileIndexHigh = 0; + uint32_t FileIndexLow = 0; + #endif + +public: + file_status() = default; + + explicit file_status(file_type Type) : basic_file_status(Type) {} + + #if defined(LLVM_ON_UNIX) + file_status(file_type Type, perms Perms, dev_t Dev, nlink_t Links, ino_t Ino, + time_t ATime, uint32_t ATimeNSec, + time_t MTime, uint32_t MTimeNSec, + uid_t UID, gid_t GID, off_t Size) + : basic_file_status(Type, Perms, ATime, ATimeNSec, MTime, MTimeNSec, + UID, GID, Size), + fs_st_dev(Dev), fs_st_nlinks(Links), fs_st_ino(Ino) {} + #elif defined(_WIN32) + file_status(file_type Type, perms Perms, uint32_t LinkCount, + uint32_t LastAccessTimeHigh, uint32_t LastAccessTimeLow, + uint32_t LastWriteTimeHigh, uint32_t LastWriteTimeLow, + uint32_t VolumeSerialNumber, uint32_t FileSizeHigh, + uint32_t FileSizeLow, uint32_t FileIndexHigh, + uint32_t FileIndexLow) + : basic_file_status(Type, Perms, LastAccessTimeHigh, LastAccessTimeLow, + LastWriteTimeHigh, LastWriteTimeLow, FileSizeHigh, + FileSizeLow), + NumLinks(LinkCount), VolumeSerialNumber(VolumeSerialNumber), + FileIndexHigh(FileIndexHigh), FileIndexLow(FileIndexLow) {} + #endif + + UniqueID getUniqueID() const; + uint32_t getLinkCount() const; +}; + +/// @} +/// @name Physical Operators +/// @{ + +/// Make \a path an absolute path. +/// +/// Makes \a path absolute using the \a current_directory if it is not already. +/// An empty \a path will result in the \a current_directory. +/// +/// /absolute/path => /absolute/path +/// relative/../path => <current-directory>/relative/../path +/// +/// @param path A path that is modified to be an absolute path. +void make_absolute(const Twine ¤t_directory, SmallVectorImpl<char> &path); + +/// Make \a path an absolute path. +/// +/// Makes \a path absolute using the current directory if it is not already. An +/// empty \a path will result in the current directory. +/// +/// /absolute/path => /absolute/path +/// relative/../path => <current-directory>/relative/../path +/// +/// @param path A path that is modified to be an absolute path. +/// @returns errc::success if \a path has been made absolute, otherwise a +/// platform-specific error_code. +std::error_code make_absolute(SmallVectorImpl<char> &path); + +/// Create all the non-existent directories in path. +/// +/// @param path Directories to create. +/// @returns errc::success if is_directory(path), otherwise a platform +/// specific error_code. If IgnoreExisting is false, also returns +/// error if the directory already existed. +std::error_code create_directories(const Twine &path, + bool IgnoreExisting = true, + perms Perms = owner_all | group_all); + +/// Create the directory in path. +/// +/// @param path Directory to create. +/// @returns errc::success if is_directory(path), otherwise a platform +/// specific error_code. If IgnoreExisting is false, also returns +/// error if the directory already existed. +std::error_code create_directory(const Twine &path, bool IgnoreExisting = true, + perms Perms = owner_all | group_all); + +/// Create a link from \a from to \a to. +/// +/// The link may be a soft or a hard link, depending on the platform. The caller +/// may not assume which one. Currently on windows it creates a hard link since +/// soft links require extra privileges. On unix, it creates a soft link since +/// hard links don't work on SMB file systems. +/// +/// @param to The path to hard link to. +/// @param from The path to hard link from. This is created. +/// @returns errc::success if the link was created, otherwise a platform +/// specific error_code. +std::error_code create_link(const Twine &to, const Twine &from); + +/// Create a hard link from \a from to \a to, or return an error. +/// +/// @param to The path to hard link to. +/// @param from The path to hard link from. This is created. +/// @returns errc::success if the link was created, otherwise a platform +/// specific error_code. +std::error_code create_hard_link(const Twine &to, const Twine &from); + +/// Collapse all . and .. patterns, resolve all symlinks, and optionally +/// expand ~ expressions to the user's home directory. +/// +/// @param path The path to resolve. +/// @param output The location to store the resolved path. +/// @param expand_tilde If true, resolves ~ expressions to the user's home +/// directory. +std::error_code real_path(const Twine &path, SmallVectorImpl<char> &output, + bool expand_tilde = false); + +/// Expands ~ expressions to the user's home directory. On Unix ~user +/// directories are resolved as well. +/// +/// @param path The path to resolve. +void expand_tilde(const Twine &path, SmallVectorImpl<char> &output); + +/// Get the current path. +/// +/// @param result Holds the current path on return. +/// @returns errc::success if the current path has been stored in result, +/// otherwise a platform-specific error_code. +std::error_code current_path(SmallVectorImpl<char> &result); + +/// Set the current path. +/// +/// @param path The path to set. +/// @returns errc::success if the current path was successfully set, +/// otherwise a platform-specific error_code. +std::error_code set_current_path(const Twine &path); + +/// Remove path. Equivalent to POSIX remove(). +/// +/// @param path Input path. +/// @returns errc::success if path has been removed or didn't exist, otherwise a +/// platform-specific error code. If IgnoreNonExisting is false, also +/// returns error if the file didn't exist. +std::error_code remove(const Twine &path, bool IgnoreNonExisting = true); + +/// Recursively delete a directory. +/// +/// @param path Input path. +/// @returns errc::success if path has been removed or didn't exist, otherwise a +/// platform-specific error code. +std::error_code remove_directories(const Twine &path, bool IgnoreErrors = true); + +/// Rename \a from to \a to. +/// +/// Files are renamed as if by POSIX rename(), except that on Windows there may +/// be a short interval of time during which the destination file does not +/// exist. +/// +/// @param from The path to rename from. +/// @param to The path to rename to. This is created. +std::error_code rename(const Twine &from, const Twine &to); + +/// Copy the contents of \a From to \a To. +/// +/// @param From The path to copy from. +/// @param To The path to copy to. This is created. +std::error_code copy_file(const Twine &From, const Twine &To); + +/// Copy the contents of \a From to \a To. +/// +/// @param From The path to copy from. +/// @param ToFD The open file descriptor of the destination file. +std::error_code copy_file(const Twine &From, int ToFD); + +/// Resize path to size. File is resized as if by POSIX truncate(). +/// +/// @param FD Input file descriptor. +/// @param Size Size to resize to. +/// @returns errc::success if \a path has been resized to \a size, otherwise a +/// platform-specific error_code. +std::error_code resize_file(int FD, uint64_t Size); + +/// Compute an MD5 hash of a file's contents. +/// +/// @param FD Input file descriptor. +/// @returns An MD5Result with the hash computed, if successful, otherwise a +/// std::error_code. +ErrorOr<MD5::MD5Result> md5_contents(int FD); + +/// Version of compute_md5 that doesn't require an open file descriptor. +ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path); + +/// @} +/// @name Physical Observers +/// @{ + +/// Does file exist? +/// +/// @param status A basic_file_status previously returned from stat. +/// @returns True if the file represented by status exists, false if it does +/// not. +bool exists(const basic_file_status &status); + +enum class AccessMode { Exist, Write, Execute }; + +/// Can the file be accessed? +/// +/// @param Path Input path. +/// @returns errc::success if the path can be accessed, otherwise a +/// platform-specific error_code. +std::error_code access(const Twine &Path, AccessMode Mode); + +/// Does file exist? +/// +/// @param Path Input path. +/// @returns True if it exists, false otherwise. +inline bool exists(const Twine &Path) { + return !access(Path, AccessMode::Exist); +} + +/// Can we execute this file? +/// +/// @param Path Input path. +/// @returns True if we can execute it, false otherwise. +bool can_execute(const Twine &Path); + +/// Can we write this file? +/// +/// @param Path Input path. +/// @returns True if we can write to it, false otherwise. +inline bool can_write(const Twine &Path) { + return !access(Path, AccessMode::Write); +} + +/// Do file_status's represent the same thing? +/// +/// @param A Input file_status. +/// @param B Input file_status. +/// +/// assert(status_known(A) || status_known(B)); +/// +/// @returns True if A and B both represent the same file system entity, false +/// otherwise. +bool equivalent(file_status A, file_status B); + +/// Do paths represent the same thing? +/// +/// assert(status_known(A) || status_known(B)); +/// +/// @param A Input path A. +/// @param B Input path B. +/// @param result Set to true if stat(A) and stat(B) have the same device and +/// inode (or equivalent). +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +std::error_code equivalent(const Twine &A, const Twine &B, bool &result); + +/// Simpler version of equivalent for clients that don't need to +/// differentiate between an error and false. +inline bool equivalent(const Twine &A, const Twine &B) { + bool result; + return !equivalent(A, B, result) && result; +} + +/// Is the file mounted on a local filesystem? +/// +/// @param path Input path. +/// @param result Set to true if \a path is on fixed media such as a hard disk, +/// false if it is not. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +std::error_code is_local(const Twine &path, bool &result); + +/// Version of is_local accepting an open file descriptor. +std::error_code is_local(int FD, bool &result); + +/// Simpler version of is_local for clients that don't need to +/// differentiate between an error and false. +inline bool is_local(const Twine &Path) { + bool Result; + return !is_local(Path, Result) && Result; +} + +/// Simpler version of is_local accepting an open file descriptor for +/// clients that don't need to differentiate between an error and false. +inline bool is_local(int FD) { + bool Result; + return !is_local(FD, Result) && Result; +} + +/// Does status represent a directory? +/// +/// @param Path The path to get the type of. +/// @param Follow For symbolic links, indicates whether to return the file type +/// of the link itself, or of the target. +/// @returns A value from the file_type enumeration indicating the type of file. +file_type get_file_type(const Twine &Path, bool Follow = true); + +/// Does status represent a directory? +/// +/// @param status A basic_file_status previously returned from status. +/// @returns status.type() == file_type::directory_file. +bool is_directory(const basic_file_status &status); + +/// Is path a directory? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a directory (after following +/// symlinks, false if it is not. Undefined otherwise. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +std::error_code is_directory(const Twine &path, bool &result); + +/// Simpler version of is_directory for clients that don't need to +/// differentiate between an error and false. +inline bool is_directory(const Twine &Path) { + bool Result; + return !is_directory(Path, Result) && Result; +} + +/// Does status represent a regular file? +/// +/// @param status A basic_file_status previously returned from status. +/// @returns status_known(status) && status.type() == file_type::regular_file. +bool is_regular_file(const basic_file_status &status); + +/// Is path a regular file? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a regular file (after following +/// symlinks), false if it is not. Undefined otherwise. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +std::error_code is_regular_file(const Twine &path, bool &result); + +/// Simpler version of is_regular_file for clients that don't need to +/// differentiate between an error and false. +inline bool is_regular_file(const Twine &Path) { + bool Result; + if (is_regular_file(Path, Result)) + return false; + return Result; +} + +/// Does status represent a symlink file? +/// +/// @param status A basic_file_status previously returned from status. +/// @returns status_known(status) && status.type() == file_type::symlink_file. +bool is_symlink_file(const basic_file_status &status); + +/// Is path a symlink file? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a symlink file, false if it is not. +/// Undefined otherwise. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +std::error_code is_symlink_file(const Twine &path, bool &result); + +/// Simpler version of is_symlink_file for clients that don't need to +/// differentiate between an error and false. +inline bool is_symlink_file(const Twine &Path) { + bool Result; + if (is_symlink_file(Path, Result)) + return false; + return Result; +} + +/// Does this status represent something that exists but is not a +/// directory or regular file? +/// +/// @param status A basic_file_status previously returned from status. +/// @returns exists(s) && !is_regular_file(s) && !is_directory(s) +bool is_other(const basic_file_status &status); + +/// Is path something that exists but is not a directory, +/// regular file, or symlink? +/// +/// @param path Input path. +/// @param result Set to true if \a path exists, but is not a directory, regular +/// file, or a symlink, false if it does not. Undefined otherwise. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +std::error_code is_other(const Twine &path, bool &result); + +/// Get file status as if by POSIX stat(). +/// +/// @param path Input path. +/// @param result Set to the file status. +/// @param follow When true, follows symlinks. Otherwise, the symlink itself is +/// statted. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +std::error_code status(const Twine &path, file_status &result, + bool follow = true); + +/// A version for when a file descriptor is already available. +std::error_code status(int FD, file_status &Result); + +#ifdef _WIN32 +/// A version for when a file descriptor is already available. +std::error_code status(file_t FD, file_status &Result); +#endif + +/// Get file creation mode mask of the process. +/// +/// @returns Mask reported by umask(2) +/// @note There is no umask on Windows. This function returns 0 always +/// on Windows. This function does not return an error_code because +/// umask(2) never fails. It is not thread safe. +unsigned getUmask(); + +/// Set file permissions. +/// +/// @param Path File to set permissions on. +/// @param Permissions New file permissions. +/// @returns errc::success if the permissions were successfully set, otherwise +/// a platform-specific error_code. +/// @note On Windows, all permissions except *_write are ignored. Using any of +/// owner_write, group_write, or all_write will make the file writable. +/// Otherwise, the file will be marked as read-only. +std::error_code setPermissions(const Twine &Path, perms Permissions); + +/// Vesion of setPermissions accepting a file descriptor. +/// TODO Delete the path based overload once we implement the FD based overload +/// on Windows. +std::error_code setPermissions(int FD, perms Permissions); + +/// Get file permissions. +/// +/// @param Path File to get permissions from. +/// @returns the permissions if they were successfully retrieved, otherwise a +/// platform-specific error_code. +/// @note On Windows, if the file does not have the FILE_ATTRIBUTE_READONLY +/// attribute, all_all will be returned. Otherwise, all_read | all_exe +/// will be returned. +ErrorOr<perms> getPermissions(const Twine &Path); + +/// Get file size. +/// +/// @param Path Input path. +/// @param Result Set to the size of the file in \a Path. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +inline std::error_code file_size(const Twine &Path, uint64_t &Result) { + file_status Status; + std::error_code EC = status(Path, Status); + if (EC) + return EC; + Result = Status.getSize(); + return std::error_code(); +} + +/// Set the file modification and access time. +/// +/// @returns errc::success if the file times were successfully set, otherwise a +/// platform-specific error_code or errc::function_not_supported on +/// platforms where the functionality isn't available. +std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, + TimePoint<> ModificationTime); + +/// Simpler version that sets both file modification and access time to the same +/// time. +inline std::error_code setLastAccessAndModificationTime(int FD, + TimePoint<> Time) { + return setLastAccessAndModificationTime(FD, Time, Time); +} + +/// Is status available? +/// +/// @param s Input file status. +/// @returns True if status() != status_error. +bool status_known(const basic_file_status &s); + +/// Is status available? +/// +/// @param path Input path. +/// @param result Set to true if status() != status_error. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +std::error_code status_known(const Twine &path, bool &result); + +enum CreationDisposition : unsigned { + /// CD_CreateAlways - When opening a file: + /// * If it already exists, truncate it. + /// * If it does not already exist, create a new file. + CD_CreateAlways = 0, + + /// CD_CreateNew - When opening a file: + /// * If it already exists, fail. + /// * If it does not already exist, create a new file. + CD_CreateNew = 1, + + /// CD_OpenExisting - When opening a file: + /// * If it already exists, open the file with the offset set to 0. + /// * If it does not already exist, fail. + CD_OpenExisting = 2, + + /// CD_OpenAlways - When opening a file: + /// * If it already exists, open the file with the offset set to 0. + /// * If it does not already exist, create a new file. + CD_OpenAlways = 3, +}; + +enum FileAccess : unsigned { + FA_Read = 1, + FA_Write = 2, +}; + +enum OpenFlags : unsigned { + OF_None = 0, + F_None = 0, // For compatibility + + /// The file should be opened in text mode on platforms that make this + /// distinction. + OF_Text = 1, + F_Text = 1, // For compatibility + + /// The file should be opened in append mode. + OF_Append = 2, + F_Append = 2, // For compatibility + + /// Delete the file on close. Only makes a difference on windows. + OF_Delete = 4, + + /// When a child process is launched, this file should remain open in the + /// child process. + OF_ChildInherit = 8, + + /// Force files Atime to be updated on access. Only makes a difference on windows. + OF_UpdateAtime = 16, +}; + +/// Create a potentially unique file name but does not create it. +/// +/// Generates a unique path suitable for a temporary file but does not +/// open or create the file. The name is based on \a Model with '%' +/// replaced by a random char in [0-9a-f]. If \a MakeAbsolute is true +/// then the system's temp directory is prepended first. If \a MakeAbsolute +/// is false the current directory will be used instead. +/// +/// This function does not check if the file exists. If you want to be sure +/// that the file does not yet exist, you should use use enough '%' characters +/// in your model to ensure this. Each '%' gives 4-bits of entropy so you can +/// use 32 of them to get 128 bits of entropy. +/// +/// Example: clang-%%-%%-%%-%%-%%.s => clang-a0-b1-c2-d3-e4.s +/// +/// @param Model Name to base unique path off of. +/// @param ResultPath Set to the file's path. +/// @param MakeAbsolute Whether to use the system temp directory. +void createUniquePath(const Twine &Model, SmallVectorImpl<char> &ResultPath, + bool MakeAbsolute); + +/// Create a uniquely named file. +/// +/// Generates a unique path suitable for a temporary file and then opens it as a +/// file. The name is based on \a Model with '%' replaced by a random char in +/// [0-9a-f]. If \a Model is not an absolute path, the temporary file will be +/// created in the current directory. +/// +/// Example: clang-%%-%%-%%-%%-%%.s => clang-a0-b1-c2-d3-e4.s +/// +/// This is an atomic operation. Either the file is created and opened, or the +/// file system is left untouched. +/// +/// The intended use is for files that are to be kept, possibly after +/// renaming them. For example, when running 'clang -c foo.o', the file can +/// be first created as foo-abc123.o and then renamed. +/// +/// @param Model Name to base unique path off of. +/// @param ResultFD Set to the opened file's file descriptor. +/// @param ResultPath Set to the opened file's absolute path. +/// @returns errc::success if Result{FD,Path} have been successfully set, +/// otherwise a platform-specific error_code. +std::error_code createUniqueFile(const Twine &Model, int &ResultFD, + SmallVectorImpl<char> &ResultPath, + unsigned Mode = all_read | all_write); + +/// Simpler version for clients that don't want an open file. An empty +/// file will still be created. +std::error_code createUniqueFile(const Twine &Model, + SmallVectorImpl<char> &ResultPath, + unsigned Mode = all_read | all_write); + +/// Represents a temporary file. +/// +/// The temporary file must be eventually discarded or given a final name and +/// kept. +/// +/// The destructor doesn't implicitly discard because there is no way to +/// properly handle errors in a destructor. +class TempFile { + bool Done = false; + TempFile(StringRef Name, int FD); + +public: + /// This creates a temporary file with createUniqueFile and schedules it for + /// deletion with sys::RemoveFileOnSignal. + static Expected<TempFile> create(const Twine &Model, + unsigned Mode = all_read | all_write); + TempFile(TempFile &&Other); + TempFile &operator=(TempFile &&Other); + + // Name of the temporary file. + std::string TmpName; + + // The open file descriptor. + int FD = -1; + + // Keep this with the given name. + Error keep(const Twine &Name); + + // Keep this with the temporary name. + Error keep(); + + // Delete the file. + Error discard(); + + // This checks that keep or delete was called. + ~TempFile(); +}; + +/// Create a file in the system temporary directory. +/// +/// The filename is of the form prefix-random_chars.suffix. Since the directory +/// is not know to the caller, Prefix and Suffix cannot have path separators. +/// The files are created with mode 0600. +/// +/// This should be used for things like a temporary .s that is removed after +/// running the assembler. +std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, + int &ResultFD, + SmallVectorImpl<char> &ResultPath); + +/// Simpler version for clients that don't want an open file. An empty +/// file will still be created. +std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, + SmallVectorImpl<char> &ResultPath); + +std::error_code createUniqueDirectory(const Twine &Prefix, + SmallVectorImpl<char> &ResultPath); + +/// Get a unique name, not currently exisiting in the filesystem. Subject +/// to race conditions, prefer to use createUniqueFile instead. +/// +/// Similar to createUniqueFile, but instead of creating a file only +/// checks if it exists. This function is subject to race conditions, if you +/// want to use the returned name to actually create a file, use +/// createUniqueFile instead. +std::error_code getPotentiallyUniqueFileName(const Twine &Model, + SmallVectorImpl<char> &ResultPath); + +/// Get a unique temporary file name, not currently exisiting in the +/// filesystem. Subject to race conditions, prefer to use createTemporaryFile +/// instead. +/// +/// Similar to createTemporaryFile, but instead of creating a file only +/// checks if it exists. This function is subject to race conditions, if you +/// want to use the returned name to actually create a file, use +/// createTemporaryFile instead. +std::error_code +getPotentiallyUniqueTempFileName(const Twine &Prefix, StringRef Suffix, + SmallVectorImpl<char> &ResultPath); + +inline OpenFlags operator|(OpenFlags A, OpenFlags B) { + return OpenFlags(unsigned(A) | unsigned(B)); +} + +inline OpenFlags &operator|=(OpenFlags &A, OpenFlags B) { + A = A | B; + return A; +} + +inline FileAccess operator|(FileAccess A, FileAccess B) { + return FileAccess(unsigned(A) | unsigned(B)); +} + +inline FileAccess &operator|=(FileAccess &A, FileAccess B) { + A = A | B; + return A; +} + +/// @brief Opens a file with the specified creation disposition, access mode, +/// and flags and returns a file descriptor. +/// +/// The caller is responsible for closing the file descriptor once they are +/// finished with it. +/// +/// @param Name The path of the file to open, relative or absolute. +/// @param ResultFD If the file could be opened successfully, its descriptor +/// is stored in this location. Otherwise, this is set to -1. +/// @param Disp Value specifying the existing-file behavior. +/// @param Access Value specifying whether to open the file in read, write, or +/// read-write mode. +/// @param Flags Additional flags. +/// @param Mode The access permissions of the file, represented in octal. +/// @returns errc::success if \a Name has been opened, otherwise a +/// platform-specific error_code. +std::error_code openFile(const Twine &Name, int &ResultFD, + CreationDisposition Disp, FileAccess Access, + OpenFlags Flags, unsigned Mode = 0666); + +/// @brief Opens a file with the specified creation disposition, access mode, +/// and flags and returns a platform-specific file object. +/// +/// The caller is responsible for closing the file object once they are +/// finished with it. +/// +/// @param Name The path of the file to open, relative or absolute. +/// @param Disp Value specifying the existing-file behavior. +/// @param Access Value specifying whether to open the file in read, write, or +/// read-write mode. +/// @param Flags Additional flags. +/// @param Mode The access permissions of the file, represented in octal. +/// @returns errc::success if \a Name has been opened, otherwise a +/// platform-specific error_code. +Expected<file_t> openNativeFile(const Twine &Name, CreationDisposition Disp, + FileAccess Access, OpenFlags Flags, + unsigned Mode = 0666); + +/// Converts from a Posix file descriptor number to a native file handle. +/// On Windows, this retreives the underlying handle. On non-Windows, this is a +/// no-op. +file_t convertFDToNativeFile(int FD); + +#ifndef _WIN32 +inline file_t convertFDToNativeFile(int FD) { return FD; } +#endif + +/// Return an open handle to standard in. On Unix, this is typically FD 0. +/// Returns kInvalidFile when the stream is closed. +file_t getStdinHandle(); + +/// Return an open handle to standard out. On Unix, this is typically FD 1. +/// Returns kInvalidFile when the stream is closed. +file_t getStdoutHandle(); + +/// Return an open handle to standard error. On Unix, this is typically FD 2. +/// Returns kInvalidFile when the stream is closed. +file_t getStderrHandle(); + +/// Reads \p Buf.size() bytes from \p FileHandle into \p Buf. Returns the number +/// of bytes actually read. On Unix, this is equivalent to `return ::read(FD, +/// Buf.data(), Buf.size())`, with error reporting. Returns 0 when reaching EOF. +/// +/// @param FileHandle File to read from. +/// @param Buf Buffer to read into. +/// @returns The number of bytes read, or error. +Expected<size_t> readNativeFile(file_t FileHandle, MutableArrayRef<char> Buf); + +/// Reads \p Buf.size() bytes from \p FileHandle at offset \p Offset into \p +/// Buf. If 'pread' is available, this will use that, otherwise it will use +/// 'lseek'. Returns the number of bytes actually read. Returns 0 when reaching +/// EOF. +/// +/// @param FileHandle File to read from. +/// @param Buf Buffer to read into. +/// @param Offset Offset into the file at which the read should occur. +/// @returns The number of bytes read, or error. +Expected<size_t> readNativeFileSlice(file_t FileHandle, + MutableArrayRef<char> Buf, + uint64_t Offset); + +/// @brief Opens the file with the given name in a write-only or read-write +/// mode, returning its open file descriptor. If the file does not exist, it +/// is created. +/// +/// The caller is responsible for closing the file descriptor once they are +/// finished with it. +/// +/// @param Name The path of the file to open, relative or absolute. +/// @param ResultFD If the file could be opened successfully, its descriptor +/// is stored in this location. Otherwise, this is set to -1. +/// @param Flags Additional flags used to determine whether the file should be +/// opened in, for example, read-write or in write-only mode. +/// @param Mode The access permissions of the file, represented in octal. +/// @returns errc::success if \a Name has been opened, otherwise a +/// platform-specific error_code. +inline std::error_code +openFileForWrite(const Twine &Name, int &ResultFD, + CreationDisposition Disp = CD_CreateAlways, + OpenFlags Flags = OF_None, unsigned Mode = 0666) { + return openFile(Name, ResultFD, Disp, FA_Write, Flags, Mode); +} + +/// @brief Opens the file with the given name in a write-only or read-write +/// mode, returning its open file descriptor. If the file does not exist, it +/// is created. +/// +/// The caller is responsible for closing the freeing the file once they are +/// finished with it. +/// +/// @param Name The path of the file to open, relative or absolute. +/// @param Flags Additional flags used to determine whether the file should be +/// opened in, for example, read-write or in write-only mode. +/// @param Mode The access permissions of the file, represented in octal. +/// @returns a platform-specific file descriptor if \a Name has been opened, +/// otherwise an error object. +inline Expected<file_t> openNativeFileForWrite(const Twine &Name, + CreationDisposition Disp, + OpenFlags Flags, + unsigned Mode = 0666) { + return openNativeFile(Name, Disp, FA_Write, Flags, Mode); +} + +/// @brief Opens the file with the given name in a write-only or read-write +/// mode, returning its open file descriptor. If the file does not exist, it +/// is created. +/// +/// The caller is responsible for closing the file descriptor once they are +/// finished with it. +/// +/// @param Name The path of the file to open, relative or absolute. +/// @param ResultFD If the file could be opened successfully, its descriptor +/// is stored in this location. Otherwise, this is set to -1. +/// @param Flags Additional flags used to determine whether the file should be +/// opened in, for example, read-write or in write-only mode. +/// @param Mode The access permissions of the file, represented in octal. +/// @returns errc::success if \a Name has been opened, otherwise a +/// platform-specific error_code. +inline std::error_code openFileForReadWrite(const Twine &Name, int &ResultFD, + CreationDisposition Disp, + OpenFlags Flags, + unsigned Mode = 0666) { + return openFile(Name, ResultFD, Disp, FA_Write | FA_Read, Flags, Mode); +} + +/// @brief Opens the file with the given name in a write-only or read-write +/// mode, returning its open file descriptor. If the file does not exist, it +/// is created. +/// +/// The caller is responsible for closing the freeing the file once they are +/// finished with it. +/// +/// @param Name The path of the file to open, relative or absolute. +/// @param Flags Additional flags used to determine whether the file should be +/// opened in, for example, read-write or in write-only mode. +/// @param Mode The access permissions of the file, represented in octal. +/// @returns a platform-specific file descriptor if \a Name has been opened, +/// otherwise an error object. +inline Expected<file_t> openNativeFileForReadWrite(const Twine &Name, + CreationDisposition Disp, + OpenFlags Flags, + unsigned Mode = 0666) { + return openNativeFile(Name, Disp, FA_Write | FA_Read, Flags, Mode); +} + +/// @brief Opens the file with the given name in a read-only mode, returning +/// its open file descriptor. +/// +/// The caller is responsible for closing the file descriptor once they are +/// finished with it. +/// +/// @param Name The path of the file to open, relative or absolute. +/// @param ResultFD If the file could be opened successfully, its descriptor +/// is stored in this location. Otherwise, this is set to -1. +/// @param RealPath If nonnull, extra work is done to determine the real path +/// of the opened file, and that path is stored in this +/// location. +/// @returns errc::success if \a Name has been opened, otherwise a +/// platform-specific error_code. +std::error_code openFileForRead(const Twine &Name, int &ResultFD, + OpenFlags Flags = OF_None, + SmallVectorImpl<char> *RealPath = nullptr); + +/// @brief Opens the file with the given name in a read-only mode, returning +/// its open file descriptor. +/// +/// The caller is responsible for closing the freeing the file once they are +/// finished with it. +/// +/// @param Name The path of the file to open, relative or absolute. +/// @param RealPath If nonnull, extra work is done to determine the real path +/// of the opened file, and that path is stored in this +/// location. +/// @returns a platform-specific file descriptor if \a Name has been opened, +/// otherwise an error object. +Expected<file_t> +openNativeFileForRead(const Twine &Name, OpenFlags Flags = OF_None, + SmallVectorImpl<char> *RealPath = nullptr); + +/// @brief Close the file object. This should be used instead of ::close for +/// portability. On error, the caller should assume the file is closed, as is +/// the case for Process::SafelyCloseFileDescriptor +/// +/// @param F On input, this is the file to close. On output, the file is +/// set to kInvalidFile. +/// +/// @returns An error code if closing the file failed. Typically, an error here +/// means that the filesystem may have failed to perform some buffered writes. +std::error_code closeFile(file_t &F); + +std::error_code getUniqueID(const Twine Path, UniqueID &Result); + +/// Get disk space usage information. +/// +/// Note: Users must be careful about "Time Of Check, Time Of Use" kind of bug. +/// Note: Windows reports results according to the quota allocated to the user. +/// +/// @param Path Input path. +/// @returns a space_info structure filled with the capacity, free, and +/// available space on the device \a Path is on. A platform specific error_code +/// is returned on error. +ErrorOr<space_info> disk_space(const Twine &Path); + +/// This class represents a memory mapped file. It is based on +/// boost::iostreams::mapped_file. +class mapped_file_region { +public: + enum mapmode { + readonly, ///< May only access map via const_data as read only. + readwrite, ///< May access map via data and modify it. Written to path. + priv ///< May modify via data, but changes are lost on destruction. + }; + +private: + /// Platform-specific mapping state. + size_t Size; + void *Mapping; +#ifdef _WIN32 + sys::fs::file_t FileHandle; +#endif + mapmode Mode; + + std::error_code init(sys::fs::file_t FD, uint64_t Offset, mapmode Mode); + +public: + mapped_file_region() = delete; + mapped_file_region(mapped_file_region&) = delete; + mapped_file_region &operator =(mapped_file_region&) = delete; + + /// \param fd An open file descriptor to map. Does not take ownership of fd. + mapped_file_region(sys::fs::file_t fd, mapmode mode, size_t length, uint64_t offset, + std::error_code &ec); + + ~mapped_file_region(); + + size_t size() const; + char *data() const; + + /// Get a const view of the data. Modifying this memory has undefined + /// behavior. + const char *const_data() const; + + /// \returns The minimum alignment offset must be. + static int alignment(); +}; + +/// Return the path to the main executable, given the value of argv[0] from +/// program startup and the address of main itself. In extremis, this function +/// may fail and return an empty path. +std::string getMainExecutable(const char *argv0, void *MainExecAddr); + +/// @} +/// @name Iterators +/// @{ + +/// directory_entry - A single entry in a directory. +class directory_entry { + // FIXME: different platforms make different information available "for free" + // when traversing a directory. The design of this class wraps most of the + // information in basic_file_status, so on platforms where we can't populate + // that whole structure, callers end up paying for a stat(). + // std::filesystem::directory_entry may be a better model. + std::string Path; + file_type Type = file_type::type_unknown; // Most platforms can provide this. + bool FollowSymlinks = true; // Affects the behavior of status(). + basic_file_status Status; // If available. + +public: + explicit directory_entry(const Twine &Path, bool FollowSymlinks = true, + file_type Type = file_type::type_unknown, + basic_file_status Status = basic_file_status()) + : Path(Path.str()), Type(Type), FollowSymlinks(FollowSymlinks), + Status(Status) {} + + directory_entry() = default; + + void replace_filename(const Twine &Filename, file_type Type, + basic_file_status Status = basic_file_status()); + + const std::string &path() const { return Path; } + // Get basic information about entry file (a subset of fs::status()). + // On most platforms this is a stat() call. + // On windows the information was already retrieved from the directory. + ErrorOr<basic_file_status> status() const; + // Get the type of this file. + // On most platforms (Linux/Mac/Windows/BSD), this was already retrieved. + // On some platforms (e.g. Solaris) this is a stat() call. + file_type type() const { + if (Type != file_type::type_unknown) + return Type; + auto S = status(); + return S ? S->type() : file_type::type_unknown; + } + + bool operator==(const directory_entry& RHS) const { return Path == RHS.Path; } + bool operator!=(const directory_entry& RHS) const { return !(*this == RHS); } + bool operator< (const directory_entry& RHS) const; + bool operator<=(const directory_entry& RHS) const; + bool operator> (const directory_entry& RHS) const; + bool operator>=(const directory_entry& RHS) const; +}; + +namespace detail { + + struct DirIterState; + + std::error_code directory_iterator_construct(DirIterState &, StringRef, bool); + std::error_code directory_iterator_increment(DirIterState &); + std::error_code directory_iterator_destruct(DirIterState &); + + /// Keeps state for the directory_iterator. + struct DirIterState { + ~DirIterState() { + directory_iterator_destruct(*this); + } + + intptr_t IterationHandle = 0; + directory_entry CurrentEntry; + }; + +} // end namespace detail + +/// directory_iterator - Iterates through the entries in path. There is no +/// operator++ because we need an error_code. If it's really needed we can make +/// it call report_fatal_error on error. +class directory_iterator { + std::shared_ptr<detail::DirIterState> State; + bool FollowSymlinks = true; + +public: + explicit directory_iterator(const Twine &path, std::error_code &ec, + bool follow_symlinks = true) + : FollowSymlinks(follow_symlinks) { + State = std::make_shared<detail::DirIterState>(); + SmallString<128> path_storage; + ec = detail::directory_iterator_construct( + *State, path.toStringRef(path_storage), FollowSymlinks); + } + + explicit directory_iterator(const directory_entry &de, std::error_code &ec, + bool follow_symlinks = true) + : FollowSymlinks(follow_symlinks) { + State = std::make_shared<detail::DirIterState>(); + ec = detail::directory_iterator_construct( + *State, de.path(), FollowSymlinks); + } + + /// Construct end iterator. + directory_iterator() = default; + + // No operator++ because we need error_code. + directory_iterator &increment(std::error_code &ec) { + ec = directory_iterator_increment(*State); + return *this; + } + + const directory_entry &operator*() const { return State->CurrentEntry; } + const directory_entry *operator->() const { return &State->CurrentEntry; } + + bool operator==(const directory_iterator &RHS) const { + if (State == RHS.State) + return true; + if (!RHS.State) + return State->CurrentEntry == directory_entry(); + if (!State) + return RHS.State->CurrentEntry == directory_entry(); + return State->CurrentEntry == RHS.State->CurrentEntry; + } + + bool operator!=(const directory_iterator &RHS) const { + return !(*this == RHS); + } +}; + +namespace detail { + + /// Keeps state for the recursive_directory_iterator. + struct RecDirIterState { + std::stack<directory_iterator, std::vector<directory_iterator>> Stack; + uint16_t Level = 0; + bool HasNoPushRequest = false; + }; + +} // end namespace detail + +/// recursive_directory_iterator - Same as directory_iterator except for it +/// recurses down into child directories. +class recursive_directory_iterator { + std::shared_ptr<detail::RecDirIterState> State; + bool Follow; + +public: + recursive_directory_iterator() = default; + explicit recursive_directory_iterator(const Twine &path, std::error_code &ec, + bool follow_symlinks = true) + : State(std::make_shared<detail::RecDirIterState>()), + Follow(follow_symlinks) { + State->Stack.push(directory_iterator(path, ec, Follow)); + if (State->Stack.top() == directory_iterator()) + State.reset(); + } + + // No operator++ because we need error_code. + recursive_directory_iterator &increment(std::error_code &ec) { + const directory_iterator end_itr = {}; + + if (State->HasNoPushRequest) + State->HasNoPushRequest = false; + else { + file_type type = State->Stack.top()->type(); + if (type == file_type::symlink_file && Follow) { + // Resolve the symlink: is it a directory to recurse into? + ErrorOr<basic_file_status> status = State->Stack.top()->status(); + if (status) + type = status->type(); + // Otherwise broken symlink, and we'll continue. + } + if (type == file_type::directory_file) { + State->Stack.push(directory_iterator(*State->Stack.top(), ec, Follow)); + if (State->Stack.top() != end_itr) { + ++State->Level; + return *this; + } + State->Stack.pop(); + } + } + + while (!State->Stack.empty() + && State->Stack.top().increment(ec) == end_itr) { + State->Stack.pop(); + --State->Level; + } + + // Check if we are done. If so, create an end iterator. + if (State->Stack.empty()) + State.reset(); + + return *this; + } + + const directory_entry &operator*() const { return *State->Stack.top(); } + const directory_entry *operator->() const { return &*State->Stack.top(); } + + // observers + /// Gets the current level. Starting path is at level 0. + int level() const { return State->Level; } + + /// Returns true if no_push has been called for this directory_entry. + bool no_push_request() const { return State->HasNoPushRequest; } + + // modifiers + /// Goes up one level if Level > 0. + void pop() { + assert(State && "Cannot pop an end iterator!"); + assert(State->Level > 0 && "Cannot pop an iterator with level < 1"); + + const directory_iterator end_itr = {}; + std::error_code ec; + do { + if (ec) + report_fatal_error("Error incrementing directory iterator."); + State->Stack.pop(); + --State->Level; + } while (!State->Stack.empty() + && State->Stack.top().increment(ec) == end_itr); + + // Check if we are done. If so, create an end iterator. + if (State->Stack.empty()) + State.reset(); + } + + /// Does not go down into the current directory_entry. + void no_push() { State->HasNoPushRequest = true; } + + bool operator==(const recursive_directory_iterator &RHS) const { + return State == RHS.State; + } + + bool operator!=(const recursive_directory_iterator &RHS) const { + return !(*this == RHS); + } +}; + +/// @} + +} // end namespace fs +} // end namespace sys +} // end namespace llvm + +#endif // LLVM_SUPPORT_FILESYSTEM_H diff --git a/third_party/llvm-project/include/llvm/Support/Format.h b/third_party/llvm-project/include/llvm/Support/Format.h new file mode 100644 index 000000000..9dd7b401b --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Format.h @@ -0,0 +1,257 @@ +//===- Format.h - Efficient printf-style formatting for streams -*- 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 format() function, which can be used with other +// LLVM subsystems to provide printf-style formatting. This gives all the power +// and risk of printf. This can be used like this (with raw_ostreams as an +// example): +// +// OS << "mynumber: " << format("%4.5f", 1234.412) << '\n'; +// +// Or if you prefer: +// +// OS << format("mynumber: %4.5f\n", 1234.412); +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_FORMAT_H +#define LLVM_SUPPORT_FORMAT_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" +#include <cassert> +#include <cstdio> +#include <tuple> +#include <utility> + +namespace llvm { + +/// This is a helper class used for handling formatted output. It is the +/// abstract base class of a templated derived class. +class format_object_base { +protected: + const char *Fmt; + ~format_object_base() = default; // Disallow polymorphic deletion. + format_object_base(const format_object_base &) = default; + virtual void home(); // Out of line virtual method. + + /// Call snprintf() for this object, on the given buffer and size. + virtual int snprint(char *Buffer, unsigned BufferSize) const = 0; + +public: + format_object_base(const char *fmt) : Fmt(fmt) {} + + /// Format the object into the specified buffer. On success, this returns + /// the length of the formatted string. If the buffer is too small, this + /// returns a length to retry with, which will be larger than BufferSize. + unsigned print(char *Buffer, unsigned BufferSize) const { + assert(BufferSize && "Invalid buffer size!"); + + // Print the string, leaving room for the terminating null. + int N = snprint(Buffer, BufferSize); + + // VC++ and old GlibC return negative on overflow, just double the size. + if (N < 0) + return BufferSize * 2; + + // Other implementations yield number of bytes needed, not including the + // final '\0'. + if (unsigned(N) >= BufferSize) + return N + 1; + + // Otherwise N is the length of output (not including the final '\0'). + return N; + } +}; + +/// These are templated helper classes used by the format function that +/// capture the object to be formatted and the format string. When actually +/// printed, this synthesizes the string into a temporary buffer provided and +/// returns whether or not it is big enough. + +// Helper to validate that format() parameters are scalars or pointers. +template <typename... Args> struct validate_format_parameters; +template <typename Arg, typename... Args> +struct validate_format_parameters<Arg, Args...> { + static_assert(std::is_scalar<Arg>::value, + "format can't be used with non fundamental / non pointer type"); + validate_format_parameters() { validate_format_parameters<Args...>(); } +}; +template <> struct validate_format_parameters<> {}; + +template <typename... Ts> +class format_object final : public format_object_base { + std::tuple<Ts...> Vals; + + template <std::size_t... Is> + int snprint_tuple(char *Buffer, unsigned BufferSize, + std::index_sequence<Is...>) const { +#ifdef _MSC_VER + return _snprintf(Buffer, BufferSize, Fmt, std::get<Is>(Vals)...); +#else + return snprintf(Buffer, BufferSize, Fmt, std::get<Is>(Vals)...); +#endif + } + +public: + format_object(const char *fmt, const Ts &... vals) + : format_object_base(fmt), Vals(vals...) { + validate_format_parameters<Ts...>(); + } + + int snprint(char *Buffer, unsigned BufferSize) const override { + return snprint_tuple(Buffer, BufferSize, std::index_sequence_for<Ts...>()); + } +}; + +/// These are helper functions used to produce formatted output. They use +/// template type deduction to construct the appropriate instance of the +/// format_object class to simplify their construction. +/// +/// This is typically used like: +/// \code +/// OS << format("%0.4f", myfloat) << '\n'; +/// \endcode + +template <typename... Ts> +inline format_object<Ts...> format(const char *Fmt, const Ts &... Vals) { + return format_object<Ts...>(Fmt, Vals...); +} + +/// This is a helper class for left_justify, right_justify, and center_justify. +class FormattedString { +public: + enum Justification { JustifyNone, JustifyLeft, JustifyRight, JustifyCenter }; + FormattedString(StringRef S, unsigned W, Justification J) + : Str(S), Width(W), Justify(J) {} + +private: + StringRef Str; + unsigned Width; + Justification Justify; + friend class raw_ostream; +}; + +/// left_justify - append spaces after string so total output is +/// \p Width characters. If \p Str is larger that \p Width, full string +/// is written with no padding. +inline FormattedString left_justify(StringRef Str, unsigned Width) { + return FormattedString(Str, Width, FormattedString::JustifyLeft); +} + +/// right_justify - add spaces before string so total output is +/// \p Width characters. If \p Str is larger that \p Width, full string +/// is written with no padding. +inline FormattedString right_justify(StringRef Str, unsigned Width) { + return FormattedString(Str, Width, FormattedString::JustifyRight); +} + +/// center_justify - add spaces before and after string so total output is +/// \p Width characters. If \p Str is larger that \p Width, full string +/// is written with no padding. +inline FormattedString center_justify(StringRef Str, unsigned Width) { + return FormattedString(Str, Width, FormattedString::JustifyCenter); +} + +/// This is a helper class used for format_hex() and format_decimal(). +class FormattedNumber { + uint64_t HexValue; + int64_t DecValue; + unsigned Width; + bool Hex; + bool Upper; + bool HexPrefix; + friend class raw_ostream; + +public: + FormattedNumber(uint64_t HV, int64_t DV, unsigned W, bool H, bool U, + bool Prefix) + : HexValue(HV), DecValue(DV), Width(W), Hex(H), Upper(U), + HexPrefix(Prefix) {} +}; + +/// format_hex - Output \p N as a fixed width hexadecimal. If number will not +/// fit in width, full number is still printed. Examples: +/// OS << format_hex(255, 4) => 0xff +/// OS << format_hex(255, 4, true) => 0xFF +/// OS << format_hex(255, 6) => 0x00ff +/// OS << format_hex(255, 2) => 0xff +inline FormattedNumber format_hex(uint64_t N, unsigned Width, + bool Upper = false) { + assert(Width <= 18 && "hex width must be <= 18"); + return FormattedNumber(N, 0, Width, true, Upper, true); +} + +/// format_hex_no_prefix - Output \p N as a fixed width hexadecimal. Does not +/// prepend '0x' to the outputted string. If number will not fit in width, +/// full number is still printed. Examples: +/// OS << format_hex_no_prefix(255, 2) => ff +/// OS << format_hex_no_prefix(255, 2, true) => FF +/// OS << format_hex_no_prefix(255, 4) => 00ff +/// OS << format_hex_no_prefix(255, 1) => ff +inline FormattedNumber format_hex_no_prefix(uint64_t N, unsigned Width, + bool Upper = false) { + assert(Width <= 16 && "hex width must be <= 16"); + return FormattedNumber(N, 0, Width, true, Upper, false); +} + +/// format_decimal - Output \p N as a right justified, fixed-width decimal. If +/// number will not fit in width, full number is still printed. Examples: +/// OS << format_decimal(0, 5) => " 0" +/// OS << format_decimal(255, 5) => " 255" +/// OS << format_decimal(-1, 3) => " -1" +/// OS << format_decimal(12345, 3) => "12345" +inline FormattedNumber format_decimal(int64_t N, unsigned Width) { + return FormattedNumber(0, N, Width, false, false, false); +} + +class FormattedBytes { + ArrayRef<uint8_t> Bytes; + + // If not None, display offsets for each line relative to starting value. + Optional<uint64_t> FirstByteOffset; + uint32_t IndentLevel; // Number of characters to indent each line. + uint32_t NumPerLine; // Number of bytes to show per line. + uint8_t ByteGroupSize; // How many hex bytes are grouped without spaces + bool Upper; // Show offset and hex bytes as upper case. + bool ASCII; // Show the ASCII bytes for the hex bytes to the right. + friend class raw_ostream; + +public: + FormattedBytes(ArrayRef<uint8_t> B, uint32_t IL, Optional<uint64_t> O, + uint32_t NPL, uint8_t BGS, bool U, bool A) + : Bytes(B), FirstByteOffset(O), IndentLevel(IL), NumPerLine(NPL), + ByteGroupSize(BGS), Upper(U), ASCII(A) { + + if (ByteGroupSize > NumPerLine) + ByteGroupSize = NumPerLine; + } +}; + +inline FormattedBytes +format_bytes(ArrayRef<uint8_t> Bytes, Optional<uint64_t> FirstByteOffset = None, + uint32_t NumPerLine = 16, uint8_t ByteGroupSize = 4, + uint32_t IndentLevel = 0, bool Upper = false) { + return FormattedBytes(Bytes, IndentLevel, FirstByteOffset, NumPerLine, + ByteGroupSize, Upper, false); +} + +inline FormattedBytes +format_bytes_with_ascii(ArrayRef<uint8_t> Bytes, + Optional<uint64_t> FirstByteOffset = None, + uint32_t NumPerLine = 16, uint8_t ByteGroupSize = 4, + uint32_t IndentLevel = 0, bool Upper = false) { + return FormattedBytes(Bytes, IndentLevel, FirstByteOffset, NumPerLine, + ByteGroupSize, Upper, true); +} + +} // end namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/FormatAdapters.h b/third_party/llvm-project/include/llvm/Support/FormatAdapters.h new file mode 100644 index 000000000..a0e8cc439 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/FormatAdapters.h @@ -0,0 +1,108 @@ +//===- FormatAdapters.h - Formatters for common LLVM types -----*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_FORMATADAPTERS_H +#define LLVM_SUPPORT_FORMATADAPTERS_H + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FormatCommon.h" +#include "llvm/Support/FormatVariadicDetails.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +template <typename T> class FormatAdapter : public detail::format_adapter { +protected: + explicit FormatAdapter(T &&Item) : Item(std::forward<T>(Item)) {} + + T Item; +}; + +namespace detail { +template <typename T> class AlignAdapter final : public FormatAdapter<T> { + AlignStyle Where; + size_t Amount; + char Fill; + +public: + AlignAdapter(T &&Item, AlignStyle Where, size_t Amount, char Fill) + : FormatAdapter<T>(std::forward<T>(Item)), Where(Where), Amount(Amount), + Fill(Fill) {} + + void format(llvm::raw_ostream &Stream, StringRef Style) { + auto Adapter = detail::build_format_adapter(std::forward<T>(this->Item)); + FmtAlign(Adapter, Where, Amount, Fill).format(Stream, Style); + } +}; + +template <typename T> class PadAdapter final : public FormatAdapter<T> { + size_t Left; + size_t Right; + +public: + PadAdapter(T &&Item, size_t Left, size_t Right) + : FormatAdapter<T>(std::forward<T>(Item)), Left(Left), Right(Right) {} + + void format(llvm::raw_ostream &Stream, StringRef Style) { + auto Adapter = detail::build_format_adapter(std::forward<T>(this->Item)); + Stream.indent(Left); + Adapter.format(Stream, Style); + Stream.indent(Right); + } +}; + +template <typename T> class RepeatAdapter final : public FormatAdapter<T> { + size_t Count; + +public: + RepeatAdapter(T &&Item, size_t Count) + : FormatAdapter<T>(std::forward<T>(Item)), Count(Count) {} + + void format(llvm::raw_ostream &Stream, StringRef Style) { + auto Adapter = detail::build_format_adapter(std::forward<T>(this->Item)); + for (size_t I = 0; I < Count; ++I) { + Adapter.format(Stream, Style); + } + } +}; + +class ErrorAdapter : public FormatAdapter<Error> { +public: + ErrorAdapter(Error &&Item) : FormatAdapter(std::move(Item)) {} + ErrorAdapter(ErrorAdapter &&) = default; + ~ErrorAdapter() { consumeError(std::move(Item)); } + void format(llvm::raw_ostream &Stream, StringRef Style) { Stream << Item; } +}; +} + +template <typename T> +detail::AlignAdapter<T> fmt_align(T &&Item, AlignStyle Where, size_t Amount, + char Fill = ' ') { + return detail::AlignAdapter<T>(std::forward<T>(Item), Where, Amount, Fill); +} + +template <typename T> +detail::PadAdapter<T> fmt_pad(T &&Item, size_t Left, size_t Right) { + return detail::PadAdapter<T>(std::forward<T>(Item), Left, Right); +} + +template <typename T> +detail::RepeatAdapter<T> fmt_repeat(T &&Item, size_t Count) { + return detail::RepeatAdapter<T>(std::forward<T>(Item), Count); +} + +// llvm::Error values must be consumed before being destroyed. +// Wrapping an error in fmt_consume explicitly indicates that the formatv_object +// should take ownership and consume it. +inline detail::ErrorAdapter fmt_consume(Error &&Item) { + return detail::ErrorAdapter(std::move(Item)); +} +} + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/FormatCommon.h b/third_party/llvm-project/include/llvm/Support/FormatCommon.h new file mode 100644 index 000000000..3c119d125 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/FormatCommon.h @@ -0,0 +1,76 @@ +//===- FormatCommon.h - Formatters for common LLVM types --------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_FORMATCOMMON_H +#define LLVM_SUPPORT_FORMATCOMMON_H + +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/FormatVariadicDetails.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +enum class AlignStyle { Left, Center, Right }; + +struct FmtAlign { + detail::format_adapter &Adapter; + AlignStyle Where; + size_t Amount; + char Fill; + + FmtAlign(detail::format_adapter &Adapter, AlignStyle Where, size_t Amount, + char Fill = ' ') + : Adapter(Adapter), Where(Where), Amount(Amount), Fill(Fill) {} + + void format(raw_ostream &S, StringRef Options) { + // If we don't need to align, we can format straight into the underlying + // stream. Otherwise we have to go through an intermediate stream first + // in order to calculate how long the output is so we can align it. + // TODO: Make the format method return the number of bytes written, that + // way we can also skip the intermediate stream for left-aligned output. + if (Amount == 0) { + Adapter.format(S, Options); + return; + } + SmallString<64> Item; + raw_svector_ostream Stream(Item); + + Adapter.format(Stream, Options); + if (Amount <= Item.size()) { + S << Item; + return; + } + + size_t PadAmount = Amount - Item.size(); + switch (Where) { + case AlignStyle::Left: + S << Item; + fill(S, PadAmount); + break; + case AlignStyle::Center: { + size_t X = PadAmount / 2; + fill(S, X); + S << Item; + fill(S, PadAmount - X); + break; + } + default: + fill(S, PadAmount); + S << Item; + break; + } + } + +private: + void fill(llvm::raw_ostream &S, uint32_t Count) { + for (uint32_t I = 0; I < Count; ++I) + S << Fill; + } +}; +} + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/FormatProviders.h b/third_party/llvm-project/include/llvm/Support/FormatProviders.h new file mode 100644 index 000000000..629a48457 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/FormatProviders.h @@ -0,0 +1,422 @@ +//===- FormatProviders.h - Formatters for common LLVM types -----*- 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 format providers for many common LLVM types, for example +// allowing precision and width specifiers for scalar and string types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_FORMATPROVIDERS_H +#define LLVM_SUPPORT_FORMATPROVIDERS_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/FormatVariadicDetails.h" +#include "llvm/Support/NativeFormatting.h" + +#include <type_traits> +#include <vector> + +namespace llvm { +namespace detail { +template <typename T> +struct use_integral_formatter + : public std::integral_constant< + bool, is_one_of<T, uint8_t, int16_t, uint16_t, int32_t, uint32_t, + int64_t, uint64_t, int, unsigned, long, unsigned long, + long long, unsigned long long>::value> {}; + +template <typename T> +struct use_char_formatter + : public std::integral_constant<bool, std::is_same<T, char>::value> {}; + +template <typename T> +struct is_cstring + : public std::integral_constant<bool, + is_one_of<T, char *, const char *>::value> { +}; + +template <typename T> +struct use_string_formatter + : public std::integral_constant<bool, + std::is_convertible<T, llvm::StringRef>::value> {}; + +template <typename T> +struct use_pointer_formatter + : public std::integral_constant<bool, std::is_pointer<T>::value && + !is_cstring<T>::value> {}; + +template <typename T> +struct use_double_formatter + : public std::integral_constant<bool, std::is_floating_point<T>::value> {}; + +class HelperFunctions { +protected: + static Optional<size_t> parseNumericPrecision(StringRef Str) { + size_t Prec; + Optional<size_t> Result; + if (Str.empty()) + Result = None; + else if (Str.getAsInteger(10, Prec)) { + assert(false && "Invalid precision specifier"); + Result = None; + } else { + assert(Prec < 100 && "Precision out of range"); + Result = std::min<size_t>(99u, Prec); + } + return Result; + } + + static bool consumeHexStyle(StringRef &Str, HexPrintStyle &Style) { + if (!Str.startswith_lower("x")) + return false; + + if (Str.consume_front("x-")) + Style = HexPrintStyle::Lower; + else if (Str.consume_front("X-")) + Style = HexPrintStyle::Upper; + else if (Str.consume_front("x+") || Str.consume_front("x")) + Style = HexPrintStyle::PrefixLower; + else if (Str.consume_front("X+") || Str.consume_front("X")) + Style = HexPrintStyle::PrefixUpper; + return true; + } + + static size_t consumeNumHexDigits(StringRef &Str, HexPrintStyle Style, + size_t Default) { + Str.consumeInteger(10, Default); + if (isPrefixedHexStyle(Style)) + Default += 2; + return Default; + } +}; +} + +/// Implementation of format_provider<T> for integral arithmetic types. +/// +/// The options string of an integral type has the grammar: +/// +/// integer_options :: [style][digits] +/// style :: <see table below> +/// digits :: <non-negative integer> 0-99 +/// +/// ========================================================================== +/// | style | Meaning | Example | Digits Meaning | +/// -------------------------------------------------------------------------- +/// | | | Input | Output | | +/// ========================================================================== +/// | x- | Hex no prefix, lower | 42 | 2a | Minimum # digits | +/// | X- | Hex no prefix, upper | 42 | 2A | Minimum # digits | +/// | x+ / x | Hex + prefix, lower | 42 | 0x2a | Minimum # digits | +/// | X+ / X | Hex + prefix, upper | 42 | 0x2A | Minimum # digits | +/// | N / n | Digit grouped number | 123456 | 123,456 | Ignored | +/// | D / d | Integer | 100000 | 100000 | Ignored | +/// | (empty) | Same as D / d | | | | +/// ========================================================================== +/// + +template <typename T> +struct format_provider< + T, typename std::enable_if<detail::use_integral_formatter<T>::value>::type> + : public detail::HelperFunctions { +private: +public: + static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { + HexPrintStyle HS; + size_t Digits = 0; + if (consumeHexStyle(Style, HS)) { + Digits = consumeNumHexDigits(Style, HS, 0); + write_hex(Stream, V, HS, Digits); + return; + } + + IntegerStyle IS = IntegerStyle::Integer; + if (Style.consume_front("N") || Style.consume_front("n")) + IS = IntegerStyle::Number; + else if (Style.consume_front("D") || Style.consume_front("d")) + IS = IntegerStyle::Integer; + + Style.consumeInteger(10, Digits); + assert(Style.empty() && "Invalid integral format style!"); + write_integer(Stream, V, Digits, IS); + } +}; + +/// Implementation of format_provider<T> for integral pointer types. +/// +/// The options string of a pointer type has the grammar: +/// +/// pointer_options :: [style][precision] +/// style :: <see table below> +/// digits :: <non-negative integer> 0-sizeof(void*) +/// +/// ========================================================================== +/// | S | Meaning | Example | +/// -------------------------------------------------------------------------- +/// | | | Input | Output | +/// ========================================================================== +/// | x- | Hex no prefix, lower | 0xDEADBEEF | deadbeef | +/// | X- | Hex no prefix, upper | 0xDEADBEEF | DEADBEEF | +/// | x+ / x | Hex + prefix, lower | 0xDEADBEEF | 0xdeadbeef | +/// | X+ / X | Hex + prefix, upper | 0xDEADBEEF | 0xDEADBEEF | +/// | (empty) | Same as X+ / X | | | +/// ========================================================================== +/// +/// The default precision is the number of nibbles in a machine word, and in all +/// cases indicates the minimum number of nibbles to print. +template <typename T> +struct format_provider< + T, typename std::enable_if<detail::use_pointer_formatter<T>::value>::type> + : public detail::HelperFunctions { +private: +public: + static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { + HexPrintStyle HS = HexPrintStyle::PrefixUpper; + consumeHexStyle(Style, HS); + size_t Digits = consumeNumHexDigits(Style, HS, sizeof(void *) * 2); + write_hex(Stream, reinterpret_cast<std::uintptr_t>(V), HS, Digits); + } +}; + +/// Implementation of format_provider<T> for c-style strings and string +/// objects such as std::string and llvm::StringRef. +/// +/// The options string of a string type has the grammar: +/// +/// string_options :: [length] +/// +/// where `length` is an optional integer specifying the maximum number of +/// characters in the string to print. If `length` is omitted, the string is +/// printed up to the null terminator. + +template <typename T> +struct format_provider< + T, typename std::enable_if<detail::use_string_formatter<T>::value>::type> { + static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { + size_t N = StringRef::npos; + if (!Style.empty() && Style.getAsInteger(10, N)) { + assert(false && "Style is not a valid integer"); + } + llvm::StringRef S = V; + Stream << S.substr(0, N); + } +}; + +/// Implementation of format_provider<T> for llvm::Twine. +/// +/// This follows the same rules as the string formatter. + +template <> struct format_provider<Twine> { + static void format(const Twine &V, llvm::raw_ostream &Stream, + StringRef Style) { + format_provider<std::string>::format(V.str(), Stream, Style); + } +}; + +/// Implementation of format_provider<T> for characters. +/// +/// The options string of a character type has the grammar: +/// +/// char_options :: (empty) | [integer_options] +/// +/// If `char_options` is empty, the character is displayed as an ASCII +/// character. Otherwise, it is treated as an integer options string. +/// +template <typename T> +struct format_provider< + T, typename std::enable_if<detail::use_char_formatter<T>::value>::type> { + static void format(const char &V, llvm::raw_ostream &Stream, + StringRef Style) { + if (Style.empty()) + Stream << V; + else { + int X = static_cast<int>(V); + format_provider<int>::format(X, Stream, Style); + } + } +}; + +/// Implementation of format_provider<T> for type `bool` +/// +/// The options string of a boolean type has the grammar: +/// +/// bool_options :: "" | "Y" | "y" | "D" | "d" | "T" | "t" +/// +/// ================================== +/// | C | Meaning | +/// ================================== +/// | Y | YES / NO | +/// | y | yes / no | +/// | D / d | Integer 0 or 1 | +/// | T | TRUE / FALSE | +/// | t | true / false | +/// | (empty) | Equivalent to 't' | +/// ================================== +template <> struct format_provider<bool> { + static void format(const bool &B, llvm::raw_ostream &Stream, + StringRef Style) { + Stream << StringSwitch<const char *>(Style) + .Case("Y", B ? "YES" : "NO") + .Case("y", B ? "yes" : "no") + .CaseLower("D", B ? "1" : "0") + .Case("T", B ? "TRUE" : "FALSE") + .Cases("t", "", B ? "true" : "false") + .Default(B ? "1" : "0"); + } +}; + +/// Implementation of format_provider<T> for floating point types. +/// +/// The options string of a floating point type has the format: +/// +/// float_options :: [style][precision] +/// style :: <see table below> +/// precision :: <non-negative integer> 0-99 +/// +/// ===================================================== +/// | style | Meaning | Example | +/// ----------------------------------------------------- +/// | | | Input | Output | +/// ===================================================== +/// | P / p | Percentage | 0.05 | 5.00% | +/// | F / f | Fixed point | 1.0 | 1.00 | +/// | E | Exponential with E | 100000 | 1.0E+05 | +/// | e | Exponential with e | 100000 | 1.0e+05 | +/// | (empty) | Same as F / f | | | +/// ===================================================== +/// +/// The default precision is 6 for exponential (E / e) and 2 for everything +/// else. + +template <typename T> +struct format_provider< + T, typename std::enable_if<detail::use_double_formatter<T>::value>::type> + : public detail::HelperFunctions { + static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { + FloatStyle S; + if (Style.consume_front("P") || Style.consume_front("p")) + S = FloatStyle::Percent; + else if (Style.consume_front("F") || Style.consume_front("f")) + S = FloatStyle::Fixed; + else if (Style.consume_front("E")) + S = FloatStyle::ExponentUpper; + else if (Style.consume_front("e")) + S = FloatStyle::Exponent; + else + S = FloatStyle::Fixed; + + Optional<size_t> Precision = parseNumericPrecision(Style); + if (!Precision.hasValue()) + Precision = getDefaultPrecision(S); + + write_double(Stream, static_cast<double>(V), S, Precision); + } +}; + +namespace detail { +template <typename IterT> +using IterValue = typename std::iterator_traits<IterT>::value_type; + +template <typename IterT> +struct range_item_has_provider + : public std::integral_constant< + bool, !uses_missing_provider<IterValue<IterT>>::value> {}; +} + +/// Implementation of format_provider<T> for ranges. +/// +/// This will print an arbitrary range as a delimited sequence of items. +/// +/// The options string of a range type has the grammar: +/// +/// range_style ::= [separator] [element_style] +/// separator ::= "$" delimeted_expr +/// element_style ::= "@" delimeted_expr +/// delimeted_expr ::= "[" expr "]" | "(" expr ")" | "<" expr ">" +/// expr ::= <any string not containing delimeter> +/// +/// where the separator expression is the string to insert between consecutive +/// items in the range and the argument expression is the Style specification to +/// be used when formatting the underlying type. The default separator if +/// unspecified is ' ' (space). The syntax of the argument expression follows +/// whatever grammar is dictated by the format provider or format adapter used +/// to format the value type. +/// +/// Note that attempting to format an `iterator_range<T>` where no format +/// provider can be found for T will result in a compile error. +/// + +template <typename IterT> class format_provider<llvm::iterator_range<IterT>> { + using value = typename std::iterator_traits<IterT>::value_type; + using reference = typename std::iterator_traits<IterT>::reference; + + static StringRef consumeOneOption(StringRef &Style, char Indicator, + StringRef Default) { + if (Style.empty()) + return Default; + if (Style.front() != Indicator) + return Default; + Style = Style.drop_front(); + if (Style.empty()) { + assert(false && "Invalid range style"); + return Default; + } + + for (const char *D : {"[]", "<>", "()"}) { + if (Style.front() != D[0]) + continue; + size_t End = Style.find_first_of(D[1]); + if (End == StringRef::npos) { + assert(false && "Missing range option end delimeter!"); + return Default; + } + StringRef Result = Style.slice(1, End); + Style = Style.drop_front(End + 1); + return Result; + } + assert(false && "Invalid range style!"); + return Default; + } + + static std::pair<StringRef, StringRef> parseOptions(StringRef Style) { + StringRef Sep = consumeOneOption(Style, '$', ", "); + StringRef Args = consumeOneOption(Style, '@', ""); + assert(Style.empty() && "Unexpected text in range option string!"); + return std::make_pair(Sep, Args); + } + +public: + static_assert(detail::range_item_has_provider<IterT>::value, + "Range value_type does not have a format provider!"); + static void format(const llvm::iterator_range<IterT> &V, + llvm::raw_ostream &Stream, StringRef Style) { + StringRef Sep; + StringRef ArgStyle; + std::tie(Sep, ArgStyle) = parseOptions(Style); + auto Begin = V.begin(); + auto End = V.end(); + if (Begin != End) { + auto Adapter = + detail::build_format_adapter(std::forward<reference>(*Begin)); + Adapter.format(Stream, ArgStyle); + ++Begin; + } + while (Begin != End) { + Stream << Sep; + auto Adapter = + detail::build_format_adapter(std::forward<reference>(*Begin)); + Adapter.format(Stream, ArgStyle); + ++Begin; + } + } +}; +} + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/FormatVariadic.h b/third_party/llvm-project/include/llvm/Support/FormatVariadic.h new file mode 100644 index 000000000..86a9d30cc --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/FormatVariadic.h @@ -0,0 +1,264 @@ +//===- FormatVariadic.h - Efficient type-safe string formatting --*- 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 formatv() function which can be used with other LLVM +// subsystems to provide printf-like formatting, but with improved safety and +// flexibility. The result of `formatv` is an object which can be streamed to +// a raw_ostream or converted to a std::string or llvm::SmallString. +// +// // Convert to std::string. +// std::string S = formatv("{0} {1}", 1234.412, "test").str(); +// +// // Convert to llvm::SmallString +// SmallString<8> S = formatv("{0} {1}", 1234.412, "test").sstr<8>(); +// +// // Stream to an existing raw_ostream. +// OS << formatv("{0} {1}", 1234.412, "test"); +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_FORMATVARIADIC_H +#define LLVM_SUPPORT_FORMATVARIADIC_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormatCommon.h" +#include "llvm/Support/FormatProviders.h" +#include "llvm/Support/FormatVariadicDetails.h" +#include "llvm/Support/raw_ostream.h" +#include <cstddef> +#include <string> +#include <tuple> +#include <utility> +#include <vector> + +namespace llvm { + +enum class ReplacementType { Empty, Format, Literal }; + +struct ReplacementItem { + ReplacementItem() = default; + explicit ReplacementItem(StringRef Literal) + : Type(ReplacementType::Literal), Spec(Literal) {} + ReplacementItem(StringRef Spec, size_t Index, size_t Align, AlignStyle Where, + char Pad, StringRef Options) + : Type(ReplacementType::Format), Spec(Spec), Index(Index), Align(Align), + Where(Where), Pad(Pad), Options(Options) {} + + ReplacementType Type = ReplacementType::Empty; + StringRef Spec; + size_t Index = 0; + size_t Align = 0; + AlignStyle Where = AlignStyle::Right; + char Pad = 0; + StringRef Options; +}; + +class formatv_object_base { +protected: + // The parameters are stored in a std::tuple, which does not provide runtime + // indexing capabilities. In order to enable runtime indexing, we use this + // structure to put the parameters into a std::vector. Since the parameters + // are not all the same type, we use some type-erasure by wrapping the + // parameters in a template class that derives from a non-template superclass. + // Essentially, we are converting a std::tuple<Derived<Ts...>> to a + // std::vector<Base*>. + struct create_adapters { + template <typename... Ts> + std::vector<detail::format_adapter *> operator()(Ts &... Items) { + return std::vector<detail::format_adapter *>{&Items...}; + } + }; + + StringRef Fmt; + std::vector<detail::format_adapter *> Adapters; + std::vector<ReplacementItem> Replacements; + + static bool consumeFieldLayout(StringRef &Spec, AlignStyle &Where, + size_t &Align, char &Pad); + + static std::pair<ReplacementItem, StringRef> + splitLiteralAndReplacement(StringRef Fmt); + +public: + formatv_object_base(StringRef Fmt, std::size_t ParamCount) + : Fmt(Fmt), Replacements(parseFormatString(Fmt)) { + Adapters.reserve(ParamCount); + } + + formatv_object_base(formatv_object_base const &rhs) = delete; + + formatv_object_base(formatv_object_base &&rhs) + : Fmt(std::move(rhs.Fmt)), + Adapters(), // Adapters are initialized by formatv_object + Replacements(std::move(rhs.Replacements)) { + Adapters.reserve(rhs.Adapters.size()); + }; + + void format(raw_ostream &S) const { + for (auto &R : Replacements) { + if (R.Type == ReplacementType::Empty) + continue; + if (R.Type == ReplacementType::Literal) { + S << R.Spec; + continue; + } + if (R.Index >= Adapters.size()) { + S << R.Spec; + continue; + } + + auto W = Adapters[R.Index]; + + FmtAlign Align(*W, R.Where, R.Align, R.Pad); + Align.format(S, R.Options); + } + } + static std::vector<ReplacementItem> parseFormatString(StringRef Fmt); + + static Optional<ReplacementItem> parseReplacementItem(StringRef Spec); + + std::string str() const { + std::string Result; + raw_string_ostream Stream(Result); + Stream << *this; + Stream.flush(); + return Result; + } + + template <unsigned N> SmallString<N> sstr() const { + SmallString<N> Result; + raw_svector_ostream Stream(Result); + Stream << *this; + return Result; + } + + template <unsigned N> operator SmallString<N>() const { return sstr<N>(); } + + operator std::string() const { return str(); } +}; + +template <typename Tuple> class formatv_object : public formatv_object_base { + // Storage for the parameter adapters. Since the base class erases the type + // of the parameters, we have to own the storage for the parameters here, and + // have the base class store type-erased pointers into this tuple. + Tuple Parameters; + +public: + formatv_object(StringRef Fmt, Tuple &&Params) + : formatv_object_base(Fmt, std::tuple_size<Tuple>::value), + Parameters(std::move(Params)) { + Adapters = apply_tuple(create_adapters(), Parameters); + } + + formatv_object(formatv_object const &rhs) = delete; + + formatv_object(formatv_object &&rhs) + : formatv_object_base(std::move(rhs)), + Parameters(std::move(rhs.Parameters)) { + Adapters = apply_tuple(create_adapters(), Parameters); + } +}; + +// Format text given a format string and replacement parameters. +// +// ===General Description=== +// +// Formats textual output. `Fmt` is a string consisting of one or more +// replacement sequences with the following grammar: +// +// rep_field ::= "{" [index] ["," layout] [":" format] "}" +// index ::= <non-negative integer> +// layout ::= [[[char]loc]width] +// format ::= <any string not containing "{" or "}"> +// char ::= <any character except "{" or "}"> +// loc ::= "-" | "=" | "+" +// width ::= <positive integer> +// +// index - A non-negative integer specifying the index of the item in the +// parameter pack to print. Any other value is invalid. +// layout - A string controlling how the field is laid out within the available +// space. +// format - A type-dependent string used to provide additional options to +// the formatting operation. Refer to the documentation of the +// various individual format providers for per-type options. +// char - The padding character. Defaults to ' ' (space). Only valid if +// `loc` is also specified. +// loc - Where to print the formatted text within the field. Only valid if +// `width` is also specified. +// '-' : The field is left aligned within the available space. +// '=' : The field is centered within the available space. +// '+' : The field is right aligned within the available space (this +// is the default). +// width - The width of the field within which to print the formatted text. +// If this is less than the required length then the `char` and `loc` +// fields are ignored, and the field is printed with no leading or +// trailing padding. If this is greater than the required length, +// then the text is output according to the value of `loc`, and padded +// as appropriate on the left and/or right by `char`. +// +// ===Special Characters=== +// +// The characters '{' and '}' are reserved and cannot appear anywhere within a +// replacement sequence. Outside of a replacement sequence, in order to print +// a literal '{' or '}' it must be doubled -- "{{" to print a literal '{' and +// "}}" to print a literal '}'. +// +// ===Parameter Indexing=== +// `index` specifies the index of the parameter in the parameter pack to format +// into the output. Note that it is possible to refer to the same parameter +// index multiple times in a given format string. This makes it possible to +// output the same value multiple times without passing it multiple times to the +// function. For example: +// +// formatv("{0} {1} {0}", "a", "bb") +// +// would yield the string "abba". This can be convenient when it is expensive +// to compute the value of the parameter, and you would otherwise have had to +// save it to a temporary. +// +// ===Formatter Search=== +// +// For a given parameter of type T, the following steps are executed in order +// until a match is found: +// +// 1. If the parameter is of class type, and inherits from format_adapter, +// Then format() is invoked on it to produce the formatted output. The +// implementation should write the formatted text into `Stream`. +// 2. If there is a suitable template specialization of format_provider<> +// for type T containing a method whose signature is: +// void format(const T &Obj, raw_ostream &Stream, StringRef Options) +// Then this method is invoked as described in Step 1. +// 3. If an appropriate operator<< for raw_ostream exists, it will be used. +// For this to work, (raw_ostream& << const T&) must return raw_ostream&. +// +// If a match cannot be found through either of the above methods, a compiler +// error is generated. +// +// ===Invalid Format String Handling=== +// +// In the case of a format string which does not match the grammar described +// above, the output is undefined. With asserts enabled, LLVM will trigger an +// assertion. Otherwise, it will try to do something reasonable, but in general +// the details of what that is are undefined. +// +template <typename... Ts> +inline auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object<decltype( + std::make_tuple(detail::build_format_adapter(std::forward<Ts>(Vals))...))> { + using ParamTuple = decltype( + std::make_tuple(detail::build_format_adapter(std::forward<Ts>(Vals))...)); + return formatv_object<ParamTuple>( + Fmt, + std::make_tuple(detail::build_format_adapter(std::forward<Ts>(Vals))...)); +} + +} // end namespace llvm + +#endif // LLVM_SUPPORT_FORMATVARIADIC_H diff --git a/third_party/llvm-project/include/llvm/Support/FormatVariadicDetails.h b/third_party/llvm-project/include/llvm/Support/FormatVariadicDetails.h new file mode 100644 index 000000000..e3c185134 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/FormatVariadicDetails.h @@ -0,0 +1,164 @@ +//===- FormatVariadicDetails.h - Helpers for FormatVariadic.h ----*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_FORMATVARIADIC_DETAILS_H +#define LLVM_SUPPORT_FORMATVARIADIC_DETAILS_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +#include <type_traits> + +namespace llvm { +template <typename T, typename Enable = void> struct format_provider {}; +class Error; + +namespace detail { +class format_adapter { + virtual void anchor(); + +protected: + virtual ~format_adapter() {} + +public: + virtual void format(raw_ostream &S, StringRef Options) = 0; +}; + +template <typename T> class provider_format_adapter : public format_adapter { + T Item; + +public: + explicit provider_format_adapter(T &&Item) : Item(std::forward<T>(Item)) {} + + void format(llvm::raw_ostream &S, StringRef Options) override { + format_provider<typename std::decay<T>::type>::format(Item, S, Options); + } +}; + +template <typename T> +class stream_operator_format_adapter : public format_adapter { + T Item; + +public: + explicit stream_operator_format_adapter(T &&Item) + : Item(std::forward<T>(Item)) {} + + void format(llvm::raw_ostream &S, StringRef Options) override { S << Item; } +}; + +template <typename T> class missing_format_adapter; + +// Test if format_provider<T> is defined on T and contains a member function +// with the signature: +// static void format(const T&, raw_stream &, StringRef); +// +template <class T> class has_FormatProvider { +public: + using Decayed = typename std::decay<T>::type; + typedef void (*Signature_format)(const Decayed &, llvm::raw_ostream &, + StringRef); + + template <typename U> + static char test(SameType<Signature_format, &U::format> *); + + template <typename U> static double test(...); + + static bool const value = + (sizeof(test<llvm::format_provider<Decayed>>(nullptr)) == 1); +}; + +// Test if raw_ostream& << T -> raw_ostream& is findable via ADL. +template <class T> class has_StreamOperator { +public: + using ConstRefT = const typename std::decay<T>::type &; + + template <typename U> + static char test(typename std::enable_if< + std::is_same<decltype(std::declval<llvm::raw_ostream &>() + << std::declval<U>()), + llvm::raw_ostream &>::value, + int *>::type); + + template <typename U> static double test(...); + + static bool const value = (sizeof(test<ConstRefT>(nullptr)) == 1); +}; + +// Simple template that decides whether a type T should use the member-function +// based format() invocation. +template <typename T> +struct uses_format_member + : public std::integral_constant< + bool, + std::is_base_of<format_adapter, + typename std::remove_reference<T>::type>::value> {}; + +// Simple template that decides whether a type T should use the format_provider +// based format() invocation. The member function takes priority, so this test +// will only be true if there is not ALSO a format member. +template <typename T> +struct uses_format_provider + : public std::integral_constant< + bool, !uses_format_member<T>::value && has_FormatProvider<T>::value> { +}; + +// Simple template that decides whether a type T should use the operator<< +// based format() invocation. This takes last priority. +template <typename T> +struct uses_stream_operator + : public std::integral_constant<bool, !uses_format_member<T>::value && + !uses_format_provider<T>::value && + has_StreamOperator<T>::value> {}; + +// Simple template that decides whether a type T has neither a member-function +// nor format_provider based implementation that it can use. Mostly used so +// that the compiler spits out a nice diagnostic when a type with no format +// implementation can be located. +template <typename T> +struct uses_missing_provider + : public std::integral_constant<bool, !uses_format_member<T>::value && + !uses_format_provider<T>::value && + !uses_stream_operator<T>::value> { +}; + +template <typename T> +typename std::enable_if<uses_format_member<T>::value, T>::type +build_format_adapter(T &&Item) { + return std::forward<T>(Item); +} + +template <typename T> +typename std::enable_if<uses_format_provider<T>::value, + provider_format_adapter<T>>::type +build_format_adapter(T &&Item) { + return provider_format_adapter<T>(std::forward<T>(Item)); +} + +template <typename T> +typename std::enable_if<uses_stream_operator<T>::value, + stream_operator_format_adapter<T>>::type +build_format_adapter(T &&Item) { + // If the caller passed an Error by value, then stream_operator_format_adapter + // would be responsible for consuming it. + // Make the caller opt into this by calling fmt_consume(). + static_assert( + !std::is_same<llvm::Error, typename std::remove_cv<T>::type>::value, + "llvm::Error-by-value must be wrapped in fmt_consume() for formatv"); + return stream_operator_format_adapter<T>(std::forward<T>(Item)); +} + +template <typename T> +typename std::enable_if<uses_missing_provider<T>::value, + missing_format_adapter<T>>::type +build_format_adapter(T &&Item) { + return missing_format_adapter<T>(); +} +} +} + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/FormattedStream.h b/third_party/llvm-project/include/llvm/Support/FormattedStream.h new file mode 100644 index 000000000..b49c8d865 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/FormattedStream.h @@ -0,0 +1,161 @@ +//===-- llvm/Support/FormattedStream.h - Formatted streams ------*- 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 contains raw_ostream implementations for streams to do +// things like pretty-print comments. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_FORMATTEDSTREAM_H +#define LLVM_SUPPORT_FORMATTEDSTREAM_H + +#include "llvm/Support/raw_ostream.h" +#include <utility> + +namespace llvm { + +/// formatted_raw_ostream - A raw_ostream that wraps another one and keeps track +/// of line and column position, allowing padding out to specific column +/// boundaries and querying the number of lines written to the stream. +/// +class formatted_raw_ostream : public raw_ostream { + /// TheStream - The real stream we output to. We set it to be + /// unbuffered, since we're already doing our own buffering. + /// + raw_ostream *TheStream; + + /// Position - The current output column and line of the data that's + /// been flushed and the portion of the buffer that's been + /// scanned. The line and column scheme is zero-based. + /// + std::pair<unsigned, unsigned> Position; + + /// Scanned - This points to one past the last character in the + /// buffer we've scanned. + /// + const char *Scanned; + + void write_impl(const char *Ptr, size_t Size) override; + + /// current_pos - Return the current position within the stream, + /// not counting the bytes currently in the buffer. + uint64_t current_pos() const override { + // Our current position in the stream is all the contents which have been + // written to the underlying stream (*not* the current position of the + // underlying stream). + return TheStream->tell(); + } + + /// ComputePosition - Examine the given output buffer and figure out the new + /// position after output. + /// + void ComputePosition(const char *Ptr, size_t size); + + void setStream(raw_ostream &Stream) { + releaseStream(); + + TheStream = &Stream; + + // This formatted_raw_ostream inherits from raw_ostream, so it'll do its + // own buffering, and it doesn't need or want TheStream to do another + // layer of buffering underneath. Resize the buffer to what TheStream + // had been using, and tell TheStream not to do its own buffering. + if (size_t BufferSize = TheStream->GetBufferSize()) + SetBufferSize(BufferSize); + else + SetUnbuffered(); + TheStream->SetUnbuffered(); + + Scanned = nullptr; + } + +public: + /// formatted_raw_ostream - Open the specified file for + /// writing. If an error occurs, information about the error is + /// put into ErrorInfo, and the stream should be immediately + /// destroyed; the string will be empty if no error occurred. + /// + /// As a side effect, the given Stream is set to be Unbuffered. + /// This is because formatted_raw_ostream does its own buffering, + /// so it doesn't want another layer of buffering to be happening + /// underneath it. + /// + formatted_raw_ostream(raw_ostream &Stream) + : TheStream(nullptr), Position(0, 0) { + setStream(Stream); + } + explicit formatted_raw_ostream() : TheStream(nullptr), Position(0, 0) { + Scanned = nullptr; + } + + ~formatted_raw_ostream() override { + flush(); + releaseStream(); + } + + /// PadToColumn - Align the output to some column number. If the current + /// column is already equal to or more than NewCol, PadToColumn inserts one + /// space. + /// + /// \param NewCol - The column to move to. + formatted_raw_ostream &PadToColumn(unsigned NewCol); + + /// getColumn - Return the column number + unsigned getColumn() { return Position.first; } + + /// getLine - Return the line number + unsigned getLine() { return Position.second; } + + raw_ostream &resetColor() override { + TheStream->resetColor(); + return *this; + } + + raw_ostream &reverseColor() override { + TheStream->reverseColor(); + return *this; + } + + raw_ostream &changeColor(enum Colors Color, bool Bold, bool BG) override { + TheStream->changeColor(Color, Bold, BG); + return *this; + } + + bool is_displayed() const override { + return TheStream->is_displayed(); + } + +private: + void releaseStream() { + // Transfer the buffer settings from this raw_ostream back to the underlying + // stream. + if (!TheStream) + return; + if (size_t BufferSize = GetBufferSize()) + TheStream->SetBufferSize(BufferSize); + else + TheStream->SetUnbuffered(); + } +}; + +/// fouts() - This returns a reference to a formatted_raw_ostream for +/// standard output. Use it like: fouts() << "foo" << "bar"; +formatted_raw_ostream &fouts(); + +/// ferrs() - This returns a reference to a formatted_raw_ostream for +/// standard error. Use it like: ferrs() << "foo" << "bar"; +formatted_raw_ostream &ferrs(); + +/// fdbgs() - This returns a reference to a formatted_raw_ostream for +/// debug output. Use it like: fdbgs() << "foo" << "bar"; +formatted_raw_ostream &fdbgs(); + +} // end llvm namespace + + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/Host.h b/third_party/llvm-project/include/llvm/Support/Host.h new file mode 100644 index 000000000..44f543c36 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Host.h @@ -0,0 +1,70 @@ +//===- llvm/Support/Host.h - Host machine characteristics --------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Methods for querying the nature of the host machine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_HOST_H +#define LLVM_SUPPORT_HOST_H + +#include "llvm/ADT/StringMap.h" + +#include <string> + +namespace llvm { +namespace sys { + + /// getDefaultTargetTriple() - Return the default target triple the compiler + /// has been configured to produce code for. + /// + /// The target triple is a string in the format of: + /// CPU_TYPE-VENDOR-OPERATING_SYSTEM + /// or + /// CPU_TYPE-VENDOR-KERNEL-OPERATING_SYSTEM + std::string getDefaultTargetTriple(); + + /// getProcessTriple() - Return an appropriate target triple for generating + /// code to be loaded into the current process, e.g. when using the JIT. + std::string getProcessTriple(); + + /// getHostCPUName - Get the LLVM name for the host CPU. The particular format + /// of the name is target dependent, and suitable for passing as -mcpu to the + /// target which matches the host. + /// + /// \return - The host CPU name, or empty if the CPU could not be determined. + StringRef getHostCPUName(); + + /// getHostCPUFeatures - Get the LLVM names for the host CPU features. + /// The particular format of the names are target dependent, and suitable for + /// passing as -mattr to the target which matches the host. + /// + /// \param Features - A string mapping feature names to either + /// true (if enabled) or false (if disabled). This routine makes no guarantees + /// about exactly which features may appear in this map, except that they are + /// all valid LLVM feature names. + /// + /// \return - True on success. + bool getHostCPUFeatures(StringMap<bool> &Features); + + /// Get the number of physical cores (as opposed to logical cores returned + /// from thread::hardware_concurrency(), which includes hyperthreads). + /// Returns -1 if unknown for the current host system. + int getHostNumPhysicalCores(); + + namespace detail { + /// Helper functions to extract HostCPUName from /proc/cpuinfo on linux. + StringRef getHostCPUNameForPowerPC(StringRef ProcCpuinfoContent); + StringRef getHostCPUNameForARM(StringRef ProcCpuinfoContent); + StringRef getHostCPUNameForS390x(StringRef ProcCpuinfoContent); + StringRef getHostCPUNameForBPF(); + } +} +} + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/LEB128.h b/third_party/llvm-project/include/llvm/Support/LEB128.h new file mode 100644 index 000000000..a02b83ca9 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/LEB128.h @@ -0,0 +1,198 @@ +//===- llvm/Support/LEB128.h - [SU]LEB128 utility functions -----*- 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 declares some utility functions for encoding SLEB128 and +// ULEB128 values. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_LEB128_H +#define LLVM_SUPPORT_LEB128_H + +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +/// Utility function to encode a SLEB128 value to an output stream. Returns +/// the length in bytes of the encoded value. +inline unsigned encodeSLEB128(int64_t Value, raw_ostream &OS, + unsigned PadTo = 0) { + bool More; + unsigned Count = 0; + do { + uint8_t Byte = Value & 0x7f; + // NOTE: this assumes that this signed shift is an arithmetic right shift. + Value >>= 7; + More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) || + ((Value == -1) && ((Byte & 0x40) != 0)))); + Count++; + if (More || Count < PadTo) + Byte |= 0x80; // Mark this byte to show that more bytes will follow. + OS << char(Byte); + } while (More); + + // Pad with 0x80 and emit a terminating byte at the end. + if (Count < PadTo) { + uint8_t PadValue = Value < 0 ? 0x7f : 0x00; + for (; Count < PadTo - 1; ++Count) + OS << char(PadValue | 0x80); + OS << char(PadValue); + Count++; + } + return Count; +} + +/// Utility function to encode a SLEB128 value to a buffer. Returns +/// the length in bytes of the encoded value. +inline unsigned encodeSLEB128(int64_t Value, uint8_t *p, unsigned PadTo = 0) { + uint8_t *orig_p = p; + unsigned Count = 0; + bool More; + do { + uint8_t Byte = Value & 0x7f; + // NOTE: this assumes that this signed shift is an arithmetic right shift. + Value >>= 7; + More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) || + ((Value == -1) && ((Byte & 0x40) != 0)))); + Count++; + if (More || Count < PadTo) + Byte |= 0x80; // Mark this byte to show that more bytes will follow. + *p++ = Byte; + } while (More); + + // Pad with 0x80 and emit a terminating byte at the end. + if (Count < PadTo) { + uint8_t PadValue = Value < 0 ? 0x7f : 0x00; + for (; Count < PadTo - 1; ++Count) + *p++ = (PadValue | 0x80); + *p++ = PadValue; + } + return (unsigned)(p - orig_p); +} + +/// Utility function to encode a ULEB128 value to an output stream. Returns +/// the length in bytes of the encoded value. +inline unsigned encodeULEB128(uint64_t Value, raw_ostream &OS, + unsigned PadTo = 0) { + unsigned Count = 0; + do { + uint8_t Byte = Value & 0x7f; + Value >>= 7; + Count++; + if (Value != 0 || Count < PadTo) + Byte |= 0x80; // Mark this byte to show that more bytes will follow. + OS << char(Byte); + } while (Value != 0); + + // Pad with 0x80 and emit a null byte at the end. + if (Count < PadTo) { + for (; Count < PadTo - 1; ++Count) + OS << '\x80'; + OS << '\x00'; + Count++; + } + return Count; +} + +/// Utility function to encode a ULEB128 value to a buffer. Returns +/// the length in bytes of the encoded value. +inline unsigned encodeULEB128(uint64_t Value, uint8_t *p, + unsigned PadTo = 0) { + uint8_t *orig_p = p; + unsigned Count = 0; + do { + uint8_t Byte = Value & 0x7f; + Value >>= 7; + Count++; + if (Value != 0 || Count < PadTo) + Byte |= 0x80; // Mark this byte to show that more bytes will follow. + *p++ = Byte; + } while (Value != 0); + + // Pad with 0x80 and emit a null byte at the end. + if (Count < PadTo) { + for (; Count < PadTo - 1; ++Count) + *p++ = '\x80'; + *p++ = '\x00'; + } + + return (unsigned)(p - orig_p); +} + +/// Utility function to decode a ULEB128 value. +inline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr, + const uint8_t *end = nullptr, + const char **error = nullptr) { + const uint8_t *orig_p = p; + uint64_t Value = 0; + unsigned Shift = 0; + if (error) + *error = nullptr; + do { + if (end && p == end) { + if (error) + *error = "malformed uleb128, extends past end"; + if (n) + *n = (unsigned)(p - orig_p); + return 0; + } + uint64_t Slice = *p & 0x7f; + if (Shift >= 64 || Slice << Shift >> Shift != Slice) { + if (error) + *error = "uleb128 too big for uint64"; + if (n) + *n = (unsigned)(p - orig_p); + return 0; + } + Value += uint64_t(*p & 0x7f) << Shift; + Shift += 7; + } while (*p++ >= 128); + if (n) + *n = (unsigned)(p - orig_p); + return Value; +} + +/// Utility function to decode a SLEB128 value. +inline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr, + const uint8_t *end = nullptr, + const char **error = nullptr) { + const uint8_t *orig_p = p; + int64_t Value = 0; + unsigned Shift = 0; + uint8_t Byte; + if (error) + *error = nullptr; + do { + if (end && p == end) { + if (error) + *error = "malformed sleb128, extends past end"; + if (n) + *n = (unsigned)(p - orig_p); + return 0; + } + Byte = *p++; + Value |= (uint64_t(Byte & 0x7f) << Shift); + Shift += 7; + } while (Byte >= 128); + // Sign extend negative numbers if needed. + if (Shift < 64 && (Byte & 0x40)) + Value |= (-1ULL) << Shift; + if (n) + *n = (unsigned)(p - orig_p); + return Value; +} + +/// Utility function to get the size of the ULEB128-encoded value. +extern unsigned getULEB128Size(uint64_t Value); + +/// Utility function to get the size of the SLEB128-encoded value. +extern unsigned getSLEB128Size(int64_t Value); + +} // namespace llvm + +#endif // LLVM_SYSTEM_LEB128_H diff --git a/third_party/llvm-project/include/llvm/Support/LICENSE.TXT b/third_party/llvm-project/include/llvm/Support/LICENSE.TXT new file mode 100644 index 000000000..3479b3fd7 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/LICENSE.TXT @@ -0,0 +1,6 @@ +LLVM System Interface Library +------------------------------------------------------------------------------- +The LLVM System Interface Library is licensed under the Illinois Open Source +License and has the following additional copyright: + +Copyright (C) 2004 eXtensible Systems, Inc. diff --git a/third_party/llvm-project/include/llvm/Support/LineIterator.h b/third_party/llvm-project/include/llvm/Support/LineIterator.h new file mode 100644 index 000000000..2a1e47bfe --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/LineIterator.h @@ -0,0 +1,87 @@ +//===- LineIterator.h - Iterator to read a text buffer's lines --*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_LINEITERATOR_H +#define LLVM_SUPPORT_LINEITERATOR_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" +#include <iterator> + +namespace llvm { + +class MemoryBuffer; + +/// A forward iterator which reads text lines from a buffer. +/// +/// This class provides a forward iterator interface for reading one line at +/// a time from a buffer. When default constructed the iterator will be the +/// "end" iterator. +/// +/// The iterator is aware of what line number it is currently processing. It +/// strips blank lines by default, and comment lines given a comment-starting +/// character. +/// +/// Note that this iterator requires the buffer to be nul terminated. +class line_iterator + : public std::iterator<std::forward_iterator_tag, StringRef> { + const MemoryBuffer *Buffer = nullptr; + char CommentMarker = '\0'; + bool SkipBlanks = true; + + unsigned LineNumber = 1; + StringRef CurrentLine; + +public: + /// Default construct an "end" iterator. + line_iterator() = default; + + /// Construct a new iterator around some memory buffer. + explicit line_iterator(const MemoryBuffer &Buffer, bool SkipBlanks = true, + char CommentMarker = '\0'); + + /// Return true if we've reached EOF or are an "end" iterator. + bool is_at_eof() const { return !Buffer; } + + /// Return true if we're an "end" iterator or have reached EOF. + bool is_at_end() const { return is_at_eof(); } + + /// Return the current line number. May return any number at EOF. + int64_t line_number() const { return LineNumber; } + + /// Advance to the next (non-empty, non-comment) line. + line_iterator &operator++() { + advance(); + return *this; + } + line_iterator operator++(int) { + line_iterator tmp(*this); + advance(); + return tmp; + } + + /// Get the current line as a \c StringRef. + StringRef operator*() const { return CurrentLine; } + const StringRef *operator->() const { return &CurrentLine; } + + friend bool operator==(const line_iterator &LHS, const line_iterator &RHS) { + return LHS.Buffer == RHS.Buffer && + LHS.CurrentLine.begin() == RHS.CurrentLine.begin(); + } + + friend bool operator!=(const line_iterator &LHS, const line_iterator &RHS) { + return !(LHS == RHS); + } + +private: + /// Advance the iterator to the next line. + void advance(); +}; +} + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/Locale.h b/third_party/llvm-project/include/llvm/Support/Locale.h new file mode 100644 index 000000000..f7a2c036e --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Locale.h @@ -0,0 +1,17 @@ +#ifndef LLVM_SUPPORT_LOCALE_H +#define LLVM_SUPPORT_LOCALE_H + +namespace llvm { +class StringRef; + +namespace sys { +namespace locale { + +int columnWidth(StringRef s); +bool isPrint(int c); + +} +} +} + +#endif // LLVM_SUPPORT_LOCALE_H diff --git a/third_party/llvm-project/include/llvm/Support/MD5.h b/third_party/llvm-project/include/llvm/Support/MD5.h new file mode 100644 index 000000000..bb2bdbf1b --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/MD5.h @@ -0,0 +1,122 @@ +/* -*- C++ -*- + * This code is derived from (original license follows): + * + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer <solar at openwall.com> + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See md5.c for more information. + */ + +#ifndef LLVM_SUPPORT_MD5_H +#define LLVM_SUPPORT_MD5_H + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Endian.h" +#include <array> +#include <cstdint> + +namespace llvm { + +template <typename T> class ArrayRef; + +class MD5 { + // Any 32-bit or wider unsigned integer data type will do. + typedef uint32_t MD5_u32plus; + + MD5_u32plus a = 0x67452301; + MD5_u32plus b = 0xefcdab89; + MD5_u32plus c = 0x98badcfe; + MD5_u32plus d = 0x10325476; + MD5_u32plus hi = 0; + MD5_u32plus lo = 0; + uint8_t buffer[64]; + MD5_u32plus block[16]; + +public: + struct MD5Result { + std::array<uint8_t, 16> Bytes; + + operator std::array<uint8_t, 16>() const { return Bytes; } + + const uint8_t &operator[](size_t I) const { return Bytes[I]; } + uint8_t &operator[](size_t I) { return Bytes[I]; } + + SmallString<32> digest() const; + + uint64_t low() const { + // Our MD5 implementation returns the result in little endian, so the low + // word is first. + using namespace support; + return endian::read<uint64_t, little, unaligned>(Bytes.data()); + } + + uint64_t high() const { + using namespace support; + return endian::read<uint64_t, little, unaligned>(Bytes.data() + 8); + } + std::pair<uint64_t, uint64_t> words() const { + using namespace support; + return std::make_pair(high(), low()); + } + }; + + MD5(); + + /// Updates the hash for the byte stream provided. + void update(ArrayRef<uint8_t> Data); + + /// Updates the hash for the StringRef provided. + void update(StringRef Str); + + /// Finishes off the hash and puts the result in result. + void final(MD5Result &Result); + + /// Translates the bytes in \p Res to a hex string that is + /// deposited into \p Str. The result will be of length 32. + static void stringifyResult(MD5Result &Result, SmallString<32> &Str); + + /// Computes the hash for a given bytes. + static std::array<uint8_t, 16> hash(ArrayRef<uint8_t> Data); + +private: + const uint8_t *body(ArrayRef<uint8_t> Data); +}; + +inline bool operator==(const MD5::MD5Result &LHS, const MD5::MD5Result &RHS) { + return LHS.Bytes == RHS.Bytes; +} + +/// Helper to compute and return lower 64 bits of the given string's MD5 hash. +inline uint64_t MD5Hash(StringRef Str) { + using namespace support; + + MD5 Hash; + Hash.update(Str); + MD5::MD5Result Result; + Hash.final(Result); + // Return the least significant word. + return Result.low(); +} + +} // end namespace llvm + +#endif // LLVM_SUPPORT_MD5_H diff --git a/third_party/llvm-project/include/llvm/Support/ManagedStatic.h b/third_party/llvm-project/include/llvm/Support/ManagedStatic.h new file mode 100644 index 000000000..4eb30f548 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/ManagedStatic.h @@ -0,0 +1 @@ +// XXX BINARYEN - we don't need this, but stuff imports it diff --git a/third_party/llvm-project/include/llvm/Support/MathExtras.h b/third_party/llvm-project/include/llvm/Support/MathExtras.h new file mode 100644 index 000000000..004a6f5f6 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/MathExtras.h @@ -0,0 +1,951 @@ +//===-- llvm/Support/MathExtras.h - Useful math functions -------*- 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 contains some functions that are useful for math stuff. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_MATHEXTRAS_H +#define LLVM_SUPPORT_MATHEXTRAS_H + +#include "llvm/Support/Compiler.h" +#include "llvm/Support/SwapByteOrder.h" +#include <algorithm> +#include <cassert> +#include <climits> +#include <cstring> +#include <limits> +#include <type_traits> + +#ifdef __ANDROID_NDK__ +#include <android/api-level.h> +#endif + +#ifdef _MSC_VER +// Declare these intrinsics manually rather including intrin.h. It's very +// expensive, and MathExtras.h is popular. +// #include <intrin.h> +extern "C" { +unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask); +unsigned char _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask); +unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask); +unsigned char _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask); +} +#endif + +namespace llvm { + +/// The behavior an operation has on an input of 0. +enum ZeroBehavior { + /// The returned value is undefined. + ZB_Undefined, + /// The returned value is numeric_limits<T>::max() + ZB_Max, + /// The returned value is numeric_limits<T>::digits + ZB_Width +}; + +/// Mathematical constants. +namespace numbers { +// TODO: Track C++20 std::numbers. +// TODO: Favor using the hexadecimal FP constants (requires C++17). +constexpr double e = 2.7182818284590452354, // (0x1.5bf0a8b145749P+1) https://oeis.org/A001113 + egamma = .57721566490153286061, // (0x1.2788cfc6fb619P-1) https://oeis.org/A001620 + ln2 = .69314718055994530942, // (0x1.62e42fefa39efP-1) https://oeis.org/A002162 + ln10 = 2.3025850929940456840, // (0x1.24bb1bbb55516P+1) https://oeis.org/A002392 + log2e = 1.4426950408889634074, // (0x1.71547652b82feP+0) + log10e = .43429448190325182765, // (0x1.bcb7b1526e50eP-2) + pi = 3.1415926535897932385, // (0x1.921fb54442d18P+1) https://oeis.org/A000796 + inv_pi = .31830988618379067154, // (0x1.45f306bc9c883P-2) https://oeis.org/A049541 + sqrtpi = 1.7724538509055160273, // (0x1.c5bf891b4ef6bP+0) https://oeis.org/A002161 + inv_sqrtpi = .56418958354775628695, // (0x1.20dd750429b6dP-1) https://oeis.org/A087197 + sqrt2 = 1.4142135623730950488, // (0x1.6a09e667f3bcdP+0) https://oeis.org/A00219 + inv_sqrt2 = .70710678118654752440, // (0x1.6a09e667f3bcdP-1) + sqrt3 = 1.7320508075688772935, // (0x1.bb67ae8584caaP+0) https://oeis.org/A002194 + inv_sqrt3 = .57735026918962576451, // (0x1.279a74590331cP-1) + phi = 1.6180339887498948482; // (0x1.9e3779b97f4a8P+0) https://oeis.org/A001622 +constexpr float ef = 2.71828183F, // (0x1.5bf0a8P+1) https://oeis.org/A001113 + egammaf = .577215665F, // (0x1.2788d0P-1) https://oeis.org/A001620 + ln2f = .693147181F, // (0x1.62e430P-1) https://oeis.org/A002162 + ln10f = 2.30258509F, // (0x1.26bb1cP+1) https://oeis.org/A002392 + log2ef = 1.44269504F, // (0x1.715476P+0) + log10ef = .434294482F, // (0x1.bcb7b2P-2) + pif = 3.14159265F, // (0x1.921fb6P+1) https://oeis.org/A000796 + inv_pif = .318309886F, // (0x1.45f306P-2) https://oeis.org/A049541 + sqrtpif = 1.77245385F, // (0x1.c5bf8aP+0) https://oeis.org/A002161 + inv_sqrtpif = .564189584F, // (0x1.20dd76P-1) https://oeis.org/A087197 + sqrt2f = 1.41421356F, // (0x1.6a09e6P+0) https://oeis.org/A002193 + inv_sqrt2f = .707106781F, // (0x1.6a09e6P-1) + sqrt3f = 1.73205081F, // (0x1.bb67aeP+0) https://oeis.org/A002194 + inv_sqrt3f = .577350269F, // (0x1.279a74P-1) + phif = 1.61803399F; // (0x1.9e377aP+0) https://oeis.org/A001622 +} // namespace numbers + +namespace detail { +template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter { + static unsigned count(T Val, ZeroBehavior) { + if (!Val) + return std::numeric_limits<T>::digits; + if (Val & 0x1) + return 0; + + // Bisection method. + unsigned ZeroBits = 0; + T Shift = std::numeric_limits<T>::digits >> 1; + T Mask = std::numeric_limits<T>::max() >> Shift; + while (Shift) { + if ((Val & Mask) == 0) { + Val >>= Shift; + ZeroBits |= Shift; + } + Shift >>= 1; + Mask >>= Shift; + } + return ZeroBits; + } +}; + +#if defined(__GNUC__) || defined(_MSC_VER) +template <typename T> struct TrailingZerosCounter<T, 4> { + static unsigned count(T Val, ZeroBehavior ZB) { + if (ZB != ZB_Undefined && Val == 0) + return 32; + +#if __has_builtin(__builtin_ctz) || defined(__GNUC__) + return __builtin_ctz(Val); +#elif defined(_MSC_VER) + unsigned long Index; + _BitScanForward(&Index, Val); + return Index; +#endif + } +}; + +#if !defined(_MSC_VER) || defined(_M_X64) +template <typename T> struct TrailingZerosCounter<T, 8> { + static unsigned count(T Val, ZeroBehavior ZB) { + if (ZB != ZB_Undefined && Val == 0) + return 64; + +#if __has_builtin(__builtin_ctzll) || defined(__GNUC__) + return __builtin_ctzll(Val); +#elif defined(_MSC_VER) + unsigned long Index; + _BitScanForward64(&Index, Val); + return Index; +#endif + } +}; +#endif +#endif +} // namespace detail + +/// Count number of 0's from the least significant bit to the most +/// stopping at the first 1. +/// +/// Only unsigned integral types are allowed. +/// +/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are +/// valid arguments. +template <typename T> +unsigned countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) { + static_assert(std::numeric_limits<T>::is_integer && + !std::numeric_limits<T>::is_signed, + "Only unsigned integral types are allowed."); + return llvm::detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB); +} + +namespace detail { +template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter { + static unsigned count(T Val, ZeroBehavior) { + if (!Val) + return std::numeric_limits<T>::digits; + + // Bisection method. + unsigned ZeroBits = 0; + for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) { + T Tmp = Val >> Shift; + if (Tmp) + Val = Tmp; + else + ZeroBits |= Shift; + } + return ZeroBits; + } +}; + +#if defined(__GNUC__) || defined(_MSC_VER) +template <typename T> struct LeadingZerosCounter<T, 4> { + static unsigned count(T Val, ZeroBehavior ZB) { + if (ZB != ZB_Undefined && Val == 0) + return 32; + +#if __has_builtin(__builtin_clz) || defined(__GNUC__) + return __builtin_clz(Val); +#elif defined(_MSC_VER) + unsigned long Index; + _BitScanReverse(&Index, Val); + return Index ^ 31; +#endif + } +}; + +#if !defined(_MSC_VER) || defined(_M_X64) +template <typename T> struct LeadingZerosCounter<T, 8> { + static unsigned count(T Val, ZeroBehavior ZB) { + if (ZB != ZB_Undefined && Val == 0) + return 64; + +#if __has_builtin(__builtin_clzll) || defined(__GNUC__) + return __builtin_clzll(Val); +#elif defined(_MSC_VER) + unsigned long Index; + _BitScanReverse64(&Index, Val); + return Index ^ 63; +#endif + } +}; +#endif +#endif +} // namespace detail + +/// Count number of 0's from the most significant bit to the least +/// stopping at the first 1. +/// +/// Only unsigned integral types are allowed. +/// +/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are +/// valid arguments. +template <typename T> +unsigned countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) { + static_assert(std::numeric_limits<T>::is_integer && + !std::numeric_limits<T>::is_signed, + "Only unsigned integral types are allowed."); + return llvm::detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB); +} + +/// Get the index of the first set bit starting from the least +/// significant bit. +/// +/// Only unsigned integral types are allowed. +/// +/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are +/// valid arguments. +template <typename T> T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) { + if (ZB == ZB_Max && Val == 0) + return std::numeric_limits<T>::max(); + + return countTrailingZeros(Val, ZB_Undefined); +} + +/// Create a bitmask with the N right-most bits set to 1, and all other +/// bits set to 0. Only unsigned types are allowed. +template <typename T> T maskTrailingOnes(unsigned N) { + static_assert(std::is_unsigned<T>::value, "Invalid type!"); + const unsigned Bits = CHAR_BIT * sizeof(T); + assert(N <= Bits && "Invalid bit index"); + return N == 0 ? 0 : (T(-1) >> (Bits - N)); +} + +/// Create a bitmask with the N left-most bits set to 1, and all other +/// bits set to 0. Only unsigned types are allowed. +template <typename T> T maskLeadingOnes(unsigned N) { + return ~maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N); +} + +/// Create a bitmask with the N right-most bits set to 0, and all other +/// bits set to 1. Only unsigned types are allowed. +template <typename T> T maskTrailingZeros(unsigned N) { + return maskLeadingOnes<T>(CHAR_BIT * sizeof(T) - N); +} + +/// Create a bitmask with the N left-most bits set to 0, and all other +/// bits set to 1. Only unsigned types are allowed. +template <typename T> T maskLeadingZeros(unsigned N) { + return maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N); +} + +/// Get the index of the last set bit starting from the least +/// significant bit. +/// +/// Only unsigned integral types are allowed. +/// +/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are +/// valid arguments. +template <typename T> T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) { + if (ZB == ZB_Max && Val == 0) + return std::numeric_limits<T>::max(); + + // Use ^ instead of - because both gcc and llvm can remove the associated ^ + // in the __builtin_clz intrinsic on x86. + return countLeadingZeros(Val, ZB_Undefined) ^ + (std::numeric_limits<T>::digits - 1); +} + +/// Macro compressed bit reversal table for 256 bits. +/// +/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable +static const unsigned char BitReverseTable256[256] = { +#define R2(n) n, n + 2 * 64, n + 1 * 64, n + 3 * 64 +#define R4(n) R2(n), R2(n + 2 * 16), R2(n + 1 * 16), R2(n + 3 * 16) +#define R6(n) R4(n), R4(n + 2 * 4), R4(n + 1 * 4), R4(n + 3 * 4) + R6(0), R6(2), R6(1), R6(3) +#undef R2 +#undef R4 +#undef R6 +}; + +/// Reverse the bits in \p Val. +template <typename T> +T reverseBits(T Val) { + unsigned char in[sizeof(Val)]; + unsigned char out[sizeof(Val)]; + std::memcpy(in, &Val, sizeof(Val)); + for (unsigned i = 0; i < sizeof(Val); ++i) + out[(sizeof(Val) - i) - 1] = BitReverseTable256[in[i]]; + std::memcpy(&Val, out, sizeof(Val)); + return Val; +} + +// NOTE: The following support functions use the _32/_64 extensions instead of +// type overloading so that signed and unsigned integers can be used without +// ambiguity. + +/// Return the high 32 bits of a 64 bit value. +constexpr inline uint32_t Hi_32(uint64_t Value) { + return static_cast<uint32_t>(Value >> 32); +} + +/// Return the low 32 bits of a 64 bit value. +constexpr inline uint32_t Lo_32(uint64_t Value) { + return static_cast<uint32_t>(Value); +} + +/// Make a 64-bit integer from a high / low pair of 32-bit integers. +constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) { + return ((uint64_t)High << 32) | (uint64_t)Low; +} + +/// Checks if an integer fits into the given bit width. +template <unsigned N> constexpr inline bool isInt(int64_t x) { + return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1))); +} +// Template specializations to get better code for common cases. +template <> constexpr inline bool isInt<8>(int64_t x) { + return static_cast<int8_t>(x) == x; +} +template <> constexpr inline bool isInt<16>(int64_t x) { + return static_cast<int16_t>(x) == x; +} +template <> constexpr inline bool isInt<32>(int64_t x) { + return static_cast<int32_t>(x) == x; +} + +/// Checks if a signed integer is an N bit number shifted left by S. +template <unsigned N, unsigned S> +constexpr inline bool isShiftedInt(int64_t x) { + static_assert( + N > 0, "isShiftedInt<0> doesn't make sense (refers to a 0-bit number."); + static_assert(N + S <= 64, "isShiftedInt<N, S> with N + S > 64 is too wide."); + return isInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0); +} + +/// Checks if an unsigned integer fits into the given bit width. +/// +/// This is written as two functions rather than as simply +/// +/// return N >= 64 || X < (UINT64_C(1) << N); +/// +/// to keep MSVC from (incorrectly) warning on isUInt<64> that we're shifting +/// left too many places. +template <unsigned N> +constexpr inline typename std::enable_if<(N < 64), bool>::type +isUInt(uint64_t X) { + static_assert(N > 0, "isUInt<0> doesn't make sense"); + return X < (UINT64_C(1) << (N)); +} +template <unsigned N> +constexpr inline typename std::enable_if<N >= 64, bool>::type +isUInt(uint64_t X) { + return true; +} + +// Template specializations to get better code for common cases. +template <> constexpr inline bool isUInt<8>(uint64_t x) { + return static_cast<uint8_t>(x) == x; +} +template <> constexpr inline bool isUInt<16>(uint64_t x) { + return static_cast<uint16_t>(x) == x; +} +template <> constexpr inline bool isUInt<32>(uint64_t x) { + return static_cast<uint32_t>(x) == x; +} + +/// Checks if a unsigned integer is an N bit number shifted left by S. +template <unsigned N, unsigned S> +constexpr inline bool isShiftedUInt(uint64_t x) { + static_assert( + N > 0, "isShiftedUInt<0> doesn't make sense (refers to a 0-bit number)"); + static_assert(N + S <= 64, + "isShiftedUInt<N, S> with N + S > 64 is too wide."); + // Per the two static_asserts above, S must be strictly less than 64. So + // 1 << S is not undefined behavior. + return isUInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0); +} + +/// Gets the maximum value for a N-bit unsigned integer. +inline uint64_t maxUIntN(uint64_t N) { + assert(N > 0 && N <= 64 && "integer width out of range"); + + // uint64_t(1) << 64 is undefined behavior, so we can't do + // (uint64_t(1) << N) - 1 + // without checking first that N != 64. But this works and doesn't have a + // branch. + return UINT64_MAX >> (64 - N); +} + +/// Gets the minimum value for a N-bit signed integer. +inline int64_t minIntN(int64_t N) { + assert(N > 0 && N <= 64 && "integer width out of range"); + + return -(UINT64_C(1)<<(N-1)); +} + +/// Gets the maximum value for a N-bit signed integer. +inline int64_t maxIntN(int64_t N) { + assert(N > 0 && N <= 64 && "integer width out of range"); + + // This relies on two's complement wraparound when N == 64, so we convert to + // int64_t only at the very end to avoid UB. + return (UINT64_C(1) << (N - 1)) - 1; +} + +/// Checks if an unsigned integer fits into the given (dynamic) bit width. +inline bool isUIntN(unsigned N, uint64_t x) { + return N >= 64 || x <= maxUIntN(N); +} + +/// Checks if an signed integer fits into the given (dynamic) bit width. +inline bool isIntN(unsigned N, int64_t x) { + return N >= 64 || (minIntN(N) <= x && x <= maxIntN(N)); +} + +/// Return true if the argument is a non-empty sequence of ones starting at the +/// least significant bit with the remainder zero (32 bit version). +/// Ex. isMask_32(0x0000FFFFU) == true. +constexpr inline bool isMask_32(uint32_t Value) { + return Value && ((Value + 1) & Value) == 0; +} + +/// Return true if the argument is a non-empty sequence of ones starting at the +/// least significant bit with the remainder zero (64 bit version). +constexpr inline bool isMask_64(uint64_t Value) { + return Value && ((Value + 1) & Value) == 0; +} + +/// Return true if the argument contains a non-empty sequence of ones with the +/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true. +constexpr inline bool isShiftedMask_32(uint32_t Value) { + return Value && isMask_32((Value - 1) | Value); +} + +/// Return true if the argument contains a non-empty sequence of ones with the +/// remainder zero (64 bit version.) +constexpr inline bool isShiftedMask_64(uint64_t Value) { + return Value && isMask_64((Value - 1) | Value); +} + +/// Return true if the argument is a power of two > 0. +/// Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.) +constexpr inline bool isPowerOf2_32(uint32_t Value) { + return Value && !(Value & (Value - 1)); +} + +/// Return true if the argument is a power of two > 0 (64 bit edition.) +constexpr inline bool isPowerOf2_64(uint64_t Value) { + return Value && !(Value & (Value - 1)); +} + +/// Return a byte-swapped representation of the 16-bit argument. +inline uint16_t ByteSwap_16(uint16_t Value) { + return sys::SwapByteOrder_16(Value); +} + +/// Return a byte-swapped representation of the 32-bit argument. +inline uint32_t ByteSwap_32(uint32_t Value) { + return sys::SwapByteOrder_32(Value); +} + +/// Return a byte-swapped representation of the 64-bit argument. +inline uint64_t ByteSwap_64(uint64_t Value) { + return sys::SwapByteOrder_64(Value); +} + +/// Count the number of ones from the most significant bit to the first +/// zero bit. +/// +/// Ex. countLeadingOnes(0xFF0FFF00) == 8. +/// Only unsigned integral types are allowed. +/// +/// \param ZB the behavior on an input of all ones. Only ZB_Width and +/// ZB_Undefined are valid arguments. +template <typename T> +unsigned countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) { + static_assert(std::numeric_limits<T>::is_integer && + !std::numeric_limits<T>::is_signed, + "Only unsigned integral types are allowed."); + return countLeadingZeros<T>(~Value, ZB); +} + +/// Count the number of ones from the least significant bit to the first +/// zero bit. +/// +/// Ex. countTrailingOnes(0x00FF00FF) == 8. +/// Only unsigned integral types are allowed. +/// +/// \param ZB the behavior on an input of all ones. Only ZB_Width and +/// ZB_Undefined are valid arguments. +template <typename T> +unsigned countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) { + static_assert(std::numeric_limits<T>::is_integer && + !std::numeric_limits<T>::is_signed, + "Only unsigned integral types are allowed."); + return countTrailingZeros<T>(~Value, ZB); +} + +namespace detail { +template <typename T, std::size_t SizeOfT> struct PopulationCounter { + static unsigned count(T Value) { + // Generic version, forward to 32 bits. + static_assert(SizeOfT <= 4, "Not implemented!"); +#if defined(__GNUC__) + return __builtin_popcount(Value); +#else + uint32_t v = Value; + v = v - ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; +#endif + } +}; + +template <typename T> struct PopulationCounter<T, 8> { + static unsigned count(T Value) { +#if defined(__GNUC__) + return __builtin_popcountll(Value); +#else + uint64_t v = Value; + v = v - ((v >> 1) & 0x5555555555555555ULL); + v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL); + v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL; + return unsigned((uint64_t)(v * 0x0101010101010101ULL) >> 56); +#endif + } +}; +} // namespace detail + +/// Count the number of set bits in a value. +/// Ex. countPopulation(0xF000F000) = 8 +/// Returns 0 if the word is zero. +template <typename T> +inline unsigned countPopulation(T Value) { + static_assert(std::numeric_limits<T>::is_integer && + !std::numeric_limits<T>::is_signed, + "Only unsigned integral types are allowed."); + return detail::PopulationCounter<T, sizeof(T)>::count(Value); +} + +/// Compile time Log2. +/// Valid only for positive powers of two. +template <size_t kValue> constexpr inline size_t CTLog2() { + static_assert(kValue > 0 && llvm::isPowerOf2_64(kValue), + "Value is not a valid power of 2"); + return 1 + CTLog2<kValue / 2>(); +} + +template <> constexpr inline size_t CTLog2<1>() { return 0; } + +/// Return the log base 2 of the specified value. +inline double Log2(double Value) { +#if defined(__ANDROID_API__) && __ANDROID_API__ < 18 + return __builtin_log(Value) / __builtin_log(2.0); +#else + return log2(Value); +#endif +} + +/// Return the floor log base 2 of the specified value, -1 if the value is zero. +/// (32 bit edition.) +/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2 +inline unsigned Log2_32(uint32_t Value) { + return 31 - countLeadingZeros(Value); +} + +/// Return the floor log base 2 of the specified value, -1 if the value is zero. +/// (64 bit edition.) +inline unsigned Log2_64(uint64_t Value) { + return 63 - countLeadingZeros(Value); +} + +/// Return the ceil log base 2 of the specified value, 32 if the value is zero. +/// (32 bit edition). +/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3 +inline unsigned Log2_32_Ceil(uint32_t Value) { + return 32 - countLeadingZeros(Value - 1); +} + +/// Return the ceil log base 2 of the specified value, 64 if the value is zero. +/// (64 bit edition.) +inline unsigned Log2_64_Ceil(uint64_t Value) { + return 64 - countLeadingZeros(Value - 1); +} + +/// Return the greatest common divisor of the values using Euclid's algorithm. +template <typename T> +inline T greatestCommonDivisor(T A, T B) { + while (B) { + T Tmp = B; + B = A % B; + A = Tmp; + } + return A; +} + +inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) { + return greatestCommonDivisor<uint64_t>(A, B); +} + +/// This function takes a 64-bit integer and returns the bit equivalent double. +inline double BitsToDouble(uint64_t Bits) { + double D; + static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes"); + memcpy(&D, &Bits, sizeof(Bits)); + return D; +} + +/// This function takes a 32-bit integer and returns the bit equivalent float. +inline float BitsToFloat(uint32_t Bits) { + float F; + static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes"); + memcpy(&F, &Bits, sizeof(Bits)); + return F; +} + +/// This function takes a double and returns the bit equivalent 64-bit integer. +/// Note that copying doubles around changes the bits of NaNs on some hosts, +/// notably x86, so this routine cannot be used if these bits are needed. +inline uint64_t DoubleToBits(double Double) { + uint64_t Bits; + static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes"); + memcpy(&Bits, &Double, sizeof(Double)); + return Bits; +} + +/// This function takes a float and returns the bit equivalent 32-bit integer. +/// Note that copying floats around changes the bits of NaNs on some hosts, +/// notably x86, so this routine cannot be used if these bits are needed. +inline uint32_t FloatToBits(float Float) { + uint32_t Bits; + static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes"); + memcpy(&Bits, &Float, sizeof(Float)); + return Bits; +} + +/// A and B are either alignments or offsets. Return the minimum alignment that +/// may be assumed after adding the two together. +constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) { + // The largest power of 2 that divides both A and B. + // + // Replace "-Value" by "1+~Value" in the following commented code to avoid + // MSVC warning C4146 + // return (A | B) & -(A | B); + return (A | B) & (1 + ~(A | B)); +} + +/// Returns the next power of two (in 64-bits) that is strictly greater than A. +/// Returns zero on overflow. +inline uint64_t NextPowerOf2(uint64_t A) { + A |= (A >> 1); + A |= (A >> 2); + A |= (A >> 4); + A |= (A >> 8); + A |= (A >> 16); + A |= (A >> 32); + return A + 1; +} + +/// Returns the power of two which is less than or equal to the given value. +/// Essentially, it is a floor operation across the domain of powers of two. +inline uint64_t PowerOf2Floor(uint64_t A) { + if (!A) return 0; + return 1ull << (63 - countLeadingZeros(A, ZB_Undefined)); +} + +/// Returns the power of two which is greater than or equal to the given value. +/// Essentially, it is a ceil operation across the domain of powers of two. +inline uint64_t PowerOf2Ceil(uint64_t A) { + if (!A) + return 0; + return NextPowerOf2(A - 1); +} + +/// Returns the next integer (mod 2**64) that is greater than or equal to +/// \p Value and is a multiple of \p Align. \p Align must be non-zero. +/// +/// If non-zero \p Skew is specified, the return value will be a minimal +/// integer that is greater than or equal to \p Value and equal to +/// \p Align * N + \p Skew for some integer N. If \p Skew is larger than +/// \p Align, its value is adjusted to '\p Skew mod \p Align'. +/// +/// Examples: +/// \code +/// alignTo(5, 8) = 8 +/// alignTo(17, 8) = 24 +/// alignTo(~0LL, 8) = 0 +/// alignTo(321, 255) = 510 +/// +/// alignTo(5, 8, 7) = 7 +/// alignTo(17, 8, 1) = 17 +/// alignTo(~0LL, 8, 3) = 3 +/// alignTo(321, 255, 42) = 552 +/// \endcode +inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew = 0) { + assert(Align != 0u && "Align can't be 0."); + Skew %= Align; + return (Value + Align - 1 - Skew) / Align * Align + Skew; +} + +/// Returns the next integer (mod 2**64) that is greater than or equal to +/// \p Value and is a multiple of \c Align. \c Align must be non-zero. +template <uint64_t Align> constexpr inline uint64_t alignTo(uint64_t Value) { + static_assert(Align != 0u, "Align must be non-zero"); + return (Value + Align - 1) / Align * Align; +} + +/// Returns the integer ceil(Numerator / Denominator). +inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) { + return alignTo(Numerator, Denominator) / Denominator; +} + +/// Returns the largest uint64_t less than or equal to \p Value and is +/// \p Skew mod \p Align. \p Align must be non-zero +inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) { + assert(Align != 0u && "Align can't be 0."); + Skew %= Align; + return (Value - Skew) / Align * Align + Skew; +} + +/// Sign-extend the number in the bottom B bits of X to a 32-bit integer. +/// Requires 0 < B <= 32. +template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) { + static_assert(B > 0, "Bit width can't be 0."); + static_assert(B <= 32, "Bit width out of range."); + return int32_t(X << (32 - B)) >> (32 - B); +} + +/// Sign-extend the number in the bottom B bits of X to a 32-bit integer. +/// Requires 0 < B < 32. +inline int32_t SignExtend32(uint32_t X, unsigned B) { + assert(B > 0 && "Bit width can't be 0."); + assert(B <= 32 && "Bit width out of range."); + return int32_t(X << (32 - B)) >> (32 - B); +} + +/// Sign-extend the number in the bottom B bits of X to a 64-bit integer. +/// Requires 0 < B < 64. +template <unsigned B> constexpr inline int64_t SignExtend64(uint64_t x) { + static_assert(B > 0, "Bit width can't be 0."); + static_assert(B <= 64, "Bit width out of range."); + return int64_t(x << (64 - B)) >> (64 - B); +} + +/// Sign-extend the number in the bottom B bits of X to a 64-bit integer. +/// Requires 0 < B < 64. +inline int64_t SignExtend64(uint64_t X, unsigned B) { + assert(B > 0 && "Bit width can't be 0."); + assert(B <= 64 && "Bit width out of range."); + return int64_t(X << (64 - B)) >> (64 - B); +} + +/// Subtract two unsigned integers, X and Y, of type T and return the absolute +/// value of the result. +template <typename T> +typename std::enable_if<std::is_unsigned<T>::value, T>::type +AbsoluteDifference(T X, T Y) { + return std::max(X, Y) - std::min(X, Y); +} + +/// Add two unsigned integers, X and Y, of type T. Clamp the result to the +/// maximum representable value of T on overflow. ResultOverflowed indicates if +/// the result is larger than the maximum representable value of type T. +template <typename T> +typename std::enable_if<std::is_unsigned<T>::value, T>::type +SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) { + bool Dummy; + bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy; + // Hacker's Delight, p. 29 + T Z = X + Y; + Overflowed = (Z < X || Z < Y); + if (Overflowed) + return std::numeric_limits<T>::max(); + else + return Z; +} + +/// Multiply two unsigned integers, X and Y, of type T. Clamp the result to the +/// maximum representable value of T on overflow. ResultOverflowed indicates if +/// the result is larger than the maximum representable value of type T. +template <typename T> +typename std::enable_if<std::is_unsigned<T>::value, T>::type +SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) { + bool Dummy; + bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy; + + // Hacker's Delight, p. 30 has a different algorithm, but we don't use that + // because it fails for uint16_t (where multiplication can have undefined + // behavior due to promotion to int), and requires a division in addition + // to the multiplication. + + Overflowed = false; + + // Log2(Z) would be either Log2Z or Log2Z + 1. + // Special case: if X or Y is 0, Log2_64 gives -1, and Log2Z + // will necessarily be less than Log2Max as desired. + int Log2Z = Log2_64(X) + Log2_64(Y); + const T Max = std::numeric_limits<T>::max(); + int Log2Max = Log2_64(Max); + if (Log2Z < Log2Max) { + return X * Y; + } + if (Log2Z > Log2Max) { + Overflowed = true; + return Max; + } + + // We're going to use the top bit, and maybe overflow one + // bit past it. Multiply all but the bottom bit then add + // that on at the end. + T Z = (X >> 1) * Y; + if (Z & ~(Max >> 1)) { + Overflowed = true; + return Max; + } + Z <<= 1; + if (X & 1) + return SaturatingAdd(Z, Y, ResultOverflowed); + + return Z; +} + +/// Multiply two unsigned integers, X and Y, and add the unsigned integer, A to +/// the product. Clamp the result to the maximum representable value of T on +/// overflow. ResultOverflowed indicates if the result is larger than the +/// maximum representable value of type T. +template <typename T> +typename std::enable_if<std::is_unsigned<T>::value, T>::type +SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) { + bool Dummy; + bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy; + + T Product = SaturatingMultiply(X, Y, &Overflowed); + if (Overflowed) + return Product; + + return SaturatingAdd(A, Product, &Overflowed); +} + +/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC. +extern const float huge_valf; + + +/// Add two signed integers, computing the two's complement truncated result, +/// returning true if overflow occured. +template <typename T> +typename std::enable_if<std::is_signed<T>::value, T>::type +AddOverflow(T X, T Y, T &Result) { +#if __has_builtin(__builtin_add_overflow) + return __builtin_add_overflow(X, Y, &Result); +#else + // Perform the unsigned addition. + using U = typename std::make_unsigned<T>::type; + const U UX = static_cast<U>(X); + const U UY = static_cast<U>(Y); + const U UResult = UX + UY; + + // Convert to signed. + Result = static_cast<T>(UResult); + + // Adding two positive numbers should result in a positive number. + if (X > 0 && Y > 0) + return Result <= 0; + // Adding two negatives should result in a negative number. + if (X < 0 && Y < 0) + return Result >= 0; + return false; +#endif +} + +/// Subtract two signed integers, computing the two's complement truncated +/// result, returning true if an overflow ocurred. +template <typename T> +typename std::enable_if<std::is_signed<T>::value, T>::type +SubOverflow(T X, T Y, T &Result) { +#if __has_builtin(__builtin_sub_overflow) + return __builtin_sub_overflow(X, Y, &Result); +#else + // Perform the unsigned addition. + using U = typename std::make_unsigned<T>::type; + const U UX = static_cast<U>(X); + const U UY = static_cast<U>(Y); + const U UResult = UX - UY; + + // Convert to signed. + Result = static_cast<T>(UResult); + + // Subtracting a positive number from a negative results in a negative number. + if (X <= 0 && Y > 0) + return Result >= 0; + // Subtracting a negative number from a positive results in a positive number. + if (X >= 0 && Y < 0) + return Result <= 0; + return false; +#endif +} + + +/// Multiply two signed integers, computing the two's complement truncated +/// result, returning true if an overflow ocurred. +template <typename T> +typename std::enable_if<std::is_signed<T>::value, T>::type +MulOverflow(T X, T Y, T &Result) { + // Perform the unsigned multiplication on absolute values. + using U = typename std::make_unsigned<T>::type; + const U UX = X < 0 ? (0 - static_cast<U>(X)) : static_cast<U>(X); + const U UY = Y < 0 ? (0 - static_cast<U>(Y)) : static_cast<U>(Y); + const U UResult = UX * UY; + + // Convert to signed. + const bool IsNegative = (X < 0) ^ (Y < 0); + Result = IsNegative ? (0 - UResult) : UResult; + + // If any of the args was 0, result is 0 and no overflow occurs. + if (UX == 0 || UY == 0) + return false; + + // UX and UY are in [1, 2^n], where n is the number of digits. + // Check how the max allowed absolute value (2^n for negative, 2^(n-1) for + // positive) divided by an argument compares to the other. + if (IsNegative) + return UX > (static_cast<U>(std::numeric_limits<T>::max()) + U(1)) / UY; + else + return UX > (static_cast<U>(std::numeric_limits<T>::max())) / UY; +} + +} // End llvm namespace + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/MemAlloc.h b/third_party/llvm-project/include/llvm/Support/MemAlloc.h new file mode 100644 index 000000000..0e5869141 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/MemAlloc.h @@ -0,0 +1,66 @@ +//===- MemAlloc.h - Memory allocation functions -----------------*- 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 +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines counterparts of C library allocation functions defined in +/// the namespace 'std'. The new allocation functions crash on allocation +/// failure instead of returning null pointer. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_MEMALLOC_H +#define LLVM_SUPPORT_MEMALLOC_H + +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include <cstdlib> + +namespace llvm { + +LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_malloc(size_t Sz) { + void *Result = std::malloc(Sz); + if (Result == nullptr) { + // It is implementation-defined whether allocation occurs if the space + // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting + // non-zero, if the space requested was zero. + if (Sz == 0) + return safe_malloc(1); + report_bad_alloc_error("Allocation failed"); + } + return Result; +} + +LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_calloc(size_t Count, + size_t Sz) { + void *Result = std::calloc(Count, Sz); + if (Result == nullptr) { + // It is implementation-defined whether allocation occurs if the space + // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting + // non-zero, if the space requested was zero. + if (Count == 0 || Sz == 0) + return safe_malloc(1); + report_bad_alloc_error("Allocation failed"); + } + return Result; +} + +LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_realloc(void *Ptr, size_t Sz) { + void *Result = std::realloc(Ptr, Sz); + if (Result == nullptr) { + // It is implementation-defined whether allocation occurs if the space + // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting + // non-zero, if the space requested was zero. + if (Sz == 0) + return safe_malloc(1); + report_bad_alloc_error("Allocation failed"); + } + return Result; +} + +} +#endif diff --git a/third_party/llvm-project/include/llvm/Support/MemoryBuffer.h b/third_party/llvm-project/include/llvm/Support/MemoryBuffer.h new file mode 100644 index 000000000..b5196cd84 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/MemoryBuffer.h @@ -0,0 +1,286 @@ +//===--- MemoryBuffer.h - Memory Buffer Interface ---------------*- 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 defines the MemoryBuffer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_MEMORYBUFFER_H +#define LLVM_SUPPORT_MEMORYBUFFER_H + +#include "llvm-c/Types.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/CBindingWrapping.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" +#include <cstddef> +#include <cstdint> +#include <memory> + +namespace llvm { + +class MemoryBufferRef; + +/// This interface provides simple read-only access to a block of memory, and +/// provides simple methods for reading files and standard input into a memory +/// buffer. In addition to basic access to the characters in the file, this +/// interface guarantees you can read one character past the end of the file, +/// and that this character will read as '\0'. +/// +/// The '\0' guarantee is needed to support an optimization -- it's intended to +/// be more efficient for clients which are reading all the data to stop +/// reading when they encounter a '\0' than to continually check the file +/// position to see if it has reached the end of the file. +class MemoryBuffer { + const char *BufferStart; // Start of the buffer. + const char *BufferEnd; // End of the buffer. + +protected: + MemoryBuffer() = default; + + void init(const char *BufStart, const char *BufEnd, + bool RequiresNullTerminator); + + static constexpr sys::fs::mapped_file_region::mapmode Mapmode = + sys::fs::mapped_file_region::readonly; + +public: + MemoryBuffer(const MemoryBuffer &) = delete; + MemoryBuffer &operator=(const MemoryBuffer &) = delete; + virtual ~MemoryBuffer(); + + const char *getBufferStart() const { return BufferStart; } + const char *getBufferEnd() const { return BufferEnd; } + size_t getBufferSize() const { return BufferEnd-BufferStart; } + + StringRef getBuffer() const { + return StringRef(BufferStart, getBufferSize()); + } + + /// Return an identifier for this buffer, typically the filename it was read + /// from. + virtual StringRef getBufferIdentifier() const { return "Unknown buffer"; } + + /// Open the specified file as a MemoryBuffer, returning a new MemoryBuffer + /// if successful, otherwise returning null. If FileSize is specified, this + /// means that the client knows that the file exists and that it has the + /// specified size. + /// + /// \param IsVolatile Set to true to indicate that the contents of the file + /// can change outside the user's control, e.g. when libclang tries to parse + /// while the user is editing/updating the file or if the file is on an NFS. + static ErrorOr<std::unique_ptr<MemoryBuffer>> + getFile(const Twine &Filename, int64_t FileSize = -1, + bool RequiresNullTerminator = true, bool IsVolatile = false); + + /// Read all of the specified file into a MemoryBuffer as a stream + /// (i.e. until EOF reached). This is useful for special files that + /// look like a regular file but have 0 size (e.g. /proc/cpuinfo on Linux). + static ErrorOr<std::unique_ptr<MemoryBuffer>> + getFileAsStream(const Twine &Filename); + + /// Given an already-open file descriptor, map some slice of it into a + /// MemoryBuffer. The slice is specified by an \p Offset and \p MapSize. + /// Since this is in the middle of a file, the buffer is not null terminated. + static ErrorOr<std::unique_ptr<MemoryBuffer>> + getOpenFileSlice(sys::fs::file_t FD, const Twine &Filename, uint64_t MapSize, + int64_t Offset, bool IsVolatile = false); + + /// Given an already-open file descriptor, read the file and return a + /// MemoryBuffer. + /// + /// \param IsVolatile Set to true to indicate that the contents of the file + /// can change outside the user's control, e.g. when libclang tries to parse + /// while the user is editing/updating the file or if the file is on an NFS. + static ErrorOr<std::unique_ptr<MemoryBuffer>> + getOpenFile(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, + bool RequiresNullTerminator = true, bool IsVolatile = false); + + /// Open the specified memory range as a MemoryBuffer. Note that InputData + /// must be null terminated if RequiresNullTerminator is true. + static std::unique_ptr<MemoryBuffer> + getMemBuffer(StringRef InputData, StringRef BufferName = "", + bool RequiresNullTerminator = true); + + static std::unique_ptr<MemoryBuffer> + getMemBuffer(MemoryBufferRef Ref, bool RequiresNullTerminator = true); + + /// Open the specified memory range as a MemoryBuffer, copying the contents + /// and taking ownership of it. InputData does not have to be null terminated. + static std::unique_ptr<MemoryBuffer> + getMemBufferCopy(StringRef InputData, const Twine &BufferName = ""); + + /// Read all of stdin into a file buffer, and return it. + static ErrorOr<std::unique_ptr<MemoryBuffer>> getSTDIN(); + + /// Open the specified file as a MemoryBuffer, or open stdin if the Filename + /// is "-". + static ErrorOr<std::unique_ptr<MemoryBuffer>> + getFileOrSTDIN(const Twine &Filename, int64_t FileSize = -1, + bool RequiresNullTerminator = true); + + /// Map a subrange of the specified file as a MemoryBuffer. + static ErrorOr<std::unique_ptr<MemoryBuffer>> + getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset, + bool IsVolatile = false); + + //===--------------------------------------------------------------------===// + // Provided for performance analysis. + //===--------------------------------------------------------------------===// + + /// The kind of memory backing used to support the MemoryBuffer. + enum BufferKind { + MemoryBuffer_Malloc, + MemoryBuffer_MMap + }; + + /// Return information on the memory mechanism used to support the + /// MemoryBuffer. + virtual BufferKind getBufferKind() const = 0; + + MemoryBufferRef getMemBufferRef() const; +}; + +/// This class is an extension of MemoryBuffer, which allows copy-on-write +/// access to the underlying contents. It only supports creation methods that +/// are guaranteed to produce a writable buffer. For example, mapping a file +/// read-only is not supported. +class WritableMemoryBuffer : public MemoryBuffer { +protected: + WritableMemoryBuffer() = default; + + static constexpr sys::fs::mapped_file_region::mapmode Mapmode = + sys::fs::mapped_file_region::priv; + +public: + using MemoryBuffer::getBuffer; + using MemoryBuffer::getBufferEnd; + using MemoryBuffer::getBufferStart; + + // const_cast is well-defined here, because the underlying buffer is + // guaranteed to have been initialized with a mutable buffer. + char *getBufferStart() { + return const_cast<char *>(MemoryBuffer::getBufferStart()); + } + char *getBufferEnd() { + return const_cast<char *>(MemoryBuffer::getBufferEnd()); + } + MutableArrayRef<char> getBuffer() { + return {getBufferStart(), getBufferEnd()}; + } + + static ErrorOr<std::unique_ptr<WritableMemoryBuffer>> + getFile(const Twine &Filename, int64_t FileSize = -1, + bool IsVolatile = false); + + /// Map a subrange of the specified file as a WritableMemoryBuffer. + static ErrorOr<std::unique_ptr<WritableMemoryBuffer>> + getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset, + bool IsVolatile = false); + + /// Allocate a new MemoryBuffer of the specified size that is not initialized. + /// Note that the caller should initialize the memory allocated by this + /// method. The memory is owned by the MemoryBuffer object. + static std::unique_ptr<WritableMemoryBuffer> + getNewUninitMemBuffer(size_t Size, const Twine &BufferName = ""); + + /// Allocate a new zero-initialized MemoryBuffer of the specified size. Note + /// that the caller need not initialize the memory allocated by this method. + /// The memory is owned by the MemoryBuffer object. + static std::unique_ptr<WritableMemoryBuffer> + getNewMemBuffer(size_t Size, const Twine &BufferName = ""); + +private: + // Hide these base class factory function so one can't write + // WritableMemoryBuffer::getXXX() + // and be surprised that he got a read-only Buffer. + using MemoryBuffer::getFileAsStream; + using MemoryBuffer::getFileOrSTDIN; + using MemoryBuffer::getMemBuffer; + using MemoryBuffer::getMemBufferCopy; + using MemoryBuffer::getOpenFile; + using MemoryBuffer::getOpenFileSlice; + using MemoryBuffer::getSTDIN; +}; + +/// This class is an extension of MemoryBuffer, which allows write access to +/// the underlying contents and committing those changes to the original source. +/// It only supports creation methods that are guaranteed to produce a writable +/// buffer. For example, mapping a file read-only is not supported. +class WriteThroughMemoryBuffer : public MemoryBuffer { +protected: + WriteThroughMemoryBuffer() = default; + + static constexpr sys::fs::mapped_file_region::mapmode Mapmode = + sys::fs::mapped_file_region::readwrite; + +public: + using MemoryBuffer::getBuffer; + using MemoryBuffer::getBufferEnd; + using MemoryBuffer::getBufferStart; + + // const_cast is well-defined here, because the underlying buffer is + // guaranteed to have been initialized with a mutable buffer. + char *getBufferStart() { + return const_cast<char *>(MemoryBuffer::getBufferStart()); + } + char *getBufferEnd() { + return const_cast<char *>(MemoryBuffer::getBufferEnd()); + } + MutableArrayRef<char> getBuffer() { + return {getBufferStart(), getBufferEnd()}; + } + + static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> + getFile(const Twine &Filename, int64_t FileSize = -1); + + /// Map a subrange of the specified file as a ReadWriteMemoryBuffer. + static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> + getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset); + +private: + // Hide these base class factory function so one can't write + // WritableMemoryBuffer::getXXX() + // and be surprised that he got a read-only Buffer. + using MemoryBuffer::getFileAsStream; + using MemoryBuffer::getFileOrSTDIN; + using MemoryBuffer::getMemBuffer; + using MemoryBuffer::getMemBufferCopy; + using MemoryBuffer::getOpenFile; + using MemoryBuffer::getOpenFileSlice; + using MemoryBuffer::getSTDIN; +}; + +class MemoryBufferRef { + StringRef Buffer; + StringRef Identifier; + +public: + MemoryBufferRef() = default; + MemoryBufferRef(const MemoryBuffer& Buffer) + : Buffer(Buffer.getBuffer()), Identifier(Buffer.getBufferIdentifier()) {} + MemoryBufferRef(StringRef Buffer, StringRef Identifier) + : Buffer(Buffer), Identifier(Identifier) {} + + StringRef getBuffer() const { return Buffer; } + + StringRef getBufferIdentifier() const { return Identifier; } + + const char *getBufferStart() const { return Buffer.begin(); } + const char *getBufferEnd() const { return Buffer.end(); } + size_t getBufferSize() const { return Buffer.size(); } +}; + +// Create wrappers for C Binding types (see CBindingWrapping.h). +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(MemoryBuffer, LLVMMemoryBufferRef) + +} // end namespace llvm + +#endif // LLVM_SUPPORT_MEMORYBUFFER_H diff --git a/third_party/llvm-project/include/llvm/Support/NativeFormatting.h b/third_party/llvm-project/include/llvm/Support/NativeFormatting.h new file mode 100644 index 000000000..825a44c77 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/NativeFormatting.h @@ -0,0 +1,48 @@ +//===- NativeFormatting.h - Low level formatting helpers ---------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_NATIVE_FORMATTING_H +#define LLVM_SUPPORT_NATIVE_FORMATTING_H + +#include "llvm/ADT/Optional.h" +#include "llvm/Support/raw_ostream.h" + +#include <cstdint> + +namespace llvm { +enum class FloatStyle { Exponent, ExponentUpper, Fixed, Percent }; +enum class IntegerStyle { + Integer, + Number, +}; +enum class HexPrintStyle { Upper, Lower, PrefixUpper, PrefixLower }; + +size_t getDefaultPrecision(FloatStyle Style); + +bool isPrefixedHexStyle(HexPrintStyle S); + +void write_integer(raw_ostream &S, unsigned int N, size_t MinDigits, + IntegerStyle Style); +void write_integer(raw_ostream &S, int N, size_t MinDigits, IntegerStyle Style); +void write_integer(raw_ostream &S, unsigned long N, size_t MinDigits, + IntegerStyle Style); +void write_integer(raw_ostream &S, long N, size_t MinDigits, + IntegerStyle Style); +void write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits, + IntegerStyle Style); +void write_integer(raw_ostream &S, long long N, size_t MinDigits, + IntegerStyle Style); + +void write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style, + Optional<size_t> Width = None); +void write_double(raw_ostream &S, double D, FloatStyle Style, + Optional<size_t> Precision = None); +} + +#endif + diff --git a/third_party/llvm-project/include/llvm/Support/Path.h b/third_party/llvm-project/include/llvm/Support/Path.h new file mode 100644 index 000000000..488f17427 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Path.h @@ -0,0 +1,464 @@ +//===- llvm/Support/Path.h - Path Operating System Concept ------*- 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 declares the llvm::sys::path namespace. It is designed after +// TR2/boost filesystem (v3), but modified to remove exception handling and the +// path class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_PATH_H +#define LLVM_SUPPORT_PATH_H + +#include "llvm/ADT/Twine.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/DataTypes.h" +#include <iterator> +#include <system_error> + +namespace llvm { +namespace sys { +namespace path { + +enum class Style { windows, posix, native }; + +/// @name Lexical Component Iterator +/// @{ + +/// Path iterator. +/// +/// This is an input iterator that iterates over the individual components in +/// \a path. The traversal order is as follows: +/// * The root-name element, if present. +/// * The root-directory element, if present. +/// * Each successive filename element, if present. +/// * Dot, if one or more trailing non-root slash characters are present. +/// Traversing backwards is possible with \a reverse_iterator +/// +/// Iteration examples. Each component is separated by ',': +/// @code +/// / => / +/// /foo => /,foo +/// foo/ => foo,. +/// /foo/bar => /,foo,bar +/// ../ => ..,. +/// C:\foo\bar => C:,/,foo,bar +/// @endcode +class const_iterator + : public iterator_facade_base<const_iterator, std::input_iterator_tag, + const StringRef> { + StringRef Path; ///< The entire path. + StringRef Component; ///< The current component. Not necessarily in Path. + size_t Position = 0; ///< The iterators current position within Path. + Style S = Style::native; ///< The path style to use. + + // An end iterator has Position = Path.size() + 1. + friend const_iterator begin(StringRef path, Style style); + friend const_iterator end(StringRef path); + +public: + reference operator*() const { return Component; } + const_iterator &operator++(); // preincrement + bool operator==(const const_iterator &RHS) const; + + /// Difference in bytes between this and RHS. + ptrdiff_t operator-(const const_iterator &RHS) const; +}; + +/// Reverse path iterator. +/// +/// This is an input iterator that iterates over the individual components in +/// \a path in reverse order. The traversal order is exactly reversed from that +/// of \a const_iterator +class reverse_iterator + : public iterator_facade_base<reverse_iterator, std::input_iterator_tag, + const StringRef> { + StringRef Path; ///< The entire path. + StringRef Component; ///< The current component. Not necessarily in Path. + size_t Position = 0; ///< The iterators current position within Path. + Style S = Style::native; ///< The path style to use. + + friend reverse_iterator rbegin(StringRef path, Style style); + friend reverse_iterator rend(StringRef path); + +public: + reference operator*() const { return Component; } + reverse_iterator &operator++(); // preincrement + bool operator==(const reverse_iterator &RHS) const; + + /// Difference in bytes between this and RHS. + ptrdiff_t operator-(const reverse_iterator &RHS) const; +}; + +/// Get begin iterator over \a path. +/// @param path Input path. +/// @returns Iterator initialized with the first component of \a path. +const_iterator begin(StringRef path, Style style = Style::native); + +/// Get end iterator over \a path. +/// @param path Input path. +/// @returns Iterator initialized to the end of \a path. +const_iterator end(StringRef path); + +/// Get reverse begin iterator over \a path. +/// @param path Input path. +/// @returns Iterator initialized with the first reverse component of \a path. +reverse_iterator rbegin(StringRef path, Style style = Style::native); + +/// Get reverse end iterator over \a path. +/// @param path Input path. +/// @returns Iterator initialized to the reverse end of \a path. +reverse_iterator rend(StringRef path); + +/// @} +/// @name Lexical Modifiers +/// @{ + +/// Remove the last component from \a path unless it is the root dir. +/// +/// Similar to the POSIX "dirname" utility. +/// +/// @code +/// directory/filename.cpp => directory/ +/// directory/ => directory +/// filename.cpp => <empty> +/// / => / +/// @endcode +/// +/// @param path A path that is modified to not have a file component. +void remove_filename(SmallVectorImpl<char> &path, Style style = Style::native); + +/// Replace the file extension of \a path with \a extension. +/// +/// @code +/// ./filename.cpp => ./filename.extension +/// ./filename => ./filename.extension +/// ./ => ./.extension +/// @endcode +/// +/// @param path A path that has its extension replaced with \a extension. +/// @param extension The extension to be added. It may be empty. It may also +/// optionally start with a '.', if it does not, one will be +/// prepended. +void replace_extension(SmallVectorImpl<char> &path, const Twine &extension, + Style style = Style::native); + +/// Replace matching path prefix with another path. +/// +/// @code +/// /foo, /old, /new => /foo +/// /old/foo, /old, /new => /new/foo +/// /foo, <empty>, /new => /new/foo +/// /old/foo, /old, <empty> => /foo +/// @endcode +/// +/// @param Path If \a Path starts with \a OldPrefix modify to instead +/// start with \a NewPrefix. +/// @param OldPrefix The path prefix to strip from \a Path. +/// @param NewPrefix The path prefix to replace \a NewPrefix with. +void replace_path_prefix(SmallVectorImpl<char> &Path, + const StringRef &OldPrefix, const StringRef &NewPrefix, + Style style = Style::native); + +/// Append to path. +/// +/// @code +/// /foo + bar/f => /foo/bar/f +/// /foo/ + bar/f => /foo/bar/f +/// foo + bar/f => foo/bar/f +/// @endcode +/// +/// @param path Set to \a path + \a component. +/// @param a The component to be appended to \a path. +void append(SmallVectorImpl<char> &path, const Twine &a, + const Twine &b = "", + const Twine &c = "", + const Twine &d = ""); + +void append(SmallVectorImpl<char> &path, Style style, const Twine &a, + const Twine &b = "", const Twine &c = "", const Twine &d = ""); + +/// Append to path. +/// +/// @code +/// /foo + [bar,f] => /foo/bar/f +/// /foo/ + [bar,f] => /foo/bar/f +/// foo + [bar,f] => foo/bar/f +/// @endcode +/// +/// @param path Set to \a path + [\a begin, \a end). +/// @param begin Start of components to append. +/// @param end One past the end of components to append. +void append(SmallVectorImpl<char> &path, const_iterator begin, + const_iterator end, Style style = Style::native); + +/// @} +/// @name Transforms (or some other better name) +/// @{ + +/// Convert path to the native form. This is used to give paths to users and +/// operating system calls in the platform's normal way. For example, on Windows +/// all '/' are converted to '\'. +/// +/// @param path A path that is transformed to native format. +/// @param result Holds the result of the transformation. +void native(const Twine &path, SmallVectorImpl<char> &result, + Style style = Style::native); + +/// Convert path to the native form in place. This is used to give paths to +/// users and operating system calls in the platform's normal way. For example, +/// on Windows all '/' are converted to '\'. +/// +/// @param path A path that is transformed to native format. +void native(SmallVectorImpl<char> &path, Style style = Style::native); + +/// Replaces backslashes with slashes if Windows. +/// +/// @param path processed path +/// @result The result of replacing backslashes with forward slashes if Windows. +/// On Unix, this function is a no-op because backslashes are valid path +/// chracters. +std::string convert_to_slash(StringRef path, Style style = Style::native); + +/// @} +/// @name Lexical Observers +/// @{ + +/// Get root name. +/// +/// @code +/// //net/hello => //net +/// c:/hello => c: (on Windows, on other platforms nothing) +/// /hello => <empty> +/// @endcode +/// +/// @param path Input path. +/// @result The root name of \a path if it has one, otherwise "". +StringRef root_name(StringRef path, Style style = Style::native); + +/// Get root directory. +/// +/// @code +/// /goo/hello => / +/// c:/hello => / +/// d/file.txt => <empty> +/// @endcode +/// +/// @param path Input path. +/// @result The root directory of \a path if it has one, otherwise +/// "". +StringRef root_directory(StringRef path, Style style = Style::native); + +/// Get root path. +/// +/// Equivalent to root_name + root_directory. +/// +/// @param path Input path. +/// @result The root path of \a path if it has one, otherwise "". +StringRef root_path(StringRef path, Style style = Style::native); + +/// Get relative path. +/// +/// @code +/// C:\hello\world => hello\world +/// foo/bar => foo/bar +/// /foo/bar => foo/bar +/// @endcode +/// +/// @param path Input path. +/// @result The path starting after root_path if one exists, otherwise "". +StringRef relative_path(StringRef path, Style style = Style::native); + +/// Get parent path. +/// +/// @code +/// / => <empty> +/// /foo => / +/// foo/../bar => foo/.. +/// @endcode +/// +/// @param path Input path. +/// @result The parent path of \a path if one exists, otherwise "". +StringRef parent_path(StringRef path, Style style = Style::native); + +/// Get filename. +/// +/// @code +/// /foo.txt => foo.txt +/// . => . +/// .. => .. +/// / => / +/// @endcode +/// +/// @param path Input path. +/// @result The filename part of \a path. This is defined as the last component +/// of \a path. Similar to the POSIX "basename" utility. +StringRef filename(StringRef path, Style style = Style::native); + +/// Get stem. +/// +/// If filename contains a dot but not solely one or two dots, result is the +/// substring of filename ending at (but not including) the last dot. Otherwise +/// it is filename. +/// +/// @code +/// /foo/bar.txt => bar +/// /foo/bar => bar +/// /foo/.txt => <empty> +/// /foo/. => . +/// /foo/.. => .. +/// @endcode +/// +/// @param path Input path. +/// @result The stem of \a path. +StringRef stem(StringRef path, Style style = Style::native); + +/// Get extension. +/// +/// If filename contains a dot but not solely one or two dots, result is the +/// substring of filename starting at (and including) the last dot, and ending +/// at the end of \a path. Otherwise "". +/// +/// @code +/// /foo/bar.txt => .txt +/// /foo/bar => <empty> +/// /foo/.txt => .txt +/// @endcode +/// +/// @param path Input path. +/// @result The extension of \a path. +StringRef extension(StringRef path, Style style = Style::native); + +/// Check whether the given char is a path separator on the host OS. +/// +/// @param value a character +/// @result true if \a value is a path separator character on the host OS +bool is_separator(char value, Style style = Style::native); + +/// Return the preferred separator for this platform. +/// +/// @result StringRef of the preferred separator, null-terminated. +StringRef get_separator(Style style = Style::native); + +/// Get the typical temporary directory for the system, e.g., +/// "/var/tmp" or "C:/TEMP" +/// +/// @param erasedOnReboot Whether to favor a path that is erased on reboot +/// rather than one that potentially persists longer. This parameter will be +/// ignored if the user or system has set the typical environment variable +/// (e.g., TEMP on Windows, TMPDIR on *nix) to specify a temporary directory. +/// +/// @param result Holds the resulting path name. +void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result); + +/// Get the user's home directory. +/// +/// @param result Holds the resulting path name. +/// @result True if a home directory is set, false otherwise. +bool home_directory(SmallVectorImpl<char> &result); + +/// Has root name? +/// +/// root_name != "" +/// +/// @param path Input path. +/// @result True if the path has a root name, false otherwise. +bool has_root_name(const Twine &path, Style style = Style::native); + +/// Has root directory? +/// +/// root_directory != "" +/// +/// @param path Input path. +/// @result True if the path has a root directory, false otherwise. +bool has_root_directory(const Twine &path, Style style = Style::native); + +/// Has root path? +/// +/// root_path != "" +/// +/// @param path Input path. +/// @result True if the path has a root path, false otherwise. +bool has_root_path(const Twine &path, Style style = Style::native); + +/// Has relative path? +/// +/// relative_path != "" +/// +/// @param path Input path. +/// @result True if the path has a relative path, false otherwise. +bool has_relative_path(const Twine &path, Style style = Style::native); + +/// Has parent path? +/// +/// parent_path != "" +/// +/// @param path Input path. +/// @result True if the path has a parent path, false otherwise. +bool has_parent_path(const Twine &path, Style style = Style::native); + +/// Has filename? +/// +/// filename != "" +/// +/// @param path Input path. +/// @result True if the path has a filename, false otherwise. +bool has_filename(const Twine &path, Style style = Style::native); + +/// Has stem? +/// +/// stem != "" +/// +/// @param path Input path. +/// @result True if the path has a stem, false otherwise. +bool has_stem(const Twine &path, Style style = Style::native); + +/// Has extension? +/// +/// extension != "" +/// +/// @param path Input path. +/// @result True if the path has a extension, false otherwise. +bool has_extension(const Twine &path, Style style = Style::native); + +/// Is path absolute? +/// +/// @param path Input path. +/// @result True if the path is absolute, false if it is not. +bool is_absolute(const Twine &path, Style style = Style::native); + +/// Is path relative? +/// +/// @param path Input path. +/// @result True if the path is relative, false if it is not. +bool is_relative(const Twine &path, Style style = Style::native); + +/// Remove redundant leading "./" pieces and consecutive separators. +/// +/// @param path Input path. +/// @result The cleaned-up \a path. +StringRef remove_leading_dotslash(StringRef path, Style style = Style::native); + +/// In-place remove any './' and optionally '../' components from a path. +/// +/// @param path processed path +/// @param remove_dot_dot specify if '../' (except for leading "../") should be +/// removed +/// @result True if path was changed +bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot = false, + Style style = Style::native); + +#if defined(_WIN32) +std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16); +#endif + +} // end namespace path +} // end namespace sys +} // end namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/PointerLikeTypeTraits.h b/third_party/llvm-project/include/llvm/Support/PointerLikeTypeTraits.h new file mode 100644 index 000000000..1e7e5b53c --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/PointerLikeTypeTraits.h @@ -0,0 +1,149 @@ +//===- llvm/Support/PointerLikeTypeTraits.h - Pointer Traits ----*- 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 defines the PointerLikeTypeTraits class. This allows data +// structures to reason about pointers and other things that are pointer sized. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_POINTERLIKETYPETRAITS_H +#define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H + +#include "llvm/Support/DataTypes.h" +#include <assert.h> +#include <type_traits> + +namespace llvm { + +/// A traits type that is used to handle pointer types and things that are just +/// wrappers for pointers as a uniform entity. +template <typename T> struct PointerLikeTypeTraits; + +namespace detail { +/// A tiny meta function to compute the log2 of a compile time constant. +template <size_t N> +struct ConstantLog2 + : std::integral_constant<size_t, ConstantLog2<N / 2>::value + 1> {}; +template <> struct ConstantLog2<1> : std::integral_constant<size_t, 0> {}; + +// Provide a trait to check if T is pointer-like. +template <typename T, typename U = void> struct HasPointerLikeTypeTraits { + static const bool value = false; +}; + +// sizeof(T) is valid only for a complete T. +template <typename T> struct HasPointerLikeTypeTraits< + T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> { + static const bool value = true; +}; + +template <typename T> struct IsPointerLike { + static const bool value = HasPointerLikeTypeTraits<T>::value; +}; + +template <typename T> struct IsPointerLike<T *> { + static const bool value = true; +}; +} // namespace detail + +// Provide PointerLikeTypeTraits for non-cvr pointers. +template <typename T> struct PointerLikeTypeTraits<T *> { + static inline void *getAsVoidPointer(T *P) { return P; } + static inline T *getFromVoidPointer(void *P) { return static_cast<T *>(P); } + + enum { NumLowBitsAvailable = detail::ConstantLog2<alignof(T)>::value }; +}; + +template <> struct PointerLikeTypeTraits<void *> { + static inline void *getAsVoidPointer(void *P) { return P; } + static inline void *getFromVoidPointer(void *P) { return P; } + + /// Note, we assume here that void* is related to raw malloc'ed memory and + /// that malloc returns objects at least 4-byte aligned. However, this may be + /// wrong, or pointers may be from something other than malloc. In this case, + /// you should specify a real typed pointer or avoid this template. + /// + /// All clients should use assertions to do a run-time check to ensure that + /// this is actually true. + enum { NumLowBitsAvailable = 2 }; +}; + +// Provide PointerLikeTypeTraits for const things. +template <typename T> struct PointerLikeTypeTraits<const T> { + typedef PointerLikeTypeTraits<T> NonConst; + + static inline const void *getAsVoidPointer(const T P) { + return NonConst::getAsVoidPointer(P); + } + static inline const T getFromVoidPointer(const void *P) { + return NonConst::getFromVoidPointer(const_cast<void *>(P)); + } + enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable }; +}; + +// Provide PointerLikeTypeTraits for const pointers. +template <typename T> struct PointerLikeTypeTraits<const T *> { + typedef PointerLikeTypeTraits<T *> NonConst; + + static inline const void *getAsVoidPointer(const T *P) { + return NonConst::getAsVoidPointer(const_cast<T *>(P)); + } + static inline const T *getFromVoidPointer(const void *P) { + return NonConst::getFromVoidPointer(const_cast<void *>(P)); + } + enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable }; +}; + +// Provide PointerLikeTypeTraits for uintptr_t. +template <> struct PointerLikeTypeTraits<uintptr_t> { + static inline void *getAsVoidPointer(uintptr_t P) { + return reinterpret_cast<void *>(P); + } + static inline uintptr_t getFromVoidPointer(void *P) { + return reinterpret_cast<uintptr_t>(P); + } + // No bits are available! + enum { NumLowBitsAvailable = 0 }; +}; + +/// Provide suitable custom traits struct for function pointers. +/// +/// Function pointers can't be directly given these traits as functions can't +/// have their alignment computed with `alignof` and we need different casting. +/// +/// To rely on higher alignment for a specialized use, you can provide a +/// customized form of this template explicitly with higher alignment, and +/// potentially use alignment attributes on functions to satisfy that. +template <int Alignment, typename FunctionPointerT> +struct FunctionPointerLikeTypeTraits { + enum { NumLowBitsAvailable = detail::ConstantLog2<Alignment>::value }; + static inline void *getAsVoidPointer(FunctionPointerT P) { + assert((reinterpret_cast<uintptr_t>(P) & + ~((uintptr_t)-1 << NumLowBitsAvailable)) == 0 && + "Alignment not satisfied for an actual function pointer!"); + return reinterpret_cast<void *>(P); + } + static inline FunctionPointerT getFromVoidPointer(void *P) { + return reinterpret_cast<FunctionPointerT>(P); + } +}; + +/// Provide a default specialization for function pointers that assumes 4-byte +/// alignment. +/// +/// We assume here that functions used with this are always at least 4-byte +/// aligned. This means that, for example, thumb functions won't work or systems +/// with weird unaligned function pointers won't work. But all practical systems +/// we support satisfy this requirement. +template <typename ReturnT, typename... ParamTs> +struct PointerLikeTypeTraits<ReturnT (*)(ParamTs...)> + : FunctionPointerLikeTypeTraits<4, ReturnT (*)(ParamTs...)> {}; + +} // end namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/Printable.h b/third_party/llvm-project/include/llvm/Support/Printable.h new file mode 100644 index 000000000..0f8670d04 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Printable.h @@ -0,0 +1,51 @@ +//===--- Printable.h - Print function helpers -------------------*- 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 defines the Printable struct. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_PRINTABLE_H +#define LLVM_SUPPORT_PRINTABLE_H + +#include <functional> + +namespace llvm { + +class raw_ostream; + +/// Simple wrapper around std::function<void(raw_ostream&)>. +/// This class is useful to construct print helpers for raw_ostream. +/// +/// Example: +/// Printable PrintRegister(unsigned Register) { +/// return Printable([Register](raw_ostream &OS) { +/// OS << getRegisterName(Register); +/// } +/// } +/// ... OS << PrintRegister(Register); ... +/// +/// Implementation note: Ideally this would just be a typedef, but doing so +/// leads to operator << being ambiguous as function has matching constructors +/// in some STL versions. I have seen the problem on gcc 4.6 libstdc++ and +/// microsoft STL. +class Printable { +public: + std::function<void(raw_ostream &OS)> Print; + Printable(std::function<void(raw_ostream &OS)> Print) + : Print(std::move(Print)) {} +}; + +inline raw_ostream &operator<<(raw_ostream &OS, const Printable &P) { + P.Print(OS); + return OS; +} + +} + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/Process.h b/third_party/llvm-project/include/llvm/Support/Process.h new file mode 100644 index 000000000..67e379125 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Process.h @@ -0,0 +1,209 @@ +//===- llvm/Support/Process.h -----------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// Provides a library for accessing information about this process and other +/// processes on the operating system. Also provides means of spawning +/// subprocess for commands. The design of this library is modeled after the +/// proposed design of the Boost.Process library, and is design specifically to +/// follow the style of standard libraries and potentially become a proposal +/// for a standard library. +/// +/// This file declares the llvm::sys::Process class which contains a collection +/// of legacy static interfaces for extracting various information about the +/// current process. The goal is to migrate users of this API over to the new +/// interfaces. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_PROCESS_H +#define LLVM_SUPPORT_PROCESS_H + +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Error.h" +#include <system_error> + +namespace llvm { +template <typename T> class ArrayRef; +class StringRef; + +namespace sys { + + +/// A collection of legacy interfaces for querying information about the +/// current executing process. +class Process { +public: + /// Get the process's page size. + /// This may fail if the underlying syscall returns an error. In most cases, + /// page size information is used for optimization, and this error can be + /// safely discarded by calling consumeError, and an estimated page size + /// substituted instead. + static Expected<unsigned> getPageSize(); + + /// Get the process's estimated page size. + /// This function always succeeds, but if the underlying syscall to determine + /// the page size fails then this will silently return an estimated page size. + /// The estimated page size is guaranteed to be a power of 2. + static unsigned getPageSizeEstimate() { + if (auto PageSize = getPageSize()) + return *PageSize; + else { + consumeError(PageSize.takeError()); + return 4096; + } + } + + /// Return process memory usage. + /// This static function will return the total amount of memory allocated + /// by the process. This only counts the memory allocated via the malloc, + /// calloc and realloc functions and includes any "free" holes in the + /// allocated space. + static size_t GetMallocUsage(); + + /// This static function will set \p user_time to the amount of CPU time + /// spent in user (non-kernel) mode and \p sys_time to the amount of CPU + /// time spent in system (kernel) mode. If the operating system does not + /// support collection of these metrics, a zero duration will be for both + /// values. + /// \param elapsed Returns the system_clock::now() giving current time + /// \param user_time Returns the current amount of user time for the process + /// \param sys_time Returns the current amount of system time for the process + static void GetTimeUsage(TimePoint<> &elapsed, + std::chrono::nanoseconds &user_time, + std::chrono::nanoseconds &sys_time); + + /// This function makes the necessary calls to the operating system to + /// prevent core files or any other kind of large memory dumps that can + /// occur when a program fails. + /// Prevent core file generation. + static void PreventCoreFiles(); + + /// true if PreventCoreFiles has been called, false otherwise. + static bool AreCoreFilesPrevented(); + + // This function returns the environment variable \arg name's value as a UTF-8 + // string. \arg Name is assumed to be in UTF-8 encoding too. + static Optional<std::string> GetEnv(StringRef name); + + /// This function searches for an existing file in the list of directories + /// in a PATH like environment variable, and returns the first file found, + /// according to the order of the entries in the PATH like environment + /// variable. If an ignore list is specified, then any folder which is in + /// the PATH like environment variable but is also in IgnoreList is not + /// considered. + static Optional<std::string> FindInEnvPath(StringRef EnvName, + StringRef FileName, + ArrayRef<std::string> IgnoreList); + + static Optional<std::string> FindInEnvPath(StringRef EnvName, + StringRef FileName); + + // This functions ensures that the standard file descriptors (input, output, + // and error) are properly mapped to a file descriptor before we use any of + // them. This should only be called by standalone programs, library + // components should not call this. + static std::error_code FixupStandardFileDescriptors(); + + // This function safely closes a file descriptor. It is not safe to retry + // close(2) when it returns with errno equivalent to EINTR; this is because + // *nixen cannot agree if the file descriptor is, in fact, closed when this + // occurs. + // + // N.B. Some operating systems, due to thread cancellation, cannot properly + // guarantee that it will or will not be closed one way or the other! + static std::error_code SafelyCloseFileDescriptor(int FD); + + /// This function determines if the standard input is connected directly + /// to a user's input (keyboard probably), rather than coming from a file + /// or pipe. + static bool StandardInIsUserInput(); + + /// This function determines if the standard output is connected to a + /// "tty" or "console" window. That is, the output would be displayed to + /// the user rather than being put on a pipe or stored in a file. + static bool StandardOutIsDisplayed(); + + /// This function determines if the standard error is connected to a + /// "tty" or "console" window. That is, the output would be displayed to + /// the user rather than being put on a pipe or stored in a file. + static bool StandardErrIsDisplayed(); + + /// This function determines if the given file descriptor is connected to + /// a "tty" or "console" window. That is, the output would be displayed to + /// the user rather than being put on a pipe or stored in a file. + static bool FileDescriptorIsDisplayed(int fd); + + /// This function determines if the given file descriptor is displayd and + /// supports colors. + static bool FileDescriptorHasColors(int fd); + + /// This function determines the number of columns in the window + /// if standard output is connected to a "tty" or "console" + /// window. If standard output is not connected to a tty or + /// console, or if the number of columns cannot be determined, + /// this routine returns zero. + static unsigned StandardOutColumns(); + + /// This function determines the number of columns in the window + /// if standard error is connected to a "tty" or "console" + /// window. If standard error is not connected to a tty or + /// console, or if the number of columns cannot be determined, + /// this routine returns zero. + static unsigned StandardErrColumns(); + + /// This function determines whether the terminal connected to standard + /// output supports colors. If standard output is not connected to a + /// terminal, this function returns false. + static bool StandardOutHasColors(); + + /// This function determines whether the terminal connected to standard + /// error supports colors. If standard error is not connected to a + /// terminal, this function returns false. + static bool StandardErrHasColors(); + + /// Enables or disables whether ANSI escape sequences are used to output + /// colors. This only has an effect on Windows. + /// Note: Setting this option is not thread-safe and should only be done + /// during initialization. + static void UseANSIEscapeCodes(bool enable); + + /// Whether changing colors requires the output to be flushed. + /// This is needed on systems that don't support escape sequences for + /// changing colors. + static bool ColorNeedsFlush(); + + /// This function returns the colorcode escape sequences. + /// If ColorNeedsFlush() is true then this function will change the colors + /// and return an empty escape sequence. In that case it is the + /// responsibility of the client to flush the output stream prior to + /// calling this function. + static const char *OutputColor(char c, bool bold, bool bg); + + /// Same as OutputColor, but only enables the bold attribute. + static const char *OutputBold(bool bg); + + /// This function returns the escape sequence to reverse forground and + /// background colors. + static const char *OutputReverse(); + + /// Resets the terminals colors, or returns an escape sequence to do so. + static const char *ResetColor(); + + /// Get the result of a process wide random number generator. The + /// generator will be automatically seeded in non-deterministic fashion. + static unsigned GetRandomNumber(); +}; + +} +} + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/Program.h b/third_party/llvm-project/include/llvm/Support/Program.h new file mode 100644 index 000000000..6b2315c5d --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Program.h @@ -0,0 +1,208 @@ +//===- llvm/Support/Program.h ------------------------------------*- 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 declares the llvm::sys::Program class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_PROGRAM_H +#define LLVM_SUPPORT_PROGRAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Support/ErrorOr.h" +#include <system_error> + +namespace llvm { +namespace sys { + + /// This is the OS-specific separator for PATH like environment variables: + // a colon on Unix or a semicolon on Windows. +#if defined(LLVM_ON_UNIX) + const char EnvPathSeparator = ':'; +#elif defined (_WIN32) + const char EnvPathSeparator = ';'; +#endif + +#if defined(_WIN32) + typedef unsigned long procid_t; // Must match the type of DWORD on Windows. + typedef void *process_t; // Must match the type of HANDLE on Windows. +#else + typedef pid_t procid_t; + typedef procid_t process_t; +#endif + + /// This struct encapsulates information about a process. + struct ProcessInfo { + enum : procid_t { InvalidPid = 0 }; + + procid_t Pid; /// The process identifier. + process_t Process; /// Platform-dependent process object. + + /// The return code, set after execution. + int ReturnCode; + + ProcessInfo(); + }; + + /// Find the first executable file \p Name in \p Paths. + /// + /// This does not perform hashing as a shell would but instead stats each PATH + /// entry individually so should generally be avoided. Core LLVM library + /// functions and options should instead require fully specified paths. + /// + /// \param Name name of the executable to find. If it contains any system + /// slashes, it will be returned as is. + /// \param Paths optional list of paths to search for \p Name. If empty it + /// will use the system PATH environment instead. + /// + /// \returns The fully qualified path to the first \p Name in \p Paths if it + /// exists. \p Name if \p Name has slashes in it. Otherwise an error. + ErrorOr<std::string> + findProgramByName(StringRef Name, ArrayRef<StringRef> Paths = {}); + + // These functions change the specified standard stream (stdin or stdout) to + // binary mode. They return errc::success if the specified stream + // was changed. Otherwise a platform dependent error is returned. + std::error_code ChangeStdinToBinary(); + std::error_code ChangeStdoutToBinary(); + + /// This function executes the program using the arguments provided. The + /// invoked program will inherit the stdin, stdout, and stderr file + /// descriptors, the environment and other configuration settings of the + /// invoking program. + /// This function waits for the program to finish, so should be avoided in + /// library functions that aren't expected to block. Consider using + /// ExecuteNoWait() instead. + /// \returns an integer result code indicating the status of the program. + /// A zero or positive value indicates the result code of the program. + /// -1 indicates failure to execute + /// -2 indicates a crash during execution or timeout + int ExecuteAndWait( + StringRef Program, ///< Path of the program to be executed. It is + ///< presumed this is the result of the findProgramByName method. + ArrayRef<StringRef> Args, ///< An array of strings that are passed to the + ///< program. The first element should be the name of the program. + ///< The array should **not** be terminated by an empty StringRef. + Optional<ArrayRef<StringRef>> Env = None, ///< An optional vector of + ///< strings to use for the program's environment. If not provided, the + ///< current program's environment will be used. If specified, the + ///< vector should **not** be terminated by an empty StringRef. + ArrayRef<Optional<StringRef>> Redirects = {}, ///< + ///< An array of optional paths. Should have a size of zero or three. + ///< If the array is empty, no redirections are performed. + ///< Otherwise, the inferior process's stdin(0), stdout(1), and stderr(2) + ///< will be redirected to the corresponding paths, if the optional path + ///< is present (not \c llvm::None). + ///< When an empty path is passed in, the corresponding file descriptor + ///< will be disconnected (ie, /dev/null'd) in a portable way. + unsigned SecondsToWait = 0, ///< If non-zero, this specifies the amount + ///< of time to wait for the child process to exit. If the time + ///< expires, the child is killed and this call returns. If zero, + ///< this function will wait until the child finishes or forever if + ///< it doesn't. + unsigned MemoryLimit = 0, ///< If non-zero, this specifies max. amount + ///< of memory can be allocated by process. If memory usage will be + ///< higher limit, the child is killed and this call returns. If zero + ///< - no memory limit. + std::string *ErrMsg = nullptr, ///< If non-zero, provides a pointer to a + ///< string instance in which error messages will be returned. If the + ///< string is non-empty upon return an error occurred while invoking the + ///< program. + bool *ExecutionFailed = nullptr); + + /// Similar to ExecuteAndWait, but returns immediately. + /// @returns The \see ProcessInfo of the newly launced process. + /// \note On Microsoft Windows systems, users will need to either call + /// \see Wait until the process finished execution or win32 CloseHandle() API + /// on ProcessInfo.ProcessHandle to avoid memory leaks. + ProcessInfo ExecuteNoWait(StringRef Program, ArrayRef<StringRef> Args, + Optional<ArrayRef<StringRef>> Env, + ArrayRef<Optional<StringRef>> Redirects = {}, + unsigned MemoryLimit = 0, + std::string *ErrMsg = nullptr, + bool *ExecutionFailed = nullptr); + + /// Return true if the given arguments fit within system-specific + /// argument length limits. + bool commandLineFitsWithinSystemLimits(StringRef Program, + ArrayRef<StringRef> Args); + + /// Return true if the given arguments fit within system-specific + /// argument length limits. + bool commandLineFitsWithinSystemLimits(StringRef Program, + ArrayRef<const char *> Args); + + /// File encoding options when writing contents that a non-UTF8 tool will + /// read (on Windows systems). For UNIX, we always use UTF-8. + enum WindowsEncodingMethod { + /// UTF-8 is the LLVM native encoding, being the same as "do not perform + /// encoding conversion". + WEM_UTF8, + WEM_CurrentCodePage, + WEM_UTF16 + }; + + /// Saves the UTF8-encoded \p contents string into the file \p FileName + /// using a specific encoding. + /// + /// This write file function adds the possibility to choose which encoding + /// to use when writing a text file. On Windows, this is important when + /// writing files with internationalization support with an encoding that is + /// different from the one used in LLVM (UTF-8). We use this when writing + /// response files, since GCC tools on MinGW only understand legacy code + /// pages, and VisualStudio tools only understand UTF-16. + /// For UNIX, using different encodings is silently ignored, since all tools + /// work well with UTF-8. + /// This function assumes that you only use UTF-8 *text* data and will convert + /// it to your desired encoding before writing to the file. + /// + /// FIXME: We use EM_CurrentCodePage to write response files for GNU tools in + /// a MinGW/MinGW-w64 environment, which has serious flaws but currently is + /// our best shot to make gcc/ld understand international characters. This + /// should be changed as soon as binutils fix this to support UTF16 on mingw. + /// + /// \returns non-zero error_code if failed + std::error_code + writeFileWithEncoding(StringRef FileName, StringRef Contents, + WindowsEncodingMethod Encoding = WEM_UTF8); + + /// This function waits for the process specified by \p PI to finish. + /// \returns A \see ProcessInfo struct with Pid set to: + /// \li The process id of the child process if the child process has changed + /// state. + /// \li 0 if the child process has not changed state. + /// \note Users of this function should always check the ReturnCode member of + /// the \see ProcessInfo returned from this function. + ProcessInfo Wait( + const ProcessInfo &PI, ///< The child process that should be waited on. + unsigned SecondsToWait, ///< If non-zero, this specifies the amount of + ///< time to wait for the child process to exit. If the time expires, the + ///< child is killed and this function returns. If zero, this function + ///< will perform a non-blocking wait on the child process. + bool WaitUntilTerminates, ///< If true, ignores \p SecondsToWait and waits + ///< until child has terminated. + std::string *ErrMsg = nullptr ///< If non-zero, provides a pointer to a + ///< string instance in which error messages will be returned. If the + ///< string is non-empty upon return an error occurred while invoking the + ///< program. + ); + +#if defined(_WIN32) + /// Given a list of command line arguments, quote and escape them as necessary + /// to build a single flat command line appropriate for calling CreateProcess + /// on + /// Windows. + std::string flattenWindowsCommandLine(ArrayRef<StringRef> Args); +#endif + } +} + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/Regex.h b/third_party/llvm-project/include/llvm/Support/Regex.h new file mode 100644 index 000000000..b2620ab4c --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Regex.h @@ -0,0 +1,109 @@ +//===-- Regex.h - Regular Expression matcher implementation -*- 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 a POSIX regular expression matcher. Both Basic and +// Extended POSIX regular expressions (ERE) are supported. EREs were extended +// to support backreferences in matches. +// This implementation also supports matching strings with embedded NUL chars. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_REGEX_H +#define LLVM_SUPPORT_REGEX_H + +#include <string> + +struct llvm_regex; + +namespace llvm { + class StringRef; + template<typename T> class SmallVectorImpl; + + class Regex { + public: + enum { + NoFlags=0, + /// Compile for matching that ignores upper/lower case distinctions. + IgnoreCase=1, + /// Compile for newline-sensitive matching. With this flag '[^' bracket + /// expressions and '.' never match newline. A ^ anchor matches the + /// null string after any newline in the string in addition to its normal + /// function, and the $ anchor matches the null string before any + /// newline in the string in addition to its normal function. + Newline=2, + /// By default, the POSIX extended regular expression (ERE) syntax is + /// assumed. Pass this flag to turn on basic regular expressions (BRE) + /// instead. + BasicRegex=4 + }; + + Regex(); + /// Compiles the given regular expression \p Regex. + /// + /// \param Regex - referenced string is no longer needed after this + /// constructor does finish. Only its compiled form is kept stored. + Regex(StringRef Regex, unsigned Flags = NoFlags); + Regex(const Regex &) = delete; + Regex &operator=(Regex regex) { + std::swap(preg, regex.preg); + std::swap(error, regex.error); + return *this; + } + Regex(Regex &®ex); + ~Regex(); + + /// isValid - returns the error encountered during regex compilation, if + /// any. + bool isValid(std::string &Error) const; + bool isValid() const { return !error; } + + /// getNumMatches - In a valid regex, return the number of parenthesized + /// matches it contains. The number filled in by match will include this + /// many entries plus one for the whole regex (as element 0). + unsigned getNumMatches() const; + + /// matches - Match the regex against a given \p String. + /// + /// \param Matches - If given, on a successful match this will be filled in + /// with references to the matched group expressions (inside \p String), + /// the first group is always the entire pattern. + /// + /// \param Error - If non-null, any errors in the matching will be recorded + /// as a non-empty string. If there is no error, it will be an empty string. + /// + /// This returns true on a successful match. + bool match(StringRef String, SmallVectorImpl<StringRef> *Matches = nullptr, + std::string *Error = nullptr) const; + + /// sub - Return the result of replacing the first match of the regex in + /// \p String with the \p Repl string. Backreferences like "\0" in the + /// replacement string are replaced with the appropriate match substring. + /// + /// Note that the replacement string has backslash escaping performed on + /// it. Invalid backreferences are ignored (replaced by empty strings). + /// + /// \param Error If non-null, any errors in the substitution (invalid + /// backreferences, trailing backslashes) will be recorded as a non-empty + /// string. If there is no error, it will be an empty string. + std::string sub(StringRef Repl, StringRef String, + std::string *Error = nullptr) const; + + /// If this function returns true, ^Str$ is an extended regular + /// expression that matches Str and only Str. + static bool isLiteralERE(StringRef Str); + + /// Turn String into a regex by escaping its special characters. + static std::string escape(StringRef String); + + private: + struct llvm_regex *preg; + int error; + }; +} + +#endif // LLVM_SUPPORT_REGEX_H diff --git a/third_party/llvm-project/include/llvm/Support/ReverseIteration.h b/third_party/llvm-project/include/llvm/Support/ReverseIteration.h new file mode 100644 index 000000000..5e0238d81 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/ReverseIteration.h @@ -0,0 +1,19 @@ +#ifndef LLVM_SUPPORT_REVERSEITERATION_H +#define LLVM_SUPPORT_REVERSEITERATION_H + +#include "llvm/Config/abi-breaking.h" +#include "llvm/Support/PointerLikeTypeTraits.h" + +namespace llvm { + +template<class T = void *> +bool shouldReverseIterate() { +#if LLVM_ENABLE_REVERSE_ITERATION + return detail::IsPointerLike<T>::value; +#else + return false; +#endif +} + +} +#endif diff --git a/third_party/llvm-project/include/llvm/Support/SMLoc.h b/third_party/llvm-project/include/llvm/Support/SMLoc.h new file mode 100644 index 000000000..d8607034e --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/SMLoc.h @@ -0,0 +1,64 @@ +//===- SMLoc.h - Source location for use with diagnostics -------*- 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 declares the SMLoc class. This class encapsulates a location in +// source code for use in diagnostics. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_SMLOC_H +#define LLVM_SUPPORT_SMLOC_H + +#include "llvm/ADT/None.h" +#include <cassert> + +namespace llvm { + +/// Represents a location in source code. +class SMLoc { + const char *Ptr = nullptr; + +public: + SMLoc() = default; + + bool isValid() const { return Ptr != nullptr; } + + bool operator==(const SMLoc &RHS) const { return RHS.Ptr == Ptr; } + bool operator!=(const SMLoc &RHS) const { return RHS.Ptr != Ptr; } + + const char *getPointer() const { return Ptr; } + + static SMLoc getFromPointer(const char *Ptr) { + SMLoc L; + L.Ptr = Ptr; + return L; + } +}; + +/// Represents a range in source code. +/// +/// SMRange is implemented using a half-open range, as is the convention in C++. +/// In the string "abc", the range [1,3) represents the substring "bc", and the +/// range [2,2) represents an empty range between the characters "b" and "c". +class SMRange { +public: + SMLoc Start, End; + + SMRange() = default; + SMRange(NoneType) {} + SMRange(SMLoc St, SMLoc En) : Start(St), End(En) { + assert(Start.isValid() == End.isValid() && + "Start and End should either both be valid or both be invalid!"); + } + + bool isValid() const { return Start.isValid(); } +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_SMLOC_H diff --git a/third_party/llvm-project/include/llvm/Support/ScopedPrinter.h b/third_party/llvm-project/include/llvm/Support/ScopedPrinter.h new file mode 100644 index 000000000..88daedc87 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/ScopedPrinter.h @@ -0,0 +1,388 @@ +//===-- ScopedPrinter.h ----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_SCOPEDPRINTER_H +#define LLVM_SUPPORT_SCOPEDPRINTER_H + +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> + +namespace llvm { + +template <typename T> struct EnumEntry { + StringRef Name; + // While Name suffices in most of the cases, in certain cases + // GNU style and LLVM style of ELFDumper do not + // display same string for same enum. The AltName if initialized appropriately + // will hold the string that GNU style emits. + // Example: + // "EM_X86_64" string on LLVM style for Elf_Ehdr->e_machine corresponds to + // "Advanced Micro Devices X86-64" on GNU style + StringRef AltName; + T Value; + EnumEntry(StringRef N, StringRef A, T V) : Name(N), AltName(A), Value(V) {} + EnumEntry(StringRef N, T V) : Name(N), AltName(N), Value(V) {} +}; + +struct HexNumber { + // To avoid sign-extension we have to explicitly cast to the appropriate + // unsigned type. The overloads are here so that every type that is implicitly + // convertible to an integer (including enums and endian helpers) can be used + // without requiring type traits or call-site changes. + HexNumber(char Value) : Value(static_cast<unsigned char>(Value)) {} + HexNumber(signed char Value) : Value(static_cast<unsigned char>(Value)) {} + HexNumber(signed short Value) : Value(static_cast<unsigned short>(Value)) {} + HexNumber(signed int Value) : Value(static_cast<unsigned int>(Value)) {} + HexNumber(signed long Value) : Value(static_cast<unsigned long>(Value)) {} + HexNumber(signed long long Value) + : Value(static_cast<unsigned long long>(Value)) {} + HexNumber(unsigned char Value) : Value(Value) {} + HexNumber(unsigned short Value) : Value(Value) {} + HexNumber(unsigned int Value) : Value(Value) {} + HexNumber(unsigned long Value) : Value(Value) {} + HexNumber(unsigned long long Value) : Value(Value) {} + uint64_t Value; +}; + +raw_ostream &operator<<(raw_ostream &OS, const HexNumber &Value); +const std::string to_hexString(uint64_t Value, bool UpperCase = true); + +template <class T> const std::string to_string(const T &Value) { + std::string number; + llvm::raw_string_ostream stream(number); + stream << Value; + return stream.str(); +} + +class ScopedPrinter { +public: + ScopedPrinter(raw_ostream &OS) : OS(OS), IndentLevel(0) {} + + void flush() { OS.flush(); } + + void indent(int Levels = 1) { IndentLevel += Levels; } + + void unindent(int Levels = 1) { + IndentLevel = std::max(0, IndentLevel - Levels); + } + + void resetIndent() { IndentLevel = 0; } + + int getIndentLevel() { return IndentLevel; } + + void setPrefix(StringRef P) { Prefix = P; } + + void printIndent() { + OS << Prefix; + for (int i = 0; i < IndentLevel; ++i) + OS << " "; + } + + template <typename T> HexNumber hex(T Value) { return HexNumber(Value); } + + template <typename T, typename TEnum> + void printEnum(StringRef Label, T Value, + ArrayRef<EnumEntry<TEnum>> EnumValues) { + StringRef Name; + bool Found = false; + for (const auto &EnumItem : EnumValues) { + if (EnumItem.Value == Value) { + Name = EnumItem.Name; + Found = true; + break; + } + } + + if (Found) { + startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n"; + } else { + startLine() << Label << ": " << hex(Value) << "\n"; + } + } + + template <typename T, typename TFlag> + void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag>> Flags, + TFlag EnumMask1 = {}, TFlag EnumMask2 = {}, + TFlag EnumMask3 = {}) { + typedef EnumEntry<TFlag> FlagEntry; + typedef SmallVector<FlagEntry, 10> FlagVector; + FlagVector SetFlags; + + for (const auto &Flag : Flags) { + if (Flag.Value == 0) + continue; + + TFlag EnumMask{}; + if (Flag.Value & EnumMask1) + EnumMask = EnumMask1; + else if (Flag.Value & EnumMask2) + EnumMask = EnumMask2; + else if (Flag.Value & EnumMask3) + EnumMask = EnumMask3; + bool IsEnum = (Flag.Value & EnumMask) != 0; + if ((!IsEnum && (Value & Flag.Value) == Flag.Value) || + (IsEnum && (Value & EnumMask) == Flag.Value)) { + SetFlags.push_back(Flag); + } + } + + llvm::sort(SetFlags, &flagName<TFlag>); + + startLine() << Label << " [ (" << hex(Value) << ")\n"; + for (const auto &Flag : SetFlags) { + startLine() << " " << Flag.Name << " (" << hex(Flag.Value) << ")\n"; + } + startLine() << "]\n"; + } + + template <typename T> void printFlags(StringRef Label, T Value) { + startLine() << Label << " [ (" << hex(Value) << ")\n"; + uint64_t Flag = 1; + uint64_t Curr = Value; + while (Curr > 0) { + if (Curr & 1) + startLine() << " " << hex(Flag) << "\n"; + Curr >>= 1; + Flag <<= 1; + } + startLine() << "]\n"; + } + + void printNumber(StringRef Label, uint64_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint32_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint16_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint8_t Value) { + startLine() << Label << ": " << unsigned(Value) << "\n"; + } + + void printNumber(StringRef Label, int64_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int32_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int16_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int8_t Value) { + startLine() << Label << ": " << int(Value) << "\n"; + } + + void printNumber(StringRef Label, const APSInt &Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printBoolean(StringRef Label, bool Value) { + startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n'; + } + + template <typename... T> void printVersion(StringRef Label, T... Version) { + startLine() << Label << ": "; + printVersionInternal(Version...); + getOStream() << "\n"; + } + + template <typename T> void printList(StringRef Label, const T &List) { + startLine() << Label << ": ["; + bool Comma = false; + for (const auto &Item : List) { + if (Comma) + OS << ", "; + OS << Item; + Comma = true; + } + OS << "]\n"; + } + + template <typename T, typename U> + void printList(StringRef Label, const T &List, const U &Printer) { + startLine() << Label << ": ["; + bool Comma = false; + for (const auto &Item : List) { + if (Comma) + OS << ", "; + Printer(OS, Item); + Comma = true; + } + OS << "]\n"; + } + + template <typename T> void printHexList(StringRef Label, const T &List) { + startLine() << Label << ": ["; + bool Comma = false; + for (const auto &Item : List) { + if (Comma) + OS << ", "; + OS << hex(Item); + Comma = true; + } + OS << "]\n"; + } + + template <typename T> void printHex(StringRef Label, T Value) { + startLine() << Label << ": " << hex(Value) << "\n"; + } + + template <typename T> void printHex(StringRef Label, StringRef Str, T Value) { + startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n"; + } + + template <typename T> + void printSymbolOffset(StringRef Label, StringRef Symbol, T Value) { + startLine() << Label << ": " << Symbol << '+' << hex(Value) << '\n'; + } + + void printString(StringRef Value) { startLine() << Value << "\n"; } + + void printString(StringRef Label, StringRef Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printString(StringRef Label, const std::string &Value) { + printString(Label, StringRef(Value)); + } + + void printString(StringRef Label, const char* Value) { + printString(Label, StringRef(Value)); + } + + template <typename T> + void printNumber(StringRef Label, StringRef Str, T Value) { + startLine() << Label << ": " << Str << " (" << Value << ")\n"; + } + + void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) { + printBinaryImpl(Label, Str, Value, false); + } + + void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) { + auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), + Value.size()); + printBinaryImpl(Label, Str, V, false); + } + + void printBinary(StringRef Label, ArrayRef<uint8_t> Value) { + printBinaryImpl(Label, StringRef(), Value, false); + } + + void printBinary(StringRef Label, ArrayRef<char> Value) { + auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, false); + } + + void printBinary(StringRef Label, StringRef Value) { + auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, false); + } + + void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value, + uint32_t StartOffset) { + printBinaryImpl(Label, StringRef(), Value, true, StartOffset); + } + + void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value) { + printBinaryImpl(Label, StringRef(), Value, true); + } + + void printBinaryBlock(StringRef Label, StringRef Value) { + auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, true); + } + + template <typename T> void printObject(StringRef Label, const T &Value) { + startLine() << Label << ": " << Value << "\n"; + } + + raw_ostream &startLine() { + printIndent(); + return OS; + } + + raw_ostream &getOStream() { return OS; } + +private: + template <typename T> void printVersionInternal(T Value) { + getOStream() << Value; + } + + template <typename S, typename T, typename... TArgs> + void printVersionInternal(S Value, T Value2, TArgs... Args) { + getOStream() << Value << "."; + printVersionInternal(Value2, Args...); + } + + template <typename T> + static bool flagName(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) { + return lhs.Name < rhs.Name; + } + + void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value, + bool Block, uint32_t StartOffset = 0); + + raw_ostream &OS; + int IndentLevel; + StringRef Prefix; +}; + +template <> +inline void +ScopedPrinter::printHex<support::ulittle16_t>(StringRef Label, + support::ulittle16_t Value) { + startLine() << Label << ": " << hex(Value) << "\n"; +} + +template<char Open, char Close> +struct DelimitedScope { + explicit DelimitedScope(ScopedPrinter &W) : W(W) { + W.startLine() << Open << '\n'; + W.indent(); + } + + DelimitedScope(ScopedPrinter &W, StringRef N) : W(W) { + W.startLine() << N; + if (!N.empty()) + W.getOStream() << ' '; + W.getOStream() << Open << '\n'; + W.indent(); + } + + ~DelimitedScope() { + W.unindent(); + W.startLine() << Close << '\n'; + } + + ScopedPrinter &W; +}; + +using DictScope = DelimitedScope<'{', '}'>; +using ListScope = DelimitedScope<'[', ']'>; + +} // namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/Signals.h b/third_party/llvm-project/include/llvm/Support/Signals.h new file mode 100644 index 000000000..a6b215a24 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Signals.h @@ -0,0 +1,90 @@ +//===- llvm/Support/Signals.h - Signal Handling support ----------*- 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 defines some helpful functions for dealing with the possibility of +// unix signals occurring while your program is running. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_SIGNALS_H +#define LLVM_SUPPORT_SIGNALS_H + +#include <string> + +namespace llvm { +class StringRef; +class raw_ostream; + +namespace sys { + + /// This function runs all the registered interrupt handlers, including the + /// removal of files registered by RemoveFileOnSignal. + void RunInterruptHandlers(); + + /// This function registers signal handlers to ensure that if a signal gets + /// delivered that the named file is removed. + /// Remove a file if a fatal signal occurs. + bool RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg = nullptr); + + /// This function removes a file from the list of files to be removed on + /// signal delivery. + void DontRemoveFileOnSignal(StringRef Filename); + + /// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the + /// process, print a stack trace and then exit. + /// Print a stack trace if a fatal signal occurs. + /// \param Argv0 the current binary name, used to find the symbolizer + /// relative to the current binary before searching $PATH; can be + /// StringRef(), in which case we will only search $PATH. + /// \param DisableCrashReporting if \c true, disable the normal crash + /// reporting mechanisms on the underlying operating system. + void PrintStackTraceOnErrorSignal(StringRef Argv0, + bool DisableCrashReporting = false); + + /// Disable all system dialog boxes that appear when the process crashes. + void DisableSystemDialogsOnCrash(); + + /// Print the stack trace using the given \c raw_ostream object. + void PrintStackTrace(raw_ostream &OS); + + // Run all registered signal handlers. + void RunSignalHandlers(); + + using SignalHandlerCallback = void (*)(void *); + + /// Add a function to be called when an abort/kill signal is delivered to the + /// process. The handler can have a cookie passed to it to identify what + /// instance of the handler it is. + void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie); + + /// This function registers a function to be called when the user "interrupts" + /// the program (typically by pressing ctrl-c). When the user interrupts the + /// program, the specified interrupt function is called instead of the program + /// being killed, and the interrupt function automatically disabled. + /// + /// Note that interrupt functions are not allowed to call any non-reentrant + /// functions. An null interrupt function pointer disables the current + /// installed function. Note also that the handler may be executed on a + /// different thread on some platforms. + void SetInterruptFunction(void (*IF)()); + + /// Registers a function to be called when an "info" signal is delivered to + /// the process. + /// + /// On POSIX systems, this will be SIGUSR1; on systems that have it, SIGINFO + /// will also be used (typically ctrl-t). + /// + /// Note that signal handlers are not allowed to call any non-reentrant + /// functions. An null function pointer disables the current installed + /// function. Note also that the handler may be executed on a different + /// thread on some platforms. + void SetInfoSignalFunction(void (*Handler)()); +} // End sys namespace +} // End llvm namespace + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/SmallVectorMemoryBuffer.h b/third_party/llvm-project/include/llvm/Support/SmallVectorMemoryBuffer.h new file mode 100644 index 000000000..b63b58e3a --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/SmallVectorMemoryBuffer.h @@ -0,0 +1,65 @@ +//===- SmallVectorMemoryBuffer.h --------------------------------*- 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 declares a wrapper class to hold the memory into which an +// object will be generated. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_OBJECTMEMORYBUFFER_H +#define LLVM_EXECUTIONENGINE_OBJECTMEMORYBUFFER_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +/// SmallVector-backed MemoryBuffer instance. +/// +/// This class enables efficient construction of MemoryBuffers from SmallVector +/// instances. This is useful for MCJIT and Orc, where object files are streamed +/// into SmallVectors, then inspected using ObjectFile (which takes a +/// MemoryBuffer). +class SmallVectorMemoryBuffer : public MemoryBuffer { +public: + /// Construct an SmallVectorMemoryBuffer from the given SmallVector + /// r-value. + /// + /// FIXME: It'd be nice for this to be a non-templated constructor taking a + /// SmallVectorImpl here instead of a templated one taking a SmallVector<N>, + /// but SmallVector's move-construction/assignment currently only take + /// SmallVectors. If/when that is fixed we can simplify this constructor and + /// the following one. + SmallVectorMemoryBuffer(SmallVectorImpl<char> &&SV) + : SV(std::move(SV)), BufferName("<in-memory object>") { + init(this->SV.begin(), this->SV.end(), false); + } + + /// Construct a named SmallVectorMemoryBuffer from the given + /// SmallVector r-value and StringRef. + SmallVectorMemoryBuffer(SmallVectorImpl<char> &&SV, StringRef Name) + : SV(std::move(SV)), BufferName(Name) { + init(this->SV.begin(), this->SV.end(), false); + } + + // Key function. + ~SmallVectorMemoryBuffer() override; + + StringRef getBufferIdentifier() const override { return BufferName; } + + BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; } + +private: + SmallVector<char, 0> SV; + std::string BufferName; +}; + +} // namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/SourceMgr.h b/third_party/llvm-project/include/llvm/Support/SourceMgr.h new file mode 100644 index 000000000..aa6026c23 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/SourceMgr.h @@ -0,0 +1,310 @@ +//===- SourceMgr.h - Manager for Source Buffers & Diagnostics ---*- 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 declares the SMDiagnostic and SourceMgr classes. This +// provides a simple substrate for diagnostics, #include handling, and other low +// level things for simple parsers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_SOURCEMGR_H +#define LLVM_SUPPORT_SOURCEMGR_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SMLoc.h" +#include <algorithm> +#include <cassert> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +namespace llvm { + +class raw_ostream; +class SMDiagnostic; +class SMFixIt; + +/// This owns the files read by a parser, handles include stacks, +/// and handles diagnostic wrangling. +class SourceMgr { +public: + enum DiagKind { + DK_Error, + DK_Warning, + DK_Remark, + DK_Note, + }; + + /// Clients that want to handle their own diagnostics in a custom way can + /// register a function pointer+context as a diagnostic handler. + /// It gets called each time PrintMessage is invoked. + using DiagHandlerTy = void (*)(const SMDiagnostic &, void *Context); + +private: + struct SrcBuffer { + /// The memory buffer for the file. + std::unique_ptr<MemoryBuffer> Buffer; + + /// Helper type for OffsetCache below: since we're storing many offsets + /// into relatively small files (often smaller than 2^8 or 2^16 bytes), + /// we select the offset vector element type dynamically based on the + /// size of Buffer. + using VariableSizeOffsets = PointerUnion4<std::vector<uint8_t> *, + std::vector<uint16_t> *, + std::vector<uint32_t> *, + std::vector<uint64_t> *>; + + /// Vector of offsets into Buffer at which there are line-endings + /// (lazily populated). Once populated, the '\n' that marks the end of + /// line number N from [1..] is at Buffer[OffsetCache[N-1]]. Since + /// these offsets are in sorted (ascending) order, they can be + /// binary-searched for the first one after any given offset (eg. an + /// offset corresponding to a particular SMLoc). + mutable VariableSizeOffsets OffsetCache; + + /// Populate \c OffsetCache and look up a given \p Ptr in it, assuming + /// it points somewhere into \c Buffer. The static type parameter \p T + /// must be an unsigned integer type from uint{8,16,32,64}_t large + /// enough to store offsets inside \c Buffer. + template<typename T> + unsigned getLineNumber(const char *Ptr) const; + + /// This is the location of the parent include, or null if at the top level. + SMLoc IncludeLoc; + + SrcBuffer() = default; + SrcBuffer(SrcBuffer &&); + SrcBuffer(const SrcBuffer &) = delete; + SrcBuffer &operator=(const SrcBuffer &) = delete; + ~SrcBuffer(); + }; + + /// This is all of the buffers that we are reading from. + std::vector<SrcBuffer> Buffers; + + // This is the list of directories we should search for include files in. + std::vector<std::string> IncludeDirectories; + + DiagHandlerTy DiagHandler = nullptr; + void *DiagContext = nullptr; + + bool isValidBufferID(unsigned i) const { return i && i <= Buffers.size(); } + +public: + SourceMgr() = default; + SourceMgr(const SourceMgr &) = delete; + SourceMgr &operator=(const SourceMgr &) = delete; + SourceMgr(SourceMgr &&) = default; + SourceMgr &operator=(SourceMgr &&) = default; + ~SourceMgr() = default; + + void setIncludeDirs(const std::vector<std::string> &Dirs) { + IncludeDirectories = Dirs; + } + + /// Specify a diagnostic handler to be invoked every time PrintMessage is + /// called. \p Ctx is passed into the handler when it is invoked. + void setDiagHandler(DiagHandlerTy DH, void *Ctx = nullptr) { + DiagHandler = DH; + DiagContext = Ctx; + } + + DiagHandlerTy getDiagHandler() const { return DiagHandler; } + void *getDiagContext() const { return DiagContext; } + + const SrcBuffer &getBufferInfo(unsigned i) const { + assert(isValidBufferID(i)); + return Buffers[i - 1]; + } + + const MemoryBuffer *getMemoryBuffer(unsigned i) const { + assert(isValidBufferID(i)); + return Buffers[i - 1].Buffer.get(); + } + + unsigned getNumBuffers() const { + return Buffers.size(); + } + + unsigned getMainFileID() const { + assert(getNumBuffers()); + return 1; + } + + SMLoc getParentIncludeLoc(unsigned i) const { + assert(isValidBufferID(i)); + return Buffers[i - 1].IncludeLoc; + } + + /// Add a new source buffer to this source manager. This takes ownership of + /// the memory buffer. + unsigned AddNewSourceBuffer(std::unique_ptr<MemoryBuffer> F, + SMLoc IncludeLoc) { + SrcBuffer NB; + NB.Buffer = std::move(F); + NB.IncludeLoc = IncludeLoc; + Buffers.push_back(std::move(NB)); + return Buffers.size(); + } + + /// Search for a file with the specified name in the current directory or in + /// one of the IncludeDirs. + /// + /// If no file is found, this returns 0, otherwise it returns the buffer ID + /// of the stacked file. The full path to the included file can be found in + /// \p IncludedFile. + unsigned AddIncludeFile(const std::string &Filename, SMLoc IncludeLoc, + std::string &IncludedFile); + + /// Return the ID of the buffer containing the specified location. + /// + /// 0 is returned if the buffer is not found. + unsigned FindBufferContainingLoc(SMLoc Loc) const; + + /// Find the line number for the specified location in the specified file. + /// This is not a fast method. + unsigned FindLineNumber(SMLoc Loc, unsigned BufferID = 0) const { + return getLineAndColumn(Loc, BufferID).first; + } + + /// Find the line and column number for the specified location in the + /// specified file. This is not a fast method. + std::pair<unsigned, unsigned> getLineAndColumn(SMLoc Loc, + unsigned BufferID = 0) const; + + /// Emit a message about the specified location with the specified string. + /// + /// \param ShowColors Display colored messages if output is a terminal and + /// the default error handler is used. + void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, + const Twine &Msg, + ArrayRef<SMRange> Ranges = None, + ArrayRef<SMFixIt> FixIts = None, + bool ShowColors = true) const; + + /// Emits a diagnostic to llvm::errs(). + void PrintMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg, + ArrayRef<SMRange> Ranges = None, + ArrayRef<SMFixIt> FixIts = None, + bool ShowColors = true) const; + + /// Emits a manually-constructed diagnostic to the given output stream. + /// + /// \param ShowColors Display colored messages if output is a terminal and + /// the default error handler is used. + void PrintMessage(raw_ostream &OS, const SMDiagnostic &Diagnostic, + bool ShowColors = true) const; + + /// Return an SMDiagnostic at the specified location with the specified + /// string. + /// + /// \param Msg If non-null, the kind of message (e.g., "error") which is + /// prefixed to the message. + SMDiagnostic GetMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg, + ArrayRef<SMRange> Ranges = None, + ArrayRef<SMFixIt> FixIts = None) const; + + /// Prints the names of included files and the line of the file they were + /// included from. A diagnostic handler can use this before printing its + /// custom formatted message. + /// + /// \param IncludeLoc The location of the include. + /// \param OS the raw_ostream to print on. + void PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const; +}; + +/// Represents a single fixit, a replacement of one range of text with another. +class SMFixIt { + SMRange Range; + + std::string Text; + +public: + // FIXME: Twine.str() is not very efficient. + SMFixIt(SMLoc Loc, const Twine &Insertion) + : Range(Loc, Loc), Text(Insertion.str()) { + assert(Loc.isValid()); + } + + // FIXME: Twine.str() is not very efficient. + SMFixIt(SMRange R, const Twine &Replacement) + : Range(R), Text(Replacement.str()) { + assert(R.isValid()); + } + + StringRef getText() const { return Text; } + SMRange getRange() const { return Range; } + + bool operator<(const SMFixIt &Other) const { + if (Range.Start.getPointer() != Other.Range.Start.getPointer()) + return Range.Start.getPointer() < Other.Range.Start.getPointer(); + if (Range.End.getPointer() != Other.Range.End.getPointer()) + return Range.End.getPointer() < Other.Range.End.getPointer(); + return Text < Other.Text; + } +}; + +/// Instances of this class encapsulate one diagnostic report, allowing +/// printing to a raw_ostream as a caret diagnostic. +class SMDiagnostic { + const SourceMgr *SM = nullptr; + SMLoc Loc; + std::string Filename; + int LineNo = 0; + int ColumnNo = 0; + SourceMgr::DiagKind Kind = SourceMgr::DK_Error; + std::string Message, LineContents; + std::vector<std::pair<unsigned, unsigned>> Ranges; + SmallVector<SMFixIt, 4> FixIts; + +public: + // Null diagnostic. + SMDiagnostic() = default; + // Diagnostic with no location (e.g. file not found, command line arg error). + SMDiagnostic(StringRef filename, SourceMgr::DiagKind Knd, StringRef Msg) + : Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd), Message(Msg) {} + + // Diagnostic with a location. + SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN, + int Line, int Col, SourceMgr::DiagKind Kind, + StringRef Msg, StringRef LineStr, + ArrayRef<std::pair<unsigned,unsigned>> Ranges, + ArrayRef<SMFixIt> FixIts = None); + + const SourceMgr *getSourceMgr() const { return SM; } + SMLoc getLoc() const { return Loc; } + StringRef getFilename() const { return Filename; } + int getLineNo() const { return LineNo; } + int getColumnNo() const { return ColumnNo; } + SourceMgr::DiagKind getKind() const { return Kind; } + StringRef getMessage() const { return Message; } + StringRef getLineContents() const { return LineContents; } + ArrayRef<std::pair<unsigned, unsigned>> getRanges() const { return Ranges; } + + void addFixIt(const SMFixIt &Hint) { + FixIts.push_back(Hint); + } + + ArrayRef<SMFixIt> getFixIts() const { + return FixIts; + } + + void print(const char *ProgName, raw_ostream &S, bool ShowColors = true, + bool ShowKindLabel = true) const; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_SOURCEMGR_H diff --git a/third_party/llvm-project/include/llvm/Support/SwapByteOrder.h b/third_party/llvm-project/include/llvm/Support/SwapByteOrder.h new file mode 100644 index 000000000..6cec87006 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/SwapByteOrder.h @@ -0,0 +1,160 @@ +//===- SwapByteOrder.h - Generic and optimized byte swaps -------*- 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 declares generic and optimized functions to swap the byte order of +// an integral type. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_SWAPBYTEORDER_H +#define LLVM_SUPPORT_SWAPBYTEORDER_H + +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DataTypes.h" +#include <cstddef> +#include <type_traits> +#if defined(_MSC_VER) && !defined(_DEBUG) +#include <stdlib.h> +#endif + +#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) +#include <endian.h> +#elif defined(_AIX) +#include <sys/machine.h> +#elif defined(__sun) +/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */ +#include <sys/types.h> +#define BIG_ENDIAN 4321 +#define LITTLE_ENDIAN 1234 +#if defined(_BIG_ENDIAN) +#define BYTE_ORDER BIG_ENDIAN +#else +#define BYTE_ORDER LITTLE_ENDIAN +#endif +#else +#if !defined(BYTE_ORDER) && !defined(_WIN32) +#include <machine/endian.h> +#endif +#endif + +namespace llvm { +namespace sys { + +#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN +constexpr bool IsBigEndianHost = true; +#else +constexpr bool IsBigEndianHost = false; +#endif + +static const bool IsLittleEndianHost = !IsBigEndianHost; + +/// SwapByteOrder_16 - This function returns a byte-swapped representation of +/// the 16-bit argument. +inline uint16_t SwapByteOrder_16(uint16_t value) { +#if defined(_MSC_VER) && !defined(_DEBUG) + // The DLL version of the runtime lacks these functions (bug!?), but in a + // release build they're replaced with BSWAP instructions anyway. + return _byteswap_ushort(value); +#else + uint16_t Hi = value << 8; + uint16_t Lo = value >> 8; + return Hi | Lo; +#endif +} + +/// This function returns a byte-swapped representation of the 32-bit argument. +inline uint32_t SwapByteOrder_32(uint32_t value) { +#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC)) + return __builtin_bswap32(value); +#elif defined(_MSC_VER) && !defined(_DEBUG) + return _byteswap_ulong(value); +#else + uint32_t Byte0 = value & 0x000000FF; + uint32_t Byte1 = value & 0x0000FF00; + uint32_t Byte2 = value & 0x00FF0000; + uint32_t Byte3 = value & 0xFF000000; + return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24); +#endif +} + +/// This function returns a byte-swapped representation of the 64-bit argument. +inline uint64_t SwapByteOrder_64(uint64_t value) { +#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC)) + return __builtin_bswap64(value); +#elif defined(_MSC_VER) && !defined(_DEBUG) + return _byteswap_uint64(value); +#else + uint64_t Hi = SwapByteOrder_32(uint32_t(value)); + uint32_t Lo = SwapByteOrder_32(uint32_t(value >> 32)); + return (Hi << 32) | Lo; +#endif +} + +inline unsigned char getSwappedBytes(unsigned char C) { return C; } +inline signed char getSwappedBytes(signed char C) { return C; } +inline char getSwappedBytes(char C) { return C; } + +inline unsigned short getSwappedBytes(unsigned short C) { return SwapByteOrder_16(C); } +inline signed short getSwappedBytes( signed short C) { return SwapByteOrder_16(C); } + +inline unsigned int getSwappedBytes(unsigned int C) { return SwapByteOrder_32(C); } +inline signed int getSwappedBytes( signed int C) { return SwapByteOrder_32(C); } + +#if __LONG_MAX__ == __INT_MAX__ +inline unsigned long getSwappedBytes(unsigned long C) { return SwapByteOrder_32(C); } +inline signed long getSwappedBytes( signed long C) { return SwapByteOrder_32(C); } +#elif __LONG_MAX__ == __LONG_LONG_MAX__ +inline unsigned long getSwappedBytes(unsigned long C) { return SwapByteOrder_64(C); } +inline signed long getSwappedBytes( signed long C) { return SwapByteOrder_64(C); } +#else +#error "Unknown long size!" +#endif + +inline unsigned long long getSwappedBytes(unsigned long long C) { + return SwapByteOrder_64(C); +} +inline signed long long getSwappedBytes(signed long long C) { + return SwapByteOrder_64(C); +} + +inline float getSwappedBytes(float C) { + union { + uint32_t i; + float f; + } in, out; + in.f = C; + out.i = SwapByteOrder_32(in.i); + return out.f; +} + +inline double getSwappedBytes(double C) { + union { + uint64_t i; + double d; + } in, out; + in.d = C; + out.i = SwapByteOrder_64(in.i); + return out.d; +} + +template <typename T> +inline typename std::enable_if<std::is_enum<T>::value, T>::type +getSwappedBytes(T C) { + return static_cast<T>( + getSwappedBytes(static_cast<typename std::underlying_type<T>::type>(C))); +} + +template<typename T> +inline void swapByteOrder(T &Value) { + Value = getSwappedBytes(Value); +} + +} // end namespace sys +} // end namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/TargetParser.h b/third_party/llvm-project/include/llvm/Support/TargetParser.h new file mode 100644 index 000000000..a7e1a752d --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/TargetParser.h @@ -0,0 +1,174 @@ +//===-- TargetParser - Parser for target features ---------------*- 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 a target parser to recognise hardware features such as +// FPU/CPU/ARCH names as well as specific support such as HDIV, etc. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_TARGETPARSER_H +#define LLVM_SUPPORT_TARGETPARSER_H + +// FIXME: vector is used because that's what clang uses for subtarget feature +// lists, but SmallVector would probably be better +#include "llvm/ADT/Triple.h" +#include "llvm/Support/ARMTargetParser.h" +#include "llvm/Support/AArch64TargetParser.h" +#include <vector> + +namespace llvm { +class StringRef; + +// Target specific information in their own namespaces. +// (ARM/AArch64 are declared in ARM/AArch64TargetParser.h) +// These should be generated from TableGen because the information is already +// there, and there is where new information about targets will be added. +// FIXME: To TableGen this we need to make some table generated files available +// even if the back-end is not compiled with LLVM, plus we need to create a new +// back-end to TableGen to create these clean tables. +namespace X86 { + +// This should be kept in sync with libcc/compiler-rt as its included by clang +// as a proxy for what's in libgcc/compiler-rt. +enum ProcessorVendors : unsigned { + VENDOR_DUMMY, +#define X86_VENDOR(ENUM, STRING) \ + ENUM, +#include "llvm/Support/X86TargetParser.def" + VENDOR_OTHER +}; + +// This should be kept in sync with libcc/compiler-rt as its included by clang +// as a proxy for what's in libgcc/compiler-rt. +enum ProcessorTypes : unsigned { + CPU_TYPE_DUMMY, +#define X86_CPU_TYPE(ARCHNAME, ENUM) \ + ENUM, +#include "llvm/Support/X86TargetParser.def" + CPU_TYPE_MAX +}; + +// This should be kept in sync with libcc/compiler-rt as its included by clang +// as a proxy for what's in libgcc/compiler-rt. +enum ProcessorSubtypes : unsigned { + CPU_SUBTYPE_DUMMY, +#define X86_CPU_SUBTYPE(ARCHNAME, ENUM) \ + ENUM, +#include "llvm/Support/X86TargetParser.def" + CPU_SUBTYPE_MAX +}; + +// This should be kept in sync with libcc/compiler-rt as it should be used +// by clang as a proxy for what's in libgcc/compiler-rt. +enum ProcessorFeatures { +#define X86_FEATURE(VAL, ENUM) \ + ENUM = VAL, +#include "llvm/Support/X86TargetParser.def" + +}; + +} // namespace X86 + +namespace AMDGPU { + +/// GPU kinds supported by the AMDGPU target. +enum GPUKind : uint32_t { + // Not specified processor. + GK_NONE = 0, + + // R600-based processors. + GK_R600 = 1, + GK_R630 = 2, + GK_RS880 = 3, + GK_RV670 = 4, + GK_RV710 = 5, + GK_RV730 = 6, + GK_RV770 = 7, + GK_CEDAR = 8, + GK_CYPRESS = 9, + GK_JUNIPER = 10, + GK_REDWOOD = 11, + GK_SUMO = 12, + GK_BARTS = 13, + GK_CAICOS = 14, + GK_CAYMAN = 15, + GK_TURKS = 16, + + GK_R600_FIRST = GK_R600, + GK_R600_LAST = GK_TURKS, + + // AMDGCN-based processors. + GK_GFX600 = 32, + GK_GFX601 = 33, + + GK_GFX700 = 40, + GK_GFX701 = 41, + GK_GFX702 = 42, + GK_GFX703 = 43, + GK_GFX704 = 44, + + GK_GFX801 = 50, + GK_GFX802 = 51, + GK_GFX803 = 52, + GK_GFX810 = 53, + + GK_GFX900 = 60, + GK_GFX902 = 61, + GK_GFX904 = 62, + GK_GFX906 = 63, + GK_GFX908 = 64, + GK_GFX909 = 65, + + GK_GFX1010 = 71, + GK_GFX1011 = 72, + GK_GFX1012 = 73, + + GK_AMDGCN_FIRST = GK_GFX600, + GK_AMDGCN_LAST = GK_GFX1012, +}; + +/// Instruction set architecture version. +struct IsaVersion { + unsigned Major; + unsigned Minor; + unsigned Stepping; +}; + +// This isn't comprehensive for now, just things that are needed from the +// frontend driver. +enum ArchFeatureKind : uint32_t { + FEATURE_NONE = 0, + + // These features only exist for r600, and are implied true for amdgcn. + FEATURE_FMA = 1 << 1, + FEATURE_LDEXP = 1 << 2, + FEATURE_FP64 = 1 << 3, + + // Common features. + FEATURE_FAST_FMA_F32 = 1 << 4, + FEATURE_FAST_DENORMAL_F32 = 1 << 5 +}; + +StringRef getArchNameAMDGCN(GPUKind AK); +StringRef getArchNameR600(GPUKind AK); +StringRef getCanonicalArchName(StringRef Arch); +GPUKind parseArchAMDGCN(StringRef CPU); +GPUKind parseArchR600(StringRef CPU); +unsigned getArchAttrAMDGCN(GPUKind AK); +unsigned getArchAttrR600(GPUKind AK); + +void fillValidArchListAMDGCN(SmallVectorImpl<StringRef> &Values); +void fillValidArchListR600(SmallVectorImpl<StringRef> &Values); + +IsaVersion getIsaVersion(StringRef GPU); + +} // namespace AMDGPU + +} // namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/TargetRegistry.h b/third_party/llvm-project/include/llvm/Support/TargetRegistry.h new file mode 100644 index 000000000..d91eabae8 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/TargetRegistry.h @@ -0,0 +1,1209 @@ +//===- Support/TargetRegistry.h - Target Registration -----------*- 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 exposes the TargetRegistry interface, which tools can use to access +// the appropriate target specific classes (TargetMachine, AsmPrinter, etc.) +// which have been registered. +// +// Target specific class implementations should register themselves using the +// appropriate TargetRegistry interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_TARGETREGISTRY_H +#define LLVM_SUPPORT_TARGETREGISTRY_H + +#include "llvm-c/DisassemblerTypes.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <iterator> +#include <memory> +#include <string> + +namespace llvm { + +class AsmPrinter; +class MCAsmBackend; +class MCAsmInfo; +class MCAsmParser; +class MCCodeEmitter; +class MCContext; +class MCDisassembler; +class MCInstPrinter; +class MCInstrAnalysis; +class MCInstrInfo; +class MCObjectWriter; +class MCRegisterInfo; +class MCRelocationInfo; +class MCStreamer; +class MCSubtargetInfo; +class MCSymbolizer; +class MCTargetAsmParser; +class MCTargetOptions; +class MCTargetStreamer; +class raw_ostream; +class raw_pwrite_stream; +class TargetMachine; +class TargetOptions; + +MCStreamer *createNullStreamer(MCContext &Ctx); +// Takes ownership of \p TAB and \p CE. + +/// Create a machine code streamer which will print out assembly for the native +/// target, suitable for compiling with a native assembler. +/// +/// \param InstPrint - If given, the instruction printer to use. If not given +/// the MCInst representation will be printed. This method takes ownership of +/// InstPrint. +/// +/// \param CE - If given, a code emitter to use to show the instruction +/// encoding inline with the assembly. This method takes ownership of \p CE. +/// +/// \param TAB - If given, a target asm backend to use to show the fixup +/// information in conjunction with encoding information. This method takes +/// ownership of \p TAB. +/// +/// \param ShowInst - Whether to show the MCInst representation inline with +/// the assembly. +MCStreamer * +createAsmStreamer(MCContext &Ctx, std::unique_ptr<formatted_raw_ostream> OS, + bool isVerboseAsm, bool useDwarfDirectory, + MCInstPrinter *InstPrint, std::unique_ptr<MCCodeEmitter> &&CE, + std::unique_ptr<MCAsmBackend> &&TAB, bool ShowInst); + +MCStreamer *createELFStreamer(MCContext &Ctx, + std::unique_ptr<MCAsmBackend> &&TAB, + std::unique_ptr<MCObjectWriter> &&OW, + std::unique_ptr<MCCodeEmitter> &&CE, + bool RelaxAll); +MCStreamer *createMachOStreamer(MCContext &Ctx, + std::unique_ptr<MCAsmBackend> &&TAB, + std::unique_ptr<MCObjectWriter> &&OW, + std::unique_ptr<MCCodeEmitter> &&CE, + bool RelaxAll, bool DWARFMustBeAtTheEnd, + bool LabelSections = false); +MCStreamer *createWasmStreamer(MCContext &Ctx, + std::unique_ptr<MCAsmBackend> &&TAB, + std::unique_ptr<MCObjectWriter> &&OW, + std::unique_ptr<MCCodeEmitter> &&CE, + bool RelaxAll); +MCStreamer *createXCOFFStreamer(MCContext &Ctx, + std::unique_ptr<MCAsmBackend> &&TAB, + std::unique_ptr<MCObjectWriter> &&OW, + std::unique_ptr<MCCodeEmitter> &&CE, + bool RelaxAll); + +MCRelocationInfo *createMCRelocationInfo(const Triple &TT, MCContext &Ctx); + +MCSymbolizer *createMCSymbolizer(const Triple &TT, LLVMOpInfoCallback GetOpInfo, + LLVMSymbolLookupCallback SymbolLookUp, + void *DisInfo, MCContext *Ctx, + std::unique_ptr<MCRelocationInfo> &&RelInfo); + +/// Target - Wrapper for Target specific information. +/// +/// For registration purposes, this is a POD type so that targets can be +/// registered without the use of static constructors. +/// +/// Targets should implement a single global instance of this class (which +/// will be zero initialized), and pass that instance to the TargetRegistry as +/// part of their initialization. +class Target { +public: + friend struct TargetRegistry; + + using ArchMatchFnTy = bool (*)(Triple::ArchType Arch); + + using MCAsmInfoCtorFnTy = MCAsmInfo *(*)(const MCRegisterInfo &MRI, + const Triple &TT, + const MCTargetOptions &Options); + using MCInstrInfoCtorFnTy = MCInstrInfo *(*)(); + using MCInstrAnalysisCtorFnTy = MCInstrAnalysis *(*)(const MCInstrInfo *Info); + using MCRegInfoCtorFnTy = MCRegisterInfo *(*)(const Triple &TT); + using MCSubtargetInfoCtorFnTy = MCSubtargetInfo *(*)(const Triple &TT, + StringRef CPU, + StringRef Features); + using TargetMachineCtorTy = TargetMachine + *(*)(const Target &T, const Triple &TT, StringRef CPU, StringRef Features, + const TargetOptions &Options, Optional<Reloc::Model> RM, + Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT); + // If it weren't for layering issues (this header is in llvm/Support, but + // depends on MC?) this should take the Streamer by value rather than rvalue + // reference. + using AsmPrinterCtorTy = AsmPrinter *(*)( + TargetMachine &TM, std::unique_ptr<MCStreamer> &&Streamer); + using MCAsmBackendCtorTy = MCAsmBackend *(*)(const Target &T, + const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options); + using MCAsmParserCtorTy = MCTargetAsmParser *(*)( + const MCSubtargetInfo &STI, MCAsmParser &P, const MCInstrInfo &MII, + const MCTargetOptions &Options); + using MCDisassemblerCtorTy = MCDisassembler *(*)(const Target &T, + const MCSubtargetInfo &STI, + MCContext &Ctx); + using MCInstPrinterCtorTy = MCInstPrinter *(*)(const Triple &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI); + using MCCodeEmitterCtorTy = MCCodeEmitter *(*)(const MCInstrInfo &II, + const MCRegisterInfo &MRI, + MCContext &Ctx); + using ELFStreamerCtorTy = + MCStreamer *(*)(const Triple &T, MCContext &Ctx, + std::unique_ptr<MCAsmBackend> &&TAB, + std::unique_ptr<MCObjectWriter> &&OW, + std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll); + using MachOStreamerCtorTy = + MCStreamer *(*)(MCContext &Ctx, std::unique_ptr<MCAsmBackend> &&TAB, + std::unique_ptr<MCObjectWriter> &&OW, + std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll, + bool DWARFMustBeAtTheEnd); + using COFFStreamerCtorTy = + MCStreamer *(*)(MCContext &Ctx, std::unique_ptr<MCAsmBackend> &&TAB, + std::unique_ptr<MCObjectWriter> &&OW, + std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll, + bool IncrementalLinkerCompatible); + using WasmStreamerCtorTy = + MCStreamer *(*)(const Triple &T, MCContext &Ctx, + std::unique_ptr<MCAsmBackend> &&TAB, + std::unique_ptr<MCObjectWriter> &&OW, + std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll); + using NullTargetStreamerCtorTy = MCTargetStreamer *(*)(MCStreamer &S); + using AsmTargetStreamerCtorTy = MCTargetStreamer *(*)( + MCStreamer &S, formatted_raw_ostream &OS, MCInstPrinter *InstPrint, + bool IsVerboseAsm); + using ObjectTargetStreamerCtorTy = MCTargetStreamer *(*)( + MCStreamer &S, const MCSubtargetInfo &STI); + using MCRelocationInfoCtorTy = MCRelocationInfo *(*)(const Triple &TT, + MCContext &Ctx); + using MCSymbolizerCtorTy = MCSymbolizer *(*)( + const Triple &TT, LLVMOpInfoCallback GetOpInfo, + LLVMSymbolLookupCallback SymbolLookUp, void *DisInfo, MCContext *Ctx, + std::unique_ptr<MCRelocationInfo> &&RelInfo); + +private: + /// Next - The next registered target in the linked list, maintained by the + /// TargetRegistry. + Target *Next; + + /// The target function for checking if an architecture is supported. + ArchMatchFnTy ArchMatchFn; + + /// Name - The target name. + const char *Name; + + /// ShortDesc - A short description of the target. + const char *ShortDesc; + + /// BackendName - The name of the backend implementation. This must match the + /// name of the 'def X : Target ...' in TableGen. + const char *BackendName; + + /// HasJIT - Whether this target supports the JIT. + bool HasJIT; + + /// MCAsmInfoCtorFn - Constructor function for this target's MCAsmInfo, if + /// registered. + MCAsmInfoCtorFnTy MCAsmInfoCtorFn; + + /// MCInstrInfoCtorFn - Constructor function for this target's MCInstrInfo, + /// if registered. + MCInstrInfoCtorFnTy MCInstrInfoCtorFn; + + /// MCInstrAnalysisCtorFn - Constructor function for this target's + /// MCInstrAnalysis, if registered. + MCInstrAnalysisCtorFnTy MCInstrAnalysisCtorFn; + + /// MCRegInfoCtorFn - Constructor function for this target's MCRegisterInfo, + /// if registered. + MCRegInfoCtorFnTy MCRegInfoCtorFn; + + /// MCSubtargetInfoCtorFn - Constructor function for this target's + /// MCSubtargetInfo, if registered. + MCSubtargetInfoCtorFnTy MCSubtargetInfoCtorFn; + + /// TargetMachineCtorFn - Construction function for this target's + /// TargetMachine, if registered. + TargetMachineCtorTy TargetMachineCtorFn; + + /// MCAsmBackendCtorFn - Construction function for this target's + /// MCAsmBackend, if registered. + MCAsmBackendCtorTy MCAsmBackendCtorFn; + + /// MCAsmParserCtorFn - Construction function for this target's + /// MCTargetAsmParser, if registered. + MCAsmParserCtorTy MCAsmParserCtorFn; + + /// AsmPrinterCtorFn - Construction function for this target's AsmPrinter, + /// if registered. + AsmPrinterCtorTy AsmPrinterCtorFn; + + /// MCDisassemblerCtorFn - Construction function for this target's + /// MCDisassembler, if registered. + MCDisassemblerCtorTy MCDisassemblerCtorFn; + + /// MCInstPrinterCtorFn - Construction function for this target's + /// MCInstPrinter, if registered. + MCInstPrinterCtorTy MCInstPrinterCtorFn; + + /// MCCodeEmitterCtorFn - Construction function for this target's + /// CodeEmitter, if registered. + MCCodeEmitterCtorTy MCCodeEmitterCtorFn; + + // Construction functions for the various object formats, if registered. + COFFStreamerCtorTy COFFStreamerCtorFn = nullptr; + MachOStreamerCtorTy MachOStreamerCtorFn = nullptr; + ELFStreamerCtorTy ELFStreamerCtorFn = nullptr; + WasmStreamerCtorTy WasmStreamerCtorFn = nullptr; + + /// Construction function for this target's null TargetStreamer, if + /// registered (default = nullptr). + NullTargetStreamerCtorTy NullTargetStreamerCtorFn = nullptr; + + /// Construction function for this target's asm TargetStreamer, if + /// registered (default = nullptr). + AsmTargetStreamerCtorTy AsmTargetStreamerCtorFn = nullptr; + + /// Construction function for this target's obj TargetStreamer, if + /// registered (default = nullptr). + ObjectTargetStreamerCtorTy ObjectTargetStreamerCtorFn = nullptr; + + /// MCRelocationInfoCtorFn - Construction function for this target's + /// MCRelocationInfo, if registered (default = llvm::createMCRelocationInfo) + MCRelocationInfoCtorTy MCRelocationInfoCtorFn = nullptr; + + /// MCSymbolizerCtorFn - Construction function for this target's + /// MCSymbolizer, if registered (default = llvm::createMCSymbolizer) + MCSymbolizerCtorTy MCSymbolizerCtorFn = nullptr; + +public: + Target() = default; + + /// @name Target Information + /// @{ + + // getNext - Return the next registered target. + const Target *getNext() const { return Next; } + + /// getName - Get the target name. + const char *getName() const { return Name; } + + /// getShortDescription - Get a short description of the target. + const char *getShortDescription() const { return ShortDesc; } + + /// getBackendName - Get the backend name. + const char *getBackendName() const { return BackendName; } + + /// @} + /// @name Feature Predicates + /// @{ + + /// hasJIT - Check if this targets supports the just-in-time compilation. + bool hasJIT() const { return HasJIT; } + + /// hasTargetMachine - Check if this target supports code generation. + bool hasTargetMachine() const { return TargetMachineCtorFn != nullptr; } + + /// hasMCAsmBackend - Check if this target supports .o generation. + bool hasMCAsmBackend() const { return MCAsmBackendCtorFn != nullptr; } + + /// hasMCAsmParser - Check if this target supports assembly parsing. + bool hasMCAsmParser() const { return MCAsmParserCtorFn != nullptr; } + + /// @} + /// @name Feature Constructors + /// @{ + + /// createMCAsmInfo - Create a MCAsmInfo implementation for the specified + /// target triple. + /// + /// \param TheTriple This argument is used to determine the target machine + /// feature set; it should always be provided. Generally this should be + /// either the target triple from the module, or the target triple of the + /// host if that does not exist. + MCAsmInfo *createMCAsmInfo(const MCRegisterInfo &MRI, StringRef TheTriple, + const MCTargetOptions &Options) const { + if (!MCAsmInfoCtorFn) + return nullptr; + return MCAsmInfoCtorFn(MRI, Triple(TheTriple), Options); + } + + /// createMCInstrInfo - Create a MCInstrInfo implementation. + /// + MCInstrInfo *createMCInstrInfo() const { + if (!MCInstrInfoCtorFn) + return nullptr; + return MCInstrInfoCtorFn(); + } + + /// createMCInstrAnalysis - Create a MCInstrAnalysis implementation. + /// + MCInstrAnalysis *createMCInstrAnalysis(const MCInstrInfo *Info) const { + if (!MCInstrAnalysisCtorFn) + return nullptr; + return MCInstrAnalysisCtorFn(Info); + } + + /// createMCRegInfo - Create a MCRegisterInfo implementation. + /// + MCRegisterInfo *createMCRegInfo(StringRef TT) const { + if (!MCRegInfoCtorFn) + return nullptr; + return MCRegInfoCtorFn(Triple(TT)); + } + + /// createMCSubtargetInfo - Create a MCSubtargetInfo implementation. + /// + /// \param TheTriple This argument is used to determine the target machine + /// feature set; it should always be provided. Generally this should be + /// either the target triple from the module, or the target triple of the + /// host if that does not exist. + /// \param CPU This specifies the name of the target CPU. + /// \param Features This specifies the string representation of the + /// additional target features. + MCSubtargetInfo *createMCSubtargetInfo(StringRef TheTriple, StringRef CPU, + StringRef Features) const { + if (!MCSubtargetInfoCtorFn) + return nullptr; + return MCSubtargetInfoCtorFn(Triple(TheTriple), CPU, Features); + } + + /// createTargetMachine - Create a target specific machine implementation + /// for the specified \p Triple. + /// + /// \param TT This argument is used to determine the target machine + /// feature set; it should always be provided. Generally this should be + /// either the target triple from the module, or the target triple of the + /// host if that does not exist. + TargetMachine *createTargetMachine(StringRef TT, StringRef CPU, + StringRef Features, + const TargetOptions &Options, + Optional<Reloc::Model> RM, + Optional<CodeModel::Model> CM = None, + CodeGenOpt::Level OL = CodeGenOpt::Default, + bool JIT = false) const { + if (!TargetMachineCtorFn) + return nullptr; + return TargetMachineCtorFn(*this, Triple(TT), CPU, Features, Options, RM, + CM, OL, JIT); + } + + /// createMCAsmBackend - Create a target specific assembly parser. + MCAsmBackend *createMCAsmBackend(const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options) const { + if (!MCAsmBackendCtorFn) + return nullptr; + return MCAsmBackendCtorFn(*this, STI, MRI, Options); + } + + /// createMCAsmParser - Create a target specific assembly parser. + /// + /// \param Parser The target independent parser implementation to use for + /// parsing and lexing. + MCTargetAsmParser *createMCAsmParser(const MCSubtargetInfo &STI, + MCAsmParser &Parser, + const MCInstrInfo &MII, + const MCTargetOptions &Options) const { + if (!MCAsmParserCtorFn) + return nullptr; + return MCAsmParserCtorFn(STI, Parser, MII, Options); + } + + /// createAsmPrinter - Create a target specific assembly printer pass. This + /// takes ownership of the MCStreamer object. + AsmPrinter *createAsmPrinter(TargetMachine &TM, + std::unique_ptr<MCStreamer> &&Streamer) const { + if (!AsmPrinterCtorFn) + return nullptr; + return AsmPrinterCtorFn(TM, std::move(Streamer)); + } + + MCDisassembler *createMCDisassembler(const MCSubtargetInfo &STI, + MCContext &Ctx) const { + if (!MCDisassemblerCtorFn) + return nullptr; + return MCDisassemblerCtorFn(*this, STI, Ctx); + } + + MCInstPrinter *createMCInstPrinter(const Triple &T, unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI) const { + if (!MCInstPrinterCtorFn) + return nullptr; + return MCInstPrinterCtorFn(T, SyntaxVariant, MAI, MII, MRI); + } + + /// createMCCodeEmitter - Create a target specific code emitter. + MCCodeEmitter *createMCCodeEmitter(const MCInstrInfo &II, + const MCRegisterInfo &MRI, + MCContext &Ctx) const { + if (!MCCodeEmitterCtorFn) + return nullptr; + return MCCodeEmitterCtorFn(II, MRI, Ctx); + } + + /// Create a target specific MCStreamer. + /// + /// \param T The target triple. + /// \param Ctx The target context. + /// \param TAB The target assembler backend object. Takes ownership. + /// \param OW The stream object. + /// \param Emitter The target independent assembler object.Takes ownership. + /// \param RelaxAll Relax all fixups? + MCStreamer *createMCObjectStreamer(const Triple &T, MCContext &Ctx, + std::unique_ptr<MCAsmBackend> &&TAB, + std::unique_ptr<MCObjectWriter> &&OW, + std::unique_ptr<MCCodeEmitter> &&Emitter, + const MCSubtargetInfo &STI, bool RelaxAll, + bool IncrementalLinkerCompatible, + bool DWARFMustBeAtTheEnd) const { + MCStreamer *S = nullptr; + switch (T.getObjectFormat()) { + case Triple::UnknownObjectFormat: + llvm_unreachable("Unknown object format"); + case Triple::COFF: + assert(T.isOSWindows() && "only Windows COFF is supported"); + S = COFFStreamerCtorFn(Ctx, std::move(TAB), std::move(OW), + std::move(Emitter), RelaxAll, + IncrementalLinkerCompatible); + break; + case Triple::MachO: + if (MachOStreamerCtorFn) + S = MachOStreamerCtorFn(Ctx, std::move(TAB), std::move(OW), + std::move(Emitter), RelaxAll, + DWARFMustBeAtTheEnd); + else + S = createMachOStreamer(Ctx, std::move(TAB), std::move(OW), + std::move(Emitter), RelaxAll, + DWARFMustBeAtTheEnd); + break; + case Triple::ELF: + if (ELFStreamerCtorFn) + S = ELFStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW), + std::move(Emitter), RelaxAll); + else + S = createELFStreamer(Ctx, std::move(TAB), std::move(OW), + std::move(Emitter), RelaxAll); + break; + case Triple::Wasm: + if (WasmStreamerCtorFn) + S = WasmStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW), + std::move(Emitter), RelaxAll); + else + S = createWasmStreamer(Ctx, std::move(TAB), std::move(OW), + std::move(Emitter), RelaxAll); + break; + case Triple::XCOFF: + S = createXCOFFStreamer(Ctx, std::move(TAB), std::move(OW), + std::move(Emitter), RelaxAll); + break; + } + if (ObjectTargetStreamerCtorFn) + ObjectTargetStreamerCtorFn(*S, STI); + return S; + } + + MCStreamer *createAsmStreamer(MCContext &Ctx, + std::unique_ptr<formatted_raw_ostream> OS, + bool IsVerboseAsm, bool UseDwarfDirectory, + MCInstPrinter *InstPrint, + std::unique_ptr<MCCodeEmitter> &&CE, + std::unique_ptr<MCAsmBackend> &&TAB, + bool ShowInst) const { + formatted_raw_ostream &OSRef = *OS; + MCStreamer *S = llvm::createAsmStreamer( + Ctx, std::move(OS), IsVerboseAsm, UseDwarfDirectory, InstPrint, + std::move(CE), std::move(TAB), ShowInst); + createAsmTargetStreamer(*S, OSRef, InstPrint, IsVerboseAsm); + return S; + } + + MCTargetStreamer *createAsmTargetStreamer(MCStreamer &S, + formatted_raw_ostream &OS, + MCInstPrinter *InstPrint, + bool IsVerboseAsm) const { + if (AsmTargetStreamerCtorFn) + return AsmTargetStreamerCtorFn(S, OS, InstPrint, IsVerboseAsm); + return nullptr; + } + + MCStreamer *createNullStreamer(MCContext &Ctx) const { + MCStreamer *S = llvm::createNullStreamer(Ctx); + createNullTargetStreamer(*S); + return S; + } + + MCTargetStreamer *createNullTargetStreamer(MCStreamer &S) const { + if (NullTargetStreamerCtorFn) + return NullTargetStreamerCtorFn(S); + return nullptr; + } + + /// createMCRelocationInfo - Create a target specific MCRelocationInfo. + /// + /// \param TT The target triple. + /// \param Ctx The target context. + MCRelocationInfo *createMCRelocationInfo(StringRef TT, MCContext &Ctx) const { + MCRelocationInfoCtorTy Fn = MCRelocationInfoCtorFn + ? MCRelocationInfoCtorFn + : llvm::createMCRelocationInfo; + return Fn(Triple(TT), Ctx); + } + + /// createMCSymbolizer - Create a target specific MCSymbolizer. + /// + /// \param TT The target triple. + /// \param GetOpInfo The function to get the symbolic information for + /// operands. + /// \param SymbolLookUp The function to lookup a symbol name. + /// \param DisInfo The pointer to the block of symbolic information for above + /// call + /// back. + /// \param Ctx The target context. + /// \param RelInfo The relocation information for this target. Takes + /// ownership. + MCSymbolizer * + createMCSymbolizer(StringRef TT, LLVMOpInfoCallback GetOpInfo, + LLVMSymbolLookupCallback SymbolLookUp, void *DisInfo, + MCContext *Ctx, + std::unique_ptr<MCRelocationInfo> &&RelInfo) const { + MCSymbolizerCtorTy Fn = + MCSymbolizerCtorFn ? MCSymbolizerCtorFn : llvm::createMCSymbolizer; + return Fn(Triple(TT), GetOpInfo, SymbolLookUp, DisInfo, Ctx, + std::move(RelInfo)); + } + + /// @} +}; + +/// TargetRegistry - Generic interface to target specific features. +struct TargetRegistry { + // FIXME: Make this a namespace, probably just move all the Register* + // functions into Target (currently they all just set members on the Target + // anyway, and Target friends this class so those functions can... + // function). + TargetRegistry() = delete; + + class iterator + : public std::iterator<std::forward_iterator_tag, Target, ptrdiff_t> { + friend struct TargetRegistry; + + const Target *Current = nullptr; + + explicit iterator(Target *T) : Current(T) {} + + public: + iterator() = default; + + bool operator==(const iterator &x) const { return Current == x.Current; } + bool operator!=(const iterator &x) const { return !operator==(x); } + + // Iterator traversal: forward iteration only + iterator &operator++() { // Preincrement + assert(Current && "Cannot increment end iterator!"); + Current = Current->getNext(); + return *this; + } + iterator operator++(int) { // Postincrement + iterator tmp = *this; + ++*this; + return tmp; + } + + const Target &operator*() const { + assert(Current && "Cannot dereference end iterator!"); + return *Current; + } + + const Target *operator->() const { return &operator*(); } + }; + + /// printRegisteredTargetsForVersion - Print the registered targets + /// appropriately for inclusion in a tool's version output. + static void printRegisteredTargetsForVersion(raw_ostream &OS); + + /// @name Registry Access + /// @{ + + static iterator_range<iterator> targets(); + + /// lookupTarget - Lookup a target based on a target triple. + /// + /// \param Triple - The triple to use for finding a target. + /// \param Error - On failure, an error string describing why no target was + /// found. + static const Target *lookupTarget(const std::string &Triple, + std::string &Error); + + /// lookupTarget - Lookup a target based on an architecture name + /// and a target triple. If the architecture name is non-empty, + /// then the lookup is done by architecture. Otherwise, the target + /// triple is used. + /// + /// \param ArchName - The architecture to use for finding a target. + /// \param TheTriple - The triple to use for finding a target. The + /// triple is updated with canonical architecture name if a lookup + /// by architecture is done. + /// \param Error - On failure, an error string describing why no target was + /// found. + static const Target *lookupTarget(const std::string &ArchName, + Triple &TheTriple, std::string &Error); + + /// @} + /// @name Target Registration + /// @{ + + /// RegisterTarget - Register the given target. Attempts to register a + /// target which has already been registered will be ignored. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Name - The target name. This should be a static string. + /// @param ShortDesc - A short target description. This should be a static + /// string. + /// @param BackendName - The name of the backend. This should be a static + /// string that is the same for all targets that share a backend + /// implementation and must match the name used in the 'def X : Target ...' in + /// TableGen. + /// @param ArchMatchFn - The arch match checking function for this target. + /// @param HasJIT - Whether the target supports JIT code + /// generation. + static void RegisterTarget(Target &T, const char *Name, const char *ShortDesc, + const char *BackendName, + Target::ArchMatchFnTy ArchMatchFn, + bool HasJIT = false); + + /// RegisterMCAsmInfo - Register a MCAsmInfo implementation for the + /// given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct a MCAsmInfo for the target. + static void RegisterMCAsmInfo(Target &T, Target::MCAsmInfoCtorFnTy Fn) { + T.MCAsmInfoCtorFn = Fn; + } + + /// RegisterMCInstrInfo - Register a MCInstrInfo implementation for the + /// given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct a MCInstrInfo for the target. + static void RegisterMCInstrInfo(Target &T, Target::MCInstrInfoCtorFnTy Fn) { + T.MCInstrInfoCtorFn = Fn; + } + + /// RegisterMCInstrAnalysis - Register a MCInstrAnalysis implementation for + /// the given target. + static void RegisterMCInstrAnalysis(Target &T, + Target::MCInstrAnalysisCtorFnTy Fn) { + T.MCInstrAnalysisCtorFn = Fn; + } + + /// RegisterMCRegInfo - Register a MCRegisterInfo implementation for the + /// given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct a MCRegisterInfo for the target. + static void RegisterMCRegInfo(Target &T, Target::MCRegInfoCtorFnTy Fn) { + T.MCRegInfoCtorFn = Fn; + } + + /// RegisterMCSubtargetInfo - Register a MCSubtargetInfo implementation for + /// the given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct a MCSubtargetInfo for the target. + static void RegisterMCSubtargetInfo(Target &T, + Target::MCSubtargetInfoCtorFnTy Fn) { + T.MCSubtargetInfoCtorFn = Fn; + } + + /// RegisterTargetMachine - Register a TargetMachine implementation for the + /// given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct a TargetMachine for the target. + static void RegisterTargetMachine(Target &T, Target::TargetMachineCtorTy Fn) { + T.TargetMachineCtorFn = Fn; + } + + /// RegisterMCAsmBackend - Register a MCAsmBackend implementation for the + /// given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct an AsmBackend for the target. + static void RegisterMCAsmBackend(Target &T, Target::MCAsmBackendCtorTy Fn) { + T.MCAsmBackendCtorFn = Fn; + } + + /// RegisterMCAsmParser - Register a MCTargetAsmParser implementation for + /// the given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct an MCTargetAsmParser for the target. + static void RegisterMCAsmParser(Target &T, Target::MCAsmParserCtorTy Fn) { + T.MCAsmParserCtorFn = Fn; + } + + /// RegisterAsmPrinter - Register an AsmPrinter implementation for the given + /// target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct an AsmPrinter for the target. + static void RegisterAsmPrinter(Target &T, Target::AsmPrinterCtorTy Fn) { + T.AsmPrinterCtorFn = Fn; + } + + /// RegisterMCDisassembler - Register a MCDisassembler implementation for + /// the given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct an MCDisassembler for the target. + static void RegisterMCDisassembler(Target &T, + Target::MCDisassemblerCtorTy Fn) { + T.MCDisassemblerCtorFn = Fn; + } + + /// RegisterMCInstPrinter - Register a MCInstPrinter implementation for the + /// given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct an MCInstPrinter for the target. + static void RegisterMCInstPrinter(Target &T, Target::MCInstPrinterCtorTy Fn) { + T.MCInstPrinterCtorFn = Fn; + } + + /// RegisterMCCodeEmitter - Register a MCCodeEmitter implementation for the + /// given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct an MCCodeEmitter for the target. + static void RegisterMCCodeEmitter(Target &T, Target::MCCodeEmitterCtorTy Fn) { + T.MCCodeEmitterCtorFn = Fn; + } + + static void RegisterCOFFStreamer(Target &T, Target::COFFStreamerCtorTy Fn) { + T.COFFStreamerCtorFn = Fn; + } + + static void RegisterMachOStreamer(Target &T, Target::MachOStreamerCtorTy Fn) { + T.MachOStreamerCtorFn = Fn; + } + + static void RegisterELFStreamer(Target &T, Target::ELFStreamerCtorTy Fn) { + T.ELFStreamerCtorFn = Fn; + } + + static void RegisterWasmStreamer(Target &T, Target::WasmStreamerCtorTy Fn) { + T.WasmStreamerCtorFn = Fn; + } + + static void RegisterNullTargetStreamer(Target &T, + Target::NullTargetStreamerCtorTy Fn) { + T.NullTargetStreamerCtorFn = Fn; + } + + static void RegisterAsmTargetStreamer(Target &T, + Target::AsmTargetStreamerCtorTy Fn) { + T.AsmTargetStreamerCtorFn = Fn; + } + + static void + RegisterObjectTargetStreamer(Target &T, + Target::ObjectTargetStreamerCtorTy Fn) { + T.ObjectTargetStreamerCtorFn = Fn; + } + + /// RegisterMCRelocationInfo - Register an MCRelocationInfo + /// implementation for the given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct an MCRelocationInfo for the target. + static void RegisterMCRelocationInfo(Target &T, + Target::MCRelocationInfoCtorTy Fn) { + T.MCRelocationInfoCtorFn = Fn; + } + + /// RegisterMCSymbolizer - Register an MCSymbolizer + /// implementation for the given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct an MCSymbolizer for the target. + static void RegisterMCSymbolizer(Target &T, Target::MCSymbolizerCtorTy Fn) { + T.MCSymbolizerCtorFn = Fn; + } + + /// @} +}; + +//===--------------------------------------------------------------------===// + +/// RegisterTarget - Helper template for registering a target, for use in the +/// target's initialization function. Usage: +/// +/// +/// Target &getTheFooTarget() { // The global target instance. +/// static Target TheFooTarget; +/// return TheFooTarget; +/// } +/// extern "C" void LLVMInitializeFooTargetInfo() { +/// RegisterTarget<Triple::foo> X(getTheFooTarget(), "foo", "Foo +/// description", "Foo" /* Backend Name */); +/// } +template <Triple::ArchType TargetArchType = Triple::UnknownArch, + bool HasJIT = false> +struct RegisterTarget { + RegisterTarget(Target &T, const char *Name, const char *Desc, + const char *BackendName) { + TargetRegistry::RegisterTarget(T, Name, Desc, BackendName, &getArchMatch, + HasJIT); + } + + static bool getArchMatch(Triple::ArchType Arch) { + return Arch == TargetArchType; + } +}; + +/// RegisterMCAsmInfo - Helper template for registering a target assembly info +/// implementation. This invokes the static "Create" method on the class to +/// actually do the construction. Usage: +/// +/// extern "C" void LLVMInitializeFooTarget() { +/// extern Target TheFooTarget; +/// RegisterMCAsmInfo<FooMCAsmInfo> X(TheFooTarget); +/// } +template <class MCAsmInfoImpl> struct RegisterMCAsmInfo { + RegisterMCAsmInfo(Target &T) { + TargetRegistry::RegisterMCAsmInfo(T, &Allocator); + } + +private: + static MCAsmInfo *Allocator(const MCRegisterInfo & /*MRI*/, const Triple &TT, + const MCTargetOptions &Options) { + return new MCAsmInfoImpl(TT, Options); + } +}; + +/// RegisterMCAsmInfoFn - Helper template for registering a target assembly info +/// implementation. This invokes the specified function to do the +/// construction. Usage: +/// +/// extern "C" void LLVMInitializeFooTarget() { +/// extern Target TheFooTarget; +/// RegisterMCAsmInfoFn X(TheFooTarget, TheFunction); +/// } +struct RegisterMCAsmInfoFn { + RegisterMCAsmInfoFn(Target &T, Target::MCAsmInfoCtorFnTy Fn) { + TargetRegistry::RegisterMCAsmInfo(T, Fn); + } +}; + +/// RegisterMCInstrInfo - Helper template for registering a target instruction +/// info implementation. This invokes the static "Create" method on the class +/// to actually do the construction. Usage: +/// +/// extern "C" void LLVMInitializeFooTarget() { +/// extern Target TheFooTarget; +/// RegisterMCInstrInfo<FooMCInstrInfo> X(TheFooTarget); +/// } +template <class MCInstrInfoImpl> struct RegisterMCInstrInfo { + RegisterMCInstrInfo(Target &T) { + TargetRegistry::RegisterMCInstrInfo(T, &Allocator); + } + +private: + static MCInstrInfo *Allocator() { return new MCInstrInfoImpl(); } +}; + +/// RegisterMCInstrInfoFn - Helper template for registering a target +/// instruction info implementation. This invokes the specified function to +/// do the construction. Usage: +/// +/// extern "C" void LLVMInitializeFooTarget() { +/// extern Target TheFooTarget; +/// RegisterMCInstrInfoFn X(TheFooTarget, TheFunction); +/// } +struct RegisterMCInstrInfoFn { + RegisterMCInstrInfoFn(Target &T, Target::MCInstrInfoCtorFnTy Fn) { + TargetRegistry::RegisterMCInstrInfo(T, Fn); + } +}; + +/// RegisterMCInstrAnalysis - Helper template for registering a target +/// instruction analyzer implementation. This invokes the static "Create" +/// method on the class to actually do the construction. Usage: +/// +/// extern "C" void LLVMInitializeFooTarget() { +/// extern Target TheFooTarget; +/// RegisterMCInstrAnalysis<FooMCInstrAnalysis> X(TheFooTarget); +/// } +template <class MCInstrAnalysisImpl> struct RegisterMCInstrAnalysis { + RegisterMCInstrAnalysis(Target &T) { + TargetRegistry::RegisterMCInstrAnalysis(T, &Allocator); + } + +private: + static MCInstrAnalysis *Allocator(const MCInstrInfo *Info) { + return new MCInstrAnalysisImpl(Info); + } +}; + +/// RegisterMCInstrAnalysisFn - Helper template for registering a target +/// instruction analyzer implementation. This invokes the specified function +/// to do the construction. Usage: +/// +/// extern "C" void LLVMInitializeFooTarget() { +/// extern Target TheFooTarget; +/// RegisterMCInstrAnalysisFn X(TheFooTarget, TheFunction); +/// } +struct RegisterMCInstrAnalysisFn { + RegisterMCInstrAnalysisFn(Target &T, Target::MCInstrAnalysisCtorFnTy Fn) { + TargetRegistry::RegisterMCInstrAnalysis(T, Fn); + } +}; + +/// RegisterMCRegInfo - Helper template for registering a target register info +/// implementation. This invokes the static "Create" method on the class to +/// actually do the construction. Usage: +/// +/// extern "C" void LLVMInitializeFooTarget() { +/// extern Target TheFooTarget; +/// RegisterMCRegInfo<FooMCRegInfo> X(TheFooTarget); +/// } +template <class MCRegisterInfoImpl> struct RegisterMCRegInfo { + RegisterMCRegInfo(Target &T) { + TargetRegistry::RegisterMCRegInfo(T, &Allocator); + } + +private: + static MCRegisterInfo *Allocator(const Triple & /*TT*/) { + return new MCRegisterInfoImpl(); + } +}; + +/// RegisterMCRegInfoFn - Helper template for registering a target register +/// info implementation. This invokes the specified function to do the +/// construction. Usage: +/// +/// extern "C" void LLVMInitializeFooTarget() { +/// extern Target TheFooTarget; +/// RegisterMCRegInfoFn X(TheFooTarget, TheFunction); +/// } +struct RegisterMCRegInfoFn { + RegisterMCRegInfoFn(Target &T, Target::MCRegInfoCtorFnTy Fn) { + TargetRegistry::RegisterMCRegInfo(T, Fn); + } +}; + +/// RegisterMCSubtargetInfo - Helper template for registering a target +/// subtarget info implementation. This invokes the static "Create" method +/// on the class to actually do the construction. Usage: +/// +/// extern "C" void LLVMInitializeFooTarget() { +/// extern Target TheFooTarget; +/// RegisterMCSubtargetInfo<FooMCSubtargetInfo> X(TheFooTarget); +/// } +template <class MCSubtargetInfoImpl> struct RegisterMCSubtargetInfo { + RegisterMCSubtargetInfo(Target &T) { + TargetRegistry::RegisterMCSubtargetInfo(T, &Allocator); + } + +private: + static MCSubtargetInfo *Allocator(const Triple & /*TT*/, StringRef /*CPU*/, + StringRef /*FS*/) { + return new MCSubtargetInfoImpl(); + } +}; + +/// RegisterMCSubtargetInfoFn - Helper template for registering a target +/// subtarget info implementation. This invokes the specified function to +/// do the construction. Usage: +/// +/// extern "C" void LLVMInitializeFooTarget() { +/// extern Target TheFooTarget; +/// RegisterMCSubtargetInfoFn X(TheFooTarget, TheFunction); +/// } +struct RegisterMCSubtargetInfoFn { + RegisterMCSubtargetInfoFn(Target &T, Target::MCSubtargetInfoCtorFnTy Fn) { + TargetRegistry::RegisterMCSubtargetInfo(T, Fn); + } +}; + +/// RegisterTargetMachine - Helper template for registering a target machine +/// implementation, for use in the target machine initialization +/// function. Usage: +/// +/// extern "C" void LLVMInitializeFooTarget() { +/// extern Target TheFooTarget; +/// RegisterTargetMachine<FooTargetMachine> X(TheFooTarget); +/// } +template <class TargetMachineImpl> struct RegisterTargetMachine { + RegisterTargetMachine(Target &T) { + TargetRegistry::RegisterTargetMachine(T, &Allocator); + } + +private: + static TargetMachine * + Allocator(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, + const TargetOptions &Options, Optional<Reloc::Model> RM, + Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT) { + return new TargetMachineImpl(T, TT, CPU, FS, Options, RM, CM, OL, JIT); + } +}; + +/// RegisterMCAsmBackend - Helper template for registering a target specific +/// assembler backend. Usage: +/// +/// extern "C" void LLVMInitializeFooMCAsmBackend() { +/// extern Target TheFooTarget; +/// RegisterMCAsmBackend<FooAsmLexer> X(TheFooTarget); +/// } +template <class MCAsmBackendImpl> struct RegisterMCAsmBackend { + RegisterMCAsmBackend(Target &T) { + TargetRegistry::RegisterMCAsmBackend(T, &Allocator); + } + +private: + static MCAsmBackend *Allocator(const Target &T, const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options) { + return new MCAsmBackendImpl(T, STI, MRI); + } +}; + +/// RegisterMCAsmParser - Helper template for registering a target specific +/// assembly parser, for use in the target machine initialization +/// function. Usage: +/// +/// extern "C" void LLVMInitializeFooMCAsmParser() { +/// extern Target TheFooTarget; +/// RegisterMCAsmParser<FooAsmParser> X(TheFooTarget); +/// } +template <class MCAsmParserImpl> struct RegisterMCAsmParser { + RegisterMCAsmParser(Target &T) { + TargetRegistry::RegisterMCAsmParser(T, &Allocator); + } + +private: + static MCTargetAsmParser *Allocator(const MCSubtargetInfo &STI, + MCAsmParser &P, const MCInstrInfo &MII, + const MCTargetOptions &Options) { + return new MCAsmParserImpl(STI, P, MII, Options); + } +}; + +/// RegisterAsmPrinter - Helper template for registering a target specific +/// assembly printer, for use in the target machine initialization +/// function. Usage: +/// +/// extern "C" void LLVMInitializeFooAsmPrinter() { +/// extern Target TheFooTarget; +/// RegisterAsmPrinter<FooAsmPrinter> X(TheFooTarget); +/// } +template <class AsmPrinterImpl> struct RegisterAsmPrinter { + RegisterAsmPrinter(Target &T) { + TargetRegistry::RegisterAsmPrinter(T, &Allocator); + } + +private: + static AsmPrinter *Allocator(TargetMachine &TM, + std::unique_ptr<MCStreamer> &&Streamer) { + return new AsmPrinterImpl(TM, std::move(Streamer)); + } +}; + +/// RegisterMCCodeEmitter - Helper template for registering a target specific +/// machine code emitter, for use in the target initialization +/// function. Usage: +/// +/// extern "C" void LLVMInitializeFooMCCodeEmitter() { +/// extern Target TheFooTarget; +/// RegisterMCCodeEmitter<FooCodeEmitter> X(TheFooTarget); +/// } +template <class MCCodeEmitterImpl> struct RegisterMCCodeEmitter { + RegisterMCCodeEmitter(Target &T) { + TargetRegistry::RegisterMCCodeEmitter(T, &Allocator); + } + +private: + static MCCodeEmitter *Allocator(const MCInstrInfo & /*II*/, + const MCRegisterInfo & /*MRI*/, + MCContext & /*Ctx*/) { + return new MCCodeEmitterImpl(); + } +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_TARGETREGISTRY_H diff --git a/third_party/llvm-project/include/llvm/Support/Threading.h b/third_party/llvm-project/include/llvm/Support/Threading.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Threading.h diff --git a/third_party/llvm-project/include/llvm/Support/TypeSize.h b/third_party/llvm-project/include/llvm/Support/TypeSize.h new file mode 100644 index 000000000..711679cdc --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/TypeSize.h @@ -0,0 +1,201 @@ +//===- TypeSize.h - Wrapper around type sizes -------------------*- 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 provides a struct that can be used to query the size of IR types +// which may be scalable vectors. It provides convenience operators so that +// it can be used in much the same way as a single scalar value. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_TYPESIZE_H +#define LLVM_SUPPORT_TYPESIZE_H + +#include <cassert> +#include <tuple> + +namespace llvm { + +class ElementCount { +public: + unsigned Min; // Minimum number of vector elements. + bool Scalable; // If true, NumElements is a multiple of 'Min' determined + // at runtime rather than compile time. + + ElementCount(unsigned Min, bool Scalable) + : Min(Min), Scalable(Scalable) {} + + ElementCount operator*(unsigned RHS) { + return { Min * RHS, Scalable }; + } + ElementCount operator/(unsigned RHS) { + return { Min / RHS, Scalable }; + } + + bool operator==(const ElementCount& RHS) const { + return Min == RHS.Min && Scalable == RHS.Scalable; + } + bool operator!=(const ElementCount& RHS) const { + return !(*this == RHS); + } +}; + +// This class is used to represent the size of types. If the type is of fixed +// size, it will represent the exact size. If the type is a scalable vector, +// it will represent the known minimum size. +class TypeSize { + uint64_t MinSize; // The known minimum size. + bool IsScalable; // If true, then the runtime size is an integer multiple + // of MinSize. + +public: + constexpr TypeSize(uint64_t MinSize, bool Scalable) + : MinSize(MinSize), IsScalable(Scalable) {} + + static constexpr TypeSize Fixed(uint64_t Size) { + return TypeSize(Size, /*IsScalable=*/false); + } + + static constexpr TypeSize Scalable(uint64_t MinSize) { + return TypeSize(MinSize, /*IsScalable=*/true); + } + + // Scalable vector types with the same minimum size as a fixed size type are + // not guaranteed to be the same size at runtime, so they are never + // considered to be equal. + friend bool operator==(const TypeSize &LHS, const TypeSize &RHS) { + return std::tie(LHS.MinSize, LHS.IsScalable) == + std::tie(RHS.MinSize, RHS.IsScalable); + } + + friend bool operator!=(const TypeSize &LHS, const TypeSize &RHS) { + return !(LHS == RHS); + } + + // For many cases, size ordering between scalable and fixed size types cannot + // be determined at compile time, so such comparisons aren't allowed. + // + // e.g. <vscale x 2 x i16> could be bigger than <4 x i32> with a runtime + // vscale >= 5, equal sized with a vscale of 4, and smaller with + // a vscale <= 3. + // + // If the scalable flags match, just perform the requested comparison + // between the minimum sizes. + friend bool operator<(const TypeSize &LHS, const TypeSize &RHS) { + assert(LHS.IsScalable == RHS.IsScalable && + "Ordering comparison of scalable and fixed types"); + + return LHS.MinSize < RHS.MinSize; + } + + friend bool operator>(const TypeSize &LHS, const TypeSize &RHS) { + return RHS < LHS; + } + + friend bool operator<=(const TypeSize &LHS, const TypeSize &RHS) { + return !(RHS < LHS); + } + + friend bool operator>=(const TypeSize &LHS, const TypeSize& RHS) { + return !(LHS < RHS); + } + + // Convenience operators to obtain relative sizes independently of + // the scalable flag. + TypeSize operator*(unsigned RHS) const { + return { MinSize * RHS, IsScalable }; + } + + friend TypeSize operator*(const unsigned LHS, const TypeSize &RHS) { + return { LHS * RHS.MinSize, RHS.IsScalable }; + } + + TypeSize operator/(unsigned RHS) const { + return { MinSize / RHS, IsScalable }; + } + + // Return the minimum size with the assumption that the size is exact. + // Use in places where a scalable size doesn't make sense (e.g. non-vector + // types, or vectors in backends which don't support scalable vectors). + uint64_t getFixedSize() const { + assert(!IsScalable && "Request for a fixed size on a scalable object"); + return MinSize; + } + + // Return the known minimum size. Use in places where the scalable property + // doesn't matter (e.g. determining alignment) or in conjunction with the + // isScalable method below. + uint64_t getKnownMinSize() const { + return MinSize; + } + + // Return whether or not the size is scalable. + bool isScalable() const { + return IsScalable; + } + + // Casts to a uint64_t if this is a fixed-width size. + // + // NOTE: This interface is obsolete and will be removed in a future version + // of LLVM in favour of calling getFixedSize() directly. + operator uint64_t() const { + return getFixedSize(); + } + + // Additional convenience operators needed to avoid ambiguous parses. + // TODO: Make uint64_t the default operator? + TypeSize operator*(uint64_t RHS) const { + return { MinSize * RHS, IsScalable }; + } + + TypeSize operator*(int RHS) const { + return { MinSize * RHS, IsScalable }; + } + + TypeSize operator*(int64_t RHS) const { + return { MinSize * RHS, IsScalable }; + } + + friend TypeSize operator*(const uint64_t LHS, const TypeSize &RHS) { + return { LHS * RHS.MinSize, RHS.IsScalable }; + } + + friend TypeSize operator*(const int LHS, const TypeSize &RHS) { + return { LHS * RHS.MinSize, RHS.IsScalable }; + } + + friend TypeSize operator*(const int64_t LHS, const TypeSize &RHS) { + return { LHS * RHS.MinSize, RHS.IsScalable }; + } + + TypeSize operator/(uint64_t RHS) const { + return { MinSize / RHS, IsScalable }; + } + + TypeSize operator/(int RHS) const { + return { MinSize / RHS, IsScalable }; + } + + TypeSize operator/(int64_t RHS) const { + return { MinSize / RHS, IsScalable }; + } +}; + +/// Returns a TypeSize with a known minimum size that is the next integer +/// (mod 2**64) that is greater than or equal to \p Value and is a multiple +/// of \p Align. \p Align must be non-zero. +/// +/// Similar to the alignTo functions in MathExtras.h +inline TypeSize alignTo(TypeSize Size, uint64_t Align) { + assert(Align != 0u && "Align must be non-zero"); + return {(Size.getKnownMinSize() + Align - 1) / Align * Align, + Size.isScalable()}; +} + +} // end namespace llvm + +#endif // LLVM_SUPPORT_TypeSize_H diff --git a/third_party/llvm-project/include/llvm/Support/Unicode.h b/third_party/llvm-project/include/llvm/Support/Unicode.h new file mode 100644 index 000000000..ca17bba2f --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/Unicode.h @@ -0,0 +1,70 @@ +//===- llvm/Support/Unicode.h - Unicode character properties -*- 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 defines functions that allow querying certain properties of Unicode +// characters. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_UNICODE_H +#define LLVM_SUPPORT_UNICODE_H + +namespace llvm { +class StringRef; + +namespace sys { +namespace unicode { + +enum ColumnWidthErrors { + ErrorInvalidUTF8 = -2, + ErrorNonPrintableCharacter = -1 +}; + +/// Determines if a character is likely to be displayed correctly on the +/// terminal. Exact implementation would have to depend on the specific +/// terminal, so we define the semantic that should be suitable for generic case +/// of a terminal capable to output Unicode characters. +/// +/// All characters from the Unicode code point range are considered printable +/// except for: +/// * C0 and C1 control character ranges; +/// * default ignorable code points as per 5.21 of +/// http://www.unicode.org/versions/Unicode6.2.0/UnicodeStandard-6.2.pdf +/// except for U+00AD SOFT HYPHEN, as it's actually displayed on most +/// terminals; +/// * format characters (category = Cf); +/// * surrogates (category = Cs); +/// * unassigned characters (category = Cn). +/// \return true if the character is considered printable. +bool isPrintable(int UCS); + +/// Gets the number of positions the UTF8-encoded \p Text is likely to occupy +/// when output on a terminal ("character width"). This depends on the +/// implementation of the terminal, and there's no standard definition of +/// character width. +/// +/// The implementation defines it in a way that is expected to be compatible +/// with a generic Unicode-capable terminal. +/// +/// \return Character width: +/// * ErrorNonPrintableCharacter (-1) if \p Text contains non-printable +/// characters (as identified by isPrintable); +/// * 0 for each non-spacing and enclosing combining mark; +/// * 2 for each CJK character excluding halfwidth forms; +/// * 1 for each of the remaining characters. +int columnWidthUTF8(StringRef Text); + +/// Fold input unicode character according the Simple unicode case folding +/// rules. +int foldCharSimple(int C); + +} // namespace unicode +} // namespace sys +} // namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/UnicodeCharRanges.h b/third_party/llvm-project/include/llvm/Support/UnicodeCharRanges.h new file mode 100644 index 000000000..73d3603b7 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/UnicodeCharRanges.h @@ -0,0 +1,103 @@ +//===--- UnicodeCharRanges.h - Types and functions for character ranges ---===// +// +// 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 +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_SUPPORT_UNICODECHARRANGES_H +#define LLVM_SUPPORT_UNICODECHARRANGES_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> + +#define DEBUG_TYPE "unicode" + +namespace llvm { +namespace sys { + +/// Represents a closed range of Unicode code points [Lower, Upper]. +struct UnicodeCharRange { + uint32_t Lower; + uint32_t Upper; +}; + +inline bool operator<(uint32_t Value, UnicodeCharRange Range) { + return Value < Range.Lower; +} +inline bool operator<(UnicodeCharRange Range, uint32_t Value) { + return Range.Upper < Value; +} + +/// Holds a reference to an ordered array of UnicodeCharRange and allows +/// to quickly check if a code point is contained in the set represented by this +/// array. +class UnicodeCharSet { +public: + typedef ArrayRef<UnicodeCharRange> CharRanges; + + /// Constructs a UnicodeCharSet instance from an array of + /// UnicodeCharRanges. + /// + /// Array pointed by \p Ranges should have the lifetime at least as long as + /// the UnicodeCharSet instance, and should not change. Array is validated by + /// the constructor, so it makes sense to create as few UnicodeCharSet + /// instances per each array of ranges, as possible. +#ifdef NDEBUG + + // FIXME: This could use constexpr + static_assert. This way we + // may get rid of NDEBUG in this header. Unfortunately there are some + // problems to get this working with MSVC 2013. Change this when + // the support for MSVC 2013 is dropped. + constexpr UnicodeCharSet(CharRanges Ranges) : Ranges(Ranges) {} +#else + UnicodeCharSet(CharRanges Ranges) : Ranges(Ranges) { + assert(rangesAreValid()); + } +#endif + + /// Returns true if the character set contains the Unicode code point + /// \p C. + bool contains(uint32_t C) const { + return std::binary_search(Ranges.begin(), Ranges.end(), C); + } + +private: + /// Returns true if each of the ranges is a proper closed range + /// [min, max], and if the ranges themselves are ordered and non-overlapping. + bool rangesAreValid() const { + uint32_t Prev = 0; + for (CharRanges::const_iterator I = Ranges.begin(), E = Ranges.end(); + I != E; ++I) { + if (I != Ranges.begin() && Prev >= I->Lower) { + LLVM_DEBUG(dbgs() << "Upper bound 0x"); + LLVM_DEBUG(dbgs().write_hex(Prev)); + LLVM_DEBUG(dbgs() << " should be less than succeeding lower bound 0x"); + LLVM_DEBUG(dbgs().write_hex(I->Lower) << "\n"); + return false; + } + if (I->Upper < I->Lower) { + LLVM_DEBUG(dbgs() << "Upper bound 0x"); + LLVM_DEBUG(dbgs().write_hex(I->Lower)); + LLVM_DEBUG(dbgs() << " should not be less than lower bound 0x"); + LLVM_DEBUG(dbgs().write_hex(I->Upper) << "\n"); + return false; + } + Prev = I->Upper; + } + + return true; + } + + const CharRanges Ranges; +}; + +} // namespace sys +} // namespace llvm + +#undef DEBUG_TYPE // "unicode" + +#endif // LLVM_SUPPORT_UNICODECHARRANGES_H diff --git a/third_party/llvm-project/include/llvm/Support/WindowsError.h b/third_party/llvm-project/include/llvm/Support/WindowsError.h new file mode 100644 index 000000000..195405224 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/WindowsError.h @@ -0,0 +1,18 @@ +//===-- WindowsError.h - Support for mapping windows errors to posix-------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_WINDOWSERROR_H +#define LLVM_SUPPORT_WINDOWSERROR_H + +#include <system_error> + +namespace llvm { +std::error_code mapWindowsError(unsigned EV); +} + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/WithColor.h b/third_party/llvm-project/include/llvm/Support/WithColor.h new file mode 100644 index 000000000..2814f7e0e --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/WithColor.h @@ -0,0 +1,118 @@ +//===- WithColor.h ----------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_WITHCOLOR_H +#define LLVM_SUPPORT_WITHCOLOR_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +#if 0 // XXX BINARYEN +extern cl::OptionCategory ColorCategory; +#endif + +class raw_ostream; + +// Symbolic names for various syntax elements. +enum class HighlightColor { + Address, + String, + Tag, + Attribute, + Enumerator, + Macro, + Error, + Warning, + Note, + Remark +}; + +/// An RAII object that temporarily switches an output stream to a specific +/// color. +class WithColor { + raw_ostream &OS; + bool DisableColors; + +public: + /// To be used like this: WithColor(OS, HighlightColor::String) << "text"; + /// @param OS The output stream + /// @param S Symbolic name for syntax element to color + /// @param DisableColors Whether to ignore color changes regardless of -color + /// and support in OS + WithColor(raw_ostream &OS, HighlightColor S, bool DisableColors = false); + /// To be used like this: WithColor(OS, raw_ostream::Black) << "text"; + /// @param OS The output stream + /// @param Color ANSI color to use, the special SAVEDCOLOR can be used to + /// change only the bold attribute, and keep colors untouched + /// @param Bold Bold/brighter text, default false + /// @param BG If true, change the background, default: change foreground + /// @param DisableColors Whether to ignore color changes regardless of -color + /// and support in OS + WithColor(raw_ostream &OS, + raw_ostream::Colors Color = raw_ostream::SAVEDCOLOR, + bool Bold = false, bool BG = false, bool DisableColors = false) + : OS(OS), DisableColors(DisableColors) { + changeColor(Color, Bold, BG); + } + ~WithColor(); + + raw_ostream &get() { return OS; } + operator raw_ostream &() { return OS; } + template <typename T> WithColor &operator<<(T &O) { + OS << O; + return *this; + } + template <typename T> WithColor &operator<<(const T &O) { + OS << O; + return *this; + } + + /// Convenience method for printing "error: " to stderr. + static raw_ostream &error(); + /// Convenience method for printing "warning: " to stderr. + static raw_ostream &warning(); + /// Convenience method for printing "note: " to stderr. + static raw_ostream ¬e(); + /// Convenience method for printing "remark: " to stderr. + static raw_ostream &remark(); + + /// Convenience method for printing "error: " to the given stream. + static raw_ostream &error(raw_ostream &OS, StringRef Prefix = "", + bool DisableColors = false); + /// Convenience method for printing "warning: " to the given stream. + static raw_ostream &warning(raw_ostream &OS, StringRef Prefix = "", + bool DisableColors = false); + /// Convenience method for printing "note: " to the given stream. + static raw_ostream ¬e(raw_ostream &OS, StringRef Prefix = "", + bool DisableColors = false); + /// Convenience method for printing "remark: " to the given stream. + static raw_ostream &remark(raw_ostream &OS, StringRef Prefix = "", + bool DisableColors = false); + + /// Determine whether colors are displayed. + bool colorsEnabled(); + + /// Change the color of text that will be output from this point forward. + /// @param Color ANSI color to use, the special SAVEDCOLOR can be used to + /// change only the bold attribute, and keep colors untouched + /// @param Bold Bold/brighter text, default false + /// @param BG If true, change the background, default: change foreground + WithColor &changeColor(raw_ostream::Colors Color, bool Bold = false, + bool BG = false); + + /// Reset the colors to terminal defaults. Call this when you are done + /// outputting colored text, or before program exit. + WithColor &resetColor(); +}; + +} // end namespace llvm + +#endif // LLVM_LIB_DEBUGINFO_WITHCOLOR_H diff --git a/third_party/llvm-project/include/llvm/Support/X86TargetParser.def b/third_party/llvm-project/include/llvm/Support/X86TargetParser.def new file mode 100644 index 000000000..4ebf2d79c --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/X86TargetParser.def @@ -0,0 +1,173 @@ +//===- X86TargetParser.def - X86 target parsing defines ---------*- 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 provides defines to build up the X86 target parser's logic. +// +//===----------------------------------------------------------------------===// + +// NOTE: NO INCLUDE GUARD DESIRED! + +#ifndef X86_VENDOR +#define X86_VENDOR(ENUM, STR) +#endif +X86_VENDOR(VENDOR_INTEL, "intel") +X86_VENDOR(VENDOR_AMD, "amd") +#undef X86_VENDOR + +// This macro is used to implement CPU types that have an alias. As of now +// there is only ever one alias. +#ifndef X86_CPU_TYPE_COMPAT_WITH_ALIAS +#define X86_CPU_TYPE_COMPAT_WITH_ALIAS(ARCHNAME, ENUM, STR, ALIAS) X86_CPU_TYPE_COMPAT(ARCHNAME, ENUM, STR) +#endif + +// This macro is used for cpu types present in compiler-rt/libgcc. +#ifndef X86_CPU_TYPE_COMPAT +#define X86_CPU_TYPE_COMPAT(ARCHNAME, ENUM, STR) X86_CPU_TYPE(ARCHNAME, ENUM) +#endif + +#ifndef X86_CPU_TYPE +#define X86_CPU_TYPE(ARCHNAME, ENUM) +#endif +// The first part of this list must match what is implemented in libgcc and +// compilert-rt. Clang uses this to know how to implement __builtin_cpu_is. +X86_CPU_TYPE_COMPAT_WITH_ALIAS("bonnell", INTEL_BONNELL, "bonnell", "atom") +X86_CPU_TYPE_COMPAT ("core2", INTEL_CORE2, "core2") +X86_CPU_TYPE_COMPAT ("nehalem", INTEL_COREI7, "corei7") +X86_CPU_TYPE_COMPAT_WITH_ALIAS("amdfam10", AMDFAM10H, "amdfam10h", "amdfam10") +X86_CPU_TYPE_COMPAT_WITH_ALIAS("bdver1", AMDFAM15H, "amdfam15h", "amdfam15") +X86_CPU_TYPE_COMPAT_WITH_ALIAS("silvermont", INTEL_SILVERMONT, "silvermont", "slm") +X86_CPU_TYPE_COMPAT ("knl", INTEL_KNL, "knl") +X86_CPU_TYPE_COMPAT ("btver1", AMD_BTVER1, "btver1") +X86_CPU_TYPE_COMPAT ("btver2", AMD_BTVER2, "btver2") +X86_CPU_TYPE_COMPAT ("znver1", AMDFAM17H, "amdfam17h") +X86_CPU_TYPE_COMPAT ("knm", INTEL_KNM, "knm") +X86_CPU_TYPE_COMPAT ("goldmont", INTEL_GOLDMONT, "goldmont") +X86_CPU_TYPE_COMPAT ("goldmont-plus", INTEL_GOLDMONT_PLUS, "goldmont-plus") +X86_CPU_TYPE_COMPAT ("tremont", INTEL_TREMONT, "tremont") +// Entries below this are not in libgcc/compiler-rt. +X86_CPU_TYPE ("i386", INTEL_i386) +X86_CPU_TYPE ("i486", INTEL_i486) +X86_CPU_TYPE ("pentium", INTEL_PENTIUM) +X86_CPU_TYPE ("pentium-mmx", INTEL_PENTIUM_MMX) +X86_CPU_TYPE ("pentiumpro", INTEL_PENTIUM_PRO) +X86_CPU_TYPE ("pentium2", INTEL_PENTIUM_II) +X86_CPU_TYPE ("pentium3", INTEL_PENTIUM_III) +X86_CPU_TYPE ("pentium4", INTEL_PENTIUM_IV) +X86_CPU_TYPE ("pentium-m", INTEL_PENTIUM_M) +X86_CPU_TYPE ("yonah", INTEL_CORE_DUO) +X86_CPU_TYPE ("nocona", INTEL_NOCONA) +X86_CPU_TYPE ("prescott", INTEL_PRESCOTT) +X86_CPU_TYPE ("i486", AMD_i486) +X86_CPU_TYPE ("pentium", AMDPENTIUM) +X86_CPU_TYPE ("athlon", AMD_ATHLON) +X86_CPU_TYPE ("athlon-xp", AMD_ATHLON_XP) +X86_CPU_TYPE ("k8", AMD_K8) +X86_CPU_TYPE ("k8-sse3", AMD_K8SSE3) +#undef X86_CPU_TYPE_COMPAT_WITH_ALIAS +#undef X86_CPU_TYPE_COMPAT +#undef X86_CPU_TYPE + +// This macro is used for cpu subtypes present in compiler-rt/libgcc. +#ifndef X86_CPU_SUBTYPE_COMPAT +#define X86_CPU_SUBTYPE_COMPAT(ARCHNAME, ENUM, STR) X86_CPU_SUBTYPE(ARCHNAME, ENUM) +#endif + +#ifndef X86_CPU_SUBTYPE +#define X86_CPU_SUBTYPE(ARCHNAME, ENUM) +#endif + +// The first part of this list must match what is implemented in libgcc and +// compilert-rt. Clang uses this to know how to implement __builtin_cpu_is. +X86_CPU_SUBTYPE_COMPAT("nehalem", INTEL_COREI7_NEHALEM, "nehalem") +X86_CPU_SUBTYPE_COMPAT("westmere", INTEL_COREI7_WESTMERE, "westmere") +X86_CPU_SUBTYPE_COMPAT("sandybridge", INTEL_COREI7_SANDYBRIDGE, "sandybridge") +X86_CPU_SUBTYPE_COMPAT("amdfam10", AMDFAM10H_BARCELONA, "barcelona") +X86_CPU_SUBTYPE_COMPAT("amdfam10", AMDFAM10H_SHANGHAI, "shanghai") +X86_CPU_SUBTYPE_COMPAT("amdfam10", AMDFAM10H_ISTANBUL, "istanbul") +X86_CPU_SUBTYPE_COMPAT("bdver1", AMDFAM15H_BDVER1, "bdver1") +X86_CPU_SUBTYPE_COMPAT("bdver2", AMDFAM15H_BDVER2, "bdver2") +X86_CPU_SUBTYPE_COMPAT("bdver3", AMDFAM15H_BDVER3, "bdver3") +X86_CPU_SUBTYPE_COMPAT("bdver4", AMDFAM15H_BDVER4, "bdver4") +X86_CPU_SUBTYPE_COMPAT("znver1", AMDFAM17H_ZNVER1, "znver1") +X86_CPU_SUBTYPE_COMPAT("ivybridge", INTEL_COREI7_IVYBRIDGE, "ivybridge") +X86_CPU_SUBTYPE_COMPAT("haswell", INTEL_COREI7_HASWELL, "haswell") +X86_CPU_SUBTYPE_COMPAT("broadwell", INTEL_COREI7_BROADWELL, "broadwell") +X86_CPU_SUBTYPE_COMPAT("skylake", INTEL_COREI7_SKYLAKE, "skylake") +X86_CPU_SUBTYPE_COMPAT("skylake-avx512", INTEL_COREI7_SKYLAKE_AVX512, "skylake-avx512") +X86_CPU_SUBTYPE_COMPAT("cannonlake", INTEL_COREI7_CANNONLAKE, "cannonlake") +X86_CPU_SUBTYPE_COMPAT("icelake-client", INTEL_COREI7_ICELAKE_CLIENT, "icelake-client") +X86_CPU_SUBTYPE_COMPAT("icelake-server", INTEL_COREI7_ICELAKE_SERVER, "icelake-server") +X86_CPU_SUBTYPE_COMPAT("znver2", AMDFAM17H_ZNVER2, "znver2") +X86_CPU_SUBTYPE_COMPAT("cascadelake", INTEL_COREI7_CASCADELAKE, "cascadelake") +// Entries below this are not in libgcc/compiler-rt. +X86_CPU_SUBTYPE ("core2", INTEL_CORE2_65) +X86_CPU_SUBTYPE ("penryn", INTEL_CORE2_45) +X86_CPU_SUBTYPE ("k6", AMDPENTIUM_K6) +X86_CPU_SUBTYPE ("k6-2", AMDPENTIUM_K62) +X86_CPU_SUBTYPE ("k6-3", AMDPENTIUM_K63) +X86_CPU_SUBTYPE ("geode", AMDPENTIUM_GEODE) +X86_CPU_SUBTYPE ("cooperlake", INTEL_COREI7_COOPERLAKE) +X86_CPU_SUBTYPE ("tigerlake", INTEL_COREI7_TIGERLAKE) +#undef X86_CPU_SUBTYPE_COMPAT +#undef X86_CPU_SUBTYPE + + +// This macro is used for cpu types present in compiler-rt/libgcc. +#ifndef X86_FEATURE_COMPAT +#define X86_FEATURE_COMPAT(VAL, ENUM, STR) X86_FEATURE(VAL, ENUM) +#endif + +#ifndef X86_FEATURE +#define X86_FEATURE(VAL, ENUM) +#endif +X86_FEATURE_COMPAT( 0, FEATURE_CMOV, "cmov") +X86_FEATURE_COMPAT( 1, FEATURE_MMX, "mmx") +X86_FEATURE_COMPAT( 2, FEATURE_POPCNT, "popcnt") +X86_FEATURE_COMPAT( 3, FEATURE_SSE, "sse") +X86_FEATURE_COMPAT( 4, FEATURE_SSE2, "sse2") +X86_FEATURE_COMPAT( 5, FEATURE_SSE3, "sse3") +X86_FEATURE_COMPAT( 6, FEATURE_SSSE3, "ssse3") +X86_FEATURE_COMPAT( 7, FEATURE_SSE4_1, "sse4.1") +X86_FEATURE_COMPAT( 8, FEATURE_SSE4_2, "sse4.2") +X86_FEATURE_COMPAT( 9, FEATURE_AVX, "avx") +X86_FEATURE_COMPAT(10, FEATURE_AVX2, "avx2") +X86_FEATURE_COMPAT(11, FEATURE_SSE4_A, "sse4a") +X86_FEATURE_COMPAT(12, FEATURE_FMA4, "fma4") +X86_FEATURE_COMPAT(13, FEATURE_XOP, "xop") +X86_FEATURE_COMPAT(14, FEATURE_FMA, "fma") +X86_FEATURE_COMPAT(15, FEATURE_AVX512F, "avx512f") +X86_FEATURE_COMPAT(16, FEATURE_BMI, "bmi") +X86_FEATURE_COMPAT(17, FEATURE_BMI2, "bmi2") +X86_FEATURE_COMPAT(18, FEATURE_AES, "aes") +X86_FEATURE_COMPAT(19, FEATURE_PCLMUL, "pclmul") +X86_FEATURE_COMPAT(20, FEATURE_AVX512VL, "avx512vl") +X86_FEATURE_COMPAT(21, FEATURE_AVX512BW, "avx512bw") +X86_FEATURE_COMPAT(22, FEATURE_AVX512DQ, "avx512dq") +X86_FEATURE_COMPAT(23, FEATURE_AVX512CD, "avx512cd") +X86_FEATURE_COMPAT(24, FEATURE_AVX512ER, "avx512er") +X86_FEATURE_COMPAT(25, FEATURE_AVX512PF, "avx512pf") +X86_FEATURE_COMPAT(26, FEATURE_AVX512VBMI, "avx512vbmi") +X86_FEATURE_COMPAT(27, FEATURE_AVX512IFMA, "avx512ifma") +X86_FEATURE_COMPAT(28, FEATURE_AVX5124VNNIW, "avx5124vnniw") +X86_FEATURE_COMPAT(29, FEATURE_AVX5124FMAPS, "avx5124fmaps") +X86_FEATURE_COMPAT(30, FEATURE_AVX512VPOPCNTDQ, "avx512vpopcntdq") +X86_FEATURE_COMPAT(31, FEATURE_AVX512VBMI2, "avx512vbmi2") +X86_FEATURE_COMPAT(32, FEATURE_GFNI, "gfni") +X86_FEATURE_COMPAT(33, FEATURE_VPCLMULQDQ, "vpclmulqdq") +X86_FEATURE_COMPAT(34, FEATURE_AVX512VNNI, "avx512vnni") +X86_FEATURE_COMPAT(35, FEATURE_AVX512BITALG, "avx512bitalg") +X86_FEATURE_COMPAT(36, FEATURE_AVX512BF16, "avx512bf16") +// Features below here are not in libgcc/compiler-rt. +X86_FEATURE (64, FEATURE_MOVBE) +X86_FEATURE (65, FEATURE_ADX) +X86_FEATURE (66, FEATURE_EM64T) +X86_FEATURE (67, FEATURE_CLFLUSHOPT) +X86_FEATURE (68, FEATURE_SHA) +X86_FEATURE (69, FEATURE_AVX512VP2INTERSECT) +#undef X86_FEATURE_COMPAT +#undef X86_FEATURE diff --git a/third_party/llvm-project/include/llvm/Support/YAMLParser.h b/third_party/llvm-project/include/llvm/Support/YAMLParser.h new file mode 100644 index 000000000..3570119a3 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/YAMLParser.h @@ -0,0 +1,619 @@ +//===- YAMLParser.h - Simple YAML parser ------------------------*- 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 is a YAML 1.2 parser. +// +// See http://www.yaml.org/spec/1.2/spec.html for the full standard. +// +// This currently does not implement the following: +// * Multi-line literal folding. +// * Tag resolution. +// * UTF-16. +// * BOMs anywhere other than the first Unicode scalar value in the file. +// +// The most important class here is Stream. This represents a YAML stream with +// 0, 1, or many documents. +// +// SourceMgr sm; +// StringRef input = getInput(); +// yaml::Stream stream(input, sm); +// +// for (yaml::document_iterator di = stream.begin(), de = stream.end(); +// di != de; ++di) { +// yaml::Node *n = di->getRoot(); +// if (n) { +// // Do something with n... +// } else +// break; +// } +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_YAMLPARSER_H +#define LLVM_SUPPORT_YAMLPARSER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/SMLoc.h" +#include <cassert> +#include <cstddef> +#include <iterator> +#include <map> +#include <memory> +#include <string> +#include <system_error> + +namespace llvm { + +class MemoryBufferRef; +class SourceMgr; +class raw_ostream; +class Twine; + +namespace yaml { + +class Document; +class document_iterator; +class Node; +class Scanner; +struct Token; + +/// Dump all the tokens in this stream to OS. +/// \returns true if there was an error, false otherwise. +bool dumpTokens(StringRef Input, raw_ostream &); + +/// Scans all tokens in input without outputting anything. This is used +/// for benchmarking the tokenizer. +/// \returns true if there was an error, false otherwise. +bool scanTokens(StringRef Input); + +/// Escape \a Input for a double quoted scalar; if \p EscapePrintable +/// is true, all UTF8 sequences will be escaped, if \p EscapePrintable is +/// false, those UTF8 sequences encoding printable unicode scalars will not be +/// escaped, but emitted verbatim. +std::string escape(StringRef Input, bool EscapePrintable = true); + +/// This class represents a YAML stream potentially containing multiple +/// documents. +class Stream { +public: + /// This keeps a reference to the string referenced by \p Input. + Stream(StringRef Input, SourceMgr &, bool ShowColors = true, + std::error_code *EC = nullptr); + + Stream(MemoryBufferRef InputBuffer, SourceMgr &, bool ShowColors = true, + std::error_code *EC = nullptr); + ~Stream(); + + document_iterator begin(); + document_iterator end(); + void skip(); + bool failed(); + + bool validate() { + skip(); + return !failed(); + } + + void printError(Node *N, const Twine &Msg); + +private: + friend class Document; + + std::unique_ptr<Scanner> scanner; + std::unique_ptr<Document> CurrentDoc; +}; + +/// Abstract base class for all Nodes. +class Node { + virtual void anchor(); + +public: + enum NodeKind { + NK_Null, + NK_Scalar, + NK_BlockScalar, + NK_KeyValue, + NK_Mapping, + NK_Sequence, + NK_Alias + }; + + Node(unsigned int Type, std::unique_ptr<Document> &, StringRef Anchor, + StringRef Tag); + + // It's not safe to copy YAML nodes; the document is streamed and the position + // is part of the state. + Node(const Node &) = delete; + void operator=(const Node &) = delete; + + void *operator new(size_t Size, BumpPtrAllocator &Alloc, + size_t Alignment = 16) noexcept { + return Alloc.Allocate(Size, Alignment); + } + + void operator delete(void *Ptr, BumpPtrAllocator &Alloc, + size_t Size) noexcept { + Alloc.Deallocate(Ptr, Size); + } + + void operator delete(void *) noexcept = delete; + + /// Get the value of the anchor attached to this node. If it does not + /// have one, getAnchor().size() will be 0. + StringRef getAnchor() const { return Anchor; } + + /// Get the tag as it was written in the document. This does not + /// perform tag resolution. + StringRef getRawTag() const { return Tag; } + + /// Get the verbatium tag for a given Node. This performs tag resoluton + /// and substitution. + std::string getVerbatimTag() const; + + SMRange getSourceRange() const { return SourceRange; } + void setSourceRange(SMRange SR) { SourceRange = SR; } + + // These functions forward to Document and Scanner. + Token &peekNext(); + Token getNext(); + Node *parseBlockNode(); + BumpPtrAllocator &getAllocator(); + void setError(const Twine &Message, Token &Location) const; + bool failed() const; + + virtual void skip() {} + + unsigned int getType() const { return TypeID; } + +protected: + std::unique_ptr<Document> &Doc; + SMRange SourceRange; + + ~Node() = default; + +private: + unsigned int TypeID; + StringRef Anchor; + /// The tag as typed in the document. + StringRef Tag; +}; + +/// A null value. +/// +/// Example: +/// !!null null +class NullNode final : public Node { + void anchor() override; + +public: + NullNode(std::unique_ptr<Document> &D) + : Node(NK_Null, D, StringRef(), StringRef()) {} + + static bool classof(const Node *N) { return N->getType() == NK_Null; } +}; + +/// A scalar node is an opaque datum that can be presented as a +/// series of zero or more Unicode scalar values. +/// +/// Example: +/// Adena +class ScalarNode final : public Node { + void anchor() override; + +public: + ScalarNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag, + StringRef Val) + : Node(NK_Scalar, D, Anchor, Tag), Value(Val) { + SMLoc Start = SMLoc::getFromPointer(Val.begin()); + SMLoc End = SMLoc::getFromPointer(Val.end()); + SourceRange = SMRange(Start, End); + } + + // Return Value without any escaping or folding or other fun YAML stuff. This + // is the exact bytes that are contained in the file (after conversion to + // utf8). + StringRef getRawValue() const { return Value; } + + /// Gets the value of this node as a StringRef. + /// + /// \param Storage is used to store the content of the returned StringRef iff + /// it requires any modification from how it appeared in the source. + /// This happens with escaped characters and multi-line literals. + StringRef getValue(SmallVectorImpl<char> &Storage) const; + + static bool classof(const Node *N) { + return N->getType() == NK_Scalar; + } + +private: + StringRef Value; + + StringRef unescapeDoubleQuoted(StringRef UnquotedValue, + StringRef::size_type Start, + SmallVectorImpl<char> &Storage) const; +}; + +/// A block scalar node is an opaque datum that can be presented as a +/// series of zero or more Unicode scalar values. +/// +/// Example: +/// | +/// Hello +/// World +class BlockScalarNode final : public Node { + void anchor() override; + +public: + BlockScalarNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag, + StringRef Value, StringRef RawVal) + : Node(NK_BlockScalar, D, Anchor, Tag), Value(Value) { + SMLoc Start = SMLoc::getFromPointer(RawVal.begin()); + SMLoc End = SMLoc::getFromPointer(RawVal.end()); + SourceRange = SMRange(Start, End); + } + + /// Gets the value of this node as a StringRef. + StringRef getValue() const { return Value; } + + static bool classof(const Node *N) { + return N->getType() == NK_BlockScalar; + } + +private: + StringRef Value; +}; + +/// A key and value pair. While not technically a Node under the YAML +/// representation graph, it is easier to treat them this way. +/// +/// TODO: Consider making this not a child of Node. +/// +/// Example: +/// Section: .text +class KeyValueNode final : public Node { + void anchor() override; + +public: + KeyValueNode(std::unique_ptr<Document> &D) + : Node(NK_KeyValue, D, StringRef(), StringRef()) {} + + /// Parse and return the key. + /// + /// This may be called multiple times. + /// + /// \returns The key, or nullptr if failed() == true. + Node *getKey(); + + /// Parse and return the value. + /// + /// This may be called multiple times. + /// + /// \returns The value, or nullptr if failed() == true. + Node *getValue(); + + void skip() override { + if (Node *Key = getKey()) { + Key->skip(); + if (Node *Val = getValue()) + Val->skip(); + } + } + + static bool classof(const Node *N) { + return N->getType() == NK_KeyValue; + } + +private: + Node *Key = nullptr; + Node *Value = nullptr; +}; + +/// This is an iterator abstraction over YAML collections shared by both +/// sequences and maps. +/// +/// BaseT must have a ValueT* member named CurrentEntry and a member function +/// increment() which must set CurrentEntry to 0 to create an end iterator. +template <class BaseT, class ValueT> +class basic_collection_iterator + : public std::iterator<std::input_iterator_tag, ValueT> { +public: + basic_collection_iterator() = default; + basic_collection_iterator(BaseT *B) : Base(B) {} + + ValueT *operator->() const { + assert(Base && Base->CurrentEntry && "Attempted to access end iterator!"); + return Base->CurrentEntry; + } + + ValueT &operator*() const { + assert(Base && Base->CurrentEntry && + "Attempted to dereference end iterator!"); + return *Base->CurrentEntry; + } + + operator ValueT *() const { + assert(Base && Base->CurrentEntry && "Attempted to access end iterator!"); + return Base->CurrentEntry; + } + + /// Note on EqualityComparable: + /// + /// The iterator is not re-entrant, + /// it is meant to be used for parsing YAML on-demand + /// Once iteration started - it can point only to one entry at a time + /// hence Base.CurrentEntry and Other.Base.CurrentEntry are equal + /// iff Base and Other.Base are equal. + bool operator==(const basic_collection_iterator &Other) const { + if (Base && (Base == Other.Base)) { + assert((Base->CurrentEntry == Other.Base->CurrentEntry) + && "Equal Bases expected to point to equal Entries"); + } + + return Base == Other.Base; + } + + bool operator!=(const basic_collection_iterator &Other) const { + return !(Base == Other.Base); + } + + basic_collection_iterator &operator++() { + assert(Base && "Attempted to advance iterator past end!"); + Base->increment(); + // Create an end iterator. + if (!Base->CurrentEntry) + Base = nullptr; + return *this; + } + +private: + BaseT *Base = nullptr; +}; + +// The following two templates are used for both MappingNode and Sequence Node. +template <class CollectionType> +typename CollectionType::iterator begin(CollectionType &C) { + assert(C.IsAtBeginning && "You may only iterate over a collection once!"); + C.IsAtBeginning = false; + typename CollectionType::iterator ret(&C); + ++ret; + return ret; +} + +template <class CollectionType> void skip(CollectionType &C) { + // TODO: support skipping from the middle of a parsed collection ;/ + assert((C.IsAtBeginning || C.IsAtEnd) && "Cannot skip mid parse!"); + if (C.IsAtBeginning) + for (typename CollectionType::iterator i = begin(C), e = C.end(); i != e; + ++i) + i->skip(); +} + +/// Represents a YAML map created from either a block map for a flow map. +/// +/// This parses the YAML stream as increment() is called. +/// +/// Example: +/// Name: _main +/// Scope: Global +class MappingNode final : public Node { + void anchor() override; + +public: + enum MappingType { + MT_Block, + MT_Flow, + MT_Inline ///< An inline mapping node is used for "[key: value]". + }; + + MappingNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag, + MappingType MT) + : Node(NK_Mapping, D, Anchor, Tag), Type(MT) {} + + friend class basic_collection_iterator<MappingNode, KeyValueNode>; + + using iterator = basic_collection_iterator<MappingNode, KeyValueNode>; + + template <class T> friend typename T::iterator yaml::begin(T &); + template <class T> friend void yaml::skip(T &); + + iterator begin() { return yaml::begin(*this); } + + iterator end() { return iterator(); } + + void skip() override { yaml::skip(*this); } + + static bool classof(const Node *N) { + return N->getType() == NK_Mapping; + } + +private: + MappingType Type; + bool IsAtBeginning = true; + bool IsAtEnd = false; + KeyValueNode *CurrentEntry = nullptr; + + void increment(); +}; + +/// Represents a YAML sequence created from either a block sequence for a +/// flow sequence. +/// +/// This parses the YAML stream as increment() is called. +/// +/// Example: +/// - Hello +/// - World +class SequenceNode final : public Node { + void anchor() override; + +public: + enum SequenceType { + ST_Block, + ST_Flow, + // Use for: + // + // key: + // - val1 + // - val2 + // + // As a BlockMappingEntry and BlockEnd are not created in this case. + ST_Indentless + }; + + SequenceNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag, + SequenceType ST) + : Node(NK_Sequence, D, Anchor, Tag), SeqType(ST) {} + + friend class basic_collection_iterator<SequenceNode, Node>; + + using iterator = basic_collection_iterator<SequenceNode, Node>; + + template <class T> friend typename T::iterator yaml::begin(T &); + template <class T> friend void yaml::skip(T &); + + void increment(); + + iterator begin() { return yaml::begin(*this); } + + iterator end() { return iterator(); } + + void skip() override { yaml::skip(*this); } + + static bool classof(const Node *N) { + return N->getType() == NK_Sequence; + } + +private: + SequenceType SeqType; + bool IsAtBeginning = true; + bool IsAtEnd = false; + bool WasPreviousTokenFlowEntry = true; // Start with an imaginary ','. + Node *CurrentEntry = nullptr; +}; + +/// Represents an alias to a Node with an anchor. +/// +/// Example: +/// *AnchorName +class AliasNode final : public Node { + void anchor() override; + +public: + AliasNode(std::unique_ptr<Document> &D, StringRef Val) + : Node(NK_Alias, D, StringRef(), StringRef()), Name(Val) {} + + StringRef getName() const { return Name; } + Node *getTarget(); + + static bool classof(const Node *N) { return N->getType() == NK_Alias; } + +private: + StringRef Name; +}; + +/// A YAML Stream is a sequence of Documents. A document contains a root +/// node. +class Document { +public: + Document(Stream &ParentStream); + + /// Root for parsing a node. Returns a single node. + Node *parseBlockNode(); + + /// Finish parsing the current document and return true if there are + /// more. Return false otherwise. + bool skip(); + + /// Parse and return the root level node. + Node *getRoot() { + if (Root) + return Root; + return Root = parseBlockNode(); + } + + const std::map<StringRef, StringRef> &getTagMap() const { return TagMap; } + +private: + friend class Node; + friend class document_iterator; + + /// Stream to read tokens from. + Stream &stream; + + /// Used to allocate nodes to. All are destroyed without calling their + /// destructor when the document is destroyed. + BumpPtrAllocator NodeAllocator; + + /// The root node. Used to support skipping a partially parsed + /// document. + Node *Root; + + /// Maps tag prefixes to their expansion. + std::map<StringRef, StringRef> TagMap; + + Token &peekNext(); + Token getNext(); + void setError(const Twine &Message, Token &Location) const; + bool failed() const; + + /// Parse %BLAH directives and return true if any were encountered. + bool parseDirectives(); + + /// Parse %YAML + void parseYAMLDirective(); + + /// Parse %TAG + void parseTAGDirective(); + + /// Consume the next token and error if it is not \a TK. + bool expectToken(int TK); +}; + +/// Iterator abstraction for Documents over a Stream. +class document_iterator { +public: + document_iterator() = default; + document_iterator(std::unique_ptr<Document> &D) : Doc(&D) {} + + bool operator==(const document_iterator &Other) const { + if (isAtEnd() || Other.isAtEnd()) + return isAtEnd() && Other.isAtEnd(); + + return Doc == Other.Doc; + } + bool operator!=(const document_iterator &Other) const { + return !(*this == Other); + } + + document_iterator operator++() { + assert(Doc && "incrementing iterator past the end."); + if (!(*Doc)->skip()) { + Doc->reset(nullptr); + } else { + Stream &S = (*Doc)->stream; + Doc->reset(new Document(S)); + } + return *this; + } + + Document &operator*() { return *Doc->get(); } + + std::unique_ptr<Document> &operator->() { return *Doc; } + +private: + bool isAtEnd() const { return !Doc || !*Doc; } + + std::unique_ptr<Document> *Doc = nullptr; +}; + +} // end namespace yaml + +} // end namespace llvm + +#endif // LLVM_SUPPORT_YAMLPARSER_H diff --git a/third_party/llvm-project/include/llvm/Support/YAMLTraits.h b/third_party/llvm-project/include/llvm/Support/YAMLTraits.h new file mode 100644 index 000000000..8642069ad --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/YAMLTraits.h @@ -0,0 +1,2043 @@ +//===- llvm/Support/YAMLTraits.h --------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_YAMLTRAITS_H +#define LLVM_SUPPORT_YAMLTRAITS_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/AlignOf.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/YAMLParser.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <cctype> +#include <cstddef> +#include <cstdint> +#include <iterator> +#include <map> +#include <memory> +#include <new> +#include <string> +#include <system_error> +#include <type_traits> +#include <vector> + +namespace llvm { +namespace yaml { + +enum class NodeKind : uint8_t { + Scalar, + Map, + Sequence, +}; + +struct EmptyContext {}; + +/// This class should be specialized by any type that needs to be converted +/// to/from a YAML mapping. For example: +/// +/// struct MappingTraits<MyStruct> { +/// static void mapping(IO &io, MyStruct &s) { +/// io.mapRequired("name", s.name); +/// io.mapRequired("size", s.size); +/// io.mapOptional("age", s.age); +/// } +/// }; +template<class T> +struct MappingTraits { + // Must provide: + // static void mapping(IO &io, T &fields); + // Optionally may provide: + // static StringRef validate(IO &io, T &fields); + // + // The optional flow flag will cause generated YAML to use a flow mapping + // (e.g. { a: 0, b: 1 }): + // static const bool flow = true; +}; + +/// This class is similar to MappingTraits<T> but allows you to pass in +/// additional context for each map operation. For example: +/// +/// struct MappingContextTraits<MyStruct, MyContext> { +/// static void mapping(IO &io, MyStruct &s, MyContext &c) { +/// io.mapRequired("name", s.name); +/// io.mapRequired("size", s.size); +/// io.mapOptional("age", s.age); +/// ++c.TimesMapped; +/// } +/// }; +template <class T, class Context> struct MappingContextTraits { + // Must provide: + // static void mapping(IO &io, T &fields, Context &Ctx); + // Optionally may provide: + // static StringRef validate(IO &io, T &fields, Context &Ctx); + // + // The optional flow flag will cause generated YAML to use a flow mapping + // (e.g. { a: 0, b: 1 }): + // static const bool flow = true; +}; + +/// This class should be specialized by any integral type that converts +/// to/from a YAML scalar where there is a one-to-one mapping between +/// in-memory values and a string in YAML. For example: +/// +/// struct ScalarEnumerationTraits<Colors> { +/// static void enumeration(IO &io, Colors &value) { +/// io.enumCase(value, "red", cRed); +/// io.enumCase(value, "blue", cBlue); +/// io.enumCase(value, "green", cGreen); +/// } +/// }; +template <typename T, typename Enable = void> struct ScalarEnumerationTraits { + // Must provide: + // static void enumeration(IO &io, T &value); +}; + +/// This class should be specialized by any integer type that is a union +/// of bit values and the YAML representation is a flow sequence of +/// strings. For example: +/// +/// struct ScalarBitSetTraits<MyFlags> { +/// static void bitset(IO &io, MyFlags &value) { +/// io.bitSetCase(value, "big", flagBig); +/// io.bitSetCase(value, "flat", flagFlat); +/// io.bitSetCase(value, "round", flagRound); +/// } +/// }; +template <typename T, typename Enable = void> struct ScalarBitSetTraits { + // Must provide: + // static void bitset(IO &io, T &value); +}; + +/// Describe which type of quotes should be used when quoting is necessary. +/// Some non-printable characters need to be double-quoted, while some others +/// are fine with simple-quoting, and some don't need any quoting. +enum class QuotingType { None, Single, Double }; + +/// This class should be specialized by type that requires custom conversion +/// to/from a yaml scalar. For example: +/// +/// template<> +/// struct ScalarTraits<MyType> { +/// static void output(const MyType &val, void*, llvm::raw_ostream &out) { +/// // stream out custom formatting +/// out << llvm::format("%x", val); +/// } +/// static StringRef input(StringRef scalar, void*, MyType &value) { +/// // parse scalar and set `value` +/// // return empty string on success, or error string +/// return StringRef(); +/// } +/// static QuotingType mustQuote(StringRef) { return QuotingType::Single; } +/// }; +template <typename T, typename Enable = void> struct ScalarTraits { + // Must provide: + // + // Function to write the value as a string: + // static void output(const T &value, void *ctxt, llvm::raw_ostream &out); + // + // Function to convert a string to a value. Returns the empty + // StringRef on success or an error string if string is malformed: + // static StringRef input(StringRef scalar, void *ctxt, T &value); + // + // Function to determine if the value should be quoted. + // static QuotingType mustQuote(StringRef); +}; + +/// This class should be specialized by type that requires custom conversion +/// to/from a YAML literal block scalar. For example: +/// +/// template <> +/// struct BlockScalarTraits<MyType> { +/// static void output(const MyType &Value, void*, llvm::raw_ostream &Out) +/// { +/// // stream out custom formatting +/// Out << Value; +/// } +/// static StringRef input(StringRef Scalar, void*, MyType &Value) { +/// // parse scalar and set `value` +/// // return empty string on success, or error string +/// return StringRef(); +/// } +/// }; +template <typename T> +struct BlockScalarTraits { + // Must provide: + // + // Function to write the value as a string: + // static void output(const T &Value, void *ctx, llvm::raw_ostream &Out); + // + // Function to convert a string to a value. Returns the empty + // StringRef on success or an error string if string is malformed: + // static StringRef input(StringRef Scalar, void *ctxt, T &Value); + // + // Optional: + // static StringRef inputTag(T &Val, std::string Tag) + // static void outputTag(const T &Val, raw_ostream &Out) +}; + +/// This class should be specialized by type that requires custom conversion +/// to/from a YAML scalar with optional tags. For example: +/// +/// template <> +/// struct TaggedScalarTraits<MyType> { +/// static void output(const MyType &Value, void*, llvm::raw_ostream +/// &ScalarOut, llvm::raw_ostream &TagOut) +/// { +/// // stream out custom formatting including optional Tag +/// Out << Value; +/// } +/// static StringRef input(StringRef Scalar, StringRef Tag, void*, MyType +/// &Value) { +/// // parse scalar and set `value` +/// // return empty string on success, or error string +/// return StringRef(); +/// } +/// static QuotingType mustQuote(const MyType &Value, StringRef) { +/// return QuotingType::Single; +/// } +/// }; +template <typename T> struct TaggedScalarTraits { + // Must provide: + // + // Function to write the value and tag as strings: + // static void output(const T &Value, void *ctx, llvm::raw_ostream &ScalarOut, + // llvm::raw_ostream &TagOut); + // + // Function to convert a string to a value. Returns the empty + // StringRef on success or an error string if string is malformed: + // static StringRef input(StringRef Scalar, StringRef Tag, void *ctxt, T + // &Value); + // + // Function to determine if the value should be quoted. + // static QuotingType mustQuote(const T &Value, StringRef Scalar); +}; + +/// This class should be specialized by any type that needs to be converted +/// to/from a YAML sequence. For example: +/// +/// template<> +/// struct SequenceTraits<MyContainer> { +/// static size_t size(IO &io, MyContainer &seq) { +/// return seq.size(); +/// } +/// static MyType& element(IO &, MyContainer &seq, size_t index) { +/// if ( index >= seq.size() ) +/// seq.resize(index+1); +/// return seq[index]; +/// } +/// }; +template<typename T, typename EnableIf = void> +struct SequenceTraits { + // Must provide: + // static size_t size(IO &io, T &seq); + // static T::value_type& element(IO &io, T &seq, size_t index); + // + // The following is option and will cause generated YAML to use + // a flow sequence (e.g. [a,b,c]). + // static const bool flow = true; +}; + +/// This class should be specialized by any type for which vectors of that +/// type need to be converted to/from a YAML sequence. +template<typename T, typename EnableIf = void> +struct SequenceElementTraits { + // Must provide: + // static const bool flow; +}; + +/// This class should be specialized by any type that needs to be converted +/// to/from a list of YAML documents. +template<typename T> +struct DocumentListTraits { + // Must provide: + // static size_t size(IO &io, T &seq); + // static T::value_type& element(IO &io, T &seq, size_t index); +}; + +/// This class should be specialized by any type that needs to be converted +/// to/from a YAML mapping in the case where the names of the keys are not known +/// in advance, e.g. a string map. +template <typename T> +struct CustomMappingTraits { + // static void inputOne(IO &io, StringRef key, T &elem); + // static void output(IO &io, T &elem); +}; + +/// This class should be specialized by any type that can be represented as +/// a scalar, map, or sequence, decided dynamically. For example: +/// +/// typedef std::unique_ptr<MyBase> MyPoly; +/// +/// template<> +/// struct PolymorphicTraits<MyPoly> { +/// static NodeKind getKind(const MyPoly &poly) { +/// return poly->getKind(); +/// } +/// static MyScalar& getAsScalar(MyPoly &poly) { +/// if (!poly || !isa<MyScalar>(poly)) +/// poly.reset(new MyScalar()); +/// return *cast<MyScalar>(poly.get()); +/// } +/// // ... +/// }; +template <typename T> struct PolymorphicTraits { + // Must provide: + // static NodeKind getKind(const T &poly); + // static scalar_type &getAsScalar(T &poly); + // static map_type &getAsMap(T &poly); + // static sequence_type &getAsSequence(T &poly); +}; + +// Only used for better diagnostics of missing traits +template <typename T> +struct MissingTrait; + +// Test if ScalarEnumerationTraits<T> is defined on type T. +template <class T> +struct has_ScalarEnumerationTraits +{ + using Signature_enumeration = void (*)(class IO&, T&); + + template <typename U> + static char test(SameType<Signature_enumeration, &U::enumeration>*); + + template <typename U> + static double test(...); + + static bool const value = + (sizeof(test<ScalarEnumerationTraits<T>>(nullptr)) == 1); +}; + +// Test if ScalarBitSetTraits<T> is defined on type T. +template <class T> +struct has_ScalarBitSetTraits +{ + using Signature_bitset = void (*)(class IO&, T&); + + template <typename U> + static char test(SameType<Signature_bitset, &U::bitset>*); + + template <typename U> + static double test(...); + + static bool const value = (sizeof(test<ScalarBitSetTraits<T>>(nullptr)) == 1); +}; + +// Test if ScalarTraits<T> is defined on type T. +template <class T> +struct has_ScalarTraits +{ + using Signature_input = StringRef (*)(StringRef, void*, T&); + using Signature_output = void (*)(const T&, void*, raw_ostream&); + using Signature_mustQuote = QuotingType (*)(StringRef); + + template <typename U> + static char test(SameType<Signature_input, &U::input> *, + SameType<Signature_output, &U::output> *, + SameType<Signature_mustQuote, &U::mustQuote> *); + + template <typename U> + static double test(...); + + static bool const value = + (sizeof(test<ScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1); +}; + +// Test if BlockScalarTraits<T> is defined on type T. +template <class T> +struct has_BlockScalarTraits +{ + using Signature_input = StringRef (*)(StringRef, void *, T &); + using Signature_output = void (*)(const T &, void *, raw_ostream &); + + template <typename U> + static char test(SameType<Signature_input, &U::input> *, + SameType<Signature_output, &U::output> *); + + template <typename U> + static double test(...); + + static bool const value = + (sizeof(test<BlockScalarTraits<T>>(nullptr, nullptr)) == 1); +}; + +// Test if TaggedScalarTraits<T> is defined on type T. +template <class T> struct has_TaggedScalarTraits { + using Signature_input = StringRef (*)(StringRef, StringRef, void *, T &); + using Signature_output = void (*)(const T &, void *, raw_ostream &, + raw_ostream &); + using Signature_mustQuote = QuotingType (*)(const T &, StringRef); + + template <typename U> + static char test(SameType<Signature_input, &U::input> *, + SameType<Signature_output, &U::output> *, + SameType<Signature_mustQuote, &U::mustQuote> *); + + template <typename U> static double test(...); + + static bool const value = + (sizeof(test<TaggedScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1); +}; + +// Test if MappingContextTraits<T> is defined on type T. +template <class T, class Context> struct has_MappingTraits { + using Signature_mapping = void (*)(class IO &, T &, Context &); + + template <typename U> + static char test(SameType<Signature_mapping, &U::mapping>*); + + template <typename U> + static double test(...); + + static bool const value = + (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); +}; + +// Test if MappingTraits<T> is defined on type T. +template <class T> struct has_MappingTraits<T, EmptyContext> { + using Signature_mapping = void (*)(class IO &, T &); + + template <typename U> + static char test(SameType<Signature_mapping, &U::mapping> *); + + template <typename U> static double test(...); + + static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); +}; + +// Test if MappingContextTraits<T>::validate() is defined on type T. +template <class T, class Context> struct has_MappingValidateTraits { + using Signature_validate = StringRef (*)(class IO &, T &, Context &); + + template <typename U> + static char test(SameType<Signature_validate, &U::validate>*); + + template <typename U> + static double test(...); + + static bool const value = + (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); +}; + +// Test if MappingTraits<T>::validate() is defined on type T. +template <class T> struct has_MappingValidateTraits<T, EmptyContext> { + using Signature_validate = StringRef (*)(class IO &, T &); + + template <typename U> + static char test(SameType<Signature_validate, &U::validate> *); + + template <typename U> static double test(...); + + static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); +}; + +// Test if SequenceTraits<T> is defined on type T. +template <class T> +struct has_SequenceMethodTraits +{ + using Signature_size = size_t (*)(class IO&, T&); + + template <typename U> + static char test(SameType<Signature_size, &U::size>*); + + template <typename U> + static double test(...); + + static bool const value = (sizeof(test<SequenceTraits<T>>(nullptr)) == 1); +}; + +// Test if CustomMappingTraits<T> is defined on type T. +template <class T> +struct has_CustomMappingTraits +{ + using Signature_input = void (*)(IO &io, StringRef key, T &v); + + template <typename U> + static char test(SameType<Signature_input, &U::inputOne>*); + + template <typename U> + static double test(...); + + static bool const value = + (sizeof(test<CustomMappingTraits<T>>(nullptr)) == 1); +}; + +// has_FlowTraits<int> will cause an error with some compilers because +// it subclasses int. Using this wrapper only instantiates the +// real has_FlowTraits only if the template type is a class. +template <typename T, bool Enabled = std::is_class<T>::value> +class has_FlowTraits +{ +public: + static const bool value = false; +}; + +// Some older gcc compilers don't support straight forward tests +// for members, so test for ambiguity cause by the base and derived +// classes both defining the member. +template <class T> +struct has_FlowTraits<T, true> +{ + struct Fallback { bool flow; }; + struct Derived : T, Fallback { }; + + template<typename C> + static char (&f(SameType<bool Fallback::*, &C::flow>*))[1]; + + template<typename C> + static char (&f(...))[2]; + + static bool const value = sizeof(f<Derived>(nullptr)) == 2; +}; + +// Test if SequenceTraits<T> is defined on type T +template<typename T> +struct has_SequenceTraits : public std::integral_constant<bool, + has_SequenceMethodTraits<T>::value > { }; + +// Test if DocumentListTraits<T> is defined on type T +template <class T> +struct has_DocumentListTraits +{ + using Signature_size = size_t (*)(class IO &, T &); + + template <typename U> + static char test(SameType<Signature_size, &U::size>*); + + template <typename U> + static double test(...); + + static bool const value = (sizeof(test<DocumentListTraits<T>>(nullptr))==1); +}; + +template <class T> struct has_PolymorphicTraits { + using Signature_getKind = NodeKind (*)(const T &); + + template <typename U> + static char test(SameType<Signature_getKind, &U::getKind> *); + + template <typename U> static double test(...); + + static bool const value = (sizeof(test<PolymorphicTraits<T>>(nullptr)) == 1); +}; + +inline bool isNumeric(StringRef S) { + const static auto skipDigits = [](StringRef Input) { + return Input.drop_front( + std::min(Input.find_first_not_of("0123456789"), Input.size())); + }; + + // Make S.front() and S.drop_front().front() (if S.front() is [+-]) calls + // safe. + if (S.empty() || S.equals("+") || S.equals("-")) + return false; + + if (S.equals(".nan") || S.equals(".NaN") || S.equals(".NAN")) + return true; + + // Infinity and decimal numbers can be prefixed with sign. + StringRef Tail = (S.front() == '-' || S.front() == '+') ? S.drop_front() : S; + + // Check for infinity first, because checking for hex and oct numbers is more + // expensive. + if (Tail.equals(".inf") || Tail.equals(".Inf") || Tail.equals(".INF")) + return true; + + // Section 10.3.2 Tag Resolution + // YAML 1.2 Specification prohibits Base 8 and Base 16 numbers prefixed with + // [-+], so S should be used instead of Tail. + if (S.startswith("0o")) + return S.size() > 2 && + S.drop_front(2).find_first_not_of("01234567") == StringRef::npos; + + if (S.startswith("0x")) + return S.size() > 2 && S.drop_front(2).find_first_not_of( + "0123456789abcdefABCDEF") == StringRef::npos; + + // Parse float: [-+]? (\. [0-9]+ | [0-9]+ (\. [0-9]* )?) ([eE] [-+]? [0-9]+)? + S = Tail; + + // Handle cases when the number starts with '.' and hence needs at least one + // digit after dot (as opposed by number which has digits before the dot), but + // doesn't have one. + if (S.startswith(".") && + (S.equals(".") || + (S.size() > 1 && std::strchr("0123456789", S[1]) == nullptr))) + return false; + + if (S.startswith("E") || S.startswith("e")) + return false; + + enum ParseState { + Default, + FoundDot, + FoundExponent, + }; + ParseState State = Default; + + S = skipDigits(S); + + // Accept decimal integer. + if (S.empty()) + return true; + + if (S.front() == '.') { + State = FoundDot; + S = S.drop_front(); + } else if (S.front() == 'e' || S.front() == 'E') { + State = FoundExponent; + S = S.drop_front(); + } else { + return false; + } + + if (State == FoundDot) { + S = skipDigits(S); + if (S.empty()) + return true; + + if (S.front() == 'e' || S.front() == 'E') { + State = FoundExponent; + S = S.drop_front(); + } else { + return false; + } + } + + assert(State == FoundExponent && "Should have found exponent at this point."); + if (S.empty()) + return false; + + if (S.front() == '+' || S.front() == '-') { + S = S.drop_front(); + if (S.empty()) + return false; + } + + return skipDigits(S).empty(); +} + +inline bool isNull(StringRef S) { + return S.equals("null") || S.equals("Null") || S.equals("NULL") || + S.equals("~"); +} + +inline bool isBool(StringRef S) { + return S.equals("true") || S.equals("True") || S.equals("TRUE") || + S.equals("false") || S.equals("False") || S.equals("FALSE"); +} + +// 5.1. Character Set +// The allowed character range explicitly excludes the C0 control block #x0-#x1F +// (except for TAB #x9, LF #xA, and CR #xD which are allowed), DEL #x7F, the C1 +// control block #x80-#x9F (except for NEL #x85 which is allowed), the surrogate +// block #xD800-#xDFFF, #xFFFE, and #xFFFF. +inline QuotingType needsQuotes(StringRef S) { + if (S.empty()) + return QuotingType::Single; + if (isspace(static_cast<unsigned char>(S.front())) || + isspace(static_cast<unsigned char>(S.back()))) + return QuotingType::Single; + if (isNull(S)) + return QuotingType::Single; + if (isBool(S)) + return QuotingType::Single; + if (isNumeric(S)) + return QuotingType::Single; + + // 7.3.3 Plain Style + // Plain scalars must not begin with most indicators, as this would cause + // ambiguity with other YAML constructs. + static constexpr char Indicators[] = R"(-?:\,[]{}#&*!|>'"%@`)"; + if (S.find_first_of(Indicators) == 0) + return QuotingType::Single; + + QuotingType MaxQuotingNeeded = QuotingType::None; + for (unsigned char C : S) { + // Alphanum is safe. + if (isAlnum(C)) + continue; + + switch (C) { + // Safe scalar characters. + case '_': + case '-': + case '^': + case '.': + case ',': + case ' ': + // TAB (0x9) is allowed in unquoted strings. + case 0x9: + continue; + // LF(0xA) and CR(0xD) may delimit values and so require at least single + // quotes. + case 0xA: + case 0xD: + MaxQuotingNeeded = QuotingType::Single; + continue; + // DEL (0x7F) are excluded from the allowed character range. + case 0x7F: + return QuotingType::Double; + // Forward slash is allowed to be unquoted, but we quote it anyway. We have + // many tests that use FileCheck against YAML output, and this output often + // contains paths. If we quote backslashes but not forward slashes then + // paths will come out either quoted or unquoted depending on which platform + // the test is run on, making FileCheck comparisons difficult. + case '/': + default: { + // C0 control block (0x0 - 0x1F) is excluded from the allowed character + // range. + if (C <= 0x1F) + return QuotingType::Double; + + // Always double quote UTF-8. + if ((C & 0x80) != 0) + return QuotingType::Double; + + // The character is not safe, at least simple quoting needed. + MaxQuotingNeeded = QuotingType::Single; + } + } + } + + return MaxQuotingNeeded; +} + +template <typename T, typename Context> +struct missingTraits + : public std::integral_constant<bool, + !has_ScalarEnumerationTraits<T>::value && + !has_ScalarBitSetTraits<T>::value && + !has_ScalarTraits<T>::value && + !has_BlockScalarTraits<T>::value && + !has_TaggedScalarTraits<T>::value && + !has_MappingTraits<T, Context>::value && + !has_SequenceTraits<T>::value && + !has_CustomMappingTraits<T>::value && + !has_DocumentListTraits<T>::value && + !has_PolymorphicTraits<T>::value> {}; + +template <typename T, typename Context> +struct validatedMappingTraits + : public std::integral_constant< + bool, has_MappingTraits<T, Context>::value && + has_MappingValidateTraits<T, Context>::value> {}; + +template <typename T, typename Context> +struct unvalidatedMappingTraits + : public std::integral_constant< + bool, has_MappingTraits<T, Context>::value && + !has_MappingValidateTraits<T, Context>::value> {}; + +// Base class for Input and Output. +class IO { +public: + IO(void *Ctxt = nullptr); + virtual ~IO(); + + virtual bool outputting() const = 0; + + virtual unsigned beginSequence() = 0; + virtual bool preflightElement(unsigned, void *&) = 0; + virtual void postflightElement(void*) = 0; + virtual void endSequence() = 0; + virtual bool canElideEmptySequence() = 0; + + virtual unsigned beginFlowSequence() = 0; + virtual bool preflightFlowElement(unsigned, void *&) = 0; + virtual void postflightFlowElement(void*) = 0; + virtual void endFlowSequence() = 0; + + virtual bool mapTag(StringRef Tag, bool Default=false) = 0; + virtual void beginMapping() = 0; + virtual void endMapping() = 0; + virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0; + virtual void postflightKey(void*) = 0; + virtual std::vector<StringRef> keys() = 0; + + virtual void beginFlowMapping() = 0; + virtual void endFlowMapping() = 0; + + virtual void beginEnumScalar() = 0; + virtual bool matchEnumScalar(const char*, bool) = 0; + virtual bool matchEnumFallback() = 0; + virtual void endEnumScalar() = 0; + + virtual bool beginBitSetScalar(bool &) = 0; + virtual bool bitSetMatch(const char*, bool) = 0; + virtual void endBitSetScalar() = 0; + + virtual void scalarString(StringRef &, QuotingType) = 0; + virtual void blockScalarString(StringRef &) = 0; + virtual void scalarTag(std::string &) = 0; + + virtual NodeKind getNodeKind() = 0; + + virtual void setError(const Twine &) = 0; + + template <typename T> + void enumCase(T &Val, const char* Str, const T ConstVal) { + if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) { + Val = ConstVal; + } + } + + // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF + template <typename T> + void enumCase(T &Val, const char* Str, const uint32_t ConstVal) { + if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) { + Val = ConstVal; + } + } + + template <typename FBT, typename T> + void enumFallback(T &Val) { + if (matchEnumFallback()) { + EmptyContext Context; + // FIXME: Force integral conversion to allow strong typedefs to convert. + FBT Res = static_cast<typename FBT::BaseType>(Val); + yamlize(*this, Res, true, Context); + Val = static_cast<T>(static_cast<typename FBT::BaseType>(Res)); + } + } + + template <typename T> + void bitSetCase(T &Val, const char* Str, const T ConstVal) { + if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { + Val = static_cast<T>(Val | ConstVal); + } + } + + // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF + template <typename T> + void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) { + if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { + Val = static_cast<T>(Val | ConstVal); + } + } + + template <typename T> + void maskedBitSetCase(T &Val, const char *Str, T ConstVal, T Mask) { + if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal)) + Val = Val | ConstVal; + } + + template <typename T> + void maskedBitSetCase(T &Val, const char *Str, uint32_t ConstVal, + uint32_t Mask) { + if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal)) + Val = Val | ConstVal; + } + + void *getContext() const; + void setContext(void *); + + template <typename T> void mapRequired(const char *Key, T &Val) { + EmptyContext Ctx; + this->processKey(Key, Val, true, Ctx); + } + + template <typename T, typename Context> + void mapRequired(const char *Key, T &Val, Context &Ctx) { + this->processKey(Key, Val, true, Ctx); + } + + template <typename T> void mapOptional(const char *Key, T &Val) { + EmptyContext Ctx; + mapOptionalWithContext(Key, Val, Ctx); + } + + template <typename T, typename DefaultT> + void mapOptional(const char *Key, T &Val, const DefaultT &Default) { + EmptyContext Ctx; + mapOptionalWithContext(Key, Val, Default, Ctx); + } + + template <typename T, typename Context> + typename std::enable_if<has_SequenceTraits<T>::value, void>::type + mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) { + // omit key/value instead of outputting empty sequence + if (this->canElideEmptySequence() && !(Val.begin() != Val.end())) + return; + this->processKey(Key, Val, false, Ctx); + } + + template <typename T, typename Context> + void mapOptionalWithContext(const char *Key, Optional<T> &Val, Context &Ctx) { + this->processKeyWithDefault(Key, Val, Optional<T>(), /*Required=*/false, + Ctx); + } + + template <typename T, typename Context> + typename std::enable_if<!has_SequenceTraits<T>::value, void>::type + mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) { + this->processKey(Key, Val, false, Ctx); + } + + template <typename T, typename Context, typename DefaultT> + void mapOptionalWithContext(const char *Key, T &Val, const DefaultT &Default, + Context &Ctx) { + static_assert(std::is_convertible<DefaultT, T>::value, + "Default type must be implicitly convertible to value type!"); + this->processKeyWithDefault(Key, Val, static_cast<const T &>(Default), + false, Ctx); + } + +private: + template <typename T, typename Context> + void processKeyWithDefault(const char *Key, Optional<T> &Val, + const Optional<T> &DefaultValue, bool Required, + Context &Ctx) { + assert(DefaultValue.hasValue() == false && + "Optional<T> shouldn't have a value!"); + void *SaveInfo; + bool UseDefault = true; + const bool sameAsDefault = outputting() && !Val.hasValue(); + if (!outputting() && !Val.hasValue()) + Val = T(); + if (Val.hasValue() && + this->preflightKey(Key, Required, sameAsDefault, UseDefault, + SaveInfo)) { + yamlize(*this, Val.getValue(), Required, Ctx); + this->postflightKey(SaveInfo); + } else { + if (UseDefault) + Val = DefaultValue; + } + } + + template <typename T, typename Context> + void processKeyWithDefault(const char *Key, T &Val, const T &DefaultValue, + bool Required, Context &Ctx) { + void *SaveInfo; + bool UseDefault; + const bool sameAsDefault = outputting() && Val == DefaultValue; + if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault, + SaveInfo) ) { + yamlize(*this, Val, Required, Ctx); + this->postflightKey(SaveInfo); + } + else { + if ( UseDefault ) + Val = DefaultValue; + } + } + + template <typename T, typename Context> + void processKey(const char *Key, T &Val, bool Required, Context &Ctx) { + void *SaveInfo; + bool UseDefault; + if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) { + yamlize(*this, Val, Required, Ctx); + this->postflightKey(SaveInfo); + } + } + +private: + void *Ctxt; +}; + +namespace detail { + +template <typename T, typename Context> +void doMapping(IO &io, T &Val, Context &Ctx) { + MappingContextTraits<T, Context>::mapping(io, Val, Ctx); +} + +template <typename T> void doMapping(IO &io, T &Val, EmptyContext &Ctx) { + MappingTraits<T>::mapping(io, Val); +} + +} // end namespace detail + +template <typename T> +typename std::enable_if<has_ScalarEnumerationTraits<T>::value, void>::type +yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { + io.beginEnumScalar(); + ScalarEnumerationTraits<T>::enumeration(io, Val); + io.endEnumScalar(); +} + +template <typename T> +typename std::enable_if<has_ScalarBitSetTraits<T>::value, void>::type +yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { + bool DoClear; + if ( io.beginBitSetScalar(DoClear) ) { + if ( DoClear ) + Val = T(); + ScalarBitSetTraits<T>::bitset(io, Val); + io.endBitSetScalar(); + } +} + +template <typename T> +typename std::enable_if<has_ScalarTraits<T>::value, void>::type +yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { + if ( io.outputting() ) { + std::string Storage; + raw_string_ostream Buffer(Storage); + ScalarTraits<T>::output(Val, io.getContext(), Buffer); + StringRef Str = Buffer.str(); + io.scalarString(Str, ScalarTraits<T>::mustQuote(Str)); + } + else { + StringRef Str; + io.scalarString(Str, ScalarTraits<T>::mustQuote(Str)); + StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val); + if ( !Result.empty() ) { + io.setError(Twine(Result)); + } + } +} + +template <typename T> +typename std::enable_if<has_BlockScalarTraits<T>::value, void>::type +yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) { + if (YamlIO.outputting()) { + std::string Storage; + raw_string_ostream Buffer(Storage); + BlockScalarTraits<T>::output(Val, YamlIO.getContext(), Buffer); + StringRef Str = Buffer.str(); + YamlIO.blockScalarString(Str); + } else { + StringRef Str; + YamlIO.blockScalarString(Str); + StringRef Result = + BlockScalarTraits<T>::input(Str, YamlIO.getContext(), Val); + if (!Result.empty()) + YamlIO.setError(Twine(Result)); + } +} + +template <typename T> +typename std::enable_if<has_TaggedScalarTraits<T>::value, void>::type +yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { + if (io.outputting()) { + std::string ScalarStorage, TagStorage; + raw_string_ostream ScalarBuffer(ScalarStorage), TagBuffer(TagStorage); + TaggedScalarTraits<T>::output(Val, io.getContext(), ScalarBuffer, + TagBuffer); + io.scalarTag(TagBuffer.str()); + StringRef ScalarStr = ScalarBuffer.str(); + io.scalarString(ScalarStr, + TaggedScalarTraits<T>::mustQuote(Val, ScalarStr)); + } else { + std::string Tag; + io.scalarTag(Tag); + StringRef Str; + io.scalarString(Str, QuotingType::None); + StringRef Result = + TaggedScalarTraits<T>::input(Str, Tag, io.getContext(), Val); + if (!Result.empty()) { + io.setError(Twine(Result)); + } + } +} + +template <typename T, typename Context> +typename std::enable_if<validatedMappingTraits<T, Context>::value, void>::type +yamlize(IO &io, T &Val, bool, Context &Ctx) { + if (has_FlowTraits<MappingTraits<T>>::value) + io.beginFlowMapping(); + else + io.beginMapping(); + if (io.outputting()) { + StringRef Err = MappingTraits<T>::validate(io, Val); + if (!Err.empty()) { + errs() << Err << "\n"; + assert(Err.empty() && "invalid struct trying to be written as yaml"); + } + } + detail::doMapping(io, Val, Ctx); + if (!io.outputting()) { + StringRef Err = MappingTraits<T>::validate(io, Val); + if (!Err.empty()) + io.setError(Err); + } + if (has_FlowTraits<MappingTraits<T>>::value) + io.endFlowMapping(); + else + io.endMapping(); +} + +template <typename T, typename Context> +typename std::enable_if<unvalidatedMappingTraits<T, Context>::value, void>::type +yamlize(IO &io, T &Val, bool, Context &Ctx) { + if (has_FlowTraits<MappingTraits<T>>::value) { + io.beginFlowMapping(); + detail::doMapping(io, Val, Ctx); + io.endFlowMapping(); + } else { + io.beginMapping(); + detail::doMapping(io, Val, Ctx); + io.endMapping(); + } +} + +template <typename T> +typename std::enable_if<has_CustomMappingTraits<T>::value, void>::type +yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { + if ( io.outputting() ) { + io.beginMapping(); + CustomMappingTraits<T>::output(io, Val); + io.endMapping(); + } else { + io.beginMapping(); + for (StringRef key : io.keys()) + CustomMappingTraits<T>::inputOne(io, key, Val); + io.endMapping(); + } +} + +template <typename T> +typename std::enable_if<has_PolymorphicTraits<T>::value, void>::type +yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { + switch (io.outputting() ? PolymorphicTraits<T>::getKind(Val) + : io.getNodeKind()) { + case NodeKind::Scalar: + return yamlize(io, PolymorphicTraits<T>::getAsScalar(Val), true, Ctx); + case NodeKind::Map: + return yamlize(io, PolymorphicTraits<T>::getAsMap(Val), true, Ctx); + case NodeKind::Sequence: + return yamlize(io, PolymorphicTraits<T>::getAsSequence(Val), true, Ctx); + } +} + +template <typename T> +typename std::enable_if<missingTraits<T, EmptyContext>::value, void>::type +yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { + char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; +} + +template <typename T, typename Context> +typename std::enable_if<has_SequenceTraits<T>::value, void>::type +yamlize(IO &io, T &Seq, bool, Context &Ctx) { + if ( has_FlowTraits< SequenceTraits<T>>::value ) { + unsigned incnt = io.beginFlowSequence(); + unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; + for(unsigned i=0; i < count; ++i) { + void *SaveInfo; + if ( io.preflightFlowElement(i, SaveInfo) ) { + yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx); + io.postflightFlowElement(SaveInfo); + } + } + io.endFlowSequence(); + } + else { + unsigned incnt = io.beginSequence(); + unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; + for(unsigned i=0; i < count; ++i) { + void *SaveInfo; + if ( io.preflightElement(i, SaveInfo) ) { + yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx); + io.postflightElement(SaveInfo); + } + } + io.endSequence(); + } +} + +template<> +struct ScalarTraits<bool> { + static void output(const bool &, void* , raw_ostream &); + static StringRef input(StringRef, void *, bool &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template<> +struct ScalarTraits<StringRef> { + static void output(const StringRef &, void *, raw_ostream &); + static StringRef input(StringRef, void *, StringRef &); + static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } +}; + +template<> +struct ScalarTraits<std::string> { + static void output(const std::string &, void *, raw_ostream &); + static StringRef input(StringRef, void *, std::string &); + static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } +}; + +template<> +struct ScalarTraits<uint8_t> { + static void output(const uint8_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, uint8_t &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template<> +struct ScalarTraits<uint16_t> { + static void output(const uint16_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, uint16_t &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template<> +struct ScalarTraits<uint32_t> { + static void output(const uint32_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, uint32_t &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template<> +struct ScalarTraits<uint64_t> { + static void output(const uint64_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, uint64_t &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template<> +struct ScalarTraits<int8_t> { + static void output(const int8_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, int8_t &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template<> +struct ScalarTraits<int16_t> { + static void output(const int16_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, int16_t &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template<> +struct ScalarTraits<int32_t> { + static void output(const int32_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, int32_t &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template<> +struct ScalarTraits<int64_t> { + static void output(const int64_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, int64_t &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template<> +struct ScalarTraits<float> { + static void output(const float &, void *, raw_ostream &); + static StringRef input(StringRef, void *, float &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template<> +struct ScalarTraits<double> { + static void output(const double &, void *, raw_ostream &); + static StringRef input(StringRef, void *, double &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +// For endian types, we use existing scalar Traits class for the underlying +// type. This way endian aware types are supported whenever the traits are +// defined for the underlying type. +template <typename value_type, support::endianness endian, size_t alignment> +struct ScalarTraits< + support::detail::packed_endian_specific_integral<value_type, endian, + alignment>, + typename std::enable_if<has_ScalarTraits<value_type>::value>::type> { + using endian_type = + support::detail::packed_endian_specific_integral<value_type, endian, + alignment>; + + static void output(const endian_type &E, void *Ctx, raw_ostream &Stream) { + ScalarTraits<value_type>::output(static_cast<value_type>(E), Ctx, Stream); + } + + static StringRef input(StringRef Str, void *Ctx, endian_type &E) { + value_type V; + auto R = ScalarTraits<value_type>::input(Str, Ctx, V); + E = static_cast<endian_type>(V); + return R; + } + + static QuotingType mustQuote(StringRef Str) { + return ScalarTraits<value_type>::mustQuote(Str); + } +}; + +template <typename value_type, support::endianness endian, size_t alignment> +struct ScalarEnumerationTraits< + support::detail::packed_endian_specific_integral<value_type, endian, + alignment>, + typename std::enable_if< + has_ScalarEnumerationTraits<value_type>::value>::type> { + using endian_type = + support::detail::packed_endian_specific_integral<value_type, endian, + alignment>; + + static void enumeration(IO &io, endian_type &E) { + value_type V = E; + ScalarEnumerationTraits<value_type>::enumeration(io, V); + E = V; + } +}; + +template <typename value_type, support::endianness endian, size_t alignment> +struct ScalarBitSetTraits< + support::detail::packed_endian_specific_integral<value_type, endian, + alignment>, + typename std::enable_if<has_ScalarBitSetTraits<value_type>::value>::type> { + using endian_type = + support::detail::packed_endian_specific_integral<value_type, endian, + alignment>; + static void bitset(IO &io, endian_type &E) { + value_type V = E; + ScalarBitSetTraits<value_type>::bitset(io, V); + E = V; + } +}; + +// Utility for use within MappingTraits<>::mapping() method +// to [de]normalize an object for use with YAML conversion. +template <typename TNorm, typename TFinal> +struct MappingNormalization { + MappingNormalization(IO &i_o, TFinal &Obj) + : io(i_o), BufPtr(nullptr), Result(Obj) { + if ( io.outputting() ) { + BufPtr = new (&Buffer) TNorm(io, Obj); + } + else { + BufPtr = new (&Buffer) TNorm(io); + } + } + + ~MappingNormalization() { + if ( ! io.outputting() ) { + Result = BufPtr->denormalize(io); + } + BufPtr->~TNorm(); + } + + TNorm* operator->() { return BufPtr; } + +private: + using Storage = AlignedCharArrayUnion<TNorm>; + + Storage Buffer; + IO &io; + TNorm *BufPtr; + TFinal &Result; +}; + +// Utility for use within MappingTraits<>::mapping() method +// to [de]normalize an object for use with YAML conversion. +template <typename TNorm, typename TFinal> +struct MappingNormalizationHeap { + MappingNormalizationHeap(IO &i_o, TFinal &Obj, BumpPtrAllocator *allocator) + : io(i_o), Result(Obj) { + if ( io.outputting() ) { + BufPtr = new (&Buffer) TNorm(io, Obj); + } + else if (allocator) { + BufPtr = allocator->Allocate<TNorm>(); + new (BufPtr) TNorm(io); + } else { + BufPtr = new TNorm(io); + } + } + + ~MappingNormalizationHeap() { + if ( io.outputting() ) { + BufPtr->~TNorm(); + } + else { + Result = BufPtr->denormalize(io); + } + } + + TNorm* operator->() { return BufPtr; } + +private: + using Storage = AlignedCharArrayUnion<TNorm>; + + Storage Buffer; + IO &io; + TNorm *BufPtr = nullptr; + TFinal &Result; +}; + +/// +/// The Input class is used to parse a yaml document into in-memory structs +/// and vectors. +/// +/// It works by using YAMLParser to do a syntax parse of the entire yaml +/// document, then the Input class builds a graph of HNodes which wraps +/// each yaml Node. The extra layer is buffering. The low level yaml +/// parser only lets you look at each node once. The buffering layer lets +/// you search and interate multiple times. This is necessary because +/// the mapRequired() method calls may not be in the same order +/// as the keys in the document. +/// +class Input : public IO { +public: + // Construct a yaml Input object from a StringRef and optional + // user-data. The DiagHandler can be specified to provide + // alternative error reporting. + Input(StringRef InputContent, + void *Ctxt = nullptr, + SourceMgr::DiagHandlerTy DiagHandler = nullptr, + void *DiagHandlerCtxt = nullptr); + Input(MemoryBufferRef Input, + void *Ctxt = nullptr, + SourceMgr::DiagHandlerTy DiagHandler = nullptr, + void *DiagHandlerCtxt = nullptr); + ~Input() override; + + // Check if there was an syntax or semantic error during parsing. + std::error_code error(); + +private: + bool outputting() const override; + bool mapTag(StringRef, bool) override; + void beginMapping() override; + void endMapping() override; + bool preflightKey(const char *, bool, bool, bool &, void *&) override; + void postflightKey(void *) override; + std::vector<StringRef> keys() override; + void beginFlowMapping() override; + void endFlowMapping() override; + unsigned beginSequence() override; + void endSequence() override; + bool preflightElement(unsigned index, void *&) override; + void postflightElement(void *) override; + unsigned beginFlowSequence() override; + bool preflightFlowElement(unsigned , void *&) override; + void postflightFlowElement(void *) override; + void endFlowSequence() override; + void beginEnumScalar() override; + bool matchEnumScalar(const char*, bool) override; + bool matchEnumFallback() override; + void endEnumScalar() override; + bool beginBitSetScalar(bool &) override; + bool bitSetMatch(const char *, bool ) override; + void endBitSetScalar() override; + void scalarString(StringRef &, QuotingType) override; + void blockScalarString(StringRef &) override; + void scalarTag(std::string &) override; + NodeKind getNodeKind() override; + void setError(const Twine &message) override; + bool canElideEmptySequence() override; + + class HNode { + virtual void anchor(); + + public: + HNode(Node *n) : _node(n) { } + virtual ~HNode() = default; + + static bool classof(const HNode *) { return true; } + + Node *_node; + }; + + class EmptyHNode : public HNode { + void anchor() override; + + public: + EmptyHNode(Node *n) : HNode(n) { } + + static bool classof(const HNode *n) { return NullNode::classof(n->_node); } + + static bool classof(const EmptyHNode *) { return true; } + }; + + class ScalarHNode : public HNode { + void anchor() override; + + public: + ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { } + + StringRef value() const { return _value; } + + static bool classof(const HNode *n) { + return ScalarNode::classof(n->_node) || + BlockScalarNode::classof(n->_node); + } + + static bool classof(const ScalarHNode *) { return true; } + + protected: + StringRef _value; + }; + + class MapHNode : public HNode { + void anchor() override; + + public: + MapHNode(Node *n) : HNode(n) { } + + static bool classof(const HNode *n) { + return MappingNode::classof(n->_node); + } + + static bool classof(const MapHNode *) { return true; } + + using NameToNode = StringMap<std::unique_ptr<HNode>>; + + NameToNode Mapping; + SmallVector<std::string, 6> ValidKeys; + }; + + class SequenceHNode : public HNode { + void anchor() override; + + public: + SequenceHNode(Node *n) : HNode(n) { } + + static bool classof(const HNode *n) { + return SequenceNode::classof(n->_node); + } + + static bool classof(const SequenceHNode *) { return true; } + + std::vector<std::unique_ptr<HNode>> Entries; + }; + + std::unique_ptr<Input::HNode> createHNodes(Node *node); + void setError(HNode *hnode, const Twine &message); + void setError(Node *node, const Twine &message); + +public: + // These are only used by operator>>. They could be private + // if those templated things could be made friends. + bool setCurrentDocument(); + bool nextDocument(); + + /// Returns the current node that's being parsed by the YAML Parser. + const Node *getCurrentNode() const; + +private: + SourceMgr SrcMgr; // must be before Strm + std::unique_ptr<llvm::yaml::Stream> Strm; + std::unique_ptr<HNode> TopNode; + std::error_code EC; + BumpPtrAllocator StringAllocator; + document_iterator DocIterator; + std::vector<bool> BitValuesUsed; + HNode *CurrentNode = nullptr; + bool ScalarMatchFound = false; +}; + +/// +/// The Output class is used to generate a yaml document from in-memory structs +/// and vectors. +/// +class Output : public IO { +public: + Output(raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70); + ~Output() override; + + /// Set whether or not to output optional values which are equal + /// to the default value. By default, when outputting if you attempt + /// to write a value that is equal to the default, the value gets ignored. + /// Sometimes, it is useful to be able to see these in the resulting YAML + /// anyway. + void setWriteDefaultValues(bool Write) { WriteDefaultValues = Write; } + + bool outputting() const override; + bool mapTag(StringRef, bool) override; + void beginMapping() override; + void endMapping() override; + bool preflightKey(const char *key, bool, bool, bool &, void *&) override; + void postflightKey(void *) override; + std::vector<StringRef> keys() override; + void beginFlowMapping() override; + void endFlowMapping() override; + unsigned beginSequence() override; + void endSequence() override; + bool preflightElement(unsigned, void *&) override; + void postflightElement(void *) override; + unsigned beginFlowSequence() override; + bool preflightFlowElement(unsigned, void *&) override; + void postflightFlowElement(void *) override; + void endFlowSequence() override; + void beginEnumScalar() override; + bool matchEnumScalar(const char*, bool) override; + bool matchEnumFallback() override; + void endEnumScalar() override; + bool beginBitSetScalar(bool &) override; + bool bitSetMatch(const char *, bool ) override; + void endBitSetScalar() override; + void scalarString(StringRef &, QuotingType) override; + void blockScalarString(StringRef &) override; + void scalarTag(std::string &) override; + NodeKind getNodeKind() override; + void setError(const Twine &message) override; + bool canElideEmptySequence() override; + + // These are only used by operator<<. They could be private + // if that templated operator could be made a friend. + void beginDocuments(); + bool preflightDocument(unsigned); + void postflightDocument(); + void endDocuments(); + +private: + void output(StringRef s); + void outputUpToEndOfLine(StringRef s); + void newLineCheck(); + void outputNewLine(); + void paddedKey(StringRef key); + void flowKey(StringRef Key); + + enum InState { + inSeqFirstElement, + inSeqOtherElement, + inFlowSeqFirstElement, + inFlowSeqOtherElement, + inMapFirstKey, + inMapOtherKey, + inFlowMapFirstKey, + inFlowMapOtherKey + }; + + static bool inSeqAnyElement(InState State); + static bool inFlowSeqAnyElement(InState State); + static bool inMapAnyKey(InState State); + static bool inFlowMapAnyKey(InState State); + + raw_ostream &Out; + int WrapColumn; + SmallVector<InState, 8> StateStack; + int Column = 0; + int ColumnAtFlowStart = 0; + int ColumnAtMapFlowStart = 0; + bool NeedBitValueComma = false; + bool NeedFlowSequenceComma = false; + bool EnumerationMatchFound = false; + bool WriteDefaultValues = false; + StringRef Padding; + StringRef PaddingBeforeContainer; +}; + +/// YAML I/O does conversion based on types. But often native data types +/// are just a typedef of built in intergral types (e.g. int). But the C++ +/// type matching system sees through the typedef and all the typedefed types +/// look like a built in type. This will cause the generic YAML I/O conversion +/// to be used. To provide better control over the YAML conversion, you can +/// use this macro instead of typedef. It will create a class with one field +/// and automatic conversion operators to and from the base type. +/// Based on BOOST_STRONG_TYPEDEF +#define LLVM_YAML_STRONG_TYPEDEF(_base, _type) \ + struct _type { \ + _type() = default; \ + _type(const _base v) : value(v) {} \ + _type(const _type &v) = default; \ + _type &operator=(const _type &rhs) = default; \ + _type &operator=(const _base &rhs) { value = rhs; return *this; } \ + operator const _base & () const { return value; } \ + bool operator==(const _type &rhs) const { return value == rhs.value; } \ + bool operator==(const _base &rhs) const { return value == rhs; } \ + bool operator<(const _type &rhs) const { return value < rhs.value; } \ + _base value; \ + using BaseType = _base; \ + }; + +/// +/// Use these types instead of uintXX_t in any mapping to have +/// its yaml output formatted as hexadecimal. +/// +LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8) +LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16) +LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32) +LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64) + +template<> +struct ScalarTraits<Hex8> { + static void output(const Hex8 &, void *, raw_ostream &); + static StringRef input(StringRef, void *, Hex8 &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template<> +struct ScalarTraits<Hex16> { + static void output(const Hex16 &, void *, raw_ostream &); + static StringRef input(StringRef, void *, Hex16 &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template<> +struct ScalarTraits<Hex32> { + static void output(const Hex32 &, void *, raw_ostream &); + static StringRef input(StringRef, void *, Hex32 &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template<> +struct ScalarTraits<Hex64> { + static void output(const Hex64 &, void *, raw_ostream &); + static StringRef input(StringRef, void *, Hex64 &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +// Define non-member operator>> so that Input can stream in a document list. +template <typename T> +inline +typename std::enable_if<has_DocumentListTraits<T>::value, Input &>::type +operator>>(Input &yin, T &docList) { + int i = 0; + EmptyContext Ctx; + while ( yin.setCurrentDocument() ) { + yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true, Ctx); + if ( yin.error() ) + return yin; + yin.nextDocument(); + ++i; + } + return yin; +} + +// Define non-member operator>> so that Input can stream in a map as a document. +template <typename T> +inline typename std::enable_if<has_MappingTraits<T, EmptyContext>::value, + Input &>::type +operator>>(Input &yin, T &docMap) { + EmptyContext Ctx; + yin.setCurrentDocument(); + yamlize(yin, docMap, true, Ctx); + return yin; +} + +// Define non-member operator>> so that Input can stream in a sequence as +// a document. +template <typename T> +inline +typename std::enable_if<has_SequenceTraits<T>::value, Input &>::type +operator>>(Input &yin, T &docSeq) { + EmptyContext Ctx; + if (yin.setCurrentDocument()) + yamlize(yin, docSeq, true, Ctx); + return yin; +} + +// Define non-member operator>> so that Input can stream in a block scalar. +template <typename T> +inline +typename std::enable_if<has_BlockScalarTraits<T>::value, Input &>::type +operator>>(Input &In, T &Val) { + EmptyContext Ctx; + if (In.setCurrentDocument()) + yamlize(In, Val, true, Ctx); + return In; +} + +// Define non-member operator>> so that Input can stream in a string map. +template <typename T> +inline +typename std::enable_if<has_CustomMappingTraits<T>::value, Input &>::type +operator>>(Input &In, T &Val) { + EmptyContext Ctx; + if (In.setCurrentDocument()) + yamlize(In, Val, true, Ctx); + return In; +} + +// Define non-member operator>> so that Input can stream in a polymorphic type. +template <typename T> +inline typename std::enable_if<has_PolymorphicTraits<T>::value, Input &>::type +operator>>(Input &In, T &Val) { + EmptyContext Ctx; + if (In.setCurrentDocument()) + yamlize(In, Val, true, Ctx); + return In; +} + +// Provide better error message about types missing a trait specialization +template <typename T> +inline typename std::enable_if<missingTraits<T, EmptyContext>::value, + Input &>::type +operator>>(Input &yin, T &docSeq) { + char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; + return yin; +} + +// Define non-member operator<< so that Output can stream out document list. +template <typename T> +inline +typename std::enable_if<has_DocumentListTraits<T>::value, Output &>::type +operator<<(Output &yout, T &docList) { + EmptyContext Ctx; + yout.beginDocuments(); + const size_t count = DocumentListTraits<T>::size(yout, docList); + for(size_t i=0; i < count; ++i) { + if ( yout.preflightDocument(i) ) { + yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true, + Ctx); + yout.postflightDocument(); + } + } + yout.endDocuments(); + return yout; +} + +// Define non-member operator<< so that Output can stream out a map. +template <typename T> +inline typename std::enable_if<has_MappingTraits<T, EmptyContext>::value, + Output &>::type +operator<<(Output &yout, T &map) { + EmptyContext Ctx; + yout.beginDocuments(); + if ( yout.preflightDocument(0) ) { + yamlize(yout, map, true, Ctx); + yout.postflightDocument(); + } + yout.endDocuments(); + return yout; +} + +// Define non-member operator<< so that Output can stream out a sequence. +template <typename T> +inline +typename std::enable_if<has_SequenceTraits<T>::value, Output &>::type +operator<<(Output &yout, T &seq) { + EmptyContext Ctx; + yout.beginDocuments(); + if ( yout.preflightDocument(0) ) { + yamlize(yout, seq, true, Ctx); + yout.postflightDocument(); + } + yout.endDocuments(); + return yout; +} + +// Define non-member operator<< so that Output can stream out a block scalar. +template <typename T> +inline +typename std::enable_if<has_BlockScalarTraits<T>::value, Output &>::type +operator<<(Output &Out, T &Val) { + EmptyContext Ctx; + Out.beginDocuments(); + if (Out.preflightDocument(0)) { + yamlize(Out, Val, true, Ctx); + Out.postflightDocument(); + } + Out.endDocuments(); + return Out; +} + +// Define non-member operator<< so that Output can stream out a string map. +template <typename T> +inline +typename std::enable_if<has_CustomMappingTraits<T>::value, Output &>::type +operator<<(Output &Out, T &Val) { + EmptyContext Ctx; + Out.beginDocuments(); + if (Out.preflightDocument(0)) { + yamlize(Out, Val, true, Ctx); + Out.postflightDocument(); + } + Out.endDocuments(); + return Out; +} + +// Define non-member operator<< so that Output can stream out a polymorphic +// type. +template <typename T> +inline typename std::enable_if<has_PolymorphicTraits<T>::value, Output &>::type +operator<<(Output &Out, T &Val) { + EmptyContext Ctx; + Out.beginDocuments(); + if (Out.preflightDocument(0)) { + // FIXME: The parser does not support explicit documents terminated with a + // plain scalar; the end-marker is included as part of the scalar token. + assert(PolymorphicTraits<T>::getKind(Val) != NodeKind::Scalar && "plain scalar documents are not supported"); + yamlize(Out, Val, true, Ctx); + Out.postflightDocument(); + } + Out.endDocuments(); + return Out; +} + +// Provide better error message about types missing a trait specialization +template <typename T> +inline typename std::enable_if<missingTraits<T, EmptyContext>::value, + Output &>::type +operator<<(Output &yout, T &seq) { + char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; + return yout; +} + +template <bool B> struct IsFlowSequenceBase {}; +template <> struct IsFlowSequenceBase<true> { static const bool flow = true; }; + +template <typename T, bool Flow> +struct SequenceTraitsImpl : IsFlowSequenceBase<Flow> { +private: + using type = typename T::value_type; + +public: + static size_t size(IO &io, T &seq) { return seq.size(); } + + static type &element(IO &io, T &seq, size_t index) { + if (index >= seq.size()) + seq.resize(index + 1); + return seq[index]; + } +}; + +// Simple helper to check an expression can be used as a bool-valued template +// argument. +template <bool> struct CheckIsBool { static const bool value = true; }; + +// If T has SequenceElementTraits, then vector<T> and SmallVector<T, N> have +// SequenceTraits that do the obvious thing. +template <typename T> +struct SequenceTraits<std::vector<T>, + typename std::enable_if<CheckIsBool< + SequenceElementTraits<T>::flow>::value>::type> + : SequenceTraitsImpl<std::vector<T>, SequenceElementTraits<T>::flow> {}; +template <typename T, unsigned N> +struct SequenceTraits<SmallVector<T, N>, + typename std::enable_if<CheckIsBool< + SequenceElementTraits<T>::flow>::value>::type> + : SequenceTraitsImpl<SmallVector<T, N>, SequenceElementTraits<T>::flow> {}; +template <typename T> +struct SequenceTraits<SmallVectorImpl<T>, + typename std::enable_if<CheckIsBool< + SequenceElementTraits<T>::flow>::value>::type> + : SequenceTraitsImpl<SmallVectorImpl<T>, SequenceElementTraits<T>::flow> {}; + +// Sequences of fundamental types use flow formatting. +template <typename T> +struct SequenceElementTraits< + T, typename std::enable_if<std::is_fundamental<T>::value>::type> { + static const bool flow = true; +}; + +// Sequences of strings use block formatting. +template<> struct SequenceElementTraits<std::string> { + static const bool flow = false; +}; +template<> struct SequenceElementTraits<StringRef> { + static const bool flow = false; +}; +template<> struct SequenceElementTraits<std::pair<std::string, std::string>> { + static const bool flow = false; +}; + +/// Implementation of CustomMappingTraits for std::map<std::string, T>. +template <typename T> struct StdMapStringCustomMappingTraitsImpl { + using map_type = std::map<std::string, T>; + + static void inputOne(IO &io, StringRef key, map_type &v) { + io.mapRequired(key.str().c_str(), v[key]); + } + + static void output(IO &io, map_type &v) { + for (auto &p : v) + io.mapRequired(p.first.c_str(), p.second); + } +}; + +} // end namespace yaml +} // end namespace llvm + +#define LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(TYPE, FLOW) \ + namespace llvm { \ + namespace yaml { \ + static_assert( \ + !std::is_fundamental<TYPE>::value && \ + !std::is_same<TYPE, std::string>::value && \ + !std::is_same<TYPE, llvm::StringRef>::value, \ + "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control"); \ + template <> struct SequenceElementTraits<TYPE> { \ + static const bool flow = FLOW; \ + }; \ + } \ + } + +/// Utility for declaring that a std::vector of a particular type +/// should be considered a YAML sequence. +#define LLVM_YAML_IS_SEQUENCE_VECTOR(type) \ + LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, false) + +/// Utility for declaring that a std::vector of a particular type +/// should be considered a YAML flow sequence. +#define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(type) \ + LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, true) + +#define LLVM_YAML_DECLARE_MAPPING_TRAITS(Type) \ + namespace llvm { \ + namespace yaml { \ + template <> struct MappingTraits<Type> { \ + static void mapping(IO &IO, Type &Obj); \ + }; \ + } \ + } + +#define LLVM_YAML_DECLARE_ENUM_TRAITS(Type) \ + namespace llvm { \ + namespace yaml { \ + template <> struct ScalarEnumerationTraits<Type> { \ + static void enumeration(IO &io, Type &Value); \ + }; \ + } \ + } + +#define LLVM_YAML_DECLARE_BITSET_TRAITS(Type) \ + namespace llvm { \ + namespace yaml { \ + template <> struct ScalarBitSetTraits<Type> { \ + static void bitset(IO &IO, Type &Options); \ + }; \ + } \ + } + +#define LLVM_YAML_DECLARE_SCALAR_TRAITS(Type, MustQuote) \ + namespace llvm { \ + namespace yaml { \ + template <> struct ScalarTraits<Type> { \ + static void output(const Type &Value, void *ctx, raw_ostream &Out); \ + static StringRef input(StringRef Scalar, void *ctxt, Type &Value); \ + static QuotingType mustQuote(StringRef) { return MustQuote; } \ + }; \ + } \ + } + +/// Utility for declaring that a std::vector of a particular type +/// should be considered a YAML document list. +#define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \ + namespace llvm { \ + namespace yaml { \ + template <unsigned N> \ + struct DocumentListTraits<SmallVector<_type, N>> \ + : public SequenceTraitsImpl<SmallVector<_type, N>, false> {}; \ + template <> \ + struct DocumentListTraits<std::vector<_type>> \ + : public SequenceTraitsImpl<std::vector<_type>, false> {}; \ + } \ + } + +/// Utility for declaring that std::map<std::string, _type> should be considered +/// a YAML map. +#define LLVM_YAML_IS_STRING_MAP(_type) \ + namespace llvm { \ + namespace yaml { \ + template <> \ + struct CustomMappingTraits<std::map<std::string, _type>> \ + : public StdMapStringCustomMappingTraitsImpl<_type> {}; \ + } \ + } + +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex64) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex32) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex16) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex8) + +#endif // LLVM_SUPPORT_YAMLTRAITS_H diff --git a/third_party/llvm-project/include/llvm/Support/circular_raw_ostream.h b/third_party/llvm-project/include/llvm/Support/circular_raw_ostream.h new file mode 100644 index 000000000..a72acd4fe --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/circular_raw_ostream.h @@ -0,0 +1,159 @@ +//===-- llvm/Support/circular_raw_ostream.h - Buffered streams --*- 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 contains raw_ostream implementations for streams to do circular +// buffering of their output. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CIRCULAR_RAW_OSTREAM_H +#define LLVM_SUPPORT_CIRCULAR_RAW_OSTREAM_H + +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + /// circular_raw_ostream - A raw_ostream which *can* save its data + /// to a circular buffer, or can pass it through directly to an + /// underlying stream if specified with a buffer of zero. + /// + class circular_raw_ostream : public raw_ostream { + public: + /// TAKE_OWNERSHIP - Tell this stream that it owns the underlying + /// stream and is responsible for cleanup, memory management + /// issues, etc. + /// + static const bool TAKE_OWNERSHIP = true; + + /// REFERENCE_ONLY - Tell this stream it should not manage the + /// held stream. + /// + static const bool REFERENCE_ONLY = false; + + private: + /// TheStream - The real stream we output to. We set it to be + /// unbuffered, since we're already doing our own buffering. + /// + raw_ostream *TheStream; + + /// OwnsStream - Are we responsible for managing the underlying + /// stream? + /// + bool OwnsStream; + + /// BufferSize - The size of the buffer in bytes. + /// + size_t BufferSize; + + /// BufferArray - The actual buffer storage. + /// + char *BufferArray; + + /// Cur - Pointer to the current output point in BufferArray. + /// + char *Cur; + + /// Filled - Indicate whether the buffer has been completely + /// filled. This helps avoid garbage output. + /// + bool Filled; + + /// Banner - A pointer to a banner to print before dumping the + /// log. + /// + const char *Banner; + + /// flushBuffer - Dump the contents of the buffer to Stream. + /// + void flushBuffer() { + if (Filled) + // Write the older portion of the buffer. + TheStream->write(Cur, BufferArray + BufferSize - Cur); + // Write the newer portion of the buffer. + TheStream->write(BufferArray, Cur - BufferArray); + Cur = BufferArray; + Filled = false; + } + + void write_impl(const char *Ptr, size_t Size) override; + + /// current_pos - Return the current position within the stream, + /// not counting the bytes currently in the buffer. + /// + uint64_t current_pos() const override { + // This has the same effect as calling TheStream.current_pos(), + // but that interface is private. + return TheStream->tell() - TheStream->GetNumBytesInBuffer(); + } + + public: + /// circular_raw_ostream - Construct an optionally + /// circular-buffered stream, handing it an underlying stream to + /// do the "real" output. + /// + /// As a side effect, if BuffSize is nonzero, the given Stream is + /// set to be Unbuffered. This is because circular_raw_ostream + /// does its own buffering, so it doesn't want another layer of + /// buffering to be happening underneath it. + /// + /// "Owns" tells the circular_raw_ostream whether it is + /// responsible for managing the held stream, doing memory + /// management of it, etc. + /// + circular_raw_ostream(raw_ostream &Stream, const char *Header, + size_t BuffSize = 0, bool Owns = REFERENCE_ONLY) + : raw_ostream(/*unbuffered*/ true), TheStream(nullptr), + OwnsStream(Owns), BufferSize(BuffSize), BufferArray(nullptr), + Filled(false), Banner(Header) { + if (BufferSize != 0) + BufferArray = new char[BufferSize]; + Cur = BufferArray; + setStream(Stream, Owns); + } + + ~circular_raw_ostream() override { + flush(); + flushBufferWithBanner(); + releaseStream(); + delete[] BufferArray; + } + + bool is_displayed() const override { + return TheStream->is_displayed(); + } + + /// setStream - Tell the circular_raw_ostream to output a + /// different stream. "Owns" tells circular_raw_ostream whether + /// it should take responsibility for managing the underlying + /// stream. + /// + void setStream(raw_ostream &Stream, bool Owns = REFERENCE_ONLY) { + releaseStream(); + TheStream = &Stream; + OwnsStream = Owns; + } + + /// flushBufferWithBanner - Force output of the buffer along with + /// a small header. + /// + void flushBufferWithBanner(); + + private: + /// releaseStream - Delete the held stream if needed. Otherwise, + /// transfer the buffer settings from this circular_raw_ostream + /// back to the underlying stream. + /// + void releaseStream() { + if (!TheStream) + return; + if (OwnsStream) + delete TheStream; + } + }; +} // end llvm namespace + +#endif diff --git a/third_party/llvm-project/include/llvm/Support/raw_ostream.h b/third_party/llvm-project/include/llvm/Support/raw_ostream.h new file mode 100644 index 000000000..705f1790b --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/raw_ostream.h @@ -0,0 +1,587 @@ +//===--- raw_ostream.h - Raw output stream ----------------------*- 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 defines the raw_ostream class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_RAW_OSTREAM_H +#define LLVM_SUPPORT_RAW_OSTREAM_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <string> +#include <system_error> + +namespace llvm { + +class formatv_object_base; +class format_object_base; +class FormattedString; +class FormattedNumber; +class FormattedBytes; + +namespace sys { +namespace fs { +enum FileAccess : unsigned; +enum OpenFlags : unsigned; +enum CreationDisposition : unsigned; +} // end namespace fs +} // end namespace sys + +/// This class implements an extremely fast bulk output stream that can *only* +/// output to a stream. It does not support seeking, reopening, rewinding, line +/// buffered disciplines etc. It is a simple buffer that outputs +/// a chunk at a time. +class raw_ostream { +private: + /// The buffer is handled in such a way that the buffer is + /// uninitialized, unbuffered, or out of space when OutBufCur >= + /// OutBufEnd. Thus a single comparison suffices to determine if we + /// need to take the slow path to write a single character. + /// + /// The buffer is in one of three states: + /// 1. Unbuffered (BufferMode == Unbuffered) + /// 1. Uninitialized (BufferMode != Unbuffered && OutBufStart == 0). + /// 2. Buffered (BufferMode != Unbuffered && OutBufStart != 0 && + /// OutBufEnd - OutBufStart >= 1). + /// + /// If buffered, then the raw_ostream owns the buffer if (BufferMode == + /// InternalBuffer); otherwise the buffer has been set via SetBuffer and is + /// managed by the subclass. + /// + /// If a subclass installs an external buffer using SetBuffer then it can wait + /// for a \see write_impl() call to handle the data which has been put into + /// this buffer. + char *OutBufStart, *OutBufEnd, *OutBufCur; + + enum class BufferKind { + Unbuffered = 0, + InternalBuffer, + ExternalBuffer + } BufferMode; + +public: + // color order matches ANSI escape sequence, don't change + enum class Colors { + BLACK = 0, + RED, + GREEN, + YELLOW, + BLUE, + MAGENTA, + CYAN, + WHITE, + SAVEDCOLOR, + RESET, + }; + + static const Colors BLACK = Colors::BLACK; + static const Colors RED = Colors::RED; + static const Colors GREEN = Colors::GREEN; + static const Colors YELLOW = Colors::YELLOW; + static const Colors BLUE = Colors::BLUE; + static const Colors MAGENTA = Colors::MAGENTA; + static const Colors CYAN = Colors::CYAN; + static const Colors WHITE = Colors::WHITE; + static const Colors SAVEDCOLOR = Colors::SAVEDCOLOR; + static const Colors RESET = Colors::RESET; + + explicit raw_ostream(bool unbuffered = false) + : BufferMode(unbuffered ? BufferKind::Unbuffered + : BufferKind::InternalBuffer) { + // Start out ready to flush. + OutBufStart = OutBufEnd = OutBufCur = nullptr; + } + + raw_ostream(const raw_ostream &) = delete; + void operator=(const raw_ostream &) = delete; + + virtual ~raw_ostream(); + + /// tell - Return the current offset with the file. + uint64_t tell() const { return current_pos() + GetNumBytesInBuffer(); } + + //===--------------------------------------------------------------------===// + // Configuration Interface + //===--------------------------------------------------------------------===// + + /// Set the stream to be buffered, with an automatically determined buffer + /// size. + void SetBuffered(); + + /// Set the stream to be buffered, using the specified buffer size. + void SetBufferSize(size_t Size) { + flush(); + SetBufferAndMode(new char[Size], Size, BufferKind::InternalBuffer); + } + + size_t GetBufferSize() const { + // If we're supposed to be buffered but haven't actually gotten around + // to allocating the buffer yet, return the value that would be used. + if (BufferMode != BufferKind::Unbuffered && OutBufStart == nullptr) + return preferred_buffer_size(); + + // Otherwise just return the size of the allocated buffer. + return OutBufEnd - OutBufStart; + } + + /// Set the stream to be unbuffered. When unbuffered, the stream will flush + /// after every write. This routine will also flush the buffer immediately + /// when the stream is being set to unbuffered. + void SetUnbuffered() { + flush(); + SetBufferAndMode(nullptr, 0, BufferKind::Unbuffered); + } + + size_t GetNumBytesInBuffer() const { + return OutBufCur - OutBufStart; + } + + //===--------------------------------------------------------------------===// + // Data Output Interface + //===--------------------------------------------------------------------===// + + void flush() { + if (OutBufCur != OutBufStart) + flush_nonempty(); + } + + raw_ostream &operator<<(char C) { + if (OutBufCur >= OutBufEnd) + return write(C); + *OutBufCur++ = C; + return *this; + } + + raw_ostream &operator<<(unsigned char C) { + if (OutBufCur >= OutBufEnd) + return write(C); + *OutBufCur++ = C; + return *this; + } + + raw_ostream &operator<<(signed char C) { + if (OutBufCur >= OutBufEnd) + return write(C); + *OutBufCur++ = C; + return *this; + } + + raw_ostream &operator<<(StringRef Str) { + // Inline fast path, particularly for strings with a known length. + size_t Size = Str.size(); + + // Make sure we can use the fast path. + if (Size > (size_t)(OutBufEnd - OutBufCur)) + return write(Str.data(), Size); + + if (Size) { + memcpy(OutBufCur, Str.data(), Size); + OutBufCur += Size; + } + return *this; + } + + raw_ostream &operator<<(const char *Str) { + // Inline fast path, particularly for constant strings where a sufficiently + // smart compiler will simplify strlen. + + return this->operator<<(StringRef(Str)); + } + + raw_ostream &operator<<(const std::string &Str) { + // Avoid the fast path, it would only increase code size for a marginal win. + return write(Str.data(), Str.length()); + } + + raw_ostream &operator<<(const SmallVectorImpl<char> &Str) { + return write(Str.data(), Str.size()); + } + + raw_ostream &operator<<(unsigned long N); + raw_ostream &operator<<(long N); + raw_ostream &operator<<(unsigned long long N); + raw_ostream &operator<<(long long N); + raw_ostream &operator<<(const void *P); + + raw_ostream &operator<<(unsigned int N) { + return this->operator<<(static_cast<unsigned long>(N)); + } + + raw_ostream &operator<<(int N) { + return this->operator<<(static_cast<long>(N)); + } + + raw_ostream &operator<<(double N); + + /// Output \p N in hexadecimal, without any prefix or padding. + raw_ostream &write_hex(unsigned long long N); + + // Change the foreground color of text. + raw_ostream &operator<<(Colors C); + + /// Output a formatted UUID with dash separators. + using uuid_t = uint8_t[16]; + raw_ostream &write_uuid(const uuid_t UUID); + + /// Output \p Str, turning '\\', '\t', '\n', '"', and anything that doesn't + /// satisfy llvm::isPrint into an escape sequence. + raw_ostream &write_escaped(StringRef Str, bool UseHexEscapes = false); + + raw_ostream &write(unsigned char C); + raw_ostream &write(const char *Ptr, size_t Size); + + // Formatted output, see the format() function in Support/Format.h. + raw_ostream &operator<<(const format_object_base &Fmt); + + // Formatted output, see the leftJustify() function in Support/Format.h. + raw_ostream &operator<<(const FormattedString &); + + // Formatted output, see the formatHex() function in Support/Format.h. + raw_ostream &operator<<(const FormattedNumber &); + + // Formatted output, see the formatv() function in Support/FormatVariadic.h. + raw_ostream &operator<<(const formatv_object_base &); + + // Formatted output, see the format_bytes() function in Support/Format.h. + raw_ostream &operator<<(const FormattedBytes &); + + /// indent - Insert 'NumSpaces' spaces. + raw_ostream &indent(unsigned NumSpaces); + + /// write_zeros - Insert 'NumZeros' nulls. + raw_ostream &write_zeros(unsigned NumZeros); + + /// Changes the foreground color of text that will be output from this point + /// forward. + /// @param Color ANSI color to use, the special SAVEDCOLOR can be used to + /// change only the bold attribute, and keep colors untouched + /// @param Bold bold/brighter text, default false + /// @param BG if true change the background, default: change foreground + /// @returns itself so it can be used within << invocations + virtual raw_ostream &changeColor(enum Colors Color, + bool Bold = false, + bool BG = false) { + (void)Color; + (void)Bold; + (void)BG; + return *this; + } + + /// Resets the colors to terminal defaults. Call this when you are done + /// outputting colored text, or before program exit. + virtual raw_ostream &resetColor() { return *this; } + + /// Reverses the foreground and background colors. + virtual raw_ostream &reverseColor() { return *this; } + + /// This function determines if this stream is connected to a "tty" or + /// "console" window. That is, the output would be displayed to the user + /// rather than being put on a pipe or stored in a file. + virtual bool is_displayed() const { return false; } + + /// This function determines if this stream is displayed and supports colors. + virtual bool has_colors() const { return is_displayed(); } + + // Enable or disable colors. Once disable_colors() is called, + // changeColor() has no effect until enable_colors() is called. + virtual void enable_colors(bool /*enable*/) {} + + //===--------------------------------------------------------------------===// + // Subclass Interface + //===--------------------------------------------------------------------===// + +private: + /// The is the piece of the class that is implemented by subclasses. This + /// writes the \p Size bytes starting at + /// \p Ptr to the underlying stream. + /// + /// This function is guaranteed to only be called at a point at which it is + /// safe for the subclass to install a new buffer via SetBuffer. + /// + /// \param Ptr The start of the data to be written. For buffered streams this + /// is guaranteed to be the start of the buffer. + /// + /// \param Size The number of bytes to be written. + /// + /// \invariant { Size > 0 } + virtual void write_impl(const char *Ptr, size_t Size) = 0; + + /// Return the current position within the stream, not counting the bytes + /// currently in the buffer. + virtual uint64_t current_pos() const = 0; + +protected: + /// Use the provided buffer as the raw_ostream buffer. This is intended for + /// use only by subclasses which can arrange for the output to go directly + /// into the desired output buffer, instead of being copied on each flush. + void SetBuffer(char *BufferStart, size_t Size) { + SetBufferAndMode(BufferStart, Size, BufferKind::ExternalBuffer); + } + + /// Return an efficient buffer size for the underlying output mechanism. + virtual size_t preferred_buffer_size() const; + + /// Return the beginning of the current stream buffer, or 0 if the stream is + /// unbuffered. + const char *getBufferStart() const { return OutBufStart; } + + //===--------------------------------------------------------------------===// + // Private Interface + //===--------------------------------------------------------------------===// +private: + /// Install the given buffer and mode. + void SetBufferAndMode(char *BufferStart, size_t Size, BufferKind Mode); + + /// Flush the current buffer, which is known to be non-empty. This outputs the + /// currently buffered data and resets the buffer to empty. + void flush_nonempty(); + + /// Copy data into the buffer. Size must not be greater than the number of + /// unused bytes in the buffer. + void copy_to_buffer(const char *Ptr, size_t Size); + + virtual void anchor(); +}; + +/// An abstract base class for streams implementations that also support a +/// pwrite operation. This is useful for code that can mostly stream out data, +/// but needs to patch in a header that needs to know the output size. +class raw_pwrite_stream : public raw_ostream { + virtual void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) = 0; + void anchor() override; + +public: + explicit raw_pwrite_stream(bool Unbuffered = false) + : raw_ostream(Unbuffered) {} + void pwrite(const char *Ptr, size_t Size, uint64_t Offset) { +#ifndef NDEBUG + uint64_t Pos = tell(); + // /dev/null always reports a pos of 0, so we cannot perform this check + // in that case. + if (Pos) + assert(Size + Offset <= Pos && "We don't support extending the stream"); +#endif + pwrite_impl(Ptr, Size, Offset); + } +}; + +//===----------------------------------------------------------------------===// +// File Output Streams +//===----------------------------------------------------------------------===// + +/// A raw_ostream that writes to a file descriptor. +/// +class raw_fd_ostream : public raw_pwrite_stream { + int FD; + bool ShouldClose; + bool SupportsSeeking = false; + bool ColorEnabled = true; + +#ifdef _WIN32 + /// True if this fd refers to a Windows console device. Mintty and other + /// terminal emulators are TTYs, but they are not consoles. + bool IsWindowsConsole = false; +#endif + + std::error_code EC; + + uint64_t pos = 0; + + /// See raw_ostream::write_impl. + void write_impl(const char *Ptr, size_t Size) override; + + void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override; + + /// Return the current position within the stream, not counting the bytes + /// currently in the buffer. + uint64_t current_pos() const override { return pos; } + + /// Determine an efficient buffer size. + size_t preferred_buffer_size() const override; + + /// Set the flag indicating that an output error has been encountered. + void error_detected(std::error_code EC) { this->EC = EC; } + + void anchor() override; + +public: + /// Open the specified file for writing. If an error occurs, information + /// about the error is put into EC, and the stream should be immediately + /// destroyed; + /// \p Flags allows optional flags to control how the file will be opened. + /// + /// As a special case, if Filename is "-", then the stream will use + /// STDOUT_FILENO instead of opening a file. This will not close the stdout + /// descriptor. + raw_fd_ostream(StringRef Filename, std::error_code &EC); + raw_fd_ostream(StringRef Filename, std::error_code &EC, + sys::fs::CreationDisposition Disp); + raw_fd_ostream(StringRef Filename, std::error_code &EC, + sys::fs::FileAccess Access); + raw_fd_ostream(StringRef Filename, std::error_code &EC, + sys::fs::OpenFlags Flags); + raw_fd_ostream(StringRef Filename, std::error_code &EC, + sys::fs::CreationDisposition Disp, sys::fs::FileAccess Access, + sys::fs::OpenFlags Flags); + + /// FD is the file descriptor that this writes to. If ShouldClose is true, + /// this closes the file when the stream is destroyed. If FD is for stdout or + /// stderr, it will not be closed. + raw_fd_ostream(int fd, bool shouldClose, bool unbuffered=false); + + ~raw_fd_ostream() override; + + /// Manually flush the stream and close the file. Note that this does not call + /// fsync. + void close(); + + bool supportsSeeking() { return SupportsSeeking; } + + /// Flushes the stream and repositions the underlying file descriptor position + /// to the offset specified from the beginning of the file. + uint64_t seek(uint64_t off); + + raw_ostream &changeColor(enum Colors colors, bool bold=false, + bool bg=false) override; + raw_ostream &resetColor() override; + + raw_ostream &reverseColor() override; + + bool is_displayed() const override; + + bool has_colors() const override; + + void enable_colors(bool enable) override { ColorEnabled = enable; } + + std::error_code error() const { return EC; } + + /// Return the value of the flag in this raw_fd_ostream indicating whether an + /// output error has been encountered. + /// This doesn't implicitly flush any pending output. Also, it doesn't + /// guarantee to detect all errors unless the stream has been closed. + bool has_error() const { return bool(EC); } + + /// Set the flag read by has_error() to false. If the error flag is set at the + /// time when this raw_ostream's destructor is called, report_fatal_error is + /// called to report the error. Use clear_error() after handling the error to + /// avoid this behavior. + /// + /// "Errors should never pass silently. + /// Unless explicitly silenced." + /// - from The Zen of Python, by Tim Peters + /// + void clear_error() { EC = std::error_code(); } +}; + +/// This returns a reference to a raw_ostream for standard output. Use it like: +/// outs() << "foo" << "bar"; +raw_ostream &outs(); + +/// This returns a reference to a raw_ostream for standard error. Use it like: +/// errs() << "foo" << "bar"; +raw_ostream &errs(); + +/// This returns a reference to a raw_ostream which simply discards output. +raw_ostream &nulls(); + +//===----------------------------------------------------------------------===// +// Output Stream Adaptors +//===----------------------------------------------------------------------===// + +/// A raw_ostream that writes to an std::string. This is a simple adaptor +/// class. This class does not encounter output errors. +class raw_string_ostream : public raw_ostream { + std::string &OS; + + /// See raw_ostream::write_impl. + void write_impl(const char *Ptr, size_t Size) override; + + /// Return the current position within the stream, not counting the bytes + /// currently in the buffer. + uint64_t current_pos() const override { return OS.size(); } + +public: + explicit raw_string_ostream(std::string &O) : OS(O) {} + ~raw_string_ostream() override; + + /// Flushes the stream contents to the target string and returns the string's + /// reference. + std::string& str() { + flush(); + return OS; + } +}; + +/// A raw_ostream that writes to an SmallVector or SmallString. This is a +/// simple adaptor class. This class does not encounter output errors. +/// raw_svector_ostream operates without a buffer, delegating all memory +/// management to the SmallString. Thus the SmallString is always up-to-date, +/// may be used directly and there is no need to call flush(). +class raw_svector_ostream : public raw_pwrite_stream { + SmallVectorImpl<char> &OS; + + /// See raw_ostream::write_impl. + void write_impl(const char *Ptr, size_t Size) override; + + void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override; + + /// Return the current position within the stream. + uint64_t current_pos() const override; + +public: + /// Construct a new raw_svector_ostream. + /// + /// \param O The vector to write to; this should generally have at least 128 + /// bytes free to avoid any extraneous memory overhead. + explicit raw_svector_ostream(SmallVectorImpl<char> &O) : OS(O) { + SetUnbuffered(); + } + + ~raw_svector_ostream() override = default; + + void flush() = delete; + + /// Return a StringRef for the vector contents. + StringRef str() { return StringRef(OS.data(), OS.size()); } +}; + +/// A raw_ostream that discards all output. +class raw_null_ostream : public raw_pwrite_stream { + /// See raw_ostream::write_impl. + void write_impl(const char *Ptr, size_t size) override; + void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override; + + /// Return the current position within the stream, not counting the bytes + /// currently in the buffer. + uint64_t current_pos() const override; + +public: + explicit raw_null_ostream() = default; + ~raw_null_ostream() override; +}; + +class buffer_ostream : public raw_svector_ostream { + raw_ostream &OS; + SmallVector<char, 0> Buffer; + + virtual void anchor() override; + +public: + buffer_ostream(raw_ostream &OS) : raw_svector_ostream(Buffer), OS(OS) {} + ~buffer_ostream() override { OS << str(); } +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_RAW_OSTREAM_H diff --git a/third_party/llvm-project/include/llvm/Support/type_traits.h b/third_party/llvm-project/include/llvm/Support/type_traits.h new file mode 100644 index 000000000..b7d48e8e1 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/type_traits.h @@ -0,0 +1,192 @@ +//===- llvm/Support/type_traits.h - Simplfied type traits -------*- 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 provides useful additions to the standard type_traits library. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_TYPE_TRAITS_H +#define LLVM_SUPPORT_TYPE_TRAITS_H + +#include "llvm/Support/Compiler.h" +#include <type_traits> +#include <utility> + +namespace llvm { + + +/// Metafunction that determines whether the given type is either an +/// integral type or an enumeration type, including enum classes. +/// +/// Note that this accepts potentially more integral types than is_integral +/// because it is based on being implicitly convertible to an integral type. +/// Also note that enum classes aren't implicitly convertible to integral types, +/// the value may therefore need to be explicitly converted before being used. +template <typename T> class is_integral_or_enum { + using UnderlyingT = typename std::remove_reference<T>::type; + +public: + static const bool value = + !std::is_class<UnderlyingT>::value && // Filter conversion operators. + !std::is_pointer<UnderlyingT>::value && + !std::is_floating_point<UnderlyingT>::value && + (std::is_enum<UnderlyingT>::value || + std::is_convertible<UnderlyingT, unsigned long long>::value); +}; + +/// If T is a pointer, just return it. If it is not, return T&. +template<typename T, typename Enable = void> +struct add_lvalue_reference_if_not_pointer { using type = T &; }; + +template <typename T> +struct add_lvalue_reference_if_not_pointer< + T, typename std::enable_if<std::is_pointer<T>::value>::type> { + using type = T; +}; + +/// If T is a pointer to X, return a pointer to const X. If it is not, +/// return const T. +template<typename T, typename Enable = void> +struct add_const_past_pointer { using type = const T; }; + +template <typename T> +struct add_const_past_pointer< + T, typename std::enable_if<std::is_pointer<T>::value>::type> { + using type = const typename std::remove_pointer<T>::type *; +}; + +template <typename T, typename Enable = void> +struct const_pointer_or_const_ref { + using type = const T &; +}; +template <typename T> +struct const_pointer_or_const_ref< + T, typename std::enable_if<std::is_pointer<T>::value>::type> { + using type = typename add_const_past_pointer<T>::type; +}; + +namespace detail { +/// Internal utility to detect trivial copy construction. +template<typename T> union copy_construction_triviality_helper { + T t; + copy_construction_triviality_helper() = default; + copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default; + ~copy_construction_triviality_helper() = default; +}; +/// Internal utility to detect trivial move construction. +template<typename T> union move_construction_triviality_helper { + T t; + move_construction_triviality_helper() = default; + move_construction_triviality_helper(move_construction_triviality_helper&&) = default; + ~move_construction_triviality_helper() = default; +}; + +template<class T> +union trivial_helper { + T t; +}; + +} // end namespace detail + +/// An implementation of `std::is_trivially_copy_constructible` since we have +/// users with STLs that don't yet include it. +template <typename T> +struct is_trivially_copy_constructible + : std::is_copy_constructible< + ::llvm::detail::copy_construction_triviality_helper<T>> {}; +template <typename T> +struct is_trivially_copy_constructible<T &> : std::true_type {}; +template <typename T> +struct is_trivially_copy_constructible<T &&> : std::false_type {}; + +/// An implementation of `std::is_trivially_move_constructible` since we have +/// users with STLs that don't yet include it. +template <typename T> +struct is_trivially_move_constructible + : std::is_move_constructible< + ::llvm::detail::move_construction_triviality_helper<T>> {}; +template <typename T> +struct is_trivially_move_constructible<T &> : std::true_type {}; +template <typename T> +struct is_trivially_move_constructible<T &&> : std::true_type {}; + + +template <typename T> +struct is_copy_assignable { + template<class F> + static auto get(F*) -> decltype(std::declval<F &>() = std::declval<const F &>(), std::true_type{}); + static std::false_type get(...); + static constexpr bool value = decltype(get((T*)nullptr))::value; +}; + +template <typename T> +struct is_move_assignable { + template<class F> + static auto get(F*) -> decltype(std::declval<F &>() = std::declval<F &&>(), std::true_type{}); + static std::false_type get(...); + static constexpr bool value = decltype(get((T*)nullptr))::value; +}; + + +// An implementation of `std::is_trivially_copyable` since STL version +// is not equally supported by all compilers, especially GCC 4.9. +// Uniform implementation of this trait is important for ABI compatibility +// as it has an impact on SmallVector's ABI (among others). +template <typename T> +class is_trivially_copyable { + + // copy constructors + static constexpr bool has_trivial_copy_constructor = + std::is_copy_constructible<detail::trivial_helper<T>>::value; + static constexpr bool has_deleted_copy_constructor = + !std::is_copy_constructible<T>::value; + + // move constructors + static constexpr bool has_trivial_move_constructor = + std::is_move_constructible<detail::trivial_helper<T>>::value; + static constexpr bool has_deleted_move_constructor = + !std::is_move_constructible<T>::value; + + // copy assign + static constexpr bool has_trivial_copy_assign = + is_copy_assignable<detail::trivial_helper<T>>::value; + static constexpr bool has_deleted_copy_assign = + !is_copy_assignable<T>::value; + + // move assign + static constexpr bool has_trivial_move_assign = + is_move_assignable<detail::trivial_helper<T>>::value; + static constexpr bool has_deleted_move_assign = + !is_move_assignable<T>::value; + + // destructor + static constexpr bool has_trivial_destructor = + std::is_destructible<detail::trivial_helper<T>>::value; + + public: + + static constexpr bool value = + has_trivial_destructor && + (has_deleted_move_assign || has_trivial_move_assign) && + (has_deleted_move_constructor || has_trivial_move_constructor) && + (has_deleted_copy_assign || has_trivial_copy_assign) && + (has_deleted_copy_constructor || has_trivial_copy_constructor); + +#ifdef HAVE_STD_IS_TRIVIALLY_COPYABLE + static_assert(value == std::is_trivially_copyable<T>::value, + "inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable"); +#endif +}; +template <typename T> +class is_trivially_copyable<T*> : public std::true_type { +}; + + +} // end namespace llvm + +#endif // LLVM_SUPPORT_TYPE_TRAITS_H |