summaryrefslogtreecommitdiff
path: root/include/llvm/Support
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/Support')
-rw-r--r--include/llvm/Support/AArch64TargetParser.def18
-rw-r--r--include/llvm/Support/AArch64TargetParser.h124
-rw-r--r--include/llvm/Support/AMDGPUMetadata.h15
-rw-r--r--include/llvm/Support/ARMTargetParser.def15
-rw-r--r--include/llvm/Support/ARMTargetParser.h264
-rw-r--r--include/llvm/Support/ARMWinEH.h88
-rw-r--r--include/llvm/Support/Allocator.h55
-rw-r--r--include/llvm/Support/BinaryStreamArray.h31
-rw-r--r--include/llvm/Support/BinaryStreamReader.h5
-rw-r--r--include/llvm/Support/BuryPointer.h30
-rw-r--r--include/llvm/Support/CFGUpdate.h118
-rw-r--r--include/llvm/Support/Chrono.h8
-rw-r--r--include/llvm/Support/CodeGen.h7
-rw-r--r--include/llvm/Support/CommandLine.h19
-rw-r--r--include/llvm/Support/Compiler.h19
-rw-r--r--include/llvm/Support/Compression.h13
-rw-r--r--include/llvm/Support/Debug.h4
-rw-r--r--include/llvm/Support/DebugCounter.h30
-rw-r--r--include/llvm/Support/Error.h105
-rw-r--r--include/llvm/Support/ErrorHandling.h4
-rw-r--r--include/llvm/Support/FileCheck.h282
-rw-r--r--include/llvm/Support/FileOutputBuffer.h4
-rw-r--r--include/llvm/Support/FileSystem.h143
-rw-r--r--include/llvm/Support/FormatVariadicDetails.h2
-rw-r--r--include/llvm/Support/GenericDomTree.h58
-rw-r--r--include/llvm/Support/GenericDomTreeConstruction.h120
-rw-r--r--include/llvm/Support/GraphWriter.h23
-rw-r--r--include/llvm/Support/ItaniumManglingCanonicalizer.h93
-rw-r--r--include/llvm/Support/JSON.h9
-rw-r--r--include/llvm/Support/LowLevelTypeImpl.h9
-rw-r--r--include/llvm/Support/MSVCErrorWorkarounds.h84
-rw-r--r--include/llvm/Support/Path.h16
-rw-r--r--include/llvm/Support/ScopedPrinter.h2
-rw-r--r--include/llvm/Support/SymbolRemappingReader.h133
-rw-r--r--include/llvm/Support/TargetOpcodes.def54
-rw-r--r--include/llvm/Support/TargetParser.h293
-rw-r--r--include/llvm/Support/Threading.h3
-rw-r--r--include/llvm/Support/Timer.h14
-rw-r--r--include/llvm/Support/VirtualFileSystem.h764
-rw-r--r--include/llvm/Support/Win64EH.h19
-rw-r--r--include/llvm/Support/WithColor.h63
-rw-r--r--include/llvm/Support/X86DisassemblerDecoderCommon.h2
-rw-r--r--include/llvm/Support/X86TargetParser.def46
-rw-r--r--include/llvm/Support/YAMLTraits.h326
-rw-r--r--include/llvm/Support/raw_ostream.h12
-rw-r--r--include/llvm/Support/type_traits.h5
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 &current_directory,
- SmallVectorImpl<char> &path);
+void make_absolute(const Twine &current_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 &note();
+ /// 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 &note(raw_ostream &OS, StringRef Prefix = "");
+ static raw_ostream &note(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;