diff options
Diffstat (limited to 'include/llvm/Support')
46 files changed, 3018 insertions, 533 deletions
diff --git a/include/llvm/Support/AArch64TargetParser.def b/include/llvm/Support/AArch64TargetParser.def index 6772e5f9b734d..e03297b7c3c32 100644 --- a/include/llvm/Support/AArch64TargetParser.def +++ b/include/llvm/Support/AArch64TargetParser.def @@ -40,6 +40,11 @@ AARCH64_ARCH("armv8.4-a", ARMV8_4A, "8.4-A", "v8.4a", (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 @@ -60,10 +65,16 @@ 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("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") #undef AARCH64_ARCH_EXT_NAME #ifndef AARCH64_CPU_NAME @@ -91,8 +102,8 @@ AARCH64_CPU_NAME("exynos-m2", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, (AArch64::AEK_CRC)) AARCH64_CPU_NAME("exynos-m3", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, (AArch64::AEK_CRC)) -AARCH64_CPU_NAME("exynos-m4", 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_FP16 | AArch64::AEK_DOTPROD)) 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, @@ -109,6 +120,9 @@ 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_PROFILE | AArch64::AEK_FP16 | AArch64::AEK_FP16FML | + AArch64::AEK_DOTPROD)) // Invalid CPU AARCH64_CPU_NAME("invalid", INVALID, FK_INVALID, true, AArch64::AEK_INVALID) #undef AARCH64_CPU_NAME diff --git a/include/llvm/Support/AArch64TargetParser.h b/include/llvm/Support/AArch64TargetParser.h new file mode 100644 index 0000000000000..76b77d4744289 --- /dev/null +++ b/include/llvm/Support/AArch64TargetParser.h @@ -0,0 +1,124 @@ +//===-- AArch64TargetParser - Parser for AArch64 features -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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, +}; + +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/include/llvm/Support/AMDGPUMetadata.h b/include/llvm/Support/AMDGPUMetadata.h index 667fb3f3da436..84851c07499d4 100644 --- a/include/llvm/Support/AMDGPUMetadata.h +++ b/include/llvm/Support/AMDGPUMetadata.h @@ -431,6 +431,21 @@ std::error_code fromString(std::string String, Metadata &HSAMetadata); /// Converts \p HSAMetadata to \p String. std::error_code toString(Metadata HSAMetadata, std::string &String); +//===----------------------------------------------------------------------===// +// HSA metadata for v3 code object. +//===----------------------------------------------------------------------===// +namespace V3 { +/// HSA metadata major version. +constexpr uint32_t VersionMajor = 1; +/// HSA metadata minor version. +constexpr uint32_t VersionMinor = 0; + +/// HSA metadata beginning assembler directive. +constexpr char AssemblerDirectiveBegin[] = ".amdgpu_metadata"; +/// HSA metadata ending assembler directive. +constexpr char AssemblerDirectiveEnd[] = ".end_amdgpu_metadata"; +} // end namespace V3 + } // end namespace HSAMD //===----------------------------------------------------------------------===// diff --git a/include/llvm/Support/ARMTargetParser.def b/include/llvm/Support/ARMTargetParser.def index 78f5410fb7338..9e844e2b464df 100644 --- a/include/llvm/Support/ARMTargetParser.def +++ b/include/llvm/Support/ARMTargetParser.def @@ -106,6 +106,11 @@ ARM_ARCH("armv8.4-a", ARMV8_4A, "8.4-A", "v8.4a", (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 | @@ -152,6 +157,8 @@ 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") #undef ARM_ARCH_EXT_NAME #ifndef ARM_HW_DIV_NAME @@ -202,10 +209,9 @@ 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("arm1176j-s", ARMV6K, FK_NONE, true, ARM::AEK_NONE) -ARM_CPU_NAME("arm1176jz-s", ARMV6KZ, FK_NONE, false, ARM::AEK_NONE) -ARM_CPU_NAME("mpcore", ARMV6K, FK_VFPV2, 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) @@ -260,7 +266,8 @@ ARM_CPU_NAME("cyclone", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) ARM_CPU_NAME("exynos-m1", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) ARM_CPU_NAME("exynos-m2", 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", 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("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) diff --git a/include/llvm/Support/ARMTargetParser.h b/include/llvm/Support/ARMTargetParser.h new file mode 100644 index 0000000000000..71acc0dc72d02 --- /dev/null +++ b/include/llvm/Support/ARMTargetParser.h @@ -0,0 +1,264 @@ +//===-- ARMTargetParser - Parser for ARM target features --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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_SVE = 1 << 13, + AEK_DOTPROD = 1 << 14, + AEK_SHA2 = 1 << 15, + AEK_AES = 1 << 16, + AEK_FP16FML = 1 << 17, + AEK_SB = 1 << 18, + // 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 +}; + +// 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); +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/include/llvm/Support/ARMWinEH.h b/include/llvm/Support/ARMWinEH.h index 1463629f45dc4..60174503ad492 100644 --- a/include/llvm/Support/ARMWinEH.h +++ b/include/llvm/Support/ARMWinEH.h @@ -207,6 +207,8 @@ std::pair<uint16_t, uint32_t> SavedRegisterMask(const RuntimeFunction &RF); /// ExceptionDataRecord - An entry in the table of exception data (.xdata) /// +/// The format on ARM is: +/// /// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 /// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 /// +-------+---------+-+-+-+---+-----------------------------------+ @@ -215,6 +217,16 @@ std::pair<uint16_t, uint32_t> SavedRegisterMask(const RuntimeFunction &RF); /// | Reserved |Ex. Code Words| (Extended Epilogue Count) | /// +-------+--------+--------------+-------------------------------+ /// +/// The format on ARM64 is: +/// +/// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 +/// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +/// +---------+---------+-+-+---+-----------------------------------+ +/// | C Wrd | Epi Cnt |E|X|Ver| Function Length | +/// +---------+------+--'-'-'---'---+-------------------------------+ +/// | Reserved |Ex. Code Words| (Extended Epilogue Count) | +/// +-------+--------+--------------+-------------------------------+ +/// /// Function Length : 18-bit field indicating the total length of the function /// in bytes divided by 2. If a function is larger than /// 512KB, then multiple pdata and xdata records must be used. @@ -225,7 +237,7 @@ std::pair<uint16_t, uint32_t> SavedRegisterMask(const RuntimeFunction &RF); /// header /// F : 1-bit field indicating that the record describes a function fragment /// (implies that no prologue is present, and prologue processing should be -/// skipped) +/// skipped) (ARM only) /// Epilogue Count : 5-bit field that differs in meaning based on the E field. /// /// If E is set, then this field specifies the index of the @@ -235,33 +247,43 @@ std::pair<uint16_t, uint32_t> SavedRegisterMask(const RuntimeFunction &RF); /// scopes. If more than 31 scopes exist, then this field and /// the Code Words field must both be set to 0 to indicate that /// an extension word is required. -/// Code Words : 4-bit field that species the number of 32-bit words needed to -/// contain all the unwind codes. If more than 15 words (63 code -/// bytes) are required, then this field and the Epilogue Count -/// field must both be set to 0 to indicate that an extension word -/// is required. +/// Code Words : 4-bit (5-bit on ARM64) field that specifies the number of +/// 32-bit words needed to contain all the unwind codes. If more +/// than 15 words (31 words on ARM64) are required, then this field +/// and the Epilogue Count field must both be set to 0 to indicate +/// that an extension word is required. /// Extended Epilogue Count, Extended Code Words : /// Valid only if Epilog Count and Code Words are both /// set to 0. Provides an 8-bit extended code word /// count and 16-bits for epilogue count /// +/// The epilogue scope format on ARM is: +/// /// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 /// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 /// +----------------+------+---+---+-------------------------------+ /// | Ep Start Idx | Cond |Res| Epilogue Start Offset | /// +----------------+------+---+-----------------------------------+ /// +/// The epilogue scope format on ARM64 is: +/// +/// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 +/// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +/// +-------------------+-------+---+-------------------------------+ +/// | Ep Start Idx | Res | Epilogue Start Offset | +/// +-------------------+-------+-----------------------------------+ +/// /// If the E bit is unset in the header, the header is followed by a series of /// epilogue scopes, which are sorted by their offset. /// /// Epilogue Start Offset: 18-bit field encoding the offset of epilogue relative /// to the start of the function in bytes divided by two /// Res : 2-bit field reserved for future expansion (must be set to 0) -/// Condition : 4-bit field providing the condition under which the epilogue is -/// executed. Unconditional epilogues should set this field to 0xe. -/// Epilogues must be entirely conditional or unconditional, and in -/// Thumb-2 mode. The epilogue beings with the first instruction -/// after the IT opcode. +/// Condition : (ARM only) 4-bit field providing the condition under which the +/// epilogue is executed. Unconditional epilogues should set this +/// field to 0xe. Epilogues must be entirely conditional or +/// unconditional, and in Thumb-2 mode. The epilogue begins with +/// the first instruction after the IT opcode. /// Epilogue Start Index : 8-bit field indicating the byte index of the first /// unwind code describing the epilogue /// @@ -293,18 +315,33 @@ struct EpilogueScope { const support::ulittle32_t ES; EpilogueScope(const support::ulittle32_t Data) : ES(Data) {} + // Same for both ARM and AArch64. uint32_t EpilogueStartOffset() const { return (ES & 0x0003ffff); } - uint8_t Res() const { + + // Different implementations for ARM and AArch64. + uint8_t ResARM() const { return ((ES & 0x000c0000) >> 18); } + + uint8_t ResAArch64() const { + return ((ES & 0x000f0000) >> 18); + } + + // Condition is only applicable to ARM. uint8_t Condition() const { return ((ES & 0x00f00000) >> 20); } - uint8_t EpilogueStartIndex() const { + + // Different implementations for ARM and AArch64. + uint8_t EpilogueStartIndexARM() const { return ((ES & 0xff000000) >> 24); } + + uint16_t EpilogueStartIndexAArch64() const { + return ((ES & 0xffc00000) >> 22); + } }; struct ExceptionDataRecord; @@ -312,13 +349,23 @@ inline size_t HeaderWords(const ExceptionDataRecord &XR); struct ExceptionDataRecord { const support::ulittle32_t *Data; + bool isAArch64; - ExceptionDataRecord(const support::ulittle32_t *Data) : Data(Data) {} + ExceptionDataRecord(const support::ulittle32_t *Data, bool isAArch64) : + Data(Data), isAArch64(isAArch64) {} uint32_t FunctionLength() const { return (Data[0] & 0x0003ffff); } + uint32_t FunctionLengthInBytesARM() const { + return FunctionLength() << 1; + } + + uint32_t FunctionLengthInBytesAArch64() const { + return FunctionLength() << 2; + } + uint8_t Vers() const { return (Data[0] & 0x000C0000) >> 18; } @@ -332,18 +379,25 @@ struct ExceptionDataRecord { } bool F() const { + assert(!isAArch64 && "Fragments are only supported on ARMv7 WinEH"); return ((Data[0] & 0x00400000) >> 22); } uint8_t EpilogueCount() const { - if (HeaderWords(*this) == 1) + if (HeaderWords(*this) == 1) { + if (isAArch64) + return (Data[0] & 0x07C00000) >> 22; return (Data[0] & 0x0f800000) >> 23; + } return Data[1] & 0x0000ffff; } uint8_t CodeWords() const { - if (HeaderWords(*this) == 1) + if (HeaderWords(*this) == 1) { + if (isAArch64) + return (Data[0] & 0xf8000000) >> 27; return (Data[0] & 0xf0000000) >> 28; + } return (Data[1] & 0x00ff0000) >> 16; } @@ -373,6 +427,8 @@ struct ExceptionDataRecord { }; inline size_t HeaderWords(const ExceptionDataRecord &XR) { + if (XR.isAArch64) + return (XR.Data[0] & 0xffc00000) ? 1 : 2; return (XR.Data[0] & 0xff800000) ? 1 : 2; } } diff --git a/include/llvm/Support/Allocator.h b/include/llvm/Support/Allocator.h index 184ac491b1f12..42d08378a6774 100644 --- a/include/llvm/Support/Allocator.h +++ b/include/llvm/Support/Allocator.h @@ -21,6 +21,7 @@ #ifndef LLVM_SUPPORT_ALLOCATOR_H #define LLVM_SUPPORT_ALLOCATOR_H +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" @@ -283,6 +284,60 @@ public: 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) diff --git a/include/llvm/Support/BinaryStreamArray.h b/include/llvm/Support/BinaryStreamArray.h index d1571cb37fc69..7c110fcb6a4b1 100644 --- a/include/llvm/Support/BinaryStreamArray.h +++ b/include/llvm/Support/BinaryStreamArray.h @@ -96,21 +96,32 @@ public: explicit VarStreamArray(const Extractor &E) : E(E) {} - explicit VarStreamArray(BinaryStreamRef Stream) : Stream(Stream) {} + explicit VarStreamArray(BinaryStreamRef Stream, uint32_t Skew = 0) + : Stream(Stream), Skew(Skew) {} - VarStreamArray(BinaryStreamRef Stream, const Extractor &E) - : Stream(Stream), E(E) {} + VarStreamArray(BinaryStreamRef Stream, const Extractor &E, uint32_t Skew = 0) + : Stream(Stream), E(E), Skew(Skew) {} Iterator begin(bool *HadError = nullptr) const { - return Iterator(*this, E, HadError); + return Iterator(*this, E, Skew, nullptr); } bool valid() const { return Stream.valid(); } + uint32_t skew() const { return Skew; } Iterator end() const { return Iterator(E); } bool empty() const { return Stream.getLength() == 0; } + VarStreamArray<ValueType, Extractor> substream(uint32_t Begin, + uint32_t End) const { + assert(Begin >= Skew); + // We should never cut off the beginning of the stream since it might be + // skewed, meaning the initial bytes are important. + BinaryStreamRef NewStream = Stream.slice(0, End); + return {NewStream, E, Begin}; + } + /// given an offset into the array's underlying stream, return an /// iterator to the record at that offset. This is considered unsafe /// since the behavior is undefined if \p Offset does not refer to the @@ -123,11 +134,17 @@ public: Extractor &getExtractor() { return E; } BinaryStreamRef getUnderlyingStream() const { return Stream; } - void setUnderlyingStream(BinaryStreamRef S) { Stream = S; } + void setUnderlyingStream(BinaryStreamRef S, uint32_t Skew = 0) { + Stream = S; + this->Skew = Skew; + } + + void drop_front() { Skew += begin()->length(); } private: BinaryStreamRef Stream; Extractor E; + uint32_t Skew; }; template <typename ValueType, typename Extractor> @@ -139,10 +156,6 @@ class VarStreamArrayIterator public: VarStreamArrayIterator(const ArrayType &Array, const Extractor &E, - bool *HadError) - : VarStreamArrayIterator(Array, E, 0, HadError) {} - - VarStreamArrayIterator(const ArrayType &Array, const Extractor &E, uint32_t Offset, bool *HadError) : IterRef(Array.Stream.drop_front(Offset)), Extract(E), Array(&Array), AbsOffset(Offset), HadError(HadError) { diff --git a/include/llvm/Support/BinaryStreamReader.h b/include/llvm/Support/BinaryStreamReader.h index fe77b550c4537..392958de30d56 100644 --- a/include/llvm/Support/BinaryStreamReader.h +++ b/include/llvm/Support/BinaryStreamReader.h @@ -203,11 +203,12 @@ public: /// \returns a success error code if the data was successfully read, otherwise /// returns an appropriate error code. template <typename T, typename U> - Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) { + Error readArray(VarStreamArray<T, U> &Array, uint32_t Size, + uint32_t Skew = 0) { BinaryStreamRef S; if (auto EC = readStreamRef(S, Size)) return EC; - Array.setUnderlyingStream(S); + Array.setUnderlyingStream(S, Skew); return Error::success(); } diff --git a/include/llvm/Support/BuryPointer.h b/include/llvm/Support/BuryPointer.h new file mode 100644 index 0000000000000..53f1f395b9229 --- /dev/null +++ b/include/llvm/Support/BuryPointer.h @@ -0,0 +1,30 @@ +//===- llvm/Support/BuryPointer.h - Memory Manipulation/Leak ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BURYPOINTER_H +#define LLVM_SUPPORT_BURYPOINTER_H + +#include <memory> + +namespace llvm { + +// In tools that will exit soon anyway, going through the process of explicitly +// deallocating resources can be unnecessary - better to leak the resources and +// let the OS clean them up when the process ends. Use this function to ensure +// the memory is not misdiagnosed as an unintentional leak by leak detection +// tools (this is achieved by preserving pointers to the object in a globally +// visible array). +void BuryPointer(const void *Ptr); +template <typename T> void BuryPointer(std::unique_ptr<T> Ptr) { + BuryPointer(Ptr.release()); +} + +} // namespace llvm + +#endif diff --git a/include/llvm/Support/CFGUpdate.h b/include/llvm/Support/CFGUpdate.h new file mode 100644 index 0000000000000..63c24a3d2a20e --- /dev/null +++ b/include/llvm/Support/CFGUpdate.h @@ -0,0 +1,118 @@ +//===- CFGUpdate.h - Encode a CFG Edge Update. ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a CFG Edge Update: Insert or Delete, and two Nodes as the +// Edge ends. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CFGUPDATE_H +#define LLVM_SUPPORT_CFGUPDATE_H + +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace cfg { +enum class UpdateKind : unsigned char { Insert, Delete }; + +template <typename NodePtr> class Update { + using NodeKindPair = PointerIntPair<NodePtr, 1, UpdateKind>; + NodePtr From; + NodeKindPair ToAndKind; + +public: + Update(UpdateKind Kind, NodePtr From, NodePtr To) + : From(From), ToAndKind(To, Kind) {} + + UpdateKind getKind() const { return ToAndKind.getInt(); } + NodePtr getFrom() const { return From; } + NodePtr getTo() const { return ToAndKind.getPointer(); } + bool operator==(const Update &RHS) const { + return From == RHS.From && ToAndKind == RHS.ToAndKind; + } + + void print(raw_ostream &OS) const { + OS << (getKind() == UpdateKind::Insert ? "Insert " : "Delete "); + getFrom()->printAsOperand(OS, false); + OS << " -> "; + getTo()->printAsOperand(OS, false); + } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const { print(dbgs()); } +#endif +}; + +// LegalizeUpdates function simplifies updates assuming a graph structure. +// This function serves double purpose: +// a) It removes redundant updates, which makes it easier to reverse-apply +// them when traversing CFG. +// b) It optimizes away updates that cancel each other out, as the end result +// is the same. +template <typename NodePtr> +void LegalizeUpdates(ArrayRef<Update<NodePtr>> AllUpdates, + SmallVectorImpl<Update<NodePtr>> &Result, + bool InverseGraph) { + // Count the total number of inserions of each edge. + // Each insertion adds 1 and deletion subtracts 1. The end number should be + // one of {-1 (deletion), 0 (NOP), +1 (insertion)}. Otherwise, the sequence + // of updates contains multiple updates of the same kind and we assert for + // that case. + SmallDenseMap<std::pair<NodePtr, NodePtr>, int, 4> Operations; + Operations.reserve(AllUpdates.size()); + + for (const auto &U : AllUpdates) { + NodePtr From = U.getFrom(); + NodePtr To = U.getTo(); + if (InverseGraph) + std::swap(From, To); // Reverse edge for postdominators. + + Operations[{From, To}] += (U.getKind() == UpdateKind::Insert ? 1 : -1); + } + + Result.clear(); + Result.reserve(Operations.size()); + for (auto &Op : Operations) { + const int NumInsertions = Op.second; + assert(std::abs(NumInsertions) <= 1 && "Unbalanced operations!"); + if (NumInsertions == 0) + continue; + const UpdateKind UK = + NumInsertions > 0 ? UpdateKind::Insert : UpdateKind::Delete; + Result.push_back({UK, Op.first.first, Op.first.second}); + } + + // Make the order consistent by not relying on pointer values within the + // set. Reuse the old Operations map. + // In the future, we should sort by something else to minimize the amount + // of work needed to perform the series of updates. + for (size_t i = 0, e = AllUpdates.size(); i != e; ++i) { + const auto &U = AllUpdates[i]; + if (!InverseGraph) + Operations[{U.getFrom(), U.getTo()}] = int(i); + else + Operations[{U.getTo(), U.getFrom()}] = int(i); + } + + llvm::sort(Result, + [&Operations](const Update<NodePtr> &A, const Update<NodePtr> &B) { + return Operations[{A.getFrom(), A.getTo()}] > + Operations[{B.getFrom(), B.getTo()}]; + }); +} + +} // end namespace cfg +} // end namespace llvm + +#endif // LLVM_SUPPORT_CFGUPDATE_H diff --git a/include/llvm/Support/Chrono.h b/include/llvm/Support/Chrono.h index 994068af3771b..57677e8d5cf14 100644 --- a/include/llvm/Support/Chrono.h +++ b/include/llvm/Support/Chrono.h @@ -47,6 +47,14 @@ toTimePoint(std::time_t T) { return time_point_cast<seconds>(system_clock::from_time_t(T)); } +/// Convert a std::time_t + nanoseconds to a TimePoint +LLVM_ATTRIBUTE_ALWAYS_INLINE 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); diff --git a/include/llvm/Support/CodeGen.h b/include/llvm/Support/CodeGen.h index 5f9e331295872..22e74167266c4 100644 --- a/include/llvm/Support/CodeGen.h +++ b/include/llvm/Support/CodeGen.h @@ -25,7 +25,7 @@ namespace llvm { // Code model types. namespace CodeModel { // Sync changes with CodeGenCWrappers.h. - enum Model { Small, Kernel, Medium, Large }; + enum Model { Tiny, Small, Kernel, Medium, Large }; } namespace PICLevel { @@ -57,6 +57,11 @@ namespace llvm { }; } + // Specify effect of frame pointer elimination optimization. + namespace FramePointer { + enum FP {All, NonLeaf, None}; + } + } // end llvm namespace #endif diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h index 799b41fbf8b0f..a8ad89384d17e 100644 --- a/include/llvm/Support/CommandLine.h +++ b/include/llvm/Support/CommandLine.h @@ -56,9 +56,18 @@ namespace cl { // Returns true on success. Otherwise, this will print the error message to // stderr and exit if \p Errs is not set (nullptr by default), or print the // error message to \p Errs and return false if \p Errs is provided. +// +// If EnvVar is not nullptr, command-line options are also parsed from the +// environment variable named by EnvVar. Precedence is given to occurrences +// from argv. This precedence is currently implemented by parsing argv after +// the environment variable, so it is only implemented correctly for options +// that give precedence to later occurrences. If your program supports options +// that give precedence to earlier occurrences, you will need to extend this +// function to support it correctly. bool ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview = "", - raw_ostream *Errs = nullptr); + raw_ostream *Errs = nullptr, + const char *EnvVar = nullptr); //===----------------------------------------------------------------------===// // ParseEnvironmentOptions - Environment variable option processing alternate @@ -147,6 +156,9 @@ enum OptionHidden { // Control whether -help shows this option // enabled, and used, the value for the flag comes from the suffix of the // argument. // +// AlwaysPrefix - Only allow the behavior enabled by the Prefix flag and reject +// the Option=Value form. +// // Grouping - With this option enabled, multiple letter options are allowed to // bunch together with only a single hyphen for the whole group. This allows // emulation of the behavior that ls uses for example: ls -la === ls -l -a @@ -156,7 +168,8 @@ enum FormattingFlags { NormalFormatting = 0x00, // Nothing special Positional = 0x01, // Is a positional argument, no '-' required Prefix = 0x02, // Can this option directly prefix its value? - Grouping = 0x03 // Can this option group with other options? + AlwaysPrefix = 0x03, // Can this option only directly prefix its value? + Grouping = 0x04 // Can this option group with other options? }; enum MiscFlags { // Miscellaneous flags to adjust argument @@ -256,7 +269,7 @@ class Option { // detail representing the non-value unsigned Value : 2; unsigned HiddenFlag : 2; // enum OptionHidden - unsigned Formatting : 2; // enum FormattingFlags + unsigned Formatting : 3; // enum FormattingFlags unsigned Misc : 3; unsigned Position = 0; // Position of last occurrence of the option unsigned AdditionalVals = 0; // Greater than 0 for multi-valued option. diff --git a/include/llvm/Support/Compiler.h b/include/llvm/Support/Compiler.h index 4de815fe61d74..14e4d6e971404 100644 --- a/include/llvm/Support/Compiler.h +++ b/include/llvm/Support/Compiler.h @@ -133,6 +133,19 @@ #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 __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. @@ -519,7 +532,7 @@ namespace llvm { /// reduced default alignment. inline void *allocate_buffer(size_t Size, size_t Alignment) { return ::operator new(Size -#if __cpp_aligned_new +#ifdef __cpp_aligned_new , std::align_val_t(Alignment) #endif @@ -535,11 +548,11 @@ inline void *allocate_buffer(size_t Size, size_t Alignment) { /// most likely using the above helper. inline void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment) { ::operator delete(Ptr -#if __cpp_sized_deallocation +#ifdef __cpp_sized_deallocation , Size #endif -#if __cpp_aligned_new +#ifdef __cpp_aligned_new , std::align_val_t(Alignment) #endif diff --git a/include/llvm/Support/Compression.h b/include/llvm/Support/Compression.h index 2d191abe4b1af..f7258f4bf8f82 100644 --- a/include/llvm/Support/Compression.h +++ b/include/llvm/Support/Compression.h @@ -23,17 +23,15 @@ class StringRef; namespace zlib { -enum CompressionLevel { - NoCompression, - DefaultCompression, - BestSpeedCompression, - BestSizeCompression -}; +static constexpr int NoCompression = 0; +static constexpr int BestSpeedCompression = 1; +static constexpr int DefaultCompression = 6; +static constexpr int BestSizeCompression = 9; bool isAvailable(); Error compress(StringRef InputBuffer, SmallVectorImpl<char> &CompressedBuffer, - CompressionLevel Level = DefaultCompression); + int Level = DefaultCompression); Error uncompress(StringRef InputBuffer, char *UncompressedBuffer, size_t &UncompressedSize); @@ -49,4 +47,3 @@ uint32_t crc32(StringRef Buffer); } // End of namespace llvm #endif - diff --git a/include/llvm/Support/Debug.h b/include/llvm/Support/Debug.h index 980abfb0e8da1..df86dbb82414a 100644 --- a/include/llvm/Support/Debug.h +++ b/include/llvm/Support/Debug.h @@ -94,6 +94,10 @@ extern bool VerifyDomInfo; /// extern bool VerifyLoopInfo; +/// Enables verification of MemorySSA. +/// +extern bool VerifyMemorySSA; + ///\} /// EnableDebugBuffering - This defaults to false. If true, the debug diff --git a/include/llvm/Support/DebugCounter.h b/include/llvm/Support/DebugCounter.h index 250fc6bb1f5cf..6eadd5c6aefff 100644 --- a/include/llvm/Support/DebugCounter.h +++ b/include/llvm/Support/DebugCounter.h @@ -55,6 +55,8 @@ namespace llvm { class DebugCounter { public: + ~DebugCounter(); + /// Returns a reference to the singleton instance. static DebugCounter &instance(); @@ -70,10 +72,9 @@ public: return instance().addCounter(Name, Desc); } inline static bool shouldExecute(unsigned CounterName) { -// Compile to nothing when debugging is off -#ifdef NDEBUG - return true; -#else + if (!isCountingEnabled()) + return true; + auto &Us = instance(); auto Result = Us.Counters.find(CounterName); if (Result != Us.Counters.end()) { @@ -93,7 +94,6 @@ public: } // Didn't find the counter, should we warn? return true; -#endif // NDEBUG } // Return true if a given counter had values set (either programatically or on @@ -142,7 +142,23 @@ public: } CounterVector::const_iterator end() const { return RegisteredCounters.end(); } + // Force-enables counting all DebugCounters. + // + // Since DebugCounters are incompatible with threading (not only do they not + // make sense, but we'll also see data races), this should only be used in + // contexts where we're certain we won't spawn threads. + static void enableAllCounters() { instance().Enabled = true; } + private: + static bool isCountingEnabled() { +// Compile to nothing when debugging is off +#ifdef NDEBUG + return false; +#else + return instance().Enabled; +#endif + } + unsigned addCounter(const std::string &Name, const std::string &Desc) { unsigned Result = RegisteredCounters.insert(Name); Counters[Result] = {}; @@ -159,6 +175,10 @@ private: }; DenseMap<unsigned, CounterInfo> Counters; CounterVector RegisteredCounters; + + // Whether we should do DebugCounting at all. DebugCounters aren't + // thread-safe, so this should always be false in multithreaded scenarios. + bool Enabled = false; }; #define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC) \ diff --git a/include/llvm/Support/Error.h b/include/llvm/Support/Error.h index 8015cab45a068..ee2cbeec97a81 100644 --- a/include/llvm/Support/Error.h +++ b/include/llvm/Support/Error.h @@ -14,8 +14,9 @@ #ifndef LLVM_SUPPORT_ERROR_H #define LLVM_SUPPORT_ERROR_H -#include "llvm/ADT/SmallVector.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" @@ -155,9 +156,10 @@ private: /// 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 { - // ErrorList needs to be able to yank ErrorInfoBase pointers out of this - // class to add to the error list. + // 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> @@ -167,6 +169,9 @@ class LLVM_NODISCARD Error { // 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() { @@ -317,7 +322,7 @@ private: /// 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 : public Error {}; +class ErrorSuccess final : public Error {}; inline ErrorSuccess Error::success() { return ErrorSuccess(); } @@ -339,6 +344,8 @@ template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) { 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; } @@ -946,10 +953,14 @@ Expected<T> handleExpected(Expected<T> ValOrErr, RecoveryFtor &&RecoveryPath, /// 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); +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. @@ -1055,6 +1066,8 @@ private: 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; } @@ -1106,10 +1119,33 @@ template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> &&E) { /// 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; @@ -1120,6 +1156,7 @@ public: private: std::string Msg; std::error_code EC; + const bool PrintMsgOnly = false; }; /// Create formatted StringError object. @@ -1134,6 +1171,53 @@ Error createStringError(std::error_code EC, char const *Fmt, Error createStringError(std::error_code EC, char const *Msg); +/// 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(std::string, Error); + +public: + void log(raw_ostream &OS) const override { + assert(Err && !FileName.empty() && "Trying to log after takeError()."); + OS << "'" << FileName << "': "; + 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(std::string F, std::unique_ptr<ErrorInfoBase> E) { + assert(E && "Cannot create FileError from Error success value."); + assert(!F.empty() && + "The file name provided to FileError must not be empty."); + FileName = F; + Err = std::move(E); + } + + static Error build(std::string F, Error E) { + return Error(std::unique_ptr<FileError>(new FileError(F, E.takePayload()))); + } + + std::string FileName; + std::unique_ptr<ErrorInfoBase> Err; +}; + +/// Concatenate a source file path and/or name with an Error. The resulting +/// Error is unchecked. +inline Error createFileError(std::string F, Error E) { + return FileError::build(F, std::move(E)); +} + +Error createFileError(std::string F, ErrorSuccess) = delete; + /// Helper for check-and-exit error handling. /// /// For tool use only. NOT FOR USE IN LIBRARY CODE. @@ -1183,6 +1267,17 @@ private: 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/include/llvm/Support/ErrorHandling.h b/include/llvm/Support/ErrorHandling.h index 39cbfed2436af..fec39e59a7170 100644 --- a/include/llvm/Support/ErrorHandling.h +++ b/include/llvm/Support/ErrorHandling.h @@ -112,8 +112,8 @@ void install_out_of_memory_new_handler(); /// 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. +/// 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. diff --git a/include/llvm/Support/FileCheck.h b/include/llvm/Support/FileCheck.h new file mode 100644 index 0000000000000..4061a26e22c50 --- /dev/null +++ b/include/llvm/Support/FileCheck.h @@ -0,0 +1,282 @@ +//==-- llvm/Support/FileCheck.h ---------------------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file has some utilities to use FileCheck as an API +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_FILECHECK_H +#define LLVM_SUPPORT_FILECHECK_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/SourceMgr.h" +#include <vector> +#include <map> + +namespace llvm { + +/// Contains info about various FileCheck options. +struct FileCheckRequest { + std::vector<std::string> CheckPrefixes; + bool NoCanonicalizeWhiteSpace = false; + std::vector<std::string> ImplicitCheckNot; + std::vector<std::string> GlobalDefines; + bool AllowEmptyInput = false; + bool MatchFullLines = false; + bool EnableVarScope = false; + bool AllowDeprecatedDagOverlap = false; + bool Verbose = false; + bool VerboseVerbose = false; +}; + + +//===----------------------------------------------------------------------===// +// Pattern Handling Code. +//===----------------------------------------------------------------------===// + +namespace Check { + +enum FileCheckKind { + CheckNone = 0, + CheckPlain, + CheckNext, + CheckSame, + CheckNot, + CheckDAG, + CheckLabel, + CheckEmpty, + + /// Indicates the pattern only matches the end of file. This is used for + /// trailing CHECK-NOTs. + CheckEOF, + + /// Marks when parsing found a -NOT check combined with another CHECK suffix. + CheckBadNot, + + /// Marks when parsing found a -COUNT directive with invalid count value. + CheckBadCount +}; + +class FileCheckType { + FileCheckKind Kind; + int Count; ///< optional Count for some checks + +public: + FileCheckType(FileCheckKind Kind = CheckNone) : Kind(Kind), Count(1) {} + FileCheckType(const FileCheckType &) = default; + + operator FileCheckKind() const { return Kind; } + + int getCount() const { return Count; } + FileCheckType &setCount(int C); + + std::string getDescription(StringRef Prefix) const; +}; +} + +struct FileCheckDiag; + +class FileCheckPattern { + SMLoc PatternLoc; + + /// A fixed string to match as the pattern or empty if this pattern requires + /// a regex match. + StringRef FixedStr; + + /// A regex string to match as the pattern or empty if this pattern requires + /// a fixed string to match. + std::string RegExStr; + + /// Entries in this vector map to uses of a variable in the pattern, e.g. + /// "foo[[bar]]baz". In this case, the RegExStr will contain "foobaz" and + /// we'll get an entry in this vector that tells us to insert the value of + /// bar at offset 3. + std::vector<std::pair<StringRef, unsigned>> VariableUses; + + /// Maps definitions of variables to their parenthesized capture numbers. + /// + /// E.g. for the pattern "foo[[bar:.*]]baz", VariableDefs will map "bar" to + /// 1. + std::map<StringRef, unsigned> VariableDefs; + + Check::FileCheckType CheckTy; + + /// Contains the number of line this pattern is in. + unsigned LineNumber; + +public: + explicit FileCheckPattern(Check::FileCheckType Ty) + : CheckTy(Ty) {} + + /// Returns the location in source code. + SMLoc getLoc() const { return PatternLoc; } + + bool ParsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM, + unsigned LineNumber, const FileCheckRequest &Req); + size_t Match(StringRef Buffer, size_t &MatchLen, + StringMap<StringRef> &VariableTable) const; + void PrintVariableUses(const SourceMgr &SM, StringRef Buffer, + const StringMap<StringRef> &VariableTable, + SMRange MatchRange = None) const; + void PrintFuzzyMatch(const SourceMgr &SM, StringRef Buffer, + const StringMap<StringRef> &VariableTable, + std::vector<FileCheckDiag> *Diags) const; + + bool hasVariable() const { + return !(VariableUses.empty() && VariableDefs.empty()); + } + + Check::FileCheckType getCheckTy() const { return CheckTy; } + + int getCount() const { return CheckTy.getCount(); } + +private: + bool AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM); + void AddBackrefToRegEx(unsigned BackrefNum); + unsigned + ComputeMatchDistance(StringRef Buffer, + const StringMap<StringRef> &VariableTable) const; + bool EvaluateExpression(StringRef Expr, std::string &Value) const; + size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM); +}; + +//===----------------------------------------------------------------------===// +/// Summary of a FileCheck diagnostic. +//===----------------------------------------------------------------------===// + +struct FileCheckDiag { + /// What is the FileCheck directive for this diagnostic? + Check::FileCheckType CheckTy; + /// Where is the FileCheck directive for this diagnostic? + unsigned CheckLine, CheckCol; + /// What type of match result does this diagnostic describe? + /// + /// A directive's supplied pattern is said to be either expected or excluded + /// depending on whether the pattern must have or must not have a match in + /// order for the directive to succeed. For example, a CHECK directive's + /// pattern is expected, and a CHECK-NOT directive's pattern is excluded. + /// All match result types whose names end with "Excluded" are for excluded + /// patterns, and all others are for expected patterns. + /// + /// There might be more than one match result for a single pattern. For + /// example, there might be several discarded matches + /// (MatchFoundButDiscarded) before either a good match + /// (MatchFoundAndExpected) or a failure to match (MatchNoneButExpected), + /// and there might be a fuzzy match (MatchFuzzy) after the latter. + enum MatchType { + /// Indicates a good match for an expected pattern. + MatchFoundAndExpected, + /// Indicates a match for an excluded pattern. + MatchFoundButExcluded, + /// Indicates a match for an expected pattern, but the match is on the + /// wrong line. + MatchFoundButWrongLine, + /// Indicates a discarded match for an expected pattern. + MatchFoundButDiscarded, + /// Indicates no match for an excluded pattern. + MatchNoneAndExcluded, + /// Indicates no match for an expected pattern, but this might follow good + /// matches when multiple matches are expected for the pattern, or it might + /// follow discarded matches for the pattern. + MatchNoneButExpected, + /// Indicates a fuzzy match that serves as a suggestion for the next + /// intended match for an expected pattern with too few or no good matches. + MatchFuzzy, + } MatchTy; + /// The search range if MatchTy is MatchNoneAndExcluded or + /// MatchNoneButExpected, or the match range otherwise. + unsigned InputStartLine; + unsigned InputStartCol; + unsigned InputEndLine; + unsigned InputEndCol; + FileCheckDiag(const SourceMgr &SM, const Check::FileCheckType &CheckTy, + SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange); +}; + +//===----------------------------------------------------------------------===// +// Check Strings. +//===----------------------------------------------------------------------===// + +/// A check that we found in the input file. +struct FileCheckString { + /// The pattern to match. + FileCheckPattern Pat; + + /// Which prefix name this check matched. + StringRef Prefix; + + /// The location in the match file that the check string was specified. + SMLoc Loc; + + /// All of the strings that are disallowed from occurring between this match + /// string and the previous one (or start of file). + std::vector<FileCheckPattern> DagNotStrings; + + FileCheckString(const FileCheckPattern &P, StringRef S, SMLoc L) + : Pat(P), Prefix(S), Loc(L) {} + + size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode, + size_t &MatchLen, StringMap<StringRef> &VariableTable, + FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const; + + bool CheckNext(const SourceMgr &SM, StringRef Buffer) const; + bool CheckSame(const SourceMgr &SM, StringRef Buffer) const; + bool CheckNot(const SourceMgr &SM, StringRef Buffer, + const std::vector<const FileCheckPattern *> &NotStrings, + StringMap<StringRef> &VariableTable, + const FileCheckRequest &Req, + std::vector<FileCheckDiag> *Diags) const; + size_t CheckDag(const SourceMgr &SM, StringRef Buffer, + std::vector<const FileCheckPattern *> &NotStrings, + StringMap<StringRef> &VariableTable, + const FileCheckRequest &Req, + std::vector<FileCheckDiag> *Diags) const; +}; + +/// FileCheck class takes the request and exposes various methods that +/// use information from the request. +class FileCheck { + FileCheckRequest Req; + +public: + FileCheck(FileCheckRequest Req) : Req(Req) {} + + // Combines the check prefixes into a single regex so that we can efficiently + // scan for any of the set. + // + // The semantics are that the longest-match wins which matches our regex + // library. + Regex buildCheckPrefixRegex(); + + /// Read the check file, which specifies the sequence of expected strings. + /// + /// The strings are added to the CheckStrings vector. Returns true in case of + /// an error, false otherwise. + bool ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE, + std::vector<FileCheckString> &CheckStrings); + + bool ValidateCheckPrefixes(); + + /// Canonicalize whitespaces in the file. Line endings are replaced with + /// UNIX-style '\n'. + StringRef CanonicalizeFile(MemoryBuffer &MB, + SmallVectorImpl<char> &OutputBuffer); + + /// Check the input to FileCheck provided in the \p Buffer against the \p + /// CheckStrings read from the check file. + /// + /// Returns false if the input fails to satisfy the checks. + bool CheckInput(SourceMgr &SM, StringRef Buffer, + ArrayRef<FileCheckString> CheckStrings, + std::vector<FileCheckDiag> *Diags = nullptr); +}; +} // namespace llvm +#endif diff --git a/include/llvm/Support/FileOutputBuffer.h b/include/llvm/Support/FileOutputBuffer.h index ee8cbb730878c..68226ca55502f 100644 --- a/include/llvm/Support/FileOutputBuffer.h +++ b/include/llvm/Support/FileOutputBuffer.h @@ -76,6 +76,10 @@ public: /// 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) {} diff --git a/include/llvm/Support/FileSystem.h b/include/llvm/Support/FileSystem.h index 02db4596bf1cb..d2042f51d8c14 100644 --- a/include/llvm/Support/FileSystem.h +++ b/include/llvm/Support/FileSystem.h @@ -160,6 +160,8 @@ 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; @@ -180,9 +182,12 @@ public: 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, time_t MTime, + 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_uid(UID), fs_st_gid(GID), + : 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, @@ -199,7 +204,20 @@ public: // 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) @@ -247,8 +265,11 @@ public: #if defined(LLVM_ON_UNIX) file_status(file_type Type, perms Perms, dev_t Dev, nlink_t Links, ino_t Ino, - time_t ATime, time_t MTime, uid_t UID, gid_t GID, off_t Size) - : basic_file_status(Type, Perms, ATime, MTime, UID, GID, Size), + 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, @@ -281,10 +302,7 @@ public: /// 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(const Twine ¤t_directory, - SmallVectorImpl<char> &path); +void make_absolute(const Twine ¤t_directory, SmallVectorImpl<char> &path); /// Make \a path an absolute path. /// @@ -349,6 +367,12 @@ std::error_code create_hard_link(const Twine &to, const Twine &from); 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. @@ -666,7 +690,15 @@ inline std::error_code file_size(const Twine &Path, uint64_t &Result) { /// @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 setLastModificationAndAccessTime(int FD, TimePoint<> Time); +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? /// @@ -693,7 +725,7 @@ enum CreationDisposition : unsigned { /// * If it does not already exist, create a new file. CD_CreateNew = 1, - /// CD_OpenAlways - When opening a file: + /// 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, @@ -1092,38 +1124,51 @@ std::string getMainExecutable(const char *argv0, void *MainExecAddr); /// @name Iterators /// @{ -/// directory_entry - A single entry in a directory. Caches the status either -/// from the result of the iteration syscall, or the first time status is -/// called. +/// 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; - bool FollowSymlinks; - basic_file_status Status; + file_type Type; // Most platforms can provide this. + bool FollowSymlinks; // Affects the behavior of status(). + basic_file_status Status; // If available. public: - explicit directory_entry(const Twine &path, bool follow_symlinks = true, - basic_file_status st = basic_file_status()) - : Path(path.str()), FollowSymlinks(follow_symlinks), Status(st) {} + 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 assign(const Twine &path, basic_file_status st = basic_file_status()) { - Path = path.str(); - Status = st; - } - - void replace_filename(const Twine &filename, - basic_file_status st = basic_file_status()); + 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; + 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 { @@ -1161,7 +1206,6 @@ public: SmallString<128> path_storage; ec = detail::directory_iterator_construct( *State, path.toStringRef(path_storage), FollowSymlinks); - update_error_code_for_current_entry(ec); } explicit directory_iterator(const directory_entry &de, std::error_code &ec, @@ -1170,7 +1214,6 @@ public: State = std::make_shared<detail::DirIterState>(); ec = detail::directory_iterator_construct( *State, de.path(), FollowSymlinks); - update_error_code_for_current_entry(ec); } /// Construct end iterator. @@ -1179,7 +1222,6 @@ public: // No operator++ because we need error_code. directory_iterator &increment(std::error_code &ec) { ec = directory_iterator_increment(*State); - update_error_code_for_current_entry(ec); return *this; } @@ -1199,26 +1241,6 @@ public: bool operator!=(const directory_iterator &RHS) const { return !(*this == RHS); } - // Other members as required by - // C++ Std, 24.1.1 Input iterators [input.iterators] - -private: - // Checks if current entry is valid and populates error code. For example, - // current entry may not exist due to broken symbol links. - void update_error_code_for_current_entry(std::error_code &ec) { - // Bail out if error has already occured earlier to avoid overwriting it. - if (ec) - return; - - // Empty directory entry is used to mark the end of an interation, it's not - // an error. - if (State->CurrentEntry == directory_entry()) - return; - - ErrorOr<basic_file_status> status = State->CurrentEntry.status(); - if (!status) - ec = status.getError(); - } }; namespace detail { @@ -1256,8 +1278,15 @@ public: if (State->HasNoPushRequest) State->HasNoPushRequest = false; else { - ErrorOr<basic_file_status> status = State->Stack.top()->status(); - if (status && is_directory(*status)) { + 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; @@ -1321,8 +1350,6 @@ public: bool operator!=(const recursive_directory_iterator &RHS) const { return !(*this == RHS); } - // Other members as required by - // C++ Std, 24.1.1 Input iterators [input.iterators] }; /// @} diff --git a/include/llvm/Support/FormatVariadicDetails.h b/include/llvm/Support/FormatVariadicDetails.h index 56dda430efda3..e8bd90f50941c 100644 --- a/include/llvm/Support/FormatVariadicDetails.h +++ b/include/llvm/Support/FormatVariadicDetails.h @@ -21,6 +21,8 @@ class Error; namespace detail { class format_adapter { + virtual void anchor(); + protected: virtual ~format_adapter() {} diff --git a/include/llvm/Support/GenericDomTree.h b/include/llvm/Support/GenericDomTree.h index c716e4a4d3009..b3018bac310ac 100644 --- a/include/llvm/Support/GenericDomTree.h +++ b/include/llvm/Support/GenericDomTree.h @@ -24,6 +24,14 @@ #ifndef LLVM_SUPPORT_GENERICDOMTREE_H #define LLVM_SUPPORT_GENERICDOMTREE_H +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/CFGUpdate.h" +#include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> #include <cstddef> @@ -32,13 +40,6 @@ #include <type_traits> #include <utility> #include <vector> -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/PointerIntPair.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/raw_ostream.h" namespace llvm { @@ -192,6 +193,10 @@ template <typename DomTreeT> void Calculate(DomTreeT &DT); template <typename DomTreeT> +void CalculateWithUpdates(DomTreeT &DT, + ArrayRef<typename DomTreeT::UpdateType> Updates); + +template <typename DomTreeT> void InsertEdge(DomTreeT &DT, typename DomTreeT::NodePtr From, typename DomTreeT::NodePtr To); @@ -199,36 +204,6 @@ template <typename DomTreeT> void DeleteEdge(DomTreeT &DT, typename DomTreeT::NodePtr From, typename DomTreeT::NodePtr To); -// UpdateKind and Update are used by the batch update API and it's easiest to -// define them here. -enum class UpdateKind : unsigned char { Insert, Delete }; - -template <typename NodePtr> -struct Update { - using NodeKindPair = PointerIntPair<NodePtr, 1, UpdateKind>; - - NodePtr From; - NodeKindPair ToAndKind; - - Update(UpdateKind Kind, NodePtr From, NodePtr To) - : From(From), ToAndKind(To, Kind) {} - - UpdateKind getKind() const { return ToAndKind.getInt(); } - NodePtr getFrom() const { return From; } - NodePtr getTo() const { return ToAndKind.getPointer(); } - bool operator==(const Update &RHS) const { - return From == RHS.From && ToAndKind == RHS.ToAndKind; - } - - friend raw_ostream &operator<<(raw_ostream &OS, const Update &U) { - OS << (U.getKind() == UpdateKind::Insert ? "Insert " : "Delete "); - U.getFrom()->printAsOperand(OS, false); - OS << " -> "; - U.getTo()->printAsOperand(OS, false); - return OS; - } -}; - template <typename DomTreeT> void ApplyUpdates(DomTreeT &DT, ArrayRef<typename DomTreeT::UpdateType> Updates); @@ -254,8 +229,8 @@ class DominatorTreeBase { using ParentType = typename std::remove_pointer<ParentPtr>::type; static constexpr bool IsPostDominator = IsPostDom; - using UpdateType = DomTreeBuilder::Update<NodePtr>; - using UpdateKind = DomTreeBuilder::UpdateKind; + using UpdateType = cfg::Update<NodePtr>; + using UpdateKind = cfg::UpdateKind; static constexpr UpdateKind Insert = UpdateKind::Insert; static constexpr UpdateKind Delete = UpdateKind::Delete; @@ -759,6 +734,11 @@ public: DomTreeBuilder::Calculate(*this); } + void recalculate(ParentType &Func, ArrayRef<UpdateType> Updates) { + Parent = &Func; + DomTreeBuilder::CalculateWithUpdates(*this, Updates); + } + /// verify - checks if the tree is correct. There are 3 level of verification: /// - Full -- verifies if the tree is correct by making sure all the /// properties (including the parent and the sibling property) diff --git a/include/llvm/Support/GenericDomTreeConstruction.h b/include/llvm/Support/GenericDomTreeConstruction.h index 103ff8ca476a9..971e8305a112c 100644 --- a/include/llvm/Support/GenericDomTreeConstruction.h +++ b/include/llvm/Support/GenericDomTreeConstruction.h @@ -71,6 +71,7 @@ struct SemiNCAInfo { DenseMap<NodePtr, InfoRec> NodeToInfo; using UpdateT = typename DomTreeT::UpdateType; + using UpdateKind = typename DomTreeT::UpdateKind; struct BatchUpdateInfo { SmallVector<UpdateT, 4> Updates; using NodePtrAndKind = PointerIntPair<NodePtr, 1, UpdateKind>; @@ -1166,7 +1167,8 @@ struct SemiNCAInfo { } BatchUpdateInfo BUI; - LegalizeUpdates(Updates, BUI.Updates); + LLVM_DEBUG(dbgs() << "Legalizing " << BUI.Updates.size() << " updates\n"); + cfg::LegalizeUpdates<NodePtr>(Updates, BUI.Updates, IsPostDom); const size_t NumLegalized = BUI.Updates.size(); BUI.FutureSuccessors.reserve(NumLegalized); @@ -1182,10 +1184,27 @@ struct SemiNCAInfo { LLVM_DEBUG(dbgs() << "About to apply " << NumLegalized << " updates\n"); LLVM_DEBUG(if (NumLegalized < 32) for (const auto &U - : reverse(BUI.Updates)) dbgs() - << '\t' << U << "\n"); + : reverse(BUI.Updates)) { + dbgs() << "\t"; + U.dump(); + dbgs() << "\n"; + }); LLVM_DEBUG(dbgs() << "\n"); + // Recalculate the DominatorTree when the number of updates + // exceeds a threshold, which usually makes direct updating slower than + // recalculation. We select this threshold proportional to the + // size of the DominatorTree. The constant is selected + // by choosing the one with an acceptable performance on some real-world + // inputs. + + // Make unittests of the incremental algorithm work + if (DT.DomTreeNodes.size() <= 100) { + if (NumLegalized > DT.DomTreeNodes.size()) + CalculateFromScratch(DT, &BUI); + } else if (NumLegalized > DT.DomTreeNodes.size() / 40) + CalculateFromScratch(DT, &BUI); + // If the DominatorTree was recalculated at some point, stop the batch // updates. Full recalculations ignore batch updates and look at the actual // CFG. @@ -1193,76 +1212,11 @@ struct SemiNCAInfo { ApplyNextUpdate(DT, BUI); } - // This function serves double purpose: - // a) It removes redundant updates, which makes it easier to reverse-apply - // them when traversing CFG. - // b) It optimizes away updates that cancel each other out, as the end result - // is the same. - // - // It relies on the property of the incremental updates that says that the - // order of updates doesn't matter. This allows us to reorder them and end up - // with the exact same DomTree every time. - // - // Following the same logic, the function doesn't care about the order of - // input updates, so it's OK to pass it an unordered sequence of updates, that - // doesn't make sense when applied sequentially, eg. performing double - // insertions or deletions and then doing an opposite update. - // - // In the future, it should be possible to schedule updates in way that - // minimizes the amount of work needed done during incremental updates. - static void LegalizeUpdates(ArrayRef<UpdateT> AllUpdates, - SmallVectorImpl<UpdateT> &Result) { - LLVM_DEBUG(dbgs() << "Legalizing " << AllUpdates.size() << " updates\n"); - // Count the total number of inserions of each edge. - // Each insertion adds 1 and deletion subtracts 1. The end number should be - // one of {-1 (deletion), 0 (NOP), +1 (insertion)}. Otherwise, the sequence - // of updates contains multiple updates of the same kind and we assert for - // that case. - SmallDenseMap<std::pair<NodePtr, NodePtr>, int, 4> Operations; - Operations.reserve(AllUpdates.size()); - - for (const auto &U : AllUpdates) { - NodePtr From = U.getFrom(); - NodePtr To = U.getTo(); - if (IsPostDom) std::swap(From, To); // Reverse edge for postdominators. - - Operations[{From, To}] += (U.getKind() == UpdateKind::Insert ? 1 : -1); - } - - Result.clear(); - Result.reserve(Operations.size()); - for (auto &Op : Operations) { - const int NumInsertions = Op.second; - assert(std::abs(NumInsertions) <= 1 && "Unbalanced operations!"); - if (NumInsertions == 0) continue; - const UpdateKind UK = - NumInsertions > 0 ? UpdateKind::Insert : UpdateKind::Delete; - Result.push_back({UK, Op.first.first, Op.first.second}); - } - - // Make the order consistent by not relying on pointer values within the - // set. Reuse the old Operations map. - // In the future, we should sort by something else to minimize the amount - // of work needed to perform the series of updates. - for (size_t i = 0, e = AllUpdates.size(); i != e; ++i) { - const auto &U = AllUpdates[i]; - if (!IsPostDom) - Operations[{U.getFrom(), U.getTo()}] = int(i); - else - Operations[{U.getTo(), U.getFrom()}] = int(i); - } - - llvm::sort(Result.begin(), Result.end(), - [&Operations](const UpdateT &A, const UpdateT &B) { - return Operations[{A.getFrom(), A.getTo()}] > - Operations[{B.getFrom(), B.getTo()}]; - }); - } - static void ApplyNextUpdate(DomTreeT &DT, BatchUpdateInfo &BUI) { assert(!BUI.Updates.empty() && "No updates to apply!"); UpdateT CurrentUpdate = BUI.Updates.pop_back_val(); - LLVM_DEBUG(dbgs() << "Applying update: " << CurrentUpdate << "\n"); + LLVM_DEBUG(dbgs() << "Applying update: "); + LLVM_DEBUG(CurrentUpdate.dump(); dbgs() << "\n"); // Move to the next snapshot of the CFG by removing the reverse-applied // current update. Since updates are performed in the same order they are @@ -1446,10 +1400,9 @@ struct SemiNCAInfo { // Make a copy and sort it such that it is possible to check if there are // no gaps between DFS numbers of adjacent children. SmallVector<TreeNodePtr, 8> Children(Node->begin(), Node->end()); - llvm::sort(Children.begin(), Children.end(), - [](const TreeNodePtr Ch1, const TreeNodePtr Ch2) { - return Ch1->getDFSNumIn() < Ch2->getDFSNumIn(); - }); + llvm::sort(Children, [](const TreeNodePtr Ch1, const TreeNodePtr Ch2) { + return Ch1->getDFSNumIn() < Ch2->getDFSNumIn(); + }); auto PrintChildrenError = [Node, &Children, PrintNodeAndDFSNums]( const TreeNodePtr FirstCh, const TreeNodePtr SecondCh) { @@ -1636,6 +1589,25 @@ void Calculate(DomTreeT &DT) { SemiNCAInfo<DomTreeT>::CalculateFromScratch(DT, nullptr); } +template <typename DomTreeT> +void CalculateWithUpdates(DomTreeT &DT, + ArrayRef<typename DomTreeT::UpdateType> Updates) { + // TODO: Move BUI creation in common method, reuse in ApplyUpdates. + typename SemiNCAInfo<DomTreeT>::BatchUpdateInfo BUI; + LLVM_DEBUG(dbgs() << "Legalizing " << BUI.Updates.size() << " updates\n"); + cfg::LegalizeUpdates<typename DomTreeT::NodePtr>(Updates, BUI.Updates, + DomTreeT::IsPostDominator); + const size_t NumLegalized = BUI.Updates.size(); + BUI.FutureSuccessors.reserve(NumLegalized); + BUI.FuturePredecessors.reserve(NumLegalized); + for (auto &U : BUI.Updates) { + BUI.FutureSuccessors[U.getFrom()].push_back({U.getTo(), U.getKind()}); + BUI.FuturePredecessors[U.getTo()].push_back({U.getFrom(), U.getKind()}); + } + + SemiNCAInfo<DomTreeT>::CalculateFromScratch(DT, &BUI); +} + template <class DomTreeT> void InsertEdge(DomTreeT &DT, typename DomTreeT::NodePtr From, typename DomTreeT::NodePtr To) { diff --git a/include/llvm/Support/GraphWriter.h b/include/llvm/Support/GraphWriter.h index c9a9f409c5223..02d98bec16e2b 100644 --- a/include/llvm/Support/GraphWriter.h +++ b/include/llvm/Support/GraphWriter.h @@ -27,6 +27,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/DOTGraphTraits.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cstddef> @@ -320,14 +321,32 @@ raw_ostream &WriteGraph(raw_ostream &O, const GraphType &G, std::string createGraphFilename(const Twine &Name, int &FD); +/// Writes graph into a provided {@code Filename}. +/// If {@code Filename} is empty, generates a random one. +/// \return The resulting filename, or an empty string if writing +/// failed. template <typename GraphType> std::string WriteGraph(const GraphType &G, const Twine &Name, - bool ShortNames = false, const Twine &Title = "") { + bool ShortNames = false, + const Twine &Title = "", + std::string Filename = "") { int FD; // Windows can't always handle long paths, so limit the length of the name. std::string N = Name.str(); N = N.substr(0, std::min<std::size_t>(N.size(), 140)); - std::string Filename = createGraphFilename(N, FD); + if (Filename.empty()) { + Filename = createGraphFilename(N, FD); + } else { + std::error_code EC = sys::fs::openFileForWrite(Filename, FD); + + // Writing over an existing file is not considered an error. + if (EC == std::errc::file_exists) { + errs() << "file exists, overwriting" << "\n"; + } else if (EC) { + errs() << "error writing into file" << "\n"; + return ""; + } + } raw_fd_ostream O(FD, /*shouldClose=*/ true); if (FD == -1) { diff --git a/include/llvm/Support/ItaniumManglingCanonicalizer.h b/include/llvm/Support/ItaniumManglingCanonicalizer.h new file mode 100644 index 0000000000000..34eb9f7deaaf7 --- /dev/null +++ b/include/llvm/Support/ItaniumManglingCanonicalizer.h @@ -0,0 +1,93 @@ +//===--- ItaniumManglingCanonicalizer.h -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a class for computing equivalence classes of mangled names +// given a set of equivalences between name fragments. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ITANIUMMANGLINGCANONICALIZER_H +#define LLVM_SUPPORT_ITANIUMMANGLINGCANONICALIZER_H + +#include "llvm/ADT/StringRef.h" + +#include <cstddef> + +namespace llvm { +/// Canonicalizer for mangled names. +/// +/// This class allows specifying a list of "equivalent" manglings. For example, +/// you can specify that Ss is equivalent to +/// NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE +/// and then manglings that refer to libstdc++'s 'std::string' will be +/// considered equivalent to manglings that are the same except that they refer +/// to libc++'s 'std::string'. +/// +/// This can be used when data (eg, profiling data) is available for a version +/// of a program built in a different configuration, with correspondingly +/// different manglings. +class ItaniumManglingCanonicalizer { +public: + ItaniumManglingCanonicalizer(); + ItaniumManglingCanonicalizer(const ItaniumManglingCanonicalizer &) = delete; + void operator=(const ItaniumManglingCanonicalizer &) = delete; + ~ItaniumManglingCanonicalizer(); + + enum class EquivalenceError { + Success, + + /// Both the equivalent manglings have already been used as components of + /// some other mangling we've looked at. It's too late to add this + /// equivalence. + ManglingAlreadyUsed, + + /// The first equivalent mangling is invalid. + InvalidFirstMangling, + + /// The second equivalent mangling is invalid. + InvalidSecondMangling, + }; + + enum class FragmentKind { + /// The mangling fragment is a <name> (or a predefined <substitution>). + Name, + /// The mangling fragment is a <type>. + Type, + /// The mangling fragment is an <encoding>. + Encoding, + }; + + /// Add an equivalence between \p First and \p Second. Both manglings must + /// live at least as long as the canonicalizer. + EquivalenceError addEquivalence(FragmentKind Kind, StringRef First, + StringRef Second); + + using Key = uintptr_t; + + /// Form a canonical key for the specified mangling. They key will be the + /// same for all equivalent manglings, and different for any two + /// non-equivalent manglings, but is otherwise unspecified. + /// + /// Returns Key() if (and only if) the mangling is not a valid Itanium C++ + /// ABI mangling. + /// + /// The string denoted by Mangling must live as long as the canonicalizer. + Key canonicalize(StringRef Mangling); + + /// Find a canonical key for the specified mangling, if one has already been + /// formed. Otherwise returns Key(). + Key lookup(StringRef Mangling); + +private: + struct Impl; + Impl *P; +}; +} // namespace llvm + +#endif // LLVM_SUPPORT_ITANIUMMANGLINGCANONICALIZER_H diff --git a/include/llvm/Support/JSON.h b/include/llvm/Support/JSON.h index da3c5ea0b25da..7a04fd52bc50e 100644 --- a/include/llvm/Support/JSON.h +++ b/include/llvm/Support/JSON.h @@ -294,9 +294,13 @@ public: Value(json::Array &&Elements) : Type(T_Array) { create<json::Array>(std::move(Elements)); } + template <typename Elt> + Value(const std::vector<Elt> &C) : Value(json::Array(C)) {} Value(json::Object &&Properties) : Type(T_Object) { create<json::Object>(std::move(Properties)); } + template <typename Elt> + Value(const std::map<std::string, Elt> &C) : Value(json::Object(C)) {} // Strings: types with value semantics. Must be valid UTF-8. Value(std::string V) : Type(T_String) { if (LLVM_UNLIKELY(!isUTF8(V))) { @@ -452,7 +456,10 @@ private: new (reinterpret_cast<T *>(Union.buffer)) T(std::forward<U>(V)...); } template <typename T> T &as() const { - return *reinterpret_cast<T *>(Union.buffer); + // Using this two-step static_cast via void * instead of reinterpret_cast + // silences a -Wstrict-aliasing false positive from GCC6 and earlier. + void *Storage = static_cast<void *>(Union.buffer); + return *static_cast<T *>(Storage); } template <typename Indenter> diff --git a/include/llvm/Support/LowLevelTypeImpl.h b/include/llvm/Support/LowLevelTypeImpl.h index a0a5a52d206e4..2a1075c9a48d3 100644 --- a/include/llvm/Support/LowLevelTypeImpl.h +++ b/include/llvm/Support/LowLevelTypeImpl.h @@ -147,6 +147,7 @@ public: bool operator!=(const LLT &RHS) const { return !(*this == RHS); } friend struct DenseMapInfo<LLT>; + friend class GISelInstProfileBuilder; private: /// LLT is packed into 64 bits as follows: @@ -231,6 +232,11 @@ private: maskAndShift(AddressSpace, PointerVectorAddressSpaceFieldInfo); } } + + uint64_t getUniqueRAWLLTData() const { + return ((uint64_t)RawData) << 2 | ((uint64_t)IsPointer) << 1 | + ((uint64_t)IsVector); + } }; inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) { @@ -250,8 +256,7 @@ template<> struct DenseMapInfo<LLT> { return Invalid; } static inline unsigned getHashValue(const LLT &Ty) { - uint64_t Val = ((uint64_t)Ty.RawData) << 2 | ((uint64_t)Ty.IsPointer) << 1 | - ((uint64_t)Ty.IsVector); + uint64_t Val = Ty.getUniqueRAWLLTData(); return DenseMapInfo<uint64_t>::getHashValue(Val); } static bool isEqual(const LLT &LHS, const LLT &RHS) { diff --git a/include/llvm/Support/MSVCErrorWorkarounds.h b/include/llvm/Support/MSVCErrorWorkarounds.h new file mode 100644 index 0000000000000..053ecf64d1e9d --- /dev/null +++ b/include/llvm/Support/MSVCErrorWorkarounds.h @@ -0,0 +1,84 @@ +//===--- MSVCErrorWorkarounds.h - Enable future<Error> in MSVC --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// MSVC's promise/future implementation requires types to be default +// constructible, so this header provides analogues of Error an Expected +// that are default constructed in a safely destructible state. +// +// FIXME: Kill off this header and migrate all users to Error/Expected once we +// move to MSVC versions that support non-default-constructible types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_MSVCERRORWORKAROUNDS_H +#define LLVM_SUPPORT_MSVCERRORWORKAROUNDS_H + +#include "llvm/Support/Error.h" + +namespace llvm { + +// A default-constructible llvm::Error that is suitable for use with MSVC's +// std::future implementation which requires default constructible types. +class MSVCPError : public Error { +public: + MSVCPError() { (void)!!*this; } + + MSVCPError(MSVCPError &&Other) : Error(std::move(Other)) {} + + MSVCPError &operator=(MSVCPError Other) { + Error::operator=(std::move(Other)); + return *this; + } + + MSVCPError(Error Err) : Error(std::move(Err)) {} +}; + +// A default-constructible llvm::Expected that is suitable for use with MSVC's +// std::future implementation, which requires default constructible types. +template <typename T> class MSVCPExpected : public Expected<T> { +public: + MSVCPExpected() + : Expected<T>(make_error<StringError>("", inconvertibleErrorCode())) { + consumeError(this->takeError()); + } + + MSVCPExpected(MSVCPExpected &&Other) : Expected<T>(std::move(Other)) {} + + MSVCPExpected &operator=(MSVCPExpected &&Other) { + Expected<T>::operator=(std::move(Other)); + return *this; + } + + MSVCPExpected(Error Err) : Expected<T>(std::move(Err)) {} + + template <typename OtherT> + MSVCPExpected( + OtherT &&Val, + typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * = + nullptr) + : Expected<T>(std::move(Val)) {} + + template <class OtherT> + MSVCPExpected( + Expected<OtherT> &&Other, + typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * = + nullptr) + : Expected<T>(std::move(Other)) {} + + template <class OtherT> + explicit MSVCPExpected( + Expected<OtherT> &&Other, + typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * = + nullptr) + : Expected<T>(std::move(Other)) {} +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_MSVCERRORWORKAROUNDS_H diff --git a/include/llvm/Support/Path.h b/include/llvm/Support/Path.h index c4cc93721d7ed..76de887b7cb4e 100644 --- a/include/llvm/Support/Path.h +++ b/include/llvm/Support/Path.h @@ -361,22 +361,6 @@ void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result); /// @result True if a home directory is set, false otherwise. bool home_directory(SmallVectorImpl<char> &result); -/// Get the user's cache directory. -/// -/// Expect the resulting path to be a directory shared with other -/// applications/services used by the user. Params \p Path1 to \p Path3 can be -/// used to append additional directory names to the resulting path. Recommended -/// pattern is <user_cache_directory>/<vendor>/<application>. -/// -/// @param Result Holds the resulting path. -/// @param Path1 Additional path to be appended to the user's cache directory -/// path. "" can be used to append nothing. -/// @param Path2 Second additional path to be appended. -/// @param Path3 Third additional path to be appended. -/// @result True if a cache directory path is set, false otherwise. -bool user_cache_directory(SmallVectorImpl<char> &Result, const Twine &Path1, - const Twine &Path2 = "", const Twine &Path3 = ""); - /// Has root name? /// /// root_name != "" diff --git a/include/llvm/Support/ScopedPrinter.h b/include/llvm/Support/ScopedPrinter.h index 062439b4f7db7..34c1a287ee106 100644 --- a/include/llvm/Support/ScopedPrinter.h +++ b/include/llvm/Support/ScopedPrinter.h @@ -138,7 +138,7 @@ public: } } - llvm::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>); + llvm::sort(SetFlags, &flagName<TFlag>); startLine() << Label << " [ (" << hex(Value) << ")\n"; for (const auto &Flag : SetFlags) { diff --git a/include/llvm/Support/SymbolRemappingReader.h b/include/llvm/Support/SymbolRemappingReader.h new file mode 100644 index 0000000000000..b457b9e817e42 --- /dev/null +++ b/include/llvm/Support/SymbolRemappingReader.h @@ -0,0 +1,133 @@ +//===- SymbolRemappingReader.h - Read symbol remapping file -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains definitions needed for reading and applying symbol +// remapping files. +// +// Support is provided only for the Itanium C++ name mangling scheme for now. +// +// NOTE: If you are making changes to this file format, please remember +// to document them in the Clang documentation at +// tools/clang/docs/UsersManual.rst. +// +// File format +// ----------- +// +// The symbol remappings are written as an ASCII text file. Blank lines and +// lines starting with a # are ignored. All other lines specify a kind of +// mangled name fragment, along with two fragments of that kind that should +// be treated as equivalent, separated by spaces. +// +// See http://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling for a +// description of the Itanium name mangling scheme. +// +// The accepted fragment kinds are: +// +// * name A <name>, such as 6foobar or St3__1 +// * type A <type>, such as Ss or N4llvm9StringRefE +// * encoding An <encoding> (a complete mangling without the leading _Z) +// +// For example: +// +// # Ignore int / long differences to treat symbols from 32-bit and 64-bit +// # builds with differing size_t / ptrdiff_t / intptr_t as equivalent. +// type i l +// type j m +// +// # Ignore differences between libc++ and libstdc++, and between libstdc++'s +// # C++98 and C++11 ABIs. +// name 3std St3__1 +// name 3std St7__cxx11 +// +// # Remap a function overload to a specialization of a template (including +// # any local symbols declared within it). +// encoding N2NS1fEi N2NS1fIiEEvT_ +// +// # Substitutions must be remapped separately from namespace 'std' for now. +// name Sa NSt3__19allocatorE +// name Sb NSt3__112basic_stringE +// type Ss NSt3__112basic_stringIcSt11char_traitsIcESaE +// # ... +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_SYMBOLREMAPPINGREADER_H +#define LLVM_SUPPORT_SYMBOLREMAPPINGREADER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ItaniumManglingCanonicalizer.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace llvm { + +class SymbolRemappingParseError : public ErrorInfo<SymbolRemappingParseError> { +public: + SymbolRemappingParseError(StringRef File, int64_t Line, Twine Message) + : File(File), Line(Line), Message(Message.str()) {} + + void log(llvm::raw_ostream &OS) const override { + OS << File << ':' << Line << ": " << Message; + } + std::error_code convertToErrorCode() const override { + return llvm::inconvertibleErrorCode(); + } + + StringRef getFileName() const { return File; } + int64_t getLineNum() const { return Line; } + StringRef getMessage() const { return Message; } + + static char ID; + +private: + std::string File; + int64_t Line; + std::string Message; +}; + +/// Reader for symbol remapping files. +/// +/// Remaps the symbol names in profile data to match those in the program +/// according to a set of rules specified in a given file. +class SymbolRemappingReader { +public: + /// Read remappings from the given buffer, which must live as long as + /// the remapper. + Error read(MemoryBuffer &B); + + /// A Key represents an equivalence class of symbol names. + using Key = uintptr_t; + + /// Construct a key for the given symbol, or return an existing one if an + /// equivalent name has already been inserted. The symbol name must live + /// as long as the remapper. + /// + /// The result will be Key() if the name cannot be remapped (typically + /// because it is not a valid mangled name). + Key insert(StringRef FunctionName) { + return Canonicalizer.canonicalize(FunctionName); + } + + /// Map the given symbol name into the key for the corresponding equivalence + /// class. + /// + /// The result will typically be Key() if no equivalent symbol has been + /// inserted, but this is not guaranteed: a Key different from all keys ever + /// returned by \c insert may be returned instead. + Key lookup(StringRef FunctionName) { + return Canonicalizer.lookup(FunctionName); + } + +private: + ItaniumManglingCanonicalizer Canonicalizer; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_SYMBOLREMAPPINGREADER_H diff --git a/include/llvm/Support/TargetOpcodes.def b/include/llvm/Support/TargetOpcodes.def index 63491a5f01d2d..3e8193a5cdcf3 100644 --- a/include/llvm/Support/TargetOpcodes.def +++ b/include/llvm/Support/TargetOpcodes.def @@ -258,6 +258,17 @@ HANDLE_TARGET_OPCODE(G_INSERT) /// larger register. HANDLE_TARGET_OPCODE(G_MERGE_VALUES) +/// Generic instruction to create a vector value from a number of scalar +/// components. +HANDLE_TARGET_OPCODE(G_BUILD_VECTOR) + +/// Generic instruction to create a vector value from a number of scalar +/// components, which have types larger than the result vector elt type. +HANDLE_TARGET_OPCODE(G_BUILD_VECTOR_TRUNC) + +/// Generic instruction to create a vector by concatenating multiple vectors. +HANDLE_TARGET_OPCODE(G_CONCAT_VECTORS) + /// Generic pointer to int conversion. HANDLE_TARGET_OPCODE(G_PTRTOINT) @@ -268,6 +279,12 @@ HANDLE_TARGET_OPCODE(G_INTTOPTR) /// COPY is the relevant instruction. HANDLE_TARGET_OPCODE(G_BITCAST) +/// INTRINSIC trunc intrinsic. +HANDLE_TARGET_OPCODE(G_INTRINSIC_TRUNC) + +/// INTRINSIC round intrinsic. +HANDLE_TARGET_OPCODE(G_INTRINSIC_ROUND) + /// Generic load (including anyext load) HANDLE_TARGET_OPCODE(G_LOAD) @@ -356,10 +373,18 @@ HANDLE_TARGET_OPCODE(G_FCMP) /// Generic select. HANDLE_TARGET_OPCODE(G_SELECT) +/// Generic unsigned add instruction, consuming the normal operands and +/// producing the result and a carry flag. +HANDLE_TARGET_OPCODE(G_UADDO) + /// Generic unsigned add instruction, consuming the normal operands plus a carry /// flag, and similarly producing the result and a carry flag. HANDLE_TARGET_OPCODE(G_UADDE) +/// Generic unsigned sub instruction, consuming the normal operands and +/// producing the result and a carry flag. +HANDLE_TARGET_OPCODE(G_USUBO) + /// Generic unsigned subtract instruction, consuming the normal operands plus a /// carry flag, and similarly producing the result and a carry flag. HANDLE_TARGET_OPCODE(G_USUBE) @@ -368,10 +393,18 @@ HANDLE_TARGET_OPCODE(G_USUBE) /// flag. HANDLE_TARGET_OPCODE(G_SADDO) +/// Generic signed add instruction, consuming the normal operands plus a carry +/// flag, and similarly producing the result and a carry flag. +HANDLE_TARGET_OPCODE(G_SADDE) + /// Generic signed subtract instruction, producing the result and a signed /// overflow flag. HANDLE_TARGET_OPCODE(G_SSUBO) +/// Generic signed sub instruction, consuming the normal operands plus a carry +/// flag, and similarly producing the result and a carry flag. +HANDLE_TARGET_OPCODE(G_SSUBE) + /// Generic unsigned multiply instruction, producing the result and a signed /// overflow flag. HANDLE_TARGET_OPCODE(G_UMULO) @@ -421,6 +454,9 @@ HANDLE_TARGET_OPCODE(G_FLOG) /// Floating point base-2 logarithm of a value. HANDLE_TARGET_OPCODE(G_FLOG2) +/// Floating point base-10 logarithm of a value. +HANDLE_TARGET_OPCODE(G_FLOG10) + /// Generic FP negation. HANDLE_TARGET_OPCODE(G_FNEG) @@ -464,9 +500,27 @@ HANDLE_TARGET_OPCODE(G_EXTRACT_VECTOR_ELT) /// Generic shufflevector. HANDLE_TARGET_OPCODE(G_SHUFFLE_VECTOR) +/// Generic count trailing zeroes. +HANDLE_TARGET_OPCODE(G_CTTZ) + +/// Same as above, undefined for zero inputs. +HANDLE_TARGET_OPCODE(G_CTTZ_ZERO_UNDEF) + +/// Generic count leading zeroes. +HANDLE_TARGET_OPCODE(G_CTLZ) + +/// Same as above, undefined for zero inputs. +HANDLE_TARGET_OPCODE(G_CTLZ_ZERO_UNDEF) + +/// Generic count bits. +HANDLE_TARGET_OPCODE(G_CTPOP) + /// Generic byte swap. HANDLE_TARGET_OPCODE(G_BSWAP) +/// Floating point ceil. +HANDLE_TARGET_OPCODE(G_FCEIL) + /// Generic AddressSpaceCast. HANDLE_TARGET_OPCODE(G_ADDRSPACE_CAST) diff --git a/include/llvm/Support/TargetParser.h b/include/llvm/Support/TargetParser.h index 08ad42dda3eb6..ace11ed410a38 100644 --- a/include/llvm/Support/TargetParser.h +++ b/include/llvm/Support/TargetParser.h @@ -18,211 +18,20 @@ // 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 into their own namespaces. These should be -// generated from TableGen because the information is already there, and there -// is where new information about targets will be added. +// 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 ARM { - -// FPU Version -enum class FPUVersion { - NONE, - VFPV2, - VFPV3, - VFPV3_FP16, - VFPV4, - VFPV5 -}; - -// 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 -}; - -// FPU names. -enum FPUKind { -#define ARM_FPU(NAME, KIND, VERSION, NEON_SUPPORT, RESTRICTION) KIND, -#include "ARMTargetParser.def" - FK_LAST -}; - -// 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" -}; - -// 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_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_SVE = 1 << 13, - AEK_DOTPROD = 1 << 14, - AEK_SHA2 = 1 << 15, - AEK_AES = 1 << 16, - // Unsupported extensions. - AEK_OS = 0x8000000, - AEK_IWMMXT = 0x10000000, - AEK_IWMMXT2 = 0x20000000, - AEK_MAVERICK = 0x40000000, - AEK_XSCALE = 0x80000000, -}; - -// 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 }; - -StringRef getCanonicalArchName(StringRef Arch); - -// 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); -StringRef getHWDivName(unsigned HWDivKind); - -// Information by Name -unsigned getDefaultFPU(StringRef CPU, ArchKind AK); -unsigned getDefaultExtensions(StringRef CPU, ArchKind AK); -StringRef getDefaultCPU(StringRef Arch); - -// Parser -unsigned parseHWDiv(StringRef HWDiv); -unsigned parseFPU(StringRef FPU); -ArchKind parseArch(StringRef Arch); -unsigned parseArchExt(StringRef ArchExt); -ArchKind parseCPUArch(StringRef CPU); -void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values); -ISAKind parseArchISA(StringRef Arch); -EndianKind parseArchEndian(StringRef Arch); -ProfileKind parseArchProfile(StringRef Arch); -unsigned parseArchVersion(StringRef Arch); - -StringRef computeDefaultTargetABI(const Triple &TT, StringRef CPU); - -} // namespace ARM - -// FIXME:This should be made into class design,to avoid dupplication. -namespace AArch64 { - -// Arch names. -enum class ArchKind { -#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) ID, -#include "AArch64TargetParser.def" -}; - -// 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, -}; - -StringRef getCanonicalArchName(StringRef Arch); - -// Information by ID -StringRef getFPUName(unsigned FPUKind); -ARM::FPUVersion getFPUVersion(unsigned FPUKind); -ARM::NeonSupportLevel getFPUNeonSupportLevel(unsigned FPUKind); -ARM::FPURestriction getFPURestriction(unsigned FPUKind); - -// FIXME: These should be moved to TargetTuple once it exists -bool getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features); -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); -unsigned checkArchVersion(StringRef Arch); - -// Information by Name -unsigned getDefaultFPU(StringRef CPU, ArchKind AK); -unsigned getDefaultExtensions(StringRef CPU, ArchKind AK); -StringRef getDefaultCPU(StringRef Arch); -AArch64::ArchKind getCPUArchKind(StringRef CPU); - -// Parser -unsigned parseFPU(StringRef FPU); -AArch64::ArchKind parseArch(StringRef Arch); -ArchExtKind parseArchExt(StringRef ArchExt); -ArchKind parseCPUArch(StringRef CPU); -void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values); -ARM::ISAKind parseArchISA(StringRef Arch); -ARM::EndianKind parseArchEndian(StringRef Arch); -ARM::ProfileKind parseArchProfile(StringRef Arch); -unsigned parseArchVersion(StringRef Arch); - -bool isX18ReservedByDefault(const Triple &TT); - -} // namespace AArch64 - namespace X86 { // This should be kept in sync with libcc/compiler-rt as its included by clang @@ -266,6 +75,96 @@ enum ProcessorFeatures { } // 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_GFX909 = 65, + + GK_AMDGCN_FIRST = GK_GFX600, + GK_AMDGCN_LAST = GK_GFX909, +}; + +/// 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/include/llvm/Support/Threading.h b/include/llvm/Support/Threading.h index e8021f648b0d5..ba7ece5e72ba7 100644 --- a/include/llvm/Support/Threading.h +++ b/include/llvm/Support/Threading.h @@ -27,7 +27,8 @@ #define LLVM_THREADING_USE_STD_CALL_ONCE 1 #elif defined(LLVM_ON_UNIX) && \ (defined(_LIBCPP_VERSION) || \ - !(defined(__NetBSD__) || defined(__OpenBSD__) || defined(__ppc__))) + !(defined(__NetBSD__) || defined(__OpenBSD__) || \ + (defined(__ppc__) || defined(__PPC__)))) // std::call_once from libc++ is used on all Unix platforms. Other // implementations like libstdc++ are known to have problems on NetBSD, // OpenBSD and PowerPC. diff --git a/include/llvm/Support/Timer.h b/include/llvm/Support/Timer.h index bfffbc3157b1c..a11c3ce3ff224 100644 --- a/include/llvm/Support/Timer.h +++ b/include/llvm/Support/Timer.h @@ -206,15 +206,23 @@ public: Description.assign(NewDescription.begin(), NewDescription.end()); } - /// Print any started timers in this group and zero them. + /// Print any started timers in this group. void print(raw_ostream &OS); - /// This static method prints all timers and clears them all out. + /// Clear all timers in this group. + void clear(); + + /// This static method prints all timers. static void printAll(raw_ostream &OS); + /// Clear out all timers. This is mostly used to disable automatic + /// printing on shutdown, when timers have already been printed explicitly + /// using \c printAll or \c printJSONValues. + static void clearAll(); + const char *printJSONValues(raw_ostream &OS, const char *delim); - /// Prints all timers as JSON key/value pairs, and clears them all out. + /// Prints all timers as JSON key/value pairs. static const char *printAllJSONValues(raw_ostream &OS, const char *delim); /// Ensure global timer group lists are initialized. This function is mostly diff --git a/include/llvm/Support/VirtualFileSystem.h b/include/llvm/Support/VirtualFileSystem.h new file mode 100644 index 0000000000000..61c3d2f46e9cd --- /dev/null +++ b/include/llvm/Support/VirtualFileSystem.h @@ -0,0 +1,764 @@ +//===- VirtualFileSystem.h - Virtual File System Layer ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the virtual file system interface vfs::FileSystem. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_VIRTUALFILESYSTEM_H +#define LLVM_SUPPORT_VIRTUALFILESYSTEM_H + +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/SourceMgr.h" +#include <cassert> +#include <cstdint> +#include <ctime> +#include <memory> +#include <stack> +#include <string> +#include <system_error> +#include <utility> +#include <vector> + +namespace llvm { + +class MemoryBuffer; + +namespace vfs { + +/// The result of a \p status operation. +class Status { + std::string Name; + llvm::sys::fs::UniqueID UID; + llvm::sys::TimePoint<> MTime; + uint32_t User; + uint32_t Group; + uint64_t Size; + llvm::sys::fs::file_type Type = llvm::sys::fs::file_type::status_error; + llvm::sys::fs::perms Perms; + +public: + // FIXME: remove when files support multiple names + bool IsVFSMapped = false; + + Status() = default; + Status(const llvm::sys::fs::file_status &Status); + Status(StringRef Name, llvm::sys::fs::UniqueID UID, + llvm::sys::TimePoint<> MTime, uint32_t User, uint32_t Group, + uint64_t Size, llvm::sys::fs::file_type Type, + llvm::sys::fs::perms Perms); + + /// Get a copy of a Status with a different name. + static Status copyWithNewName(const Status &In, StringRef NewName); + static Status copyWithNewName(const llvm::sys::fs::file_status &In, + StringRef NewName); + + /// Returns the name that should be used for this file or directory. + StringRef getName() const { return Name; } + + /// @name Status interface from llvm::sys::fs + /// @{ + llvm::sys::fs::file_type getType() const { return Type; } + llvm::sys::fs::perms getPermissions() const { return Perms; } + llvm::sys::TimePoint<> getLastModificationTime() const { return MTime; } + llvm::sys::fs::UniqueID getUniqueID() const { return UID; } + uint32_t getUser() const { return User; } + uint32_t getGroup() const { return Group; } + uint64_t getSize() const { return Size; } + /// @} + /// @name Status queries + /// These are static queries in llvm::sys::fs. + /// @{ + bool equivalent(const Status &Other) const; + bool isDirectory() const; + bool isRegularFile() const; + bool isOther() const; + bool isSymlink() const; + bool isStatusKnown() const; + bool exists() const; + /// @} +}; + +/// Represents an open file. +class File { +public: + /// Destroy the file after closing it (if open). + /// Sub-classes should generally call close() inside their destructors. We + /// cannot do that from the base class, since close is virtual. + virtual ~File(); + + /// Get the status of the file. + virtual llvm::ErrorOr<Status> status() = 0; + + /// Get the name of the file + virtual llvm::ErrorOr<std::string> getName() { + if (auto Status = status()) + return Status->getName().str(); + else + return Status.getError(); + } + + /// Get the contents of the file as a \p MemoryBuffer. + virtual llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> + getBuffer(const Twine &Name, int64_t FileSize = -1, + bool RequiresNullTerminator = true, bool IsVolatile = false) = 0; + + /// Closes the file. + virtual std::error_code close() = 0; +}; + +/// A member of a directory, yielded by a directory_iterator. +/// Only information available on most platforms is included. +class directory_entry { + std::string Path; + llvm::sys::fs::file_type Type; + +public: + directory_entry() = default; + directory_entry(std::string Path, llvm::sys::fs::file_type Type) + : Path(std::move(Path)), Type(Type) {} + + llvm::StringRef path() const { return Path; } + llvm::sys::fs::file_type type() const { return Type; } +}; + +namespace detail { + +/// An interface for virtual file systems to provide an iterator over the +/// (non-recursive) contents of a directory. +struct DirIterImpl { + virtual ~DirIterImpl(); + + /// Sets \c CurrentEntry to the next entry in the directory on success, + /// to directory_entry() at end, or returns a system-defined \c error_code. + virtual std::error_code increment() = 0; + + directory_entry CurrentEntry; +}; + +} // namespace detail + +/// An input iterator over the entries in a virtual path, similar to +/// llvm::sys::fs::directory_iterator. +class directory_iterator { + std::shared_ptr<detail::DirIterImpl> Impl; // Input iterator semantics on copy + +public: + directory_iterator(std::shared_ptr<detail::DirIterImpl> I) + : Impl(std::move(I)) { + assert(Impl.get() != nullptr && "requires non-null implementation"); + if (Impl->CurrentEntry.path().empty()) + Impl.reset(); // Normalize the end iterator to Impl == nullptr. + } + + /// Construct an 'end' iterator. + directory_iterator() = default; + + /// Equivalent to operator++, with an error code. + directory_iterator &increment(std::error_code &EC) { + assert(Impl && "attempting to increment past end"); + EC = Impl->increment(); + if (Impl->CurrentEntry.path().empty()) + Impl.reset(); // Normalize the end iterator to Impl == nullptr. + return *this; + } + + const directory_entry &operator*() const { return Impl->CurrentEntry; } + const directory_entry *operator->() const { return &Impl->CurrentEntry; } + + bool operator==(const directory_iterator &RHS) const { + if (Impl && RHS.Impl) + return Impl->CurrentEntry.path() == RHS.Impl->CurrentEntry.path(); + return !Impl && !RHS.Impl; + } + bool operator!=(const directory_iterator &RHS) const { + return !(*this == RHS); + } +}; + +class FileSystem; + +namespace detail { + +/// Keeps state for the recursive_directory_iterator. +struct RecDirIterState { + std::stack<directory_iterator, std::vector<directory_iterator>> Stack; + bool HasNoPushRequest = false; +}; + +} // end namespace detail + +/// An input iterator over the recursive contents of a virtual path, +/// similar to llvm::sys::fs::recursive_directory_iterator. +class recursive_directory_iterator { + FileSystem *FS; + std::shared_ptr<detail::RecDirIterState> + State; // Input iterator semantics on copy. + +public: + recursive_directory_iterator(FileSystem &FS, const Twine &Path, + std::error_code &EC); + + /// Construct an 'end' iterator. + recursive_directory_iterator() = default; + + /// Equivalent to operator++, with an error code. + recursive_directory_iterator &increment(std::error_code &EC); + + const directory_entry &operator*() const { return *State->Stack.top(); } + const directory_entry *operator->() const { return &*State->Stack.top(); } + + bool operator==(const recursive_directory_iterator &Other) const { + return State == Other.State; // identity + } + bool operator!=(const recursive_directory_iterator &RHS) const { + return !(*this == RHS); + } + + /// Gets the current level. Starting path is at level 0. + int level() const { + assert(!State->Stack.empty() && + "Cannot get level without any iteration state"); + return State->Stack.size() - 1; + } + + void no_push() { State->HasNoPushRequest = true; } +}; + +/// The virtual file system interface. +class FileSystem : public llvm::ThreadSafeRefCountedBase<FileSystem> { +public: + virtual ~FileSystem(); + + /// Get the status of the entry at \p Path, if one exists. + virtual llvm::ErrorOr<Status> status(const Twine &Path) = 0; + + /// Get a \p File object for the file at \p Path, if one exists. + virtual llvm::ErrorOr<std::unique_ptr<File>> + openFileForRead(const Twine &Path) = 0; + + /// This is a convenience method that opens a file, gets its content and then + /// closes the file. + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> + getBufferForFile(const Twine &Name, int64_t FileSize = -1, + bool RequiresNullTerminator = true, bool IsVolatile = false); + + /// Get a directory_iterator for \p Dir. + /// \note The 'end' iterator is directory_iterator(). + virtual directory_iterator dir_begin(const Twine &Dir, + std::error_code &EC) = 0; + + /// Set the working directory. This will affect all following operations on + /// this file system and may propagate down for nested file systems. + virtual std::error_code setCurrentWorkingDirectory(const Twine &Path) = 0; + + /// Get the working directory of this file system. + virtual llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const = 0; + + /// Gets real path of \p Path e.g. collapse all . and .. patterns, resolve + /// symlinks. For real file system, this uses `llvm::sys::fs::real_path`. + /// This returns errc::operation_not_permitted if not implemented by subclass. + virtual std::error_code getRealPath(const Twine &Path, + SmallVectorImpl<char> &Output) const; + + /// Check whether a file exists. Provided for convenience. + bool exists(const Twine &Path); + + /// Is the file mounted on a local filesystem? + virtual std::error_code isLocal(const Twine &Path, bool &Result); + + /// 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 success if \a path has been made absolute, otherwise a + /// platform-specific error_code. + std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const; +}; + +/// Gets an \p vfs::FileSystem for the 'real' file system, as seen by +/// the operating system. +IntrusiveRefCntPtr<FileSystem> getRealFileSystem(); + +/// A file system that allows overlaying one \p AbstractFileSystem on top +/// of another. +/// +/// Consists of a stack of >=1 \p FileSystem objects, which are treated as being +/// one merged file system. When there is a directory that exists in more than +/// one file system, the \p OverlayFileSystem contains a directory containing +/// the union of their contents. The attributes (permissions, etc.) of the +/// top-most (most recently added) directory are used. When there is a file +/// that exists in more than one file system, the file in the top-most file +/// system overrides the other(s). +class OverlayFileSystem : public FileSystem { + using FileSystemList = SmallVector<IntrusiveRefCntPtr<FileSystem>, 1>; + + /// The stack of file systems, implemented as a list in order of + /// their addition. + FileSystemList FSList; + +public: + OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> Base); + + /// Pushes a file system on top of the stack. + void pushOverlay(IntrusiveRefCntPtr<FileSystem> FS); + + llvm::ErrorOr<Status> status(const Twine &Path) override; + llvm::ErrorOr<std::unique_ptr<File>> + openFileForRead(const Twine &Path) override; + directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override; + std::error_code setCurrentWorkingDirectory(const Twine &Path) override; + std::error_code isLocal(const Twine &Path, bool &Result) override; + std::error_code getRealPath(const Twine &Path, + SmallVectorImpl<char> &Output) const override; + + using iterator = FileSystemList::reverse_iterator; + using const_iterator = FileSystemList::const_reverse_iterator; + + /// Get an iterator pointing to the most recently added file system. + iterator overlays_begin() { return FSList.rbegin(); } + const_iterator overlays_begin() const { return FSList.rbegin(); } + + /// Get an iterator pointing one-past the least recently added file + /// system. + iterator overlays_end() { return FSList.rend(); } + const_iterator overlays_end() const { return FSList.rend(); } +}; + +/// By default, this delegates all calls to the underlying file system. This +/// is useful when derived file systems want to override some calls and still +/// proxy other calls. +class ProxyFileSystem : public FileSystem { +public: + explicit ProxyFileSystem(IntrusiveRefCntPtr<FileSystem> FS) + : FS(std::move(FS)) {} + + llvm::ErrorOr<Status> status(const Twine &Path) override { + return FS->status(Path); + } + llvm::ErrorOr<std::unique_ptr<File>> + openFileForRead(const Twine &Path) override { + return FS->openFileForRead(Path); + } + directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override { + return FS->dir_begin(Dir, EC); + } + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override { + return FS->getCurrentWorkingDirectory(); + } + std::error_code setCurrentWorkingDirectory(const Twine &Path) override { + return FS->setCurrentWorkingDirectory(Path); + } + std::error_code getRealPath(const Twine &Path, + SmallVectorImpl<char> &Output) const override { + return FS->getRealPath(Path, Output); + } + std::error_code isLocal(const Twine &Path, bool &Result) override { + return FS->isLocal(Path, Result); + } + +protected: + FileSystem &getUnderlyingFS() { return *FS; } + +private: + IntrusiveRefCntPtr<FileSystem> FS; + + virtual void anchor(); +}; + +namespace detail { + +class InMemoryDirectory; +class InMemoryFile; + +} // namespace detail + +/// An in-memory file system. +class InMemoryFileSystem : public FileSystem { + std::unique_ptr<detail::InMemoryDirectory> Root; + std::string WorkingDirectory; + bool UseNormalizedPaths = true; + + /// If HardLinkTarget is non-null, a hardlink is created to the To path which + /// must be a file. If it is null then it adds the file as the public addFile. + bool addFile(const Twine &Path, time_t ModificationTime, + std::unique_ptr<llvm::MemoryBuffer> Buffer, + Optional<uint32_t> User, Optional<uint32_t> Group, + Optional<llvm::sys::fs::file_type> Type, + Optional<llvm::sys::fs::perms> Perms, + const detail::InMemoryFile *HardLinkTarget); + +public: + explicit InMemoryFileSystem(bool UseNormalizedPaths = true); + ~InMemoryFileSystem() override; + + /// Add a file containing a buffer or a directory to the VFS with a + /// path. The VFS owns the buffer. If present, User, Group, Type + /// and Perms apply to the newly-created file or directory. + /// \return true if the file or directory was successfully added, + /// false if the file or directory already exists in the file system with + /// different contents. + bool addFile(const Twine &Path, time_t ModificationTime, + std::unique_ptr<llvm::MemoryBuffer> Buffer, + Optional<uint32_t> User = None, Optional<uint32_t> Group = None, + Optional<llvm::sys::fs::file_type> Type = None, + Optional<llvm::sys::fs::perms> Perms = None); + + /// Add a hard link to a file. + /// Here hard links are not intended to be fully equivalent to the classical + /// filesystem. Both the hard link and the file share the same buffer and + /// status (and thus have the same UniqueID). Because of this there is no way + /// to distinguish between the link and the file after the link has been + /// added. + /// + /// The To path must be an existing file or a hardlink. The From file must not + /// have been added before. The To Path must not be a directory. The From Node + /// is added as a hard link which points to the resolved file of To Node. + /// \return true if the above condition is satisfied and hardlink was + /// successfully created, false otherwise. + bool addHardLink(const Twine &From, const Twine &To); + + /// Add a buffer to the VFS with a path. The VFS does not own the buffer. + /// If present, User, Group, Type and Perms apply to the newly-created file + /// or directory. + /// \return true if the file or directory was successfully added, + /// false if the file or directory already exists in the file system with + /// different contents. + bool addFileNoOwn(const Twine &Path, time_t ModificationTime, + llvm::MemoryBuffer *Buffer, Optional<uint32_t> User = None, + Optional<uint32_t> Group = None, + Optional<llvm::sys::fs::file_type> Type = None, + Optional<llvm::sys::fs::perms> Perms = None); + + std::string toString() const; + + /// Return true if this file system normalizes . and .. in paths. + bool useNormalizedPaths() const { return UseNormalizedPaths; } + + llvm::ErrorOr<Status> status(const Twine &Path) override; + llvm::ErrorOr<std::unique_ptr<File>> + openFileForRead(const Twine &Path) override; + directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; + + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override { + return WorkingDirectory; + } + /// Canonicalizes \p Path by combining with the current working + /// directory and normalizing the path (e.g. remove dots). If the current + /// working directory is not set, this returns errc::operation_not_permitted. + /// + /// This doesn't resolve symlinks as they are not supported in in-memory file + /// system. + std::error_code getRealPath(const Twine &Path, + SmallVectorImpl<char> &Output) const override; + std::error_code isLocal(const Twine &Path, bool &Result) override; + std::error_code setCurrentWorkingDirectory(const Twine &Path) override; +}; + +/// Get a globally unique ID for a virtual file or directory. +llvm::sys::fs::UniqueID getNextVirtualUniqueID(); + +/// Gets a \p FileSystem for a virtual file system described in YAML +/// format. +IntrusiveRefCntPtr<FileSystem> +getVFSFromYAML(std::unique_ptr<llvm::MemoryBuffer> Buffer, + llvm::SourceMgr::DiagHandlerTy DiagHandler, + StringRef YAMLFilePath, void *DiagContext = nullptr, + IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem()); + +struct YAMLVFSEntry { + template <typename T1, typename T2> + YAMLVFSEntry(T1 &&VPath, T2 &&RPath) + : VPath(std::forward<T1>(VPath)), RPath(std::forward<T2>(RPath)) {} + std::string VPath; + std::string RPath; +}; + +class VFSFromYamlDirIterImpl; +class RedirectingFileSystemParser; + +/// A virtual file system parsed from a YAML file. +/// +/// Currently, this class allows creating virtual directories and mapping +/// virtual file paths to existing external files, available in \c ExternalFS. +/// +/// The basic structure of the parsed file is: +/// \verbatim +/// { +/// 'version': <version number>, +/// <optional configuration> +/// 'roots': [ +/// <directory entries> +/// ] +/// } +/// \endverbatim +/// +/// All configuration options are optional. +/// 'case-sensitive': <boolean, default=true> +/// 'use-external-names': <boolean, default=true> +/// 'overlay-relative': <boolean, default=false> +/// 'fallthrough': <boolean, default=true> +/// +/// Virtual directories are represented as +/// \verbatim +/// { +/// 'type': 'directory', +/// 'name': <string>, +/// 'contents': [ <file or directory entries> ] +/// } +/// \endverbatim +/// +/// The default attributes for virtual directories are: +/// \verbatim +/// MTime = now() when created +/// Perms = 0777 +/// User = Group = 0 +/// Size = 0 +/// UniqueID = unspecified unique value +/// \endverbatim +/// +/// Re-mapped files are represented as +/// \verbatim +/// { +/// 'type': 'file', +/// 'name': <string>, +/// 'use-external-name': <boolean> # Optional +/// 'external-contents': <path to external file> +/// } +/// \endverbatim +/// +/// and inherit their attributes from the external contents. +/// +/// In both cases, the 'name' field may contain multiple path components (e.g. +/// /path/to/file). However, any directory that contains more than one child +/// must be uniquely represented by a directory entry. +class RedirectingFileSystem : public vfs::FileSystem { +public: + enum EntryKind { EK_Directory, EK_File }; + + /// A single file or directory in the VFS. + class Entry { + EntryKind Kind; + std::string Name; + + public: + Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {} + virtual ~Entry() = default; + + StringRef getName() const { return Name; } + EntryKind getKind() const { return Kind; } + }; + + class RedirectingDirectoryEntry : public Entry { + std::vector<std::unique_ptr<Entry>> Contents; + Status S; + + public: + RedirectingDirectoryEntry(StringRef Name, + std::vector<std::unique_ptr<Entry>> Contents, + Status S) + : Entry(EK_Directory, Name), Contents(std::move(Contents)), + S(std::move(S)) {} + RedirectingDirectoryEntry(StringRef Name, Status S) + : Entry(EK_Directory, Name), S(std::move(S)) {} + + Status getStatus() { return S; } + + void addContent(std::unique_ptr<Entry> Content) { + Contents.push_back(std::move(Content)); + } + + Entry *getLastContent() const { return Contents.back().get(); } + + using iterator = decltype(Contents)::iterator; + + iterator contents_begin() { return Contents.begin(); } + iterator contents_end() { return Contents.end(); } + + static bool classof(const Entry *E) { return E->getKind() == EK_Directory; } + }; + + class RedirectingFileEntry : public Entry { + public: + enum NameKind { NK_NotSet, NK_External, NK_Virtual }; + + private: + std::string ExternalContentsPath; + NameKind UseName; + + public: + RedirectingFileEntry(StringRef Name, StringRef ExternalContentsPath, + NameKind UseName) + : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath), + UseName(UseName) {} + + StringRef getExternalContentsPath() const { return ExternalContentsPath; } + + /// whether to use the external path as the name for this file. + bool useExternalName(bool GlobalUseExternalName) const { + return UseName == NK_NotSet ? GlobalUseExternalName + : (UseName == NK_External); + } + + NameKind getUseName() const { return UseName; } + + static bool classof(const Entry *E) { return E->getKind() == EK_File; } + }; + +private: + friend class VFSFromYamlDirIterImpl; + friend class RedirectingFileSystemParser; + + /// The root(s) of the virtual file system. + std::vector<std::unique_ptr<Entry>> Roots; + + /// The file system to use for external references. + IntrusiveRefCntPtr<FileSystem> ExternalFS; + + /// If IsRelativeOverlay is set, this represents the directory + /// path that should be prefixed to each 'external-contents' entry + /// when reading from YAML files. + std::string ExternalContentsPrefixDir; + + /// @name Configuration + /// @{ + + /// Whether to perform case-sensitive comparisons. + /// + /// Currently, case-insensitive matching only works correctly with ASCII. + bool CaseSensitive = true; + + /// IsRelativeOverlay marks whether a ExternalContentsPrefixDir path must + /// be prefixed in every 'external-contents' when reading from YAML files. + bool IsRelativeOverlay = false; + + /// Whether to use to use the value of 'external-contents' for the + /// names of files. This global value is overridable on a per-file basis. + bool UseExternalNames = true; + + /// Whether to attempt a file lookup in external file system after it wasn't + /// found in VFS. + bool IsFallthrough = true; + /// @} + + /// Virtual file paths and external files could be canonicalized without "..", + /// "." and "./" in their paths. FIXME: some unittests currently fail on + /// win32 when using remove_dots and remove_leading_dotslash on paths. + bool UseCanonicalizedPaths = +#ifdef _WIN32 + false; +#else + true; +#endif + + RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS) + : ExternalFS(std::move(ExternalFS)) {} + + /// Looks up the path <tt>[Start, End)</tt> in \p From, possibly + /// recursing into the contents of \p From if it is a directory. + ErrorOr<Entry *> lookupPath(llvm::sys::path::const_iterator Start, + llvm::sys::path::const_iterator End, + Entry *From) const; + + /// Get the status of a given an \c Entry. + ErrorOr<Status> status(const Twine &Path, Entry *E); + +public: + /// Looks up \p Path in \c Roots. + ErrorOr<Entry *> lookupPath(const Twine &Path) const; + + /// Parses \p Buffer, which is expected to be in YAML format and + /// returns a virtual file system representing its contents. + static RedirectingFileSystem * + create(std::unique_ptr<MemoryBuffer> Buffer, + SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, + void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS); + + ErrorOr<Status> status(const Twine &Path) override; + ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override; + + std::error_code getRealPath(const Twine &Path, + SmallVectorImpl<char> &Output) const override; + + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override; + + std::error_code setCurrentWorkingDirectory(const Twine &Path) override; + + std::error_code isLocal(const Twine &Path, bool &Result) override; + + directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; + + void setExternalContentsPrefixDir(StringRef PrefixDir); + + StringRef getExternalContentsPrefixDir() const; + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const; + LLVM_DUMP_METHOD void dumpEntry(Entry *E, int NumSpaces = 0) const; +#endif +}; + +/// Collect all pairs of <virtual path, real path> entries from the +/// \p YAMLFilePath. This is used by the module dependency collector to forward +/// the entries into the reproducer output VFS YAML file. +void collectVFSFromYAML( + std::unique_ptr<llvm::MemoryBuffer> Buffer, + llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, + SmallVectorImpl<YAMLVFSEntry> &CollectedEntries, + void *DiagContext = nullptr, + IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem()); + +class YAMLVFSWriter { + std::vector<YAMLVFSEntry> Mappings; + Optional<bool> IsCaseSensitive; + Optional<bool> IsOverlayRelative; + Optional<bool> UseExternalNames; + std::string OverlayDir; + +public: + YAMLVFSWriter() = default; + + void addFileMapping(StringRef VirtualPath, StringRef RealPath); + + void setCaseSensitivity(bool CaseSensitive) { + IsCaseSensitive = CaseSensitive; + } + + void setUseExternalNames(bool UseExtNames) { UseExternalNames = UseExtNames; } + + void setOverlayDir(StringRef OverlayDirectory) { + IsOverlayRelative = true; + OverlayDir.assign(OverlayDirectory.str()); + } + + const std::vector<YAMLVFSEntry> &getMappings() const { return Mappings; } + + void write(llvm::raw_ostream &OS); +}; + +} // namespace vfs +} // namespace llvm + +#endif // LLVM_SUPPORT_VIRTUALFILESYSTEM_H diff --git a/include/llvm/Support/Win64EH.h b/include/llvm/Support/Win64EH.h index 928eb906de0c4..e27bf1b3a1a50 100644 --- a/include/llvm/Support/Win64EH.h +++ b/include/llvm/Support/Win64EH.h @@ -33,7 +33,24 @@ enum UnwindOpcodes { UOP_SaveNonVolBig, UOP_SaveXMM128 = 8, UOP_SaveXMM128Big, - UOP_PushMachFrame + UOP_PushMachFrame, + // The following set of unwind opcodes is for ARM64. They are documented at + // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling + UOP_AllocMedium, + UOP_SaveFPLRX, + UOP_SaveFPLR, + UOP_SaveReg, + UOP_SaveRegX, + UOP_SaveRegP, + UOP_SaveRegPX, + UOP_SaveFReg, + UOP_SaveFRegX, + UOP_SaveFRegP, + UOP_SaveFRegPX, + UOP_SetFP, + UOP_AddFP, + UOP_Nop, + UOP_End }; /// UnwindCode - This union describes a single operation in a function prolog, diff --git a/include/llvm/Support/WithColor.h b/include/llvm/Support/WithColor.h index 85fc5fa0cf14d..76842d1c3dc8e 100644 --- a/include/llvm/Support/WithColor.h +++ b/include/llvm/Support/WithColor.h @@ -29,23 +29,49 @@ enum class HighlightColor { Macro, Error, Warning, - Note + Note, + Remark }; /// An RAII object that temporarily switches an output stream to a specific /// color. class WithColor { raw_ostream &OS; - /// Determine whether colors should be displayed. - bool colorsEnabled(raw_ostream &OS); + bool DisableColors; public: /// To be used like this: WithColor(OS, HighlightColor::String) << "text"; - WithColor(raw_ostream &OS, HighlightColor S); + /// @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(); @@ -53,13 +79,36 @@ public: 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 = ""); + 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 = ""); + 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 = ""); + 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 diff --git a/include/llvm/Support/X86DisassemblerDecoderCommon.h b/include/llvm/Support/X86DisassemblerDecoderCommon.h index 185b357efef5f..466dd309909ac 100644 --- a/include/llvm/Support/X86DisassemblerDecoderCommon.h +++ b/include/llvm/Support/X86DisassemblerDecoderCommon.h @@ -414,7 +414,7 @@ enum OperandEncoding { ENUM_ENTRY(TYPE_R16, "2-byte") \ ENUM_ENTRY(TYPE_R32, "4-byte") \ ENUM_ENTRY(TYPE_R64, "8-byte") \ - ENUM_ENTRY(TYPE_IMM, "immediate operand") \ + ENUM_ENTRY(TYPE_IMM, "immediate operand") \ ENUM_ENTRY(TYPE_IMM3, "1-byte immediate operand between 0 and 7") \ ENUM_ENTRY(TYPE_IMM5, "1-byte immediate operand between 0 and 31") \ ENUM_ENTRY(TYPE_AVX512ICC, "1-byte immediate operand for AVX512 icmp") \ diff --git a/include/llvm/Support/X86TargetParser.def b/include/llvm/Support/X86TargetParser.def index e4af0657a3501..e9bede545d3f7 100644 --- a/include/llvm/Support/X86TargetParser.def +++ b/include/llvm/Support/X86TargetParser.def @@ -34,17 +34,20 @@ X86_VENDOR(VENDOR_AMD, "amd") #ifndef X86_CPU_TYPE #define X86_CPU_TYPE(ARCHNAME, ENUM) #endif -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_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) @@ -64,9 +67,6 @@ 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) -X86_CPU_TYPE ("goldmont", INTEL_GOLDMONT) -X86_CPU_TYPE ("goldmont-plus", INTEL_GOLDMONT_PLUS) -X86_CPU_TYPE ("tremont", INTEL_TREMONT) #undef X86_CPU_TYPE_COMPAT_WITH_ALIAS #undef X86_CPU_TYPE_COMPAT #undef X86_CPU_TYPE @@ -97,9 +97,12 @@ 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") // 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 ("cascadelake", INTEL_COREI7_CASCADELAKE) X86_CPU_SUBTYPE ("k6", AMDPENTIUM_K6) X86_CPU_SUBTYPE ("k6-2", AMDPENTIUM_K62) X86_CPU_SUBTYPE ("k6-3", AMDPENTIUM_K63) @@ -147,11 +150,16 @@ 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") // Features below here are not in libgcc/compiler-rt. -X86_FEATURE (32, FEATURE_MOVBE) -X86_FEATURE (33, FEATURE_ADX) -X86_FEATURE (34, FEATURE_EM64T) -X86_FEATURE (35, FEATURE_CLFLUSHOPT) -X86_FEATURE (36, FEATURE_SHA) +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) #undef X86_FEATURE_COMPAT #undef X86_FEATURE diff --git a/include/llvm/Support/YAMLTraits.h b/include/llvm/Support/YAMLTraits.h index 4b8c4e958288f..3d790e96fff76 100644 --- a/include/llvm/Support/YAMLTraits.h +++ b/include/llvm/Support/YAMLTraits.h @@ -27,6 +27,7 @@ #include <cctype> #include <cstddef> #include <cstdint> +#include <iterator> #include <map> #include <memory> #include <new> @@ -38,6 +39,12 @@ 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 @@ -144,14 +151,14 @@ struct ScalarTraits { // Must provide: // // Function to write the value as a string: - //static void output(const T &value, void *ctxt, llvm::raw_ostream &out); + // 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); + // static StringRef input(StringRef scalar, void *ctxt, T &value); // // Function to determine if the value should be quoted. - //static QuotingType mustQuote(StringRef); + // static QuotingType mustQuote(StringRef); }; /// This class should be specialized by type that requires custom conversion @@ -162,7 +169,7 @@ struct ScalarTraits { /// static void output(const MyType &Value, void*, llvm::raw_ostream &Out) /// { /// // stream out custom formatting -/// Out << Val; +/// Out << Value; /// } /// static StringRef input(StringRef Scalar, void*, MyType &Value) { /// // parse scalar and set `value` @@ -180,6 +187,47 @@ struct BlockScalarTraits { // 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 @@ -233,6 +281,31 @@ struct CustomMappingTraits { // 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; @@ -249,7 +322,6 @@ struct has_ScalarEnumerationTraits template <typename U> static double test(...); -public: static bool const value = (sizeof(test<ScalarEnumerationTraits<T>>(nullptr)) == 1); }; @@ -266,7 +338,6 @@ struct has_ScalarBitSetTraits template <typename U> static double test(...); -public: static bool const value = (sizeof(test<ScalarBitSetTraits<T>>(nullptr)) == 1); }; @@ -286,7 +357,6 @@ struct has_ScalarTraits template <typename U> static double test(...); -public: static bool const value = (sizeof(test<ScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1); }; @@ -305,11 +375,28 @@ struct has_BlockScalarTraits template <typename U> static double test(...); -public: 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 &); @@ -320,7 +407,6 @@ template <class T, class Context> struct has_MappingTraits { template <typename U> static double test(...); -public: static bool const value = (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); }; @@ -334,7 +420,6 @@ template <class T> struct has_MappingTraits<T, EmptyContext> { template <typename U> static double test(...); -public: static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); }; @@ -348,7 +433,6 @@ template <class T, class Context> struct has_MappingValidateTraits { template <typename U> static double test(...); -public: static bool const value = (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); }; @@ -362,7 +446,6 @@ template <class T> struct has_MappingValidateTraits<T, EmptyContext> { template <typename U> static double test(...); -public: static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); }; @@ -378,7 +461,6 @@ struct has_SequenceMethodTraits template <typename U> static double test(...); -public: static bool const value = (sizeof(test<SequenceTraits<T>>(nullptr)) == 1); }; @@ -394,7 +476,6 @@ struct has_CustomMappingTraits template <typename U> static double test(...); -public: static bool const value = (sizeof(test<CustomMappingTraits<T>>(nullptr)) == 1); }; @@ -424,7 +505,6 @@ struct has_FlowTraits<T, true> template<typename C> static char (&f(...))[2]; -public: static bool const value = sizeof(f<Derived>(nullptr)) == 2; }; @@ -445,50 +525,114 @@ struct has_DocumentListTraits template <typename U> static double test(...); -public: static bool const value = (sizeof(test<DocumentListTraits<T>>(nullptr))==1); }; -inline bool isNumber(StringRef S) { - static const char OctalChars[] = "01234567"; - if (S.startswith("0") && - S.drop_front().find_first_not_of(OctalChars) == StringRef::npos) - return true; +template <class T> struct has_PolymorphicTraits { + using Signature_getKind = NodeKind (*)(const T &); - if (S.startswith("0o") && - S.drop_front(2).find_first_not_of(OctalChars) == StringRef::npos) - return true; + template <typename U> + static char test(SameType<Signature_getKind, &U::getKind> *); - static const char HexChars[] = "0123456789abcdefABCDEF"; - if (S.startswith("0x") && - S.drop_front(2).find_first_not_of(HexChars) == StringRef::npos) - return true; + template <typename U> static double test(...); - static const char DecChars[] = "0123456789"; - if (S.find_first_not_of(DecChars) == StringRef::npos) - return true; + static bool const value = (sizeof(test<PolymorphicTraits<T>>(nullptr)) == 1); +}; - if (S.equals(".inf") || S.equals(".Inf") || S.equals(".INF")) - return true; +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())); + }; - Regex FloatMatcher("^(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?$"); - if (FloatMatcher.match(S)) + // 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; - return false; -} + // Infinity and decimal numbers can be prefixed with sign. + StringRef Tail = (S.front() == '-' || S.front() == '+') ? S.drop_front() : S; -inline bool isNumeric(StringRef S) { - if ((S.front() == '-' || S.front() == '+') && isNumber(S.drop_front())) + // 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; - if (isNumber(S)) - 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; - if (S.equals(".nan") || S.equals(".NaN") || S.equals(".NAN")) + S = skipDigits(S); + + // Accept decimal integer. + if (S.empty()) return true; - return false; + 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) { @@ -535,7 +679,6 @@ inline QuotingType needsQuotes(StringRef S) { // Safe scalar characters. case '_': case '-': - case '/': case '^': case '.': case ',': @@ -552,6 +695,12 @@ inline QuotingType needsQuotes(StringRef S) { // 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. @@ -578,10 +727,12 @@ struct missingTraits !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_DocumentListTraits<T>::value && + !has_PolymorphicTraits<T>::value> {}; template <typename T, typename Context> struct validatedMappingTraits @@ -635,6 +786,9 @@ public: 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; @@ -869,6 +1023,31 @@ yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) { } } +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) { @@ -925,6 +1104,20 @@ yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { } 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>)]; @@ -1202,6 +1395,8 @@ private: 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; @@ -1347,6 +1542,8 @@ public: 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; @@ -1366,14 +1563,21 @@ private: void flowKey(StringRef Key); enum InState { - inSeq, - inFlowSeq, + 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; @@ -1509,6 +1713,16 @@ operator>>(Input &In, T &Val) { 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, @@ -1597,6 +1811,24 @@ operator<<(Output &Out, T &Val) { 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, diff --git a/include/llvm/Support/raw_ostream.h b/include/llvm/Support/raw_ostream.h index b9ea9b5817f2f..d062e716209dd 100644 --- a/include/llvm/Support/raw_ostream.h +++ b/include/llvm/Support/raw_ostream.h @@ -367,12 +367,18 @@ class raw_fd_ostream : public raw_pwrite_stream { int FD; bool ShouldClose; + bool SupportsSeeking; + +#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; - bool SupportsSeeking; - /// See raw_ostream::write_impl. void write_impl(const char *Ptr, size_t Size) override; @@ -548,6 +554,8 @@ 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(); } diff --git a/include/llvm/Support/type_traits.h b/include/llvm/Support/type_traits.h index 55d84f138f071..e7b8f2517b8aa 100644 --- a/include/llvm/Support/type_traits.h +++ b/include/llvm/Support/type_traits.h @@ -30,9 +30,10 @@ namespace llvm { template <typename T> struct isPodLike { // std::is_trivially_copyable is available in libc++ with clang, libstdc++ - // that comes with GCC 5. + // that comes with GCC 5. MSVC 2015 and newer also have + // std::is_trivially_copyable. #if (__has_feature(is_trivially_copyable) && defined(_LIBCPP_VERSION)) || \ - (defined(__GNUC__) && __GNUC__ >= 5) + (defined(__GNUC__) && __GNUC__ >= 5) || defined(_MSC_VER) // If the compiler supports the is_trivially_copyable trait use it, as it // matches the definition of isPodLike closely. static const bool value = std::is_trivially_copyable<T>::value; |
