diff options
author | Alon Zakai <azakai@google.com> | 2019-12-19 09:04:08 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-12-19 09:04:08 -0800 |
commit | 4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6 (patch) | |
tree | 91bffc2d47b1fe4bba01e7ada77006ef340bd138 /third_party/llvm-project/include/llvm/Support | |
parent | 0048f5b004ddf50e750aa335d0be314a73852058 (diff) | |
download | binaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.tar.gz binaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.tar.bz2 binaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.zip |
DWARF parsing and writing support using LLVM (#2520)
This imports LLVM code for DWARF handling. That code has the
Apache 2 license like us. It's also the same code used to
emit DWARF in the common toolchain, so it seems like a safe choice.
This adds two passes: --dwarfdump which runs the same code LLVM
runs for llvm-dwarfdump. This shows we can parse it ok, and will
be useful for debugging. And --dwarfupdate writes out the DWARF
sections (unchanged from what we read, so it just roundtrips - for
updating we need #2515).
This puts LLVM in thirdparty which is added here.
All the LLVM code is behind USE_LLVM_DWARF, which is on
by default, but off in JS for now, as it increases code size by 20%.
This current approach imports the LLVM files directly. This is not
how they are intended to be used, so it required a bunch of
local changes - more than I expected actually, for the platform-specific
stuff. For now this seems to work, so it may be good enough, but
in the long term we may want to switch to linking against libllvm.
A downside to doing that is that binaryen users would need to
have an LLVM build, and even in the waterfall builds we'd have a
problem - while we ship LLVM there anyhow, we constantly update
it, which means that binaryen would need to be on latest llvm all
the time too (which otherwise, given DWARF is quite stable, we
might not need to constantly update).
An even larger issue is that as I did this work I learned about how
DWARF works in LLVM, and while the reading code is easy to
reuse, the writing code is trickier. The main code path is heavily
integrated with the MC layer, which we don't have - we might want
to create a "fake MC layer" for that, but it sounds hard. Instead,
there is the YAML path which is used mostly for testing, and which
can convert DWARF to and from YAML and from binary. Using
the non-YAML parts there, we can convert binary DWARF to
the YAML layer's nice Info data, then convert that to binary. This
works, however, this is not the path LLVM uses normally, and it
supports only some basic DWARF sections - I had to add ranges
support, in fact. So if we need more complex things, we may end
up needing to use the MC layer approach, or consider some other
DWARF library. However, hopefully that should not affect the core
binaryen code which just calls a library for DWARF stuff.
Helps #2400
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 |