summaryrefslogtreecommitdiff
path: root/include/llvm/Support
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
commit044eb2f6afba375a914ac9d8024f8f5142bb912e (patch)
tree1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /include/llvm/Support
parenteb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff)
Notes
Diffstat (limited to 'include/llvm/Support')
-rw-r--r--include/llvm/Support/AArch64TargetParser.def63
-rw-r--r--include/llvm/Support/AMDGPUKernelDescriptor.h139
-rw-r--r--include/llvm/Support/AMDGPUMetadata.h (renamed from include/llvm/Support/AMDGPUCodeObjectMetadata.h)231
-rw-r--r--include/llvm/Support/ARMTargetParser.def279
-rw-r--r--include/llvm/Support/Allocator.h3
-rw-r--r--include/llvm/Support/AtomicOrdering.h21
-rw-r--r--include/llvm/Support/BinaryByteStream.h76
-rw-r--r--include/llvm/Support/BinaryItemStream.h2
-rw-r--r--include/llvm/Support/BinaryStream.h26
-rw-r--r--include/llvm/Support/BinaryStreamRef.h92
-rw-r--r--include/llvm/Support/CMakeLists.txt66
-rw-r--r--include/llvm/Support/CachePruning.h9
-rw-r--r--include/llvm/Support/Chrono.h14
-rw-r--r--include/llvm/Support/CodeGen.h2
-rw-r--r--include/llvm/Support/CodeGenCWrappers.h18
-rw-r--r--include/llvm/Support/CodeGenCoverage.h37
-rw-r--r--include/llvm/Support/CommandLine.h33
-rw-r--r--include/llvm/Support/ConvertUTF.h8
-rw-r--r--include/llvm/Support/DebugCounter.h2
-rw-r--r--include/llvm/Support/Error.h683
-rw-r--r--include/llvm/Support/FileOutputBuffer.h38
-rw-r--r--include/llvm/Support/FileSystem.h247
-rw-r--r--include/llvm/Support/FormatVariadic.h12
-rw-r--r--include/llvm/Support/FormatVariadicDetails.h2
-rw-r--r--include/llvm/Support/GCOV.h460
-rw-r--r--include/llvm/Support/GenericDomTree.h201
-rw-r--r--include/llvm/Support/GenericDomTreeConstruction.h1008
-rw-r--r--include/llvm/Support/Host.h2
-rw-r--r--include/llvm/Support/KnownBits.h6
-rw-r--r--include/llvm/Support/LEB128.h42
-rw-r--r--include/llvm/Support/LockFileManager.h9
-rw-r--r--include/llvm/Support/LowLevelTypeImpl.h45
-rw-r--r--include/llvm/Support/MathExtras.h7
-rw-r--r--include/llvm/Support/Memory.h41
-rw-r--r--include/llvm/Support/MemoryBuffer.h3
-rw-r--r--include/llvm/Support/Parallel.h10
-rw-r--r--include/llvm/Support/PointerLikeTypeTraits.h42
-rw-r--r--include/llvm/Support/Printable.h2
-rw-r--r--include/llvm/Support/Process.h12
-rw-r--r--include/llvm/Support/Program.h51
-rw-r--r--include/llvm/Support/ReverseIteration.h12
-rw-r--r--include/llvm/Support/ScaledNumber.h8
-rw-r--r--include/llvm/Support/SourceMgr.h3
-rw-r--r--include/llvm/Support/SpecialCaseList.h91
-rw-r--r--include/llvm/Support/TarWriter.h2
-rw-r--r--include/llvm/Support/TargetParser.h212
-rw-r--r--include/llvm/Support/TargetRegistry.h164
-rw-r--r--include/llvm/Support/ThreadPool.h4
-rw-r--r--include/llvm/Support/Threading.h8
-rw-r--r--include/llvm/Support/ToolOutputFile.h12
-rw-r--r--include/llvm/Support/X86TargetParser.def155
-rw-r--r--include/llvm/Support/YAMLParser.h14
-rw-r--r--include/llvm/Support/YAMLTraits.h124
-rw-r--r--include/llvm/Support/raw_ostream.h29
54 files changed, 2968 insertions, 1914 deletions
diff --git a/include/llvm/Support/AArch64TargetParser.def b/include/llvm/Support/AArch64TargetParser.def
index 09f9602a24d9..30c7924ea5f1 100644
--- a/include/llvm/Support/AArch64TargetParser.def
+++ b/include/llvm/Support/AArch64TargetParser.def
@@ -16,19 +16,25 @@
#ifndef AARCH64_ARCH
#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT)
#endif
-AARCH64_ARCH("invalid", AK_INVALID, nullptr, nullptr,
+AARCH64_ARCH("invalid", INVALID, "", "",
ARMBuildAttrs::CPUArch::v8_A, FK_NONE, AArch64::AEK_NONE)
-AARCH64_ARCH("armv8-a", AK_ARMV8A, "8-A", "v8", ARMBuildAttrs::CPUArch::v8_A,
+AARCH64_ARCH("armv8-a", ARMV8A, "8-A", "v8", ARMBuildAttrs::CPUArch::v8_A,
FK_CRYPTO_NEON_FP_ARMV8,
(AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_SIMD))
-AARCH64_ARCH("armv8.1-a", AK_ARMV8_1A, "8.1-A", "v8.1a",
+AARCH64_ARCH("armv8.1-a", ARMV8_1A, "8.1-A", "v8.1a",
ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
(AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
- AArch64::AEK_SIMD | AArch64::AEK_LSE))
-AARCH64_ARCH("armv8.2-a", AK_ARMV8_2A, "8.2-A", "v8.2a",
+ AArch64::AEK_SIMD | AArch64::AEK_LSE | AArch64::AEK_RDM))
+AARCH64_ARCH("armv8.2-a", ARMV8_2A, "8.2-A", "v8.2a",
ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
(AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
- AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE))
+ AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE |
+ AArch64::AEK_RDM))
+AARCH64_ARCH("armv8.3-a", ARMV8_3A, "8.3-A", "v8.3a",
+ ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
+ (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE |
+ AArch64::AEK_RDM | AArch64::AEK_RCPC))
#undef AARCH64_ARCH
#ifndef AARCH64_ARCH_EXT_NAME
@@ -39,50 +45,59 @@ AARCH64_ARCH_EXT_NAME("invalid", AArch64::AEK_INVALID, nullptr, nullptr)
AARCH64_ARCH_EXT_NAME("none", AArch64::AEK_NONE, nullptr, nullptr)
AARCH64_ARCH_EXT_NAME("crc", AArch64::AEK_CRC, "+crc", "-crc")
AARCH64_ARCH_EXT_NAME("lse", AArch64::AEK_LSE, "+lse", "-lse")
+AARCH64_ARCH_EXT_NAME("rdm", AArch64::AEK_RDM, "+rdm", "-rdm")
AARCH64_ARCH_EXT_NAME("crypto", AArch64::AEK_CRYPTO, "+crypto","-crypto")
+AARCH64_ARCH_EXT_NAME("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("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")
#undef AARCH64_ARCH_EXT_NAME
#ifndef AARCH64_CPU_NAME
#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)
#endif
-AARCH64_CPU_NAME("cortex-a35", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+AARCH64_CPU_NAME("cortex-a35", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC))
-AARCH64_CPU_NAME("cortex-a53", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, true,
+AARCH64_CPU_NAME("cortex-a53", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, true,
(AArch64::AEK_CRC))
-AARCH64_CPU_NAME("cortex-a57", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+AARCH64_CPU_NAME("cortex-a55", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+ (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC))
+AARCH64_CPU_NAME("cortex-a57", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC))
-AARCH64_CPU_NAME("cortex-a72", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+AARCH64_CPU_NAME("cortex-a72", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC))
-AARCH64_CPU_NAME("cortex-a73", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+AARCH64_CPU_NAME("cortex-a73", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC))
-AARCH64_CPU_NAME("cyclone", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+AARCH64_CPU_NAME("cortex-a75", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+ (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC))
+AARCH64_CPU_NAME("cyclone", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_NONE))
-AARCH64_CPU_NAME("exynos-m1", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
- (AArch64::AEK_CRC))
-AARCH64_CPU_NAME("exynos-m2", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+AARCH64_CPU_NAME("exynos-m1", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC))
-AARCH64_CPU_NAME("exynos-m3", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+AARCH64_CPU_NAME("exynos-m2", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC))
-AARCH64_CPU_NAME("falkor", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+AARCH64_CPU_NAME("exynos-m3", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC))
-AARCH64_CPU_NAME("kryo", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+AARCH64_CPU_NAME("falkor", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+ (AArch64::AEK_CRC | AArch64::AEK_RDM))
+AARCH64_CPU_NAME("saphira", ARMV8_3A, FK_CRYPTO_NEON_FP_ARMV8, false,
+ (AArch64::AEK_PROFILE))
+AARCH64_CPU_NAME("kryo", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC))
-AARCH64_CPU_NAME("thunderx2t99", AK_ARMV8_1A, FK_CRYPTO_NEON_FP_ARMV8, false,
+AARCH64_CPU_NAME("thunderx2t99", ARMV8_1A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_NONE))
-AARCH64_CPU_NAME("thunderx", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+AARCH64_CPU_NAME("thunderx", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC | AArch64::AEK_PROFILE))
-AARCH64_CPU_NAME("thunderxt88", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+AARCH64_CPU_NAME("thunderxt88", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC | AArch64::AEK_PROFILE))
-AARCH64_CPU_NAME("thunderxt81", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+AARCH64_CPU_NAME("thunderxt81", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC | AArch64::AEK_PROFILE))
-AARCH64_CPU_NAME("thunderxt83", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+AARCH64_CPU_NAME("thunderxt83", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC | AArch64::AEK_PROFILE))
// Invalid CPU
-AARCH64_CPU_NAME("invalid", AK_INVALID, FK_INVALID, true, AArch64::AEK_INVALID)
+AARCH64_CPU_NAME("invalid", INVALID, FK_INVALID, true, AArch64::AEK_INVALID)
#undef AARCH64_CPU_NAME
diff --git a/include/llvm/Support/AMDGPUKernelDescriptor.h b/include/llvm/Support/AMDGPUKernelDescriptor.h
new file mode 100644
index 000000000000..ce2c0c1c959e
--- /dev/null
+++ b/include/llvm/Support/AMDGPUKernelDescriptor.h
@@ -0,0 +1,139 @@
+//===--- AMDGPUKernelDescriptor.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// \brief AMDGPU kernel descriptor definitions. For more information, visit
+/// https://llvm.org/docs/AMDGPUUsage.html#kernel-descriptor-for-gfx6-gfx9
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_AMDGPUKERNELDESCRIPTOR_H
+#define LLVM_SUPPORT_AMDGPUKERNELDESCRIPTOR_H
+
+#include <cstdint>
+
+// Creates enumeration entries used for packing bits into integers. Enumeration
+// entries include bit shift amount, bit width, and bit mask.
+#define AMDGPU_BITS_ENUM_ENTRY(name, shift, width) \
+ name ## _SHIFT = (shift), \
+ name ## _WIDTH = (width), \
+ name = (((1 << (width)) - 1) << (shift)) \
+
+// Gets bits for specified bit mask from specified source.
+#define AMDGPU_BITS_GET(src, mask) \
+ ((src & mask) >> mask ## _SHIFT) \
+
+// Sets bits for specified bit mask in specified destination.
+#define AMDGPU_BITS_SET(dst, mask, val) \
+ dst &= (~(1 << mask ## _SHIFT) & ~mask); \
+ dst |= (((val) << mask ## _SHIFT) & mask) \
+
+namespace llvm {
+namespace AMDGPU {
+namespace HSAKD {
+
+/// \brief Floating point rounding modes.
+enum : uint8_t {
+ AMDGPU_FLOAT_ROUND_MODE_NEAR_EVEN = 0,
+ AMDGPU_FLOAT_ROUND_MODE_PLUS_INFINITY = 1,
+ AMDGPU_FLOAT_ROUND_MODE_MINUS_INFINITY = 2,
+ AMDGPU_FLOAT_ROUND_MODE_ZERO = 3,
+};
+
+/// \brief Floating point denorm modes.
+enum : uint8_t {
+ AMDGPU_FLOAT_DENORM_MODE_FLUSH_SRC_DST = 0,
+ AMDGPU_FLOAT_DENORM_MODE_FLUSH_DST = 1,
+ AMDGPU_FLOAT_DENORM_MODE_FLUSH_SRC = 2,
+ AMDGPU_FLOAT_DENORM_MODE_FLUSH_NONE = 3,
+};
+
+/// \brief System VGPR workitem IDs.
+enum : uint8_t {
+ AMDGPU_SYSTEM_VGPR_WORKITEM_ID_X = 0,
+ AMDGPU_SYSTEM_VGPR_WORKITEM_ID_X_Y = 1,
+ AMDGPU_SYSTEM_VGPR_WORKITEM_ID_X_Y_Z = 2,
+ AMDGPU_SYSTEM_VGPR_WORKITEM_ID_UNDEFINED = 3,
+};
+
+/// \brief Compute program resource register one layout.
+enum ComputePgmRsrc1 {
+ AMDGPU_BITS_ENUM_ENTRY(GRANULATED_WORKITEM_VGPR_COUNT, 0, 6),
+ AMDGPU_BITS_ENUM_ENTRY(GRANULATED_WAVEFRONT_SGPR_COUNT, 6, 4),
+ AMDGPU_BITS_ENUM_ENTRY(PRIORITY, 10, 2),
+ AMDGPU_BITS_ENUM_ENTRY(FLOAT_ROUND_MODE_32, 12, 2),
+ AMDGPU_BITS_ENUM_ENTRY(FLOAT_ROUND_MODE_16_64, 14, 2),
+ AMDGPU_BITS_ENUM_ENTRY(FLOAT_DENORM_MODE_32, 16, 2),
+ AMDGPU_BITS_ENUM_ENTRY(FLOAT_DENORM_MODE_16_64, 18, 2),
+ AMDGPU_BITS_ENUM_ENTRY(PRIV, 20, 1),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_DX10_CLAMP, 21, 1),
+ AMDGPU_BITS_ENUM_ENTRY(DEBUG_MODE, 22, 1),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_IEEE_MODE, 23, 1),
+ AMDGPU_BITS_ENUM_ENTRY(BULKY, 24, 1),
+ AMDGPU_BITS_ENUM_ENTRY(CDBG_USER, 25, 1),
+ AMDGPU_BITS_ENUM_ENTRY(FP16_OVFL, 26, 1),
+ AMDGPU_BITS_ENUM_ENTRY(RESERVED0, 27, 5),
+};
+
+/// \brief Compute program resource register two layout.
+enum ComputePgmRsrc2 {
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_SGPR_PRIVATE_SEGMENT_WAVE_OFFSET, 0, 1),
+ AMDGPU_BITS_ENUM_ENTRY(USER_SGPR_COUNT, 1, 5),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_TRAP_HANDLER, 6, 1),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_SGPR_WORKGROUP_ID_X, 7, 1),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_SGPR_WORKGROUP_ID_Y, 8, 1),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_SGPR_WORKGROUP_ID_Z, 9, 1),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_SGPR_WORKGROUP_INFO, 10, 1),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_VGPR_WORKITEM_ID, 11, 2),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_ADDRESS_WATCH, 13, 1),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_MEMORY, 14, 1),
+ AMDGPU_BITS_ENUM_ENTRY(GRANULATED_LDS_SIZE, 15, 9),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_IEEE_754_FP_INVALID_OPERATION, 24, 1),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_FP_DENORMAL_SOURCE, 25, 1),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_IEEE_754_FP_DIVISION_BY_ZERO, 26, 1),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_IEEE_754_FP_OVERFLOW, 27, 1),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_IEEE_754_FP_UNDERFLOW, 28, 1),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_IEEE_754_FP_INEXACT, 29, 1),
+ AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_INT_DIVIDE_BY_ZERO, 30, 1),
+ AMDGPU_BITS_ENUM_ENTRY(RESERVED1, 31, 1),
+};
+
+/// \brief Kernel descriptor layout. This layout should be kept backwards
+/// compatible as it is consumed by the command processor.
+struct KernelDescriptor final {
+ uint32_t GroupSegmentFixedSize;
+ uint32_t PrivateSegmentFixedSize;
+ uint32_t MaxFlatWorkGroupSize;
+ uint64_t IsDynamicCallStack : 1;
+ uint64_t IsXNACKEnabled : 1;
+ uint64_t Reserved0 : 30;
+ int64_t KernelCodeEntryByteOffset;
+ uint64_t Reserved1[3];
+ uint32_t ComputePgmRsrc1;
+ uint32_t ComputePgmRsrc2;
+ uint64_t EnableSGPRPrivateSegmentBuffer : 1;
+ uint64_t EnableSGPRDispatchPtr : 1;
+ uint64_t EnableSGPRQueuePtr : 1;
+ uint64_t EnableSGPRKernargSegmentPtr : 1;
+ uint64_t EnableSGPRDispatchID : 1;
+ uint64_t EnableSGPRFlatScratchInit : 1;
+ uint64_t EnableSGPRPrivateSegmentSize : 1;
+ uint64_t EnableSGPRGridWorkgroupCountX : 1;
+ uint64_t EnableSGPRGridWorkgroupCountY : 1;
+ uint64_t EnableSGPRGridWorkgroupCountZ : 1;
+ uint64_t Reserved2 : 54;
+
+ KernelDescriptor() = default;
+};
+
+} // end namespace HSAKD
+} // end namespace AMDGPU
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_AMDGPUKERNELDESCRIPTOR_H
diff --git a/include/llvm/Support/AMDGPUCodeObjectMetadata.h b/include/llvm/Support/AMDGPUMetadata.h
index d274c5ee9184..00039a75c51d 100644
--- a/include/llvm/Support/AMDGPUCodeObjectMetadata.h
+++ b/include/llvm/Support/AMDGPUMetadata.h
@@ -1,4 +1,4 @@
-//===--- AMDGPUCodeObjectMetadata.h -----------------------------*- C++ -*-===//
+//===--- AMDGPUMetadata.h ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -8,14 +8,13 @@
//===----------------------------------------------------------------------===//
//
/// \file
-/// \brief AMDGPU Code Object Metadata definitions and in-memory
-/// representations.
+/// \brief AMDGPU metadata definitions and in-memory representations.
///
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_SUPPORT_AMDGPUCODEOBJECTMETADATA_H
-#define LLVM_SUPPORT_AMDGPUCODEOBJECTMETADATA_H
+#ifndef LLVM_SUPPORT_AMDGPUMETADATA_H
+#define LLVM_SUPPORT_AMDGPUMETADATA_H
#include <cstdint>
#include <string>
@@ -26,21 +25,19 @@ namespace llvm {
namespace AMDGPU {
//===----------------------------------------------------------------------===//
-// Code Object Metadata.
+// HSA metadata.
//===----------------------------------------------------------------------===//
-namespace CodeObject {
+namespace HSAMD {
-/// \brief Code object metadata major version.
-constexpr uint32_t MetadataVersionMajor = 1;
-/// \brief Code object metadata minor version.
-constexpr uint32_t MetadataVersionMinor = 0;
+/// \brief HSA metadata major version.
+constexpr uint32_t VersionMajor = 1;
+/// \brief HSA metadata minor version.
+constexpr uint32_t VersionMinor = 0;
-/// \brief Code object metadata beginning assembler directive.
-constexpr char MetadataAssemblerDirectiveBegin[] =
- ".amdgpu_code_object_metadata";
-/// \brief Code object metadata ending assembler directive.
-constexpr char MetadataAssemblerDirectiveEnd[] =
- ".end_amdgpu_code_object_metadata";
+/// \brief HSA metadata beginning assembler directive.
+constexpr char AssemblerDirectiveBegin[] = ".amd_amdgpu_hsa_metadata";
+/// \brief HSA metadata ending assembler directive.
+constexpr char AssemblerDirectiveEnd[] = ".end_amd_amdgpu_hsa_metadata";
/// \brief Access qualifiers.
enum class AccessQualifier : uint8_t {
@@ -115,6 +112,8 @@ constexpr char ReqdWorkGroupSize[] = "ReqdWorkGroupSize";
constexpr char WorkGroupSizeHint[] = "WorkGroupSizeHint";
/// \brief Key for Kernel::Attr::Metadata::mVecTypeHint.
constexpr char VecTypeHint[] = "VecTypeHint";
+/// \brief Key for Kernel::Attr::Metadata::mRuntimeHandle.
+constexpr char RuntimeHandle[] = "RuntimeHandle";
} // end namespace Key
/// \brief In-memory representation of kernel attributes metadata.
@@ -125,20 +124,22 @@ struct Metadata final {
std::vector<uint32_t> mWorkGroupSizeHint = std::vector<uint32_t>();
/// \brief 'vec_type_hint' attribute. Optional.
std::string mVecTypeHint = std::string();
+ /// \brief External symbol created by runtime to store the kernel address
+ /// for enqueued blocks.
+ std::string mRuntimeHandle = std::string();
/// \brief Default constructor.
Metadata() = default;
/// \returns True if kernel attributes metadata is empty, false otherwise.
bool empty() const {
- return mReqdWorkGroupSize.empty() &&
- mWorkGroupSizeHint.empty() &&
- mVecTypeHint.empty();
+ return !notEmpty();
}
/// \returns True if kernel attributes metadata is not empty, false otherwise.
bool notEmpty() const {
- return !empty();
+ return !mReqdWorkGroupSize.empty() || !mWorkGroupSizeHint.empty() ||
+ !mVecTypeHint.empty() || !mRuntimeHandle.empty();
}
};
@@ -150,6 +151,10 @@ struct Metadata final {
namespace Arg {
namespace Key {
+/// \brief Key for Kernel::Arg::Metadata::mName.
+constexpr char Name[] = "Name";
+/// \brief Key for Kernel::Arg::Metadata::mTypeName.
+constexpr char TypeName[] = "TypeName";
/// \brief Key for Kernel::Arg::Metadata::mSize.
constexpr char Size[] = "Size";
/// \brief Key for Kernel::Arg::Metadata::mAlign.
@@ -160,26 +165,28 @@ constexpr char ValueKind[] = "ValueKind";
constexpr char ValueType[] = "ValueType";
/// \brief Key for Kernel::Arg::Metadata::mPointeeAlign.
constexpr char PointeeAlign[] = "PointeeAlign";
-/// \brief Key for Kernel::Arg::Metadata::mAccQual.
-constexpr char AccQual[] = "AccQual";
/// \brief Key for Kernel::Arg::Metadata::mAddrSpaceQual.
constexpr char AddrSpaceQual[] = "AddrSpaceQual";
+/// \brief Key for Kernel::Arg::Metadata::mAccQual.
+constexpr char AccQual[] = "AccQual";
+/// \brief Key for Kernel::Arg::Metadata::mActualAccQual.
+constexpr char ActualAccQual[] = "ActualAccQual";
/// \brief Key for Kernel::Arg::Metadata::mIsConst.
constexpr char IsConst[] = "IsConst";
-/// \brief Key for Kernel::Arg::Metadata::mIsPipe.
-constexpr char IsPipe[] = "IsPipe";
/// \brief Key for Kernel::Arg::Metadata::mIsRestrict.
constexpr char IsRestrict[] = "IsRestrict";
/// \brief Key for Kernel::Arg::Metadata::mIsVolatile.
constexpr char IsVolatile[] = "IsVolatile";
-/// \brief Key for Kernel::Arg::Metadata::mName.
-constexpr char Name[] = "Name";
-/// \brief Key for Kernel::Arg::Metadata::mTypeName.
-constexpr char TypeName[] = "TypeName";
+/// \brief Key for Kernel::Arg::Metadata::mIsPipe.
+constexpr char IsPipe[] = "IsPipe";
} // end namespace Key
/// \brief In-memory representation of kernel argument metadata.
struct Metadata final {
+ /// \brief Name. Optional.
+ std::string mName = std::string();
+ /// \brief Type name. Optional.
+ std::string mTypeName = std::string();
/// \brief Size in bytes. Required.
uint32_t mSize = 0;
/// \brief Alignment in bytes. Required.
@@ -190,22 +197,20 @@ struct Metadata final {
ValueType mValueType = ValueType::Unknown;
/// \brief Pointee alignment in bytes. Optional.
uint32_t mPointeeAlign = 0;
- /// \brief Access qualifier. Optional.
- AccessQualifier mAccQual = AccessQualifier::Unknown;
/// \brief Address space qualifier. Optional.
AddressSpaceQualifier mAddrSpaceQual = AddressSpaceQualifier::Unknown;
+ /// \brief Access qualifier. Optional.
+ AccessQualifier mAccQual = AccessQualifier::Unknown;
+ /// \brief Actual access qualifier. Optional.
+ AccessQualifier mActualAccQual = AccessQualifier::Unknown;
/// \brief True if 'const' qualifier is specified. Optional.
bool mIsConst = false;
- /// \brief True if 'pipe' qualifier is specified. Optional.
- bool mIsPipe = false;
/// \brief True if 'restrict' qualifier is specified. Optional.
bool mIsRestrict = false;
/// \brief True if 'volatile' qualifier is specified. Optional.
bool mIsVolatile = false;
- /// \brief Name. Optional.
- std::string mName = std::string();
- /// \brief Type name. Optional.
- std::string mTypeName = std::string();
+ /// \brief True if 'pipe' qualifier is specified. Optional.
+ bool mIsPipe = false;
/// \brief Default constructor.
Metadata() = default;
@@ -221,51 +226,63 @@ namespace CodeProps {
namespace Key {
/// \brief Key for Kernel::CodeProps::Metadata::mKernargSegmentSize.
constexpr char KernargSegmentSize[] = "KernargSegmentSize";
-/// \brief Key for Kernel::CodeProps::Metadata::mWorkgroupGroupSegmentSize.
-constexpr char WorkgroupGroupSegmentSize[] = "WorkgroupGroupSegmentSize";
-/// \brief Key for Kernel::CodeProps::Metadata::mWorkitemPrivateSegmentSize.
-constexpr char WorkitemPrivateSegmentSize[] = "WorkitemPrivateSegmentSize";
-/// \brief Key for Kernel::CodeProps::Metadata::mWavefrontNumSGPRs.
-constexpr char WavefrontNumSGPRs[] = "WavefrontNumSGPRs";
-/// \brief Key for Kernel::CodeProps::Metadata::mWorkitemNumVGPRs.
-constexpr char WorkitemNumVGPRs[] = "WorkitemNumVGPRs";
+/// \brief Key for Kernel::CodeProps::Metadata::mGroupSegmentFixedSize.
+constexpr char GroupSegmentFixedSize[] = "GroupSegmentFixedSize";
+/// \brief Key for Kernel::CodeProps::Metadata::mPrivateSegmentFixedSize.
+constexpr char PrivateSegmentFixedSize[] = "PrivateSegmentFixedSize";
/// \brief Key for Kernel::CodeProps::Metadata::mKernargSegmentAlign.
constexpr char KernargSegmentAlign[] = "KernargSegmentAlign";
-/// \brief Key for Kernel::CodeProps::Metadata::mGroupSegmentAlign.
-constexpr char GroupSegmentAlign[] = "GroupSegmentAlign";
-/// \brief Key for Kernel::CodeProps::Metadata::mPrivateSegmentAlign.
-constexpr char PrivateSegmentAlign[] = "PrivateSegmentAlign";
/// \brief Key for Kernel::CodeProps::Metadata::mWavefrontSize.
constexpr char WavefrontSize[] = "WavefrontSize";
+/// \brief Key for Kernel::CodeProps::Metadata::mNumSGPRs.
+constexpr char NumSGPRs[] = "NumSGPRs";
+/// \brief Key for Kernel::CodeProps::Metadata::mNumVGPRs.
+constexpr char NumVGPRs[] = "NumVGPRs";
+/// \brief Key for Kernel::CodeProps::Metadata::mMaxFlatWorkGroupSize.
+constexpr char MaxFlatWorkGroupSize[] = "MaxFlatWorkGroupSize";
+/// \brief Key for Kernel::CodeProps::Metadata::mIsDynamicCallStack.
+constexpr char IsDynamicCallStack[] = "IsDynamicCallStack";
+/// \brief Key for Kernel::CodeProps::Metadata::mIsXNACKEnabled.
+constexpr char IsXNACKEnabled[] = "IsXNACKEnabled";
+/// \brief Key for Kernel::CodeProps::Metadata::mNumSpilledSGPRs.
+constexpr char NumSpilledSGPRs[] = "NumSpilledSGPRs";
+/// \brief Key for Kernel::CodeProps::Metadata::mNumSpilledVGPRs.
+constexpr char NumSpilledVGPRs[] = "NumSpilledVGPRs";
} // end namespace Key
/// \brief In-memory representation of kernel code properties metadata.
struct Metadata final {
/// \brief Size in bytes of the kernarg segment memory. Kernarg segment memory
- /// holds the values of the arguments to the kernel. Optional.
+ /// holds the values of the arguments to the kernel. Required.
uint64_t mKernargSegmentSize = 0;
/// \brief Size in bytes of the group segment memory required by a workgroup.
/// This value does not include any dynamically allocated group segment memory
- /// that may be added when the kernel is dispatched. Optional.
- uint32_t mWorkgroupGroupSegmentSize = 0;
+ /// that may be added when the kernel is dispatched. Required.
+ uint32_t mGroupSegmentFixedSize = 0;
/// \brief Size in bytes of the private segment memory required by a workitem.
- /// Private segment memory includes arg, spill and private segments. Optional.
- uint32_t mWorkitemPrivateSegmentSize = 0;
+ /// Private segment memory includes arg, spill and private segments. Required.
+ uint32_t mPrivateSegmentFixedSize = 0;
+ /// \brief Maximum byte alignment of variables used by the kernel in the
+ /// kernarg memory segment. Required.
+ uint32_t mKernargSegmentAlign = 0;
+ /// \brief Wavefront size. Required.
+ uint32_t mWavefrontSize = 0;
/// \brief Total number of SGPRs used by a wavefront. Optional.
- uint16_t mWavefrontNumSGPRs = 0;
+ uint16_t mNumSGPRs = 0;
/// \brief Total number of VGPRs used by a workitem. Optional.
- uint16_t mWorkitemNumVGPRs = 0;
- /// \brief Maximum byte alignment of variables used by the kernel in the
- /// kernarg memory segment. Expressed as a power of two. Optional.
- uint8_t mKernargSegmentAlign = 0;
- /// \brief Maximum byte alignment of variables used by the kernel in the
- /// group memory segment. Expressed as a power of two. Optional.
- uint8_t mGroupSegmentAlign = 0;
- /// \brief Maximum byte alignment of variables used by the kernel in the
- /// private memory segment. Expressed as a power of two. Optional.
- uint8_t mPrivateSegmentAlign = 0;
- /// \brief Wavefront size. Expressed as a power of two. Optional.
- uint8_t mWavefrontSize = 0;
+ uint16_t mNumVGPRs = 0;
+ /// \brief Maximum flat work-group size supported by the kernel. Optional.
+ uint32_t mMaxFlatWorkGroupSize = 0;
+ /// \brief True if the generated machine code is using a dynamically sized
+ /// call stack. Optional.
+ bool mIsDynamicCallStack = false;
+ /// \brief True if the generated machine code is capable of supporting XNACK.
+ /// Optional.
+ bool mIsXNACKEnabled = false;
+ /// \brief Number of SGPRs spilled by a wavefront. Optional.
+ uint16_t mNumSpilledSGPRs = 0;
+ /// \brief Number of VGPRs spilled by a workitem. Optional.
+ uint16_t mNumSpilledVGPRs = 0;
/// \brief Default constructor.
Metadata() = default;
@@ -279,10 +296,7 @@ struct Metadata final {
/// \returns True if kernel code properties metadata is not empty, false
/// otherwise.
bool notEmpty() const {
- return mKernargSegmentSize || mWorkgroupGroupSegmentSize ||
- mWorkitemPrivateSegmentSize || mWavefrontNumSGPRs ||
- mWorkitemNumVGPRs || mKernargSegmentAlign || mGroupSegmentAlign ||
- mPrivateSegmentAlign || mWavefrontSize;
+ return true;
}
};
@@ -348,6 +362,8 @@ struct Metadata final {
namespace Key {
/// \brief Key for Kernel::Metadata::mName.
constexpr char Name[] = "Name";
+/// \brief Key for Kernel::Metadata::mSymbolName.
+constexpr char SymbolName[] = "SymbolName";
/// \brief Key for Kernel::Metadata::mLanguage.
constexpr char Language[] = "Language";
/// \brief Key for Kernel::Metadata::mLanguageVersion.
@@ -364,8 +380,10 @@ constexpr char DebugProps[] = "DebugProps";
/// \brief In-memory representation of kernel metadata.
struct Metadata final {
- /// \brief Name. Required.
+ /// \brief Kernel source name. Required.
std::string mName = std::string();
+ /// \brief Kernel descriptor name. Required.
+ std::string mSymbolName = std::string();
/// \brief Language. Optional.
std::string mLanguage = std::string();
/// \brief Language version. Optional.
@@ -386,37 +404,78 @@ struct Metadata final {
} // end namespace Kernel
namespace Key {
-/// \brief Key for CodeObject::Metadata::mVersion.
+/// \brief Key for HSA::Metadata::mVersion.
constexpr char Version[] = "Version";
-/// \brief Key for CodeObject::Metadata::mPrintf.
+/// \brief Key for HSA::Metadata::mPrintf.
constexpr char Printf[] = "Printf";
-/// \brief Key for CodeObject::Metadata::mKernels.
+/// \brief Key for HSA::Metadata::mKernels.
constexpr char Kernels[] = "Kernels";
} // end namespace Key
-/// \brief In-memory representation of code object metadata.
+/// \brief In-memory representation of HSA metadata.
struct Metadata final {
- /// \brief Code object metadata version. Required.
+ /// \brief HSA metadata version. Required.
std::vector<uint32_t> mVersion = std::vector<uint32_t>();
/// \brief Printf metadata. Optional.
std::vector<std::string> mPrintf = std::vector<std::string>();
- /// \brief Kernels metadata. Optional.
+ /// \brief Kernels metadata. Required.
std::vector<Kernel::Metadata> mKernels = std::vector<Kernel::Metadata>();
/// \brief Default constructor.
Metadata() = default;
+};
+
+/// \brief Converts \p String to \p HSAMetadata.
+std::error_code fromString(std::string String, Metadata &HSAMetadata);
- /// \brief Converts \p YamlString to \p CodeObjectMetadata.
- static std::error_code fromYamlString(std::string YamlString,
- Metadata &CodeObjectMetadata);
+/// \brief Converts \p HSAMetadata to \p String.
+std::error_code toString(Metadata HSAMetadata, std::string &String);
- /// \brief Converts \p CodeObjectMetadata to \p YamlString.
- static std::error_code toYamlString(Metadata CodeObjectMetadata,
- std::string &YamlString);
+} // end namespace HSAMD
+
+//===----------------------------------------------------------------------===//
+// PAL metadata.
+//===----------------------------------------------------------------------===//
+namespace PALMD {
+
+/// \brief PAL metadata assembler directive.
+constexpr char AssemblerDirective[] = ".amd_amdgpu_pal_metadata";
+
+/// \brief PAL metadata keys.
+enum Key : uint32_t {
+ LS_NUM_USED_VGPRS = 0x10000021,
+ HS_NUM_USED_VGPRS = 0x10000022,
+ ES_NUM_USED_VGPRS = 0x10000023,
+ GS_NUM_USED_VGPRS = 0x10000024,
+ VS_NUM_USED_VGPRS = 0x10000025,
+ PS_NUM_USED_VGPRS = 0x10000026,
+ CS_NUM_USED_VGPRS = 0x10000027,
+
+ LS_NUM_USED_SGPRS = 0x10000028,
+ HS_NUM_USED_SGPRS = 0x10000029,
+ ES_NUM_USED_SGPRS = 0x1000002a,
+ GS_NUM_USED_SGPRS = 0x1000002b,
+ VS_NUM_USED_SGPRS = 0x1000002c,
+ PS_NUM_USED_SGPRS = 0x1000002d,
+ CS_NUM_USED_SGPRS = 0x1000002e,
+
+ LS_SCRATCH_SIZE = 0x10000044,
+ HS_SCRATCH_SIZE = 0x10000045,
+ ES_SCRATCH_SIZE = 0x10000046,
+ GS_SCRATCH_SIZE = 0x10000047,
+ VS_SCRATCH_SIZE = 0x10000048,
+ PS_SCRATCH_SIZE = 0x10000049,
+ CS_SCRATCH_SIZE = 0x1000004a
};
-} // end namespace CodeObject
+/// \brief PAL metadata represented as a vector.
+typedef std::vector<uint32_t> Metadata;
+
+/// \brief Converts \p PALMetadata to \p String.
+std::error_code toString(const Metadata &PALMetadata, std::string &String);
+
+} // end namespace PALMD
} // end namespace AMDGPU
} // end namespace llvm
-#endif // LLVM_SUPPORT_AMDGPUCODEOBJECTMETADATA_H
+#endif // LLVM_SUPPORT_AMDGPUMETADATA_H
diff --git a/include/llvm/Support/ARMTargetParser.def b/include/llvm/Support/ARMTargetParser.def
index 65cb2715a6a5..6c8eff1a8f84 100644
--- a/include/llvm/Support/ARMTargetParser.def
+++ b/include/llvm/Support/ARMTargetParser.def
@@ -16,105 +16,109 @@
#ifndef ARM_FPU
#define ARM_FPU(NAME, KIND, VERSION, NEON_SUPPORT, RESTRICTION)
#endif
-ARM_FPU("invalid", FK_INVALID, FV_NONE, NS_None, FR_None)
-ARM_FPU("none", FK_NONE, FV_NONE, NS_None, FR_None)
-ARM_FPU("vfp", FK_VFP, FV_VFPV2, NS_None, FR_None)
-ARM_FPU("vfpv2", FK_VFPV2, FV_VFPV2, NS_None, FR_None)
-ARM_FPU("vfpv3", FK_VFPV3, FV_VFPV3, NS_None, FR_None)
-ARM_FPU("vfpv3-fp16", FK_VFPV3_FP16, FV_VFPV3_FP16, NS_None, FR_None)
-ARM_FPU("vfpv3-d16", FK_VFPV3_D16, FV_VFPV3, NS_None, FR_D16)
-ARM_FPU("vfpv3-d16-fp16", FK_VFPV3_D16_FP16, FV_VFPV3_FP16, NS_None, FR_D16)
-ARM_FPU("vfpv3xd", FK_VFPV3XD, FV_VFPV3, NS_None, FR_SP_D16)
-ARM_FPU("vfpv3xd-fp16", FK_VFPV3XD_FP16, FV_VFPV3_FP16, NS_None, FR_SP_D16)
-ARM_FPU("vfpv4", FK_VFPV4, FV_VFPV4, NS_None, FR_None)
-ARM_FPU("vfpv4-d16", FK_VFPV4_D16, FV_VFPV4, NS_None, FR_D16)
-ARM_FPU("fpv4-sp-d16", FK_FPV4_SP_D16, FV_VFPV4, NS_None, FR_SP_D16)
-ARM_FPU("fpv5-d16", FK_FPV5_D16, FV_VFPV5, NS_None, FR_D16)
-ARM_FPU("fpv5-sp-d16", FK_FPV5_SP_D16, FV_VFPV5, NS_None, FR_SP_D16)
-ARM_FPU("fp-armv8", FK_FP_ARMV8, FV_VFPV5, NS_None, FR_None)
-ARM_FPU("neon", FK_NEON, FV_VFPV3, NS_Neon, FR_None)
-ARM_FPU("neon-fp16", FK_NEON_FP16, FV_VFPV3_FP16, NS_Neon, FR_None)
-ARM_FPU("neon-vfpv4", FK_NEON_VFPV4, FV_VFPV4, NS_Neon, FR_None)
-ARM_FPU("neon-fp-armv8", FK_NEON_FP_ARMV8, FV_VFPV5, NS_Neon, FR_None)
-ARM_FPU("crypto-neon-fp-armv8", FK_CRYPTO_NEON_FP_ARMV8, FV_VFPV5, NS_Crypto,
- FR_None)
-ARM_FPU("softvfp", FK_SOFTVFP, FV_NONE, NS_None, FR_None)
+ARM_FPU("invalid", FK_INVALID, FPUVersion::NONE, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("none", FK_NONE, FPUVersion::NONE, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("vfp", FK_VFP, FPUVersion::VFPV2, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("vfpv2", FK_VFPV2, FPUVersion::VFPV2, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("vfpv3", FK_VFPV3, FPUVersion::VFPV3, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("vfpv3-fp16", FK_VFPV3_FP16, FPUVersion::VFPV3_FP16, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("vfpv3-d16", FK_VFPV3_D16, FPUVersion::VFPV3, NeonSupportLevel::None, FPURestriction::D16)
+ARM_FPU("vfpv3-d16-fp16", FK_VFPV3_D16_FP16, FPUVersion::VFPV3_FP16, NeonSupportLevel::None, FPURestriction::D16)
+ARM_FPU("vfpv3xd", FK_VFPV3XD, FPUVersion::VFPV3, NeonSupportLevel::None, FPURestriction::SP_D16)
+ARM_FPU("vfpv3xd-fp16", FK_VFPV3XD_FP16, FPUVersion::VFPV3_FP16, NeonSupportLevel::None, FPURestriction::SP_D16)
+ARM_FPU("vfpv4", FK_VFPV4, FPUVersion::VFPV4, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("vfpv4-d16", FK_VFPV4_D16, FPUVersion::VFPV4, NeonSupportLevel::None, FPURestriction::D16)
+ARM_FPU("fpv4-sp-d16", FK_FPV4_SP_D16, FPUVersion::VFPV4, NeonSupportLevel::None, FPURestriction::SP_D16)
+ARM_FPU("fpv5-d16", FK_FPV5_D16, FPUVersion::VFPV5, NeonSupportLevel::None, FPURestriction::D16)
+ARM_FPU("fpv5-sp-d16", FK_FPV5_SP_D16, FPUVersion::VFPV5, NeonSupportLevel::None, FPURestriction::SP_D16)
+ARM_FPU("fp-armv8", FK_FP_ARMV8, FPUVersion::VFPV5, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("neon", FK_NEON, FPUVersion::VFPV3, NeonSupportLevel::Neon, FPURestriction::None)
+ARM_FPU("neon-fp16", FK_NEON_FP16, FPUVersion::VFPV3_FP16, NeonSupportLevel::Neon, FPURestriction::None)
+ARM_FPU("neon-vfpv4", FK_NEON_VFPV4, FPUVersion::VFPV4, NeonSupportLevel::Neon, FPURestriction::None)
+ARM_FPU("neon-fp-armv8", FK_NEON_FP_ARMV8, FPUVersion::VFPV5, NeonSupportLevel::Neon, FPURestriction::None)
+ARM_FPU("crypto-neon-fp-armv8", FK_CRYPTO_NEON_FP_ARMV8, FPUVersion::VFPV5, NeonSupportLevel::Crypto,
+ FPURestriction::None)
+ARM_FPU("softvfp", FK_SOFTVFP, FPUVersion::NONE, NeonSupportLevel::None, FPURestriction::None)
#undef ARM_FPU
#ifndef ARM_ARCH
#define ARM_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT)
#endif
-ARM_ARCH("invalid", AK_INVALID, nullptr, nullptr,
+ARM_ARCH("invalid", INVALID, "", "",
ARMBuildAttrs::CPUArch::Pre_v4, FK_NONE, ARM::AEK_NONE)
-ARM_ARCH("armv2", AK_ARMV2, "2", "v2", ARMBuildAttrs::CPUArch::Pre_v4,
+ARM_ARCH("armv2", ARMV2, "2", "v2", ARMBuildAttrs::CPUArch::Pre_v4,
FK_NONE, ARM::AEK_NONE)
-ARM_ARCH("armv2a", AK_ARMV2A, "2A", "v2a", ARMBuildAttrs::CPUArch::Pre_v4,
+ARM_ARCH("armv2a", ARMV2A, "2A", "v2a", ARMBuildAttrs::CPUArch::Pre_v4,
FK_NONE, ARM::AEK_NONE)
-ARM_ARCH("armv3", AK_ARMV3, "3", "v3", ARMBuildAttrs::CPUArch::Pre_v4,
+ARM_ARCH("armv3", ARMV3, "3", "v3", ARMBuildAttrs::CPUArch::Pre_v4,
FK_NONE, ARM::AEK_NONE)
-ARM_ARCH("armv3m", AK_ARMV3M, "3M", "v3m", ARMBuildAttrs::CPUArch::Pre_v4,
+ARM_ARCH("armv3m", ARMV3M, "3M", "v3m", ARMBuildAttrs::CPUArch::Pre_v4,
FK_NONE, ARM::AEK_NONE)
-ARM_ARCH("armv4", AK_ARMV4, "4", "v4", ARMBuildAttrs::CPUArch::v4,
+ARM_ARCH("armv4", ARMV4, "4", "v4", ARMBuildAttrs::CPUArch::v4,
FK_NONE, ARM::AEK_NONE)
-ARM_ARCH("armv4t", AK_ARMV4T, "4T", "v4t", ARMBuildAttrs::CPUArch::v4T,
+ARM_ARCH("armv4t", ARMV4T, "4T", "v4t", ARMBuildAttrs::CPUArch::v4T,
FK_NONE, ARM::AEK_NONE)
-ARM_ARCH("armv5t", AK_ARMV5T, "5T", "v5", ARMBuildAttrs::CPUArch::v5T,
+ARM_ARCH("armv5t", ARMV5T, "5T", "v5", ARMBuildAttrs::CPUArch::v5T,
FK_NONE, ARM::AEK_NONE)
-ARM_ARCH("armv5te", AK_ARMV5TE, "5TE", "v5e", ARMBuildAttrs::CPUArch::v5TE,
+ARM_ARCH("armv5te", ARMV5TE, "5TE", "v5e", ARMBuildAttrs::CPUArch::v5TE,
FK_NONE, ARM::AEK_DSP)
-ARM_ARCH("armv5tej", AK_ARMV5TEJ, "5TEJ", "v5e", ARMBuildAttrs::CPUArch::v5TEJ,
+ARM_ARCH("armv5tej", ARMV5TEJ, "5TEJ", "v5e", ARMBuildAttrs::CPUArch::v5TEJ,
FK_NONE, ARM::AEK_DSP)
-ARM_ARCH("armv6", AK_ARMV6, "6", "v6", ARMBuildAttrs::CPUArch::v6,
+ARM_ARCH("armv6", ARMV6, "6", "v6", ARMBuildAttrs::CPUArch::v6,
FK_VFPV2, ARM::AEK_DSP)
-ARM_ARCH("armv6k", AK_ARMV6K, "6K", "v6k", ARMBuildAttrs::CPUArch::v6K,
+ARM_ARCH("armv6k", ARMV6K, "6K", "v6k", ARMBuildAttrs::CPUArch::v6K,
FK_VFPV2, ARM::AEK_DSP)
-ARM_ARCH("armv6t2", AK_ARMV6T2, "6T2", "v6t2", ARMBuildAttrs::CPUArch::v6T2,
+ARM_ARCH("armv6t2", ARMV6T2, "6T2", "v6t2", ARMBuildAttrs::CPUArch::v6T2,
FK_NONE, ARM::AEK_DSP)
-ARM_ARCH("armv6kz", AK_ARMV6KZ, "6KZ", "v6kz", ARMBuildAttrs::CPUArch::v6KZ,
+ARM_ARCH("armv6kz", ARMV6KZ, "6KZ", "v6kz", ARMBuildAttrs::CPUArch::v6KZ,
FK_VFPV2, (ARM::AEK_SEC | ARM::AEK_DSP))
-ARM_ARCH("armv6-m", AK_ARMV6M, "6-M", "v6m", ARMBuildAttrs::CPUArch::v6_M,
+ARM_ARCH("armv6-m", ARMV6M, "6-M", "v6m", ARMBuildAttrs::CPUArch::v6_M,
FK_NONE, ARM::AEK_NONE)
-ARM_ARCH("armv7-a", AK_ARMV7A, "7-A", "v7", ARMBuildAttrs::CPUArch::v7,
+ARM_ARCH("armv7-a", ARMV7A, "7-A", "v7", ARMBuildAttrs::CPUArch::v7,
FK_NEON, ARM::AEK_DSP)
-ARM_ARCH("armv7ve", AK_ARMV7VE, "7VE", "v7ve", ARMBuildAttrs::CPUArch::v7,
+ARM_ARCH("armv7ve", ARMV7VE, "7VE", "v7ve", ARMBuildAttrs::CPUArch::v7,
FK_NEON, (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT |
ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP))
-ARM_ARCH("armv7-r", AK_ARMV7R, "7-R", "v7r", ARMBuildAttrs::CPUArch::v7,
+ARM_ARCH("armv7-r", ARMV7R, "7-R", "v7r", ARMBuildAttrs::CPUArch::v7,
FK_NONE, (ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP))
-ARM_ARCH("armv7-m", AK_ARMV7M, "7-M", "v7m", ARMBuildAttrs::CPUArch::v7,
+ARM_ARCH("armv7-m", ARMV7M, "7-M", "v7m", ARMBuildAttrs::CPUArch::v7,
FK_NONE, ARM::AEK_HWDIVTHUMB)
-ARM_ARCH("armv7e-m", AK_ARMV7EM, "7E-M", "v7em", ARMBuildAttrs::CPUArch::v7E_M,
+ARM_ARCH("armv7e-m", ARMV7EM, "7E-M", "v7em", ARMBuildAttrs::CPUArch::v7E_M,
FK_NONE, (ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP))
-ARM_ARCH("armv8-a", AK_ARMV8A, "8-A", "v8", ARMBuildAttrs::CPUArch::v8_A,
+ARM_ARCH("armv8-a", ARMV8A, "8-A", "v8", ARMBuildAttrs::CPUArch::v8_A,
FK_CRYPTO_NEON_FP_ARMV8,
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC))
-ARM_ARCH("armv8.1-a", AK_ARMV8_1A, "8.1-A", "v8.1a",
+ARM_ARCH("armv8.1-a", ARMV8_1A, "8.1-A", "v8.1a",
ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC))
-ARM_ARCH("armv8.2-a", AK_ARMV8_2A, "8.2-A", "v8.2a",
+ARM_ARCH("armv8.2-a", ARMV8_2A, "8.2-A", "v8.2a",
ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS))
-ARM_ARCH("armv8-r", AK_ARMV8R, "8-R", "v8r", ARMBuildAttrs::CPUArch::v8_R,
+ARM_ARCH("armv8.3-a", ARMV8_3A, "8.3-A", "v8.3a",
+ ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
+ (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS))
+ARM_ARCH("armv8-r", ARMV8R, "8-R", "v8r", ARMBuildAttrs::CPUArch::v8_R,
FK_NEON_FP_ARMV8,
(ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB |
ARM::AEK_DSP | ARM::AEK_CRC))
-ARM_ARCH("armv8-m.base", AK_ARMV8MBaseline, "8-M.Baseline", "v8m.base",
+ARM_ARCH("armv8-m.base", ARMV8MBaseline, "8-M.Baseline", "v8m.base",
ARMBuildAttrs::CPUArch::v8_M_Base, FK_NONE, ARM::AEK_HWDIVTHUMB)
-ARM_ARCH("armv8-m.main", AK_ARMV8MMainline, "8-M.Mainline", "v8m.main",
+ARM_ARCH("armv8-m.main", ARMV8MMainline, "8-M.Mainline", "v8m.main",
ARMBuildAttrs::CPUArch::v8_M_Main, FK_FPV5_D16, ARM::AEK_HWDIVTHUMB)
// Non-standard Arch names.
-ARM_ARCH("iwmmxt", AK_IWMMXT, "iwmmxt", "", ARMBuildAttrs::CPUArch::v5TE,
+ARM_ARCH("iwmmxt", IWMMXT, "iwmmxt", "", ARMBuildAttrs::CPUArch::v5TE,
FK_NONE, ARM::AEK_NONE)
-ARM_ARCH("iwmmxt2", AK_IWMMXT2, "iwmmxt2", "", ARMBuildAttrs::CPUArch::v5TE,
+ARM_ARCH("iwmmxt2", IWMMXT2, "iwmmxt2", "", ARMBuildAttrs::CPUArch::v5TE,
FK_NONE, ARM::AEK_NONE)
-ARM_ARCH("xscale", AK_XSCALE, "xscale", "v5e", ARMBuildAttrs::CPUArch::v5TE,
+ARM_ARCH("xscale", XSCALE, "xscale", "v5e", ARMBuildAttrs::CPUArch::v5TE,
FK_NONE, ARM::AEK_NONE)
-ARM_ARCH("armv7s", AK_ARMV7S, "7-S", "v7s", ARMBuildAttrs::CPUArch::v7,
+ARM_ARCH("armv7s", ARMV7S, "7-S", "v7s", ARMBuildAttrs::CPUArch::v7,
FK_NEON_VFPV4, ARM::AEK_DSP)
-ARM_ARCH("armv7k", AK_ARMV7K, "7-K", "v7k", ARMBuildAttrs::CPUArch::v7,
+ARM_ARCH("armv7k", ARMV7K, "7-K", "v7k", ARMBuildAttrs::CPUArch::v7,
FK_NONE, ARM::AEK_DSP)
#undef ARM_ARCH
@@ -126,6 +130,7 @@ ARM_ARCH_EXT_NAME("invalid", ARM::AEK_INVALID, nullptr, nullptr)
ARM_ARCH_EXT_NAME("none", ARM::AEK_NONE, nullptr, nullptr)
ARM_ARCH_EXT_NAME("crc", ARM::AEK_CRC, "+crc", "-crc")
ARM_ARCH_EXT_NAME("crypto", ARM::AEK_CRYPTO, "+crypto","-crypto")
+ARM_ARCH_EXT_NAME("dotprod", ARM::AEK_DOTPROD, "+dotprod","-dotprod")
ARM_ARCH_EXT_NAME("dsp", ARM::AEK_DSP, "+dsp", "-dsp")
ARM_ARCH_EXT_NAME("fp", ARM::AEK_FP, nullptr, nullptr)
ARM_ARCH_EXT_NAME("idiv", (ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB), nullptr, nullptr)
@@ -155,101 +160,105 @@ ARM_HW_DIV_NAME("arm,thumb", (ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB))
#ifndef ARM_CPU_NAME
#define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)
#endif
-ARM_CPU_NAME("arm2", AK_ARMV2, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("arm3", AK_ARMV2A, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("arm6", AK_ARMV3, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("arm7m", AK_ARMV3M, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("arm8", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm810", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("strongarm", AK_ARMV4, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("strongarm110", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("strongarm1100", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("strongarm1110", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm7tdmi", AK_ARMV4T, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("arm7tdmi-s", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm710t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm720t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm9", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm9tdmi", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm920", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm920t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm922t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm9312", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm940t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("ep9312", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm10tdmi", AK_ARMV5T, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("arm1020t", AK_ARMV5T, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm9e", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm946e-s", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm966e-s", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm968e-s", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm10e", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm1020e", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm1022e", AK_ARMV5TE, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("arm926ej-s", AK_ARMV5TEJ, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("arm1136j-s", AK_ARMV6, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm1136jf-s", AK_ARMV6, FK_VFPV2, true, ARM::AEK_NONE)
-ARM_CPU_NAME("arm1136jz-s", AK_ARMV6, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm1176j-s", AK_ARMV6K, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("arm1176jz-s", AK_ARMV6KZ, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("mpcore", AK_ARMV6K, FK_VFPV2, false, ARM::AEK_NONE)
-ARM_CPU_NAME("mpcorenovfp", AK_ARMV6K, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("arm1176jzf-s", AK_ARMV6KZ, FK_VFPV2, true, ARM::AEK_NONE)
-ARM_CPU_NAME("arm1156t2-s", AK_ARMV6T2, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("arm1156t2f-s", AK_ARMV6T2, FK_VFPV2, false, ARM::AEK_NONE)
-ARM_CPU_NAME("cortex-m0", AK_ARMV6M, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("cortex-m0plus", AK_ARMV6M, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("cortex-m1", AK_ARMV6M, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("sc000", AK_ARMV6M, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("cortex-a5", AK_ARMV7A, FK_NEON_VFPV4, false,
+ARM_CPU_NAME("arm2", ARMV2, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm3", ARMV2A, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm6", ARMV3, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm7m", ARMV3M, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm8", ARMV4, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm810", ARMV4, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("strongarm", ARMV4, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("strongarm110", ARMV4, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("strongarm1100", ARMV4, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("strongarm1110", ARMV4, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm7tdmi", ARMV4T, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm7tdmi-s", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm710t", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm720t", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm9", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm9tdmi", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm920", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm920t", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm922t", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm9312", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm940t", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("ep9312", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm10tdmi", ARMV5T, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1020t", ARMV5T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm9e", ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm946e-s", ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm966e-s", ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm968e-s", ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm10e", ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1020e", ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1022e", ARMV5TE, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm926ej-s", ARMV5TEJ, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1136j-s", ARMV6, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1136jf-s", ARMV6, FK_VFPV2, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1136jz-s", ARMV6, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("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("mpcorenovfp", ARMV6K, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1176jzf-s", ARMV6KZ, FK_VFPV2, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1156t2-s", ARMV6T2, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1156t2f-s", ARMV6T2, FK_VFPV2, false, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m0", ARMV6M, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m0plus", ARMV6M, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m1", ARMV6M, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("sc000", ARMV6M, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-a5", ARMV7A, FK_NEON_VFPV4, false,
(ARM::AEK_SEC | ARM::AEK_MP))
-ARM_CPU_NAME("cortex-a7", AK_ARMV7A, FK_NEON_VFPV4, false,
+ARM_CPU_NAME("cortex-a7", ARMV7A, FK_NEON_VFPV4, false,
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
ARM::AEK_HWDIVTHUMB))
-ARM_CPU_NAME("cortex-a8", AK_ARMV7A, FK_NEON, false, ARM::AEK_SEC)
-ARM_CPU_NAME("cortex-a9", AK_ARMV7A, FK_NEON_FP16, false, (ARM::AEK_SEC | ARM::AEK_MP))
-ARM_CPU_NAME("cortex-a12", AK_ARMV7A, FK_NEON_VFPV4, false,
+ARM_CPU_NAME("cortex-a8", ARMV7A, FK_NEON, false, ARM::AEK_SEC)
+ARM_CPU_NAME("cortex-a9", ARMV7A, FK_NEON_FP16, false, (ARM::AEK_SEC | ARM::AEK_MP))
+ARM_CPU_NAME("cortex-a12", ARMV7A, FK_NEON_VFPV4, false,
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
ARM::AEK_HWDIVTHUMB))
-ARM_CPU_NAME("cortex-a15", AK_ARMV7A, FK_NEON_VFPV4, false,
+ARM_CPU_NAME("cortex-a15", ARMV7A, FK_NEON_VFPV4, false,
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
ARM::AEK_HWDIVTHUMB))
-ARM_CPU_NAME("cortex-a17", AK_ARMV7A, FK_NEON_VFPV4, false,
+ARM_CPU_NAME("cortex-a17", ARMV7A, FK_NEON_VFPV4, false,
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
ARM::AEK_HWDIVTHUMB))
-ARM_CPU_NAME("krait", AK_ARMV7A, FK_NEON_VFPV4, false,
+ARM_CPU_NAME("krait", ARMV7A, FK_NEON_VFPV4, false,
(ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB))
-ARM_CPU_NAME("cortex-r4", AK_ARMV7R, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("cortex-r4f", AK_ARMV7R, FK_VFPV3_D16, false, ARM::AEK_NONE)
-ARM_CPU_NAME("cortex-r5", AK_ARMV7R, FK_VFPV3_D16, false,
+ARM_CPU_NAME("cortex-r4", ARMV7R, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-r4f", ARMV7R, FK_VFPV3_D16, false, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-r5", ARMV7R, FK_VFPV3_D16, false,
(ARM::AEK_MP | ARM::AEK_HWDIVARM))
-ARM_CPU_NAME("cortex-r7", AK_ARMV7R, FK_VFPV3_D16_FP16, false,
+ARM_CPU_NAME("cortex-r7", ARMV7R, FK_VFPV3_D16_FP16, false,
(ARM::AEK_MP | ARM::AEK_HWDIVARM))
-ARM_CPU_NAME("cortex-r8", AK_ARMV7R, FK_VFPV3_D16_FP16, false,
+ARM_CPU_NAME("cortex-r8", ARMV7R, FK_VFPV3_D16_FP16, false,
(ARM::AEK_MP | ARM::AEK_HWDIVARM))
-ARM_CPU_NAME("cortex-r52", AK_ARMV8R, FK_NEON_FP_ARMV8, true, ARM::AEK_NONE)
-ARM_CPU_NAME("sc300", AK_ARMV7M, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("cortex-m3", AK_ARMV7M, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("cortex-m4", AK_ARMV7EM, FK_FPV4_SP_D16, true, ARM::AEK_NONE)
-ARM_CPU_NAME("cortex-m7", AK_ARMV7EM, FK_FPV5_D16, false, ARM::AEK_NONE)
-ARM_CPU_NAME("cortex-m23", AK_ARMV8MBaseline, FK_NONE, false, ARM::AEK_NONE)
-ARM_CPU_NAME("cortex-m33", AK_ARMV8MMainline, FK_FPV5_SP_D16, false, ARM::AEK_DSP)
-ARM_CPU_NAME("cortex-a32", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
-ARM_CPU_NAME("cortex-a35", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
-ARM_CPU_NAME("cortex-a53", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
-ARM_CPU_NAME("cortex-a57", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
-ARM_CPU_NAME("cortex-a72", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
-ARM_CPU_NAME("cortex-a73", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
-ARM_CPU_NAME("cyclone", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
-ARM_CPU_NAME("exynos-m1", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
-ARM_CPU_NAME("exynos-m2", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
-ARM_CPU_NAME("exynos-m3", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
-ARM_CPU_NAME("kryo", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("cortex-r52", ARMV8R, FK_NEON_FP_ARMV8, true, ARM::AEK_NONE)
+ARM_CPU_NAME("sc300", ARMV7M, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m3", ARMV7M, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m4", ARMV7EM, FK_FPV4_SP_D16, true, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m7", ARMV7EM, FK_FPV5_D16, false, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m23", ARMV8MBaseline, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m33", ARMV8MMainline, FK_FPV5_SP_D16, false, ARM::AEK_DSP)
+ARM_CPU_NAME("cortex-a32", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("cortex-a35", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("cortex-a53", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("cortex-a55", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+ (ARM::AEK_FP16 | ARM::AEK_DOTPROD))
+ARM_CPU_NAME("cortex-a57", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("cortex-a72", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("cortex-a73", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("cortex-a75", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+ (ARM::AEK_FP16 | ARM::AEK_DOTPROD))
+ARM_CPU_NAME("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("kryo", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
// Non-standard Arch names.
-ARM_CPU_NAME("iwmmxt", AK_IWMMXT, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("xscale", AK_XSCALE, FK_NONE, true, ARM::AEK_NONE)
-ARM_CPU_NAME("swift", AK_ARMV7S, FK_NEON_VFPV4, true,
+ARM_CPU_NAME("iwmmxt", IWMMXT, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("xscale", XSCALE, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("swift", ARMV7S, FK_NEON_VFPV4, true,
(ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB))
// Invalid CPU
-ARM_CPU_NAME("invalid", AK_INVALID, FK_INVALID, true, ARM::AEK_INVALID)
+ARM_CPU_NAME("invalid", INVALID, FK_INVALID, true, ARM::AEK_INVALID)
#undef ARM_CPU_NAME
diff --git a/include/llvm/Support/Allocator.h b/include/llvm/Support/Allocator.h
index a5e662f4c588..a94aa8fb1f2a 100644
--- a/include/llvm/Support/Allocator.h
+++ b/include/llvm/Support/Allocator.h
@@ -269,6 +269,9 @@ public:
// Pull in base class overloads.
using AllocatorBase<BumpPtrAllocatorImpl>::Allocate;
+ // Bump pointer allocators are expected to never free their storage; and
+ // clients expect pointers to remain valid for non-dereferencing uses even
+ // after deallocation.
void Deallocate(const void *Ptr, size_t Size) {
__asan_poison_memory_region(Ptr, Size);
}
diff --git a/include/llvm/Support/AtomicOrdering.h b/include/llvm/Support/AtomicOrdering.h
index 001804248b85..e93b755aa63b 100644
--- a/include/llvm/Support/AtomicOrdering.h
+++ b/include/llvm/Support/AtomicOrdering.h
@@ -42,7 +42,7 @@ bool operator>=(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
// Validate an integral value which isn't known to fit within the enum's range
// is a valid AtomicOrderingCABI.
-template <typename Int> static inline bool isValidAtomicOrderingCABI(Int I) {
+template <typename Int> inline bool isValidAtomicOrderingCABI(Int I) {
return (Int)AtomicOrderingCABI::relaxed <= I &&
I <= (Int)AtomicOrderingCABI::seq_cst;
}
@@ -72,13 +72,13 @@ bool operator>=(AtomicOrdering, AtomicOrdering) = delete;
// Validate an integral value which isn't known to fit within the enum's range
// is a valid AtomicOrdering.
-template <typename Int> static inline bool isValidAtomicOrdering(Int I) {
+template <typename Int> inline bool isValidAtomicOrdering(Int I) {
return static_cast<Int>(AtomicOrdering::NotAtomic) <= I &&
I <= static_cast<Int>(AtomicOrdering::SequentiallyConsistent);
}
/// String used by LLVM IR to represent atomic ordering.
-static inline const char *toIRString(AtomicOrdering ao) {
+inline const char *toIRString(AtomicOrdering ao) {
static const char *names[8] = {"not_atomic", "unordered", "monotonic",
"consume", "acquire", "release",
"acq_rel", "seq_cst"};
@@ -87,7 +87,7 @@ static inline const char *toIRString(AtomicOrdering ao) {
/// Returns true if ao is stronger than other as defined by the AtomicOrdering
/// lattice, which is based on C++'s definition.
-static inline bool isStrongerThan(AtomicOrdering ao, AtomicOrdering other) {
+inline bool isStrongerThan(AtomicOrdering ao, AtomicOrdering other) {
static const bool lookup[8][8] = {
// NA UN RX CO AC RE AR SC
/* NotAtomic */ {false, false, false, false, false, false, false, false},
@@ -102,8 +102,7 @@ static inline bool isStrongerThan(AtomicOrdering ao, AtomicOrdering other) {
return lookup[static_cast<size_t>(ao)][static_cast<size_t>(other)];
}
-static inline bool isAtLeastOrStrongerThan(AtomicOrdering ao,
- AtomicOrdering other) {
+inline bool isAtLeastOrStrongerThan(AtomicOrdering ao, AtomicOrdering other) {
static const bool lookup[8][8] = {
// NA UN RX CO AC RE AR SC
/* NotAtomic */ { true, false, false, false, false, false, false, false},
@@ -118,23 +117,23 @@ static inline bool isAtLeastOrStrongerThan(AtomicOrdering ao,
return lookup[static_cast<size_t>(ao)][static_cast<size_t>(other)];
}
-static inline bool isStrongerThanUnordered(AtomicOrdering ao) {
+inline bool isStrongerThanUnordered(AtomicOrdering ao) {
return isStrongerThan(ao, AtomicOrdering::Unordered);
}
-static inline bool isStrongerThanMonotonic(AtomicOrdering ao) {
+inline bool isStrongerThanMonotonic(AtomicOrdering ao) {
return isStrongerThan(ao, AtomicOrdering::Monotonic);
}
-static inline bool isAcquireOrStronger(AtomicOrdering ao) {
+inline bool isAcquireOrStronger(AtomicOrdering ao) {
return isAtLeastOrStrongerThan(ao, AtomicOrdering::Acquire);
}
-static inline bool isReleaseOrStronger(AtomicOrdering ao) {
+inline bool isReleaseOrStronger(AtomicOrdering ao) {
return isAtLeastOrStrongerThan(ao, AtomicOrdering::Release);
}
-static inline AtomicOrderingCABI toCABI(AtomicOrdering ao) {
+inline AtomicOrderingCABI toCABI(AtomicOrdering ao) {
static const AtomicOrderingCABI lookup[8] = {
/* NotAtomic */ AtomicOrderingCABI::relaxed,
/* Unordered */ AtomicOrderingCABI::relaxed,
diff --git a/include/llvm/Support/BinaryByteStream.h b/include/llvm/Support/BinaryByteStream.h
index 694be28e07e1..db1ccba1398b 100644
--- a/include/llvm/Support/BinaryByteStream.h
+++ b/include/llvm/Support/BinaryByteStream.h
@@ -41,7 +41,7 @@ public:
Error readBytes(uint32_t Offset, uint32_t Size,
ArrayRef<uint8_t> &Buffer) override {
- if (auto EC = checkOffset(Offset, Size))
+ if (auto EC = checkOffsetForRead(Offset, Size))
return EC;
Buffer = Data.slice(Offset, Size);
return Error::success();
@@ -49,7 +49,7 @@ public:
Error readLongestContiguousChunk(uint32_t Offset,
ArrayRef<uint8_t> &Buffer) override {
- if (auto EC = checkOffset(Offset, 1))
+ if (auto EC = checkOffsetForRead(Offset, 1))
return EC;
Buffer = Data.slice(Offset);
return Error::success();
@@ -114,7 +114,7 @@ public:
if (Buffer.empty())
return Error::success();
- if (auto EC = checkOffset(Offset, Buffer.size()))
+ if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
return EC;
uint8_t *DataPtr = const_cast<uint8_t *>(Data.data());
@@ -131,6 +131,76 @@ private:
BinaryByteStream ImmutableStream;
};
+/// \brief An implementation of WritableBinaryStream which can write at its end
+/// causing the underlying data to grow. This class owns the underlying data.
+class AppendingBinaryByteStream : public WritableBinaryStream {
+ std::vector<uint8_t> Data;
+ llvm::support::endianness Endian = llvm::support::little;
+
+public:
+ AppendingBinaryByteStream() = default;
+ AppendingBinaryByteStream(llvm::support::endianness Endian)
+ : Endian(Endian) {}
+
+ void clear() { Data.clear(); }
+
+ llvm::support::endianness getEndian() const override { return Endian; }
+
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) override {
+ if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
+ return EC;
+
+ Buffer = makeArrayRef(Data).slice(Offset, Size);
+ return Error::success();
+ }
+
+ void insert(uint32_t Offset, ArrayRef<uint8_t> Bytes) {
+ Data.insert(Data.begin() + Offset, Bytes.begin(), Bytes.end());
+ }
+
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) override {
+ if (auto EC = checkOffsetForWrite(Offset, 1))
+ return EC;
+
+ Buffer = makeArrayRef(Data).slice(Offset);
+ return Error::success();
+ }
+
+ uint32_t getLength() override { return Data.size(); }
+
+ Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override {
+ if (Buffer.empty())
+ return Error::success();
+
+ // This is well-defined for any case except where offset is strictly
+ // greater than the current length. If offset is equal to the current
+ // length, we can still grow. If offset is beyond the current length, we
+ // would have to decide how to deal with the intermediate uninitialized
+ // bytes. So we punt on that case for simplicity and just say it's an
+ // error.
+ if (Offset > getLength())
+ return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
+
+ uint32_t RequiredSize = Offset + Buffer.size();
+ if (RequiredSize > Data.size())
+ Data.resize(RequiredSize);
+
+ ::memcpy(Data.data() + Offset, Buffer.data(), Buffer.size());
+ return Error::success();
+ }
+
+ Error commit() override { return Error::success(); }
+
+ /// \brief Return the properties of this stream.
+ virtual BinaryStreamFlags getFlags() const override {
+ return BSF_Write | BSF_Append;
+ }
+
+ MutableArrayRef<uint8_t> data() { return Data; }
+};
+
/// \brief An implementation of WritableBinaryStream backed by an llvm
/// FileOutputBuffer.
class FileBufferByteStream : public WritableBinaryStream {
diff --git a/include/llvm/Support/BinaryItemStream.h b/include/llvm/Support/BinaryItemStream.h
index fe7e6caeaafb..278723ddf8da 100644
--- a/include/llvm/Support/BinaryItemStream.h
+++ b/include/llvm/Support/BinaryItemStream.h
@@ -45,7 +45,7 @@ public:
if (!ExpectedIndex)
return ExpectedIndex.takeError();
const auto &Item = Items[*ExpectedIndex];
- if (auto EC = checkOffset(Offset, Size))
+ if (auto EC = checkOffsetForRead(Offset, Size))
return EC;
if (Size > Traits::length(Item))
return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
diff --git a/include/llvm/Support/BinaryStream.h b/include/llvm/Support/BinaryStream.h
index a227117e063e..d69a03eccfdb 100644
--- a/include/llvm/Support/BinaryStream.h
+++ b/include/llvm/Support/BinaryStream.h
@@ -11,6 +11,7 @@
#define LLVM_SUPPORT_BINARYSTREAM_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/Support/BinaryStreamError.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
@@ -18,6 +19,13 @@
namespace llvm {
+enum BinaryStreamFlags {
+ BSF_None = 0,
+ BSF_Write = 1, // Stream supports writing.
+ BSF_Append = 2, // Writing can occur at offset == length.
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ BSF_Append)
+};
+
/// \brief An interface for accessing data in a stream-like format, but which
/// discourages copying. Instead of specifying a buffer in which to copy
/// data on a read, the API returns an ArrayRef to data owned by the stream's
@@ -45,8 +53,11 @@ public:
/// \brief Return the number of bytes of data in this stream.
virtual uint32_t getLength() = 0;
+ /// \brief Return the properties of this stream.
+ virtual BinaryStreamFlags getFlags() const { return BSF_None; }
+
protected:
- Error checkOffset(uint32_t Offset, uint32_t DataSize) {
+ Error checkOffsetForRead(uint32_t Offset, uint32_t DataSize) {
if (Offset > getLength())
return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
if (getLength() < DataSize + Offset)
@@ -71,6 +82,19 @@ public:
/// \brief For buffered streams, commits changes to the backing store.
virtual Error commit() = 0;
+
+ /// \brief Return the properties of this stream.
+ BinaryStreamFlags getFlags() const override { return BSF_Write; }
+
+protected:
+ Error checkOffsetForWrite(uint32_t Offset, uint32_t DataSize) {
+ if (!(getFlags() & BSF_Append))
+ return checkOffsetForRead(Offset, DataSize);
+
+ if (Offset > getLength())
+ return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
+ return Error::success();
+ }
};
} // end namespace llvm
diff --git a/include/llvm/Support/BinaryStreamRef.h b/include/llvm/Support/BinaryStreamRef.h
index 6d5135cb258d..5cf355be6fe9 100644
--- a/include/llvm/Support/BinaryStreamRef.h
+++ b/include/llvm/Support/BinaryStreamRef.h
@@ -11,6 +11,7 @@
#define LLVM_SUPPORT_BINARYSTREAMREF_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/Support/BinaryStream.h"
#include "llvm/Support/BinaryStreamError.h"
#include "llvm/Support/Error.h"
@@ -24,47 +25,74 @@ namespace llvm {
template <class RefType, class StreamType> class BinaryStreamRefBase {
protected:
BinaryStreamRefBase() = default;
+ explicit BinaryStreamRefBase(StreamType &BorrowedImpl)
+ : BorrowedImpl(&BorrowedImpl), ViewOffset(0) {
+ if (!(BorrowedImpl.getFlags() & BSF_Append))
+ Length = BorrowedImpl.getLength();
+ }
+
BinaryStreamRefBase(std::shared_ptr<StreamType> SharedImpl, uint32_t Offset,
- uint32_t Length)
+ Optional<uint32_t> Length)
: SharedImpl(SharedImpl), BorrowedImpl(SharedImpl.get()),
ViewOffset(Offset), Length(Length) {}
BinaryStreamRefBase(StreamType &BorrowedImpl, uint32_t Offset,
- uint32_t Length)
+ Optional<uint32_t> Length)
: BorrowedImpl(&BorrowedImpl), ViewOffset(Offset), Length(Length) {}
- BinaryStreamRefBase(const BinaryStreamRefBase &Other) {
- SharedImpl = Other.SharedImpl;
- BorrowedImpl = Other.BorrowedImpl;
- ViewOffset = Other.ViewOffset;
- Length = Other.Length;
- }
+ BinaryStreamRefBase(const BinaryStreamRefBase &Other) = default;
+ BinaryStreamRefBase &operator=(const BinaryStreamRefBase &Other) = default;
+
+ BinaryStreamRefBase &operator=(BinaryStreamRefBase &&Other) = default;
+ BinaryStreamRefBase(BinaryStreamRefBase &&Other) = default;
public:
llvm::support::endianness getEndian() const {
return BorrowedImpl->getEndian();
}
- uint32_t getLength() const { return Length; }
+ uint32_t getLength() const {
+ if (Length.hasValue())
+ return *Length;
- /// Return a new BinaryStreamRef with the first \p N elements removed.
+ return BorrowedImpl ? (BorrowedImpl->getLength() - ViewOffset) : 0;
+ }
+
+ /// Return a new BinaryStreamRef with the first \p N elements removed. If
+ /// this BinaryStreamRef is length-tracking, then the resulting one will be
+ /// too.
RefType drop_front(uint32_t N) const {
if (!BorrowedImpl)
return RefType();
- N = std::min(N, Length);
+ N = std::min(N, getLength());
RefType Result(static_cast<const RefType &>(*this));
+ if (N == 0)
+ return Result;
+
Result.ViewOffset += N;
- Result.Length -= N;
+ if (Result.Length.hasValue())
+ *Result.Length -= N;
return Result;
}
- /// Return a new BinaryStreamRef with the first \p N elements removed.
+ /// Return a new BinaryStreamRef with the last \p N elements removed. If
+ /// this BinaryStreamRef is length-tracking and \p N is greater than 0, then
+ /// this BinaryStreamRef will no longer length-track.
RefType drop_back(uint32_t N) const {
if (!BorrowedImpl)
return RefType();
- N = std::min(N, Length);
RefType Result(static_cast<const RefType &>(*this));
- Result.Length -= N;
+ N = std::min(N, getLength());
+
+ if (N == 0)
+ return Result;
+
+ // Since we're dropping non-zero bytes from the end, stop length-tracking
+ // by setting the length of the resulting StreamRef to an explicit value.
+ if (!Result.Length.hasValue())
+ Result.Length = getLength();
+
+ *Result.Length -= N;
return Result;
}
@@ -105,7 +133,7 @@ public:
}
protected:
- Error checkOffset(uint32_t Offset, uint32_t DataSize) const {
+ Error checkOffsetForRead(uint32_t Offset, uint32_t DataSize) const {
if (Offset > getLength())
return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
if (getLength() < DataSize + Offset)
@@ -116,7 +144,7 @@ protected:
std::shared_ptr<StreamType> SharedImpl;
StreamType *BorrowedImpl = nullptr;
uint32_t ViewOffset = 0;
- uint32_t Length = 0;
+ Optional<uint32_t> Length;
};
/// \brief BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It
@@ -131,18 +159,22 @@ class BinaryStreamRef
friend BinaryStreamRefBase<BinaryStreamRef, BinaryStream>;
friend class WritableBinaryStreamRef;
BinaryStreamRef(std::shared_ptr<BinaryStream> Impl, uint32_t ViewOffset,
- uint32_t Length)
+ Optional<uint32_t> Length)
: BinaryStreamRefBase(Impl, ViewOffset, Length) {}
public:
BinaryStreamRef() = default;
BinaryStreamRef(BinaryStream &Stream);
- BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, uint32_t Length);
+ BinaryStreamRef(BinaryStream &Stream, uint32_t Offset,
+ Optional<uint32_t> Length);
explicit BinaryStreamRef(ArrayRef<uint8_t> Data,
llvm::support::endianness Endian);
explicit BinaryStreamRef(StringRef Data, llvm::support::endianness Endian);
- BinaryStreamRef(const BinaryStreamRef &Other);
+ BinaryStreamRef(const BinaryStreamRef &Other) = default;
+ BinaryStreamRef &operator=(const BinaryStreamRef &Other) = default;
+ BinaryStreamRef(BinaryStreamRef &&Other) = default;
+ BinaryStreamRef &operator=(BinaryStreamRef &&Other) = default;
// Use BinaryStreamRef.slice() instead.
BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset,
@@ -193,17 +225,31 @@ class WritableBinaryStreamRef
WritableBinaryStream> {
friend BinaryStreamRefBase<WritableBinaryStreamRef, WritableBinaryStream>;
WritableBinaryStreamRef(std::shared_ptr<WritableBinaryStream> Impl,
- uint32_t ViewOffset, uint32_t Length)
+ uint32_t ViewOffset, Optional<uint32_t> Length)
: BinaryStreamRefBase(Impl, ViewOffset, Length) {}
+ Error checkOffsetForWrite(uint32_t Offset, uint32_t DataSize) const {
+ if (!(BorrowedImpl->getFlags() & BSF_Append))
+ return checkOffsetForRead(Offset, DataSize);
+
+ if (Offset > getLength())
+ return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
+ return Error::success();
+ }
+
public:
WritableBinaryStreamRef() = default;
WritableBinaryStreamRef(WritableBinaryStream &Stream);
WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset,
- uint32_t Length);
+ Optional<uint32_t> Length);
explicit WritableBinaryStreamRef(MutableArrayRef<uint8_t> Data,
llvm::support::endianness Endian);
- WritableBinaryStreamRef(const WritableBinaryStreamRef &Other);
+ WritableBinaryStreamRef(const WritableBinaryStreamRef &Other) = default;
+ WritableBinaryStreamRef &
+ operator=(const WritableBinaryStreamRef &Other) = default;
+
+ WritableBinaryStreamRef(WritableBinaryStreamRef &&Other) = default;
+ WritableBinaryStreamRef &operator=(WritableBinaryStreamRef &&Other) = default;
// Use WritableBinaryStreamRef.slice() instead.
WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint32_t Offset,
diff --git a/include/llvm/Support/CMakeLists.txt b/include/llvm/Support/CMakeLists.txt
index 95752cf01856..bf662c77351d 100644
--- a/include/llvm/Support/CMakeLists.txt
+++ b/include/llvm/Support/CMakeLists.txt
@@ -1,38 +1,3 @@
-# Figure out if we can track VC revisions.
-function(find_first_existing_file out_var)
- foreach(file ${ARGN})
- if(EXISTS "${file}")
- set(${out_var} "${file}" PARENT_SCOPE)
- return()
- endif()
- endforeach()
-endfunction()
-
-macro(find_first_existing_vc_file out_var path)
- if ( LLVM_APPEND_VC_REV )
- find_program(git_executable NAMES git git.exe git.cmd)
- # Run from a subdirectory to force git to print an absolute path.
- execute_process(COMMAND ${git_executable} rev-parse --git-dir
- WORKING_DIRECTORY ${path}/cmake
- RESULT_VARIABLE git_result
- OUTPUT_VARIABLE git_dir
- ERROR_QUIET)
- if(git_result EQUAL 0)
- string(STRIP "${git_dir}" git_dir)
- set(${out_var} "${git_dir}/logs/HEAD")
- # some branchless cases (e.g. 'repo') may not yet have .git/logs/HEAD
- if (NOT EXISTS "${git_dir}/logs/HEAD")
- file(WRITE "${git_dir}/logs/HEAD" "")
- endif()
- else()
- find_first_existing_file(${out_var}
- "${path}/.svn/wc.db" # SVN 1.7
- "${path}/.svn/entries" # SVN 1.6
- )
- endif()
- endif()
-endmacro()
-
find_first_existing_vc_file(llvm_vc "${LLVM_MAIN_SRC_DIR}")
# The VC revision include that we want to generate.
@@ -40,7 +5,20 @@ set(version_inc "${CMAKE_CURRENT_BINARY_DIR}/VCSRevision.h")
set(get_svn_script "${LLVM_CMAKE_PATH}/GenerateVersionFromCVS.cmake")
-if(DEFINED llvm_vc)
+file(WRITE "${version_inc}.empty" "")
+if((DEFINED llvm_vc) AND LLVM_APPEND_VC_REV)
+
+ execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files
+ "${version_inc}.empty" "${version_inc}"
+ RESULT_VARIABLE files_not_equal
+ OUTPUT_QUIET
+ ERROR_QUIET)
+ # Remove ${version_inc} if it's empty -- toggling LLVM_APPEND_VC_REV
+ # from OFF to ON.
+ if(NOT files_not_equal)
+ file(REMOVE "${version_inc}")
+ endif()
+
# Create custom target to generate the VC revision include.
add_custom_command(OUTPUT "${version_inc}"
DEPENDS "${llvm_vc}" "${get_svn_script}"
@@ -49,13 +27,17 @@ if(DEFINED llvm_vc)
"-DNAME=LLVM_REVISION"
"-DHEADER_FILE=${version_inc}"
-P "${get_svn_script}")
-
- # Mark the generated header as being generated.
- set_source_files_properties("${version_inc}"
- PROPERTIES GENERATED TRUE
- HEADER_FILE_ONLY TRUE)
else()
- file(WRITE "${version_inc}" "")
+ # Make sure ${version_inc} is an empty file.
+ execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "${version_inc}.empty" "${version_inc}")
endif()
+file(REMOVE "${version_inc}.empty")
+
+# Mark the generated header as being generated.
+set_source_files_properties("${version_inc}"
+ PROPERTIES GENERATED TRUE
+ HEADER_FILE_ONLY TRUE)
add_custom_target(llvm_vcsrevision_h DEPENDS "${version_inc}")
+set_target_properties(llvm_vcsrevision_h PROPERTIES FOLDER "Misc")
diff --git a/include/llvm/Support/CachePruning.h b/include/llvm/Support/CachePruning.h
index 46e34358573b..c577e9b8b631 100644
--- a/include/llvm/Support/CachePruning.h
+++ b/include/llvm/Support/CachePruning.h
@@ -46,6 +46,15 @@ struct CachePruningPolicy {
/// of available space on the disk will be reduced to the amount of available
/// space. A value of 0 disables the absolute size-based pruning.
uint64_t MaxSizeBytes = 0;
+
+ /// The maximum number of files in the cache directory. A value of 0 disables
+ /// the number of files based pruning.
+ ///
+ /// This defaults to 1000000 because with that many files there are
+ /// diminishing returns on the effectiveness of the cache, and some file
+ /// systems have a limit on how many files can be contained in a directory
+ /// (notably ext4, which is limited to around 6000000 files).
+ uint64_t MaxSizeFiles = 1000000;
};
/// Parse the given string as a cache pruning policy. Defaults are taken from a
diff --git a/include/llvm/Support/Chrono.h b/include/llvm/Support/Chrono.h
index 6118ed0476ed..994068af3771 100644
--- a/include/llvm/Support/Chrono.h
+++ b/include/llvm/Support/Chrono.h
@@ -51,6 +51,20 @@ toTimePoint(std::time_t T) {
raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP);
+/// Format provider for TimePoint<>
+///
+/// The options string is a strftime format string, with extensions:
+/// - %L is millis: 000-999
+/// - %f is micros: 000000-999999
+/// - %N is nanos: 000000000 - 999999999
+///
+/// If no options are given, the default format is "%Y-%m-%d %H:%M:%S.%N".
+template <>
+struct format_provider<sys::TimePoint<>> {
+ static void format(const sys::TimePoint<> &TP, llvm::raw_ostream &OS,
+ StringRef Style);
+};
+
/// Implementation of format_provider<T> for duration types.
///
/// The options string of a duration type has the grammar:
diff --git a/include/llvm/Support/CodeGen.h b/include/llvm/Support/CodeGen.h
index 941c112b0dd2..5f9e33129587 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 { Default, JITDefault, Small, Kernel, Medium, Large };
+ enum Model { Small, Kernel, Medium, Large };
}
namespace PICLevel {
diff --git a/include/llvm/Support/CodeGenCWrappers.h b/include/llvm/Support/CodeGenCWrappers.h
index 6db4433a4350..47971e80cefb 100644
--- a/include/llvm/Support/CodeGenCWrappers.h
+++ b/include/llvm/Support/CodeGenCWrappers.h
@@ -17,17 +17,20 @@
#define LLVM_SUPPORT_CODEGENCWRAPPERS_H
#include "llvm-c/TargetMachine.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/ErrorHandling.h"
namespace llvm {
-inline CodeModel::Model unwrap(LLVMCodeModel Model) {
+inline Optional<CodeModel::Model> unwrap(LLVMCodeModel Model, bool &JIT) {
+ JIT = false;
switch (Model) {
- case LLVMCodeModelDefault:
- return CodeModel::Default;
case LLVMCodeModelJITDefault:
- return CodeModel::JITDefault;
+ JIT = true;
+ LLVM_FALLTHROUGH;
+ case LLVMCodeModelDefault:
+ return None;
case LLVMCodeModelSmall:
return CodeModel::Small;
case LLVMCodeModelKernel:
@@ -37,15 +40,11 @@ inline CodeModel::Model unwrap(LLVMCodeModel Model) {
case LLVMCodeModelLarge:
return CodeModel::Large;
}
- return CodeModel::Default;
+ return CodeModel::Small;
}
inline LLVMCodeModel wrap(CodeModel::Model Model) {
switch (Model) {
- case CodeModel::Default:
- return LLVMCodeModelDefault;
- case CodeModel::JITDefault:
- return LLVMCodeModelJITDefault;
case CodeModel::Small:
return LLVMCodeModelSmall;
case CodeModel::Kernel:
@@ -61,4 +60,3 @@ inline LLVMCodeModel wrap(CodeModel::Model Model) {
} // end llvm namespace
#endif
-
diff --git a/include/llvm/Support/CodeGenCoverage.h b/include/llvm/Support/CodeGenCoverage.h
new file mode 100644
index 000000000000..d5bd837bff28
--- /dev/null
+++ b/include/llvm/Support/CodeGenCoverage.h
@@ -0,0 +1,37 @@
+//== llvm/Support/CodeGenCoverage.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 provides rule coverage tracking for tablegen-erated CodeGen.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CODEGENCOVERAGE_H
+#define LLVM_SUPPORT_CODEGENCOVERAGE_H
+
+#include "llvm/ADT/BitVector.h"
+
+namespace llvm {
+class LLVMContext;
+class MemoryBuffer;
+
+class CodeGenCoverage {
+protected:
+ BitVector RuleCoverage;
+
+public:
+ CodeGenCoverage();
+
+ void setCovered(uint64_t RuleID);
+ bool isCovered(uint64_t RuleID);
+
+ bool parse(MemoryBuffer &Buffer, StringRef BackendName);
+ bool emit(StringRef FilePrefix, StringRef BackendName) const;
+ void reset();
+};
+} // end namespace llvm
+
+#endif // ifndef LLVM_SUPPORT_CODEGENCOVERAGE_H
diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h
index 71d2f0293083..d1901db7c68e 100644
--- a/include/llvm/Support/CommandLine.h
+++ b/include/llvm/Support/CommandLine.h
@@ -66,12 +66,15 @@ bool ParseCommandLineOptions(int argc, const char *const *argv,
void ParseEnvironmentOptions(const char *progName, const char *envvar,
const char *Overview = "");
+// Function pointer type for printing version information.
+using VersionPrinterTy = std::function<void(raw_ostream &)>;
+
///===---------------------------------------------------------------------===//
/// SetVersionPrinter - Override the default (LLVM specific) version printer
/// used to print out the version when --version is given
/// on the command line. This allows other systems using the
/// CommandLine utilities to print their own version string.
-void SetVersionPrinter(void (*func)());
+void SetVersionPrinter(VersionPrinterTy func);
///===---------------------------------------------------------------------===//
/// AddExtraVersionPrinter - Add an extra printer to use in addition to the
@@ -80,7 +83,7 @@ void SetVersionPrinter(void (*func)());
/// which will be called after the basic LLVM version
/// printing is complete. Each can then add additional
/// information specific to the tool.
-void AddExtraVersionPrinter(void (*func)());
+void AddExtraVersionPrinter(VersionPrinterTy func);
// PrintOptionValues - Print option values.
// With -print-options print the difference between option values and defaults.
@@ -263,7 +266,7 @@ public:
StringRef ValueStr; // String describing what the value of this option is
OptionCategory *Category; // The Category this option belongs to
SmallPtrSet<SubCommand *, 4> Subs; // The subcommands this option belongs to.
- bool FullyInitialized = false; // Has addArguemnt been called?
+ bool FullyInitialized = false; // Has addArgument been called?
inline enum NumOccurrencesFlag getNumOccurrencesFlag() const {
return (enum NumOccurrencesFlag)Occurrences;
@@ -346,6 +349,8 @@ public:
virtual void printOptionValue(size_t GlobalWidth, bool Force) const = 0;
+ virtual void setDefault() = 0;
+
static void printHelpStr(StringRef HelpStr, size_t Indent,
size_t FirstLineIndentedBy);
@@ -1315,6 +1320,20 @@ class opt : public Option,
}
}
+ template <class T, class = typename std::enable_if<
+ std::is_assignable<T&, T>::value>::type>
+ void setDefaultImpl() {
+ const OptionValue<DataType> &V = this->getDefault();
+ if (V.hasValue())
+ this->setValue(V.getValue());
+ }
+
+ template <class T, class = typename std::enable_if<
+ !std::is_assignable<T&, T>::value>::type>
+ void setDefaultImpl(...) {}
+
+ void setDefault() override { setDefaultImpl<DataType>(); }
+
void done() {
addArgument();
Parser.initialize();
@@ -1490,6 +1509,8 @@ class list : public Option, public list_storage<DataType, StorageClass> {
void printOptionValue(size_t /*GlobalWidth*/, bool /*Force*/) const override {
}
+ void setDefault() override {}
+
void done() {
addArgument();
Parser.initialize();
@@ -1631,6 +1652,8 @@ class bits : public Option, public bits_storage<DataType, Storage> {
void printOptionValue(size_t /*GlobalWidth*/, bool /*Force*/) const override {
}
+ void setDefault() override {}
+
void done() {
addArgument();
Parser.initialize();
@@ -1681,6 +1704,8 @@ class alias : public Option {
void printOptionValue(size_t /*GlobalWidth*/, bool /*Force*/) const override {
}
+ void setDefault() override { AliasFor->setDefault(); }
+
ValueExpected getValueExpectedFlagDefault() const override {
return AliasFor->getValueExpectedFlag();
}
@@ -1737,8 +1762,6 @@ void PrintVersionMessage();
/// This function just prints the help message, exactly the same way as if the
/// -help or -help-hidden option had been given on the command line.
///
-/// NOTE: THIS FUNCTION TERMINATES THE PROGRAM!
-///
/// \param Hidden if true will print hidden options
/// \param Categorized if true print options in categories
void PrintHelpMessage(bool Hidden = false, bool Categorized = false);
diff --git a/include/llvm/Support/ConvertUTF.h b/include/llvm/Support/ConvertUTF.h
index bd439f360216..99ae171aeabb 100644
--- a/include/llvm/Support/ConvertUTF.h
+++ b/include/llvm/Support/ConvertUTF.h
@@ -242,10 +242,10 @@ bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr);
*
* \sa ConvertUTF8toUTF32
*/
-static inline ConversionResult convertUTF8Sequence(const UTF8 **source,
- const UTF8 *sourceEnd,
- UTF32 *target,
- ConversionFlags flags) {
+inline ConversionResult convertUTF8Sequence(const UTF8 **source,
+ const UTF8 *sourceEnd,
+ UTF32 *target,
+ ConversionFlags flags) {
if (*source == sourceEnd)
return sourceExhausted;
unsigned size = getNumBytesForUTF8(**source);
diff --git a/include/llvm/Support/DebugCounter.h b/include/llvm/Support/DebugCounter.h
index a533feae7fa3..52e1bd71a2f2 100644
--- a/include/llvm/Support/DebugCounter.h
+++ b/include/llvm/Support/DebugCounter.h
@@ -159,7 +159,7 @@ private:
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC) \
static const unsigned VARNAME = \
- DebugCounter::registerCounter(COUNTERNAME, DESC);
+ DebugCounter::registerCounter(COUNTERNAME, DESC)
} // namespace llvm
#endif
diff --git a/include/llvm/Support/Error.h b/include/llvm/Support/Error.h
index 9a7fa0ae6356..8567af392fb0 100644
--- a/include/llvm/Support/Error.h
+++ b/include/llvm/Support/Error.h
@@ -246,18 +246,20 @@ public:
}
private:
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ // assertIsChecked() happens very frequently, but under normal circumstances
+ // is supposed to be a no-op. So we want it to be inlined, but having a bunch
+ // of debug prints can cause the function to be too large for inlining. So
+ // it's important that we define this function out of line so that it can't be
+ // inlined.
+ LLVM_ATTRIBUTE_NORETURN
+ void fatalUncheckedError() const;
+#endif
+
void assertIsChecked() {
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
- if (!getChecked() || getPtr()) {
- dbgs() << "Program aborted due to an unhandled Error:\n";
- if (getPtr())
- getPtr()->log(dbgs());
- else
- dbgs()
- << "Error value was Success. (Note: Success values must still be "
- "checked prior to being destroyed).\n";
- abort();
- }
+ if (LLVM_UNLIKELY(!getChecked() || getPtr()))
+ fatalUncheckedError();
#endif
}
@@ -407,235 +409,6 @@ inline Error joinErrors(Error E1, Error E2) {
return ErrorList::join(std::move(E1), std::move(E2));
}
-/// Helper for testing applicability of, and applying, handlers for
-/// ErrorInfo types.
-template <typename HandlerT>
-class ErrorHandlerTraits
- : public ErrorHandlerTraits<decltype(
- &std::remove_reference<HandlerT>::type::operator())> {};
-
-// Specialization functions of the form 'Error (const ErrT&)'.
-template <typename ErrT> class ErrorHandlerTraits<Error (&)(ErrT &)> {
-public:
- static bool appliesTo(const ErrorInfoBase &E) {
- return E.template isA<ErrT>();
- }
-
- template <typename HandlerT>
- static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
- assert(appliesTo(*E) && "Applying incorrect handler");
- return H(static_cast<ErrT &>(*E));
- }
-};
-
-// Specialization functions of the form 'void (const ErrT&)'.
-template <typename ErrT> class ErrorHandlerTraits<void (&)(ErrT &)> {
-public:
- static bool appliesTo(const ErrorInfoBase &E) {
- return E.template isA<ErrT>();
- }
-
- template <typename HandlerT>
- static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
- assert(appliesTo(*E) && "Applying incorrect handler");
- H(static_cast<ErrT &>(*E));
- return Error::success();
- }
-};
-
-/// Specialization for functions of the form 'Error (std::unique_ptr<ErrT>)'.
-template <typename ErrT>
-class ErrorHandlerTraits<Error (&)(std::unique_ptr<ErrT>)> {
-public:
- static bool appliesTo(const ErrorInfoBase &E) {
- return E.template isA<ErrT>();
- }
-
- template <typename HandlerT>
- static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
- assert(appliesTo(*E) && "Applying incorrect handler");
- std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release()));
- return H(std::move(SubE));
- }
-};
-
-/// Specialization for functions of the form 'Error (std::unique_ptr<ErrT>)'.
-template <typename ErrT>
-class ErrorHandlerTraits<void (&)(std::unique_ptr<ErrT>)> {
-public:
- static bool appliesTo(const ErrorInfoBase &E) {
- return E.template isA<ErrT>();
- }
-
- template <typename HandlerT>
- static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
- assert(appliesTo(*E) && "Applying incorrect handler");
- std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release()));
- H(std::move(SubE));
- return Error::success();
- }
-};
-
-// Specialization for member functions of the form 'RetT (const ErrT&)'.
-template <typename C, typename RetT, typename ErrT>
-class ErrorHandlerTraits<RetT (C::*)(ErrT &)>
- : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
-
-// Specialization for member functions of the form 'RetT (const ErrT&) const'.
-template <typename C, typename RetT, typename ErrT>
-class ErrorHandlerTraits<RetT (C::*)(ErrT &) const>
- : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
-
-// Specialization for member functions of the form 'RetT (const ErrT&)'.
-template <typename C, typename RetT, typename ErrT>
-class ErrorHandlerTraits<RetT (C::*)(const ErrT &)>
- : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
-
-// Specialization for member functions of the form 'RetT (const ErrT&) const'.
-template <typename C, typename RetT, typename ErrT>
-class ErrorHandlerTraits<RetT (C::*)(const ErrT &) const>
- : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
-
-/// Specialization for member functions of the form
-/// 'RetT (std::unique_ptr<ErrT>) const'.
-template <typename C, typename RetT, typename ErrT>
-class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>)>
- : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
-
-/// Specialization for member functions of the form
-/// 'RetT (std::unique_ptr<ErrT>) const'.
-template <typename C, typename RetT, typename ErrT>
-class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>) const>
- : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
-
-inline Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload) {
- return Error(std::move(Payload));
-}
-
-template <typename HandlerT, typename... HandlerTs>
-Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload,
- HandlerT &&Handler, HandlerTs &&... Handlers) {
- if (ErrorHandlerTraits<HandlerT>::appliesTo(*Payload))
- return ErrorHandlerTraits<HandlerT>::apply(std::forward<HandlerT>(Handler),
- std::move(Payload));
- return handleErrorImpl(std::move(Payload),
- std::forward<HandlerTs>(Handlers)...);
-}
-
-/// Pass the ErrorInfo(s) contained in E to their respective handlers. Any
-/// unhandled errors (or Errors returned by handlers) are re-concatenated and
-/// returned.
-/// Because this function returns an error, its result must also be checked
-/// or returned. If you intend to handle all errors use handleAllErrors
-/// (which returns void, and will abort() on unhandled errors) instead.
-template <typename... HandlerTs>
-Error handleErrors(Error E, HandlerTs &&... Hs) {
- if (!E)
- return Error::success();
-
- std::unique_ptr<ErrorInfoBase> Payload = E.takePayload();
-
- if (Payload->isA<ErrorList>()) {
- ErrorList &List = static_cast<ErrorList &>(*Payload);
- Error R;
- for (auto &P : List.Payloads)
- R = ErrorList::join(
- std::move(R),
- handleErrorImpl(std::move(P), std::forward<HandlerTs>(Hs)...));
- return R;
- }
-
- return handleErrorImpl(std::move(Payload), std::forward<HandlerTs>(Hs)...);
-}
-
-/// Behaves the same as handleErrors, except that it requires that all
-/// errors be handled by the given handlers. If any unhandled error remains
-/// after the handlers have run, abort() will be called.
-template <typename... HandlerTs>
-void handleAllErrors(Error E, HandlerTs &&... Handlers) {
- auto F = handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...);
- // Cast 'F' to bool to set the 'Checked' flag if it's a success value:
- (void)!F;
-}
-
-/// Check that E is a non-error, then drop it.
-inline void handleAllErrors(Error E) {
- // Cast 'E' to a bool to set the 'Checked' flag if it's a success value:
- (void)!E;
-}
-
-/// Log all errors (if any) in E to OS. If there are any errors, ErrorBanner
-/// will be printed before the first one is logged. A newline will be printed
-/// after each error.
-///
-/// This is useful in the base level of your program to allow clean termination
-/// (allowing clean deallocation of resources, etc.), while reporting error
-/// information to the user.
-void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner);
-
-/// Write all error messages (if any) in E to a string. The newline character
-/// is used to separate error messages.
-inline std::string toString(Error E) {
- SmallVector<std::string, 2> Errors;
- handleAllErrors(std::move(E), [&Errors](const ErrorInfoBase &EI) {
- Errors.push_back(EI.message());
- });
- return join(Errors.begin(), Errors.end(), "\n");
-}
-
-/// Consume a Error without doing anything. This method should be used
-/// only where an error can be considered a reasonable and expected return
-/// value.
-///
-/// Uses of this method are potentially indicative of design problems: If it's
-/// legitimate to do nothing while processing an "error", the error-producer
-/// might be more clearly refactored to return an Optional<T>.
-inline void consumeError(Error Err) {
- handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {});
-}
-
-/// Helper for Errors used as out-parameters.
-///
-/// This helper is for use with the Error-as-out-parameter idiom, where an error
-/// is passed to a function or method by reference, rather than being returned.
-/// In such cases it is helpful to set the checked bit on entry to the function
-/// so that the error can be written to (unchecked Errors abort on assignment)
-/// and clear the checked bit on exit so that clients cannot accidentally forget
-/// to check the result. This helper performs these actions automatically using
-/// RAII:
-///
-/// @code{.cpp}
-/// Result foo(Error &Err) {
-/// ErrorAsOutParameter ErrAsOutParam(&Err); // 'Checked' flag set
-/// // <body of foo>
-/// // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed.
-/// }
-/// @endcode
-///
-/// ErrorAsOutParameter takes an Error* rather than Error& so that it can be
-/// used with optional Errors (Error pointers that are allowed to be null). If
-/// ErrorAsOutParameter took an Error reference, an instance would have to be
-/// created inside every condition that verified that Error was non-null. By
-/// taking an Error pointer we can just create one instance at the top of the
-/// function.
-class ErrorAsOutParameter {
-public:
- ErrorAsOutParameter(Error *Err) : Err(Err) {
- // Raise the checked bit if Err is success.
- if (Err)
- (void)!!*Err;
- }
-
- ~ErrorAsOutParameter() {
- // Clear the checked bit.
- if (Err && !*Err)
- *Err = Error::success();
- }
-
-private:
- Error *Err;
-};
-
/// Tagged union holding either a T or a Error.
///
/// This class parallels ErrorOr, but replaces error_code with Error. Since
@@ -861,19 +634,26 @@ private:
#endif
}
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ LLVM_ATTRIBUTE_NORETURN
+ LLVM_ATTRIBUTE_NOINLINE
+ void fatalUncheckedExpected() const {
+ dbgs() << "Expected<T> must be checked before access or destruction.\n";
+ if (HasError) {
+ dbgs() << "Unchecked Expected<T> contained error:\n";
+ (*getErrorStorage())->log(dbgs());
+ } else
+ dbgs() << "Expected<T> value was in success state. (Note: Expected<T> "
+ "values in success mode must still be checked prior to being "
+ "destroyed).\n";
+ abort();
+ }
+#endif
+
void assertIsChecked() {
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
- if (Unchecked) {
- dbgs() << "Expected<T> must be checked before access or destruction.\n";
- if (HasError) {
- dbgs() << "Unchecked Expected<T> contained error:\n";
- (*getErrorStorage())->log(dbgs());
- } else
- dbgs() << "Expected<T> value was in success state. (Note: Expected<T> "
- "values in success mode must still be checked prior to being "
- "destroyed).\n";
- abort();
- }
+ if (LLVM_UNLIKELY(Unchecked))
+ fatalUncheckedExpected();
#endif
}
@@ -887,6 +667,344 @@ private:
#endif
};
+/// Report a serious error, calling any installed error handler. See
+/// ErrorHandling.h.
+LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err,
+ bool gen_crash_diag = true);
+
+/// Report a fatal error if Err is a failure value.
+///
+/// This function can be used to wrap calls to fallible functions ONLY when it
+/// is known that the Error will always be a success value. E.g.
+///
+/// @code{.cpp}
+/// // foo only attempts the fallible operation if DoFallibleOperation is
+/// // true. If DoFallibleOperation is false then foo always returns
+/// // Error::success().
+/// Error foo(bool DoFallibleOperation);
+///
+/// cantFail(foo(false));
+/// @endcode
+inline void cantFail(Error Err, const char *Msg = nullptr) {
+ if (Err) {
+ if (!Msg)
+ Msg = "Failure value returned from cantFail wrapped call";
+ llvm_unreachable(Msg);
+ }
+}
+
+/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and
+/// returns the contained value.
+///
+/// This function can be used to wrap calls to fallible functions ONLY when it
+/// is known that the Error will always be a success value. E.g.
+///
+/// @code{.cpp}
+/// // foo only attempts the fallible operation if DoFallibleOperation is
+/// // true. If DoFallibleOperation is false then foo always returns an int.
+/// Expected<int> foo(bool DoFallibleOperation);
+///
+/// int X = cantFail(foo(false));
+/// @endcode
+template <typename T>
+T cantFail(Expected<T> ValOrErr, const char *Msg = nullptr) {
+ if (ValOrErr)
+ return std::move(*ValOrErr);
+ else {
+ if (!Msg)
+ Msg = "Failure value returned from cantFail wrapped call";
+ llvm_unreachable(Msg);
+ }
+}
+
+/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and
+/// returns the contained reference.
+///
+/// This function can be used to wrap calls to fallible functions ONLY when it
+/// is known that the Error will always be a success value. E.g.
+///
+/// @code{.cpp}
+/// // foo only attempts the fallible operation if DoFallibleOperation is
+/// // true. If DoFallibleOperation is false then foo always returns a Bar&.
+/// Expected<Bar&> foo(bool DoFallibleOperation);
+///
+/// Bar &X = cantFail(foo(false));
+/// @endcode
+template <typename T>
+T& cantFail(Expected<T&> ValOrErr, const char *Msg = nullptr) {
+ if (ValOrErr)
+ return *ValOrErr;
+ else {
+ if (!Msg)
+ Msg = "Failure value returned from cantFail wrapped call";
+ llvm_unreachable(Msg);
+ }
+}
+
+/// Helper for testing applicability of, and applying, handlers for
+/// ErrorInfo types.
+template <typename HandlerT>
+class ErrorHandlerTraits
+ : public ErrorHandlerTraits<decltype(
+ &std::remove_reference<HandlerT>::type::operator())> {};
+
+// Specialization functions of the form 'Error (const ErrT&)'.
+template <typename ErrT> class ErrorHandlerTraits<Error (&)(ErrT &)> {
+public:
+ static bool appliesTo(const ErrorInfoBase &E) {
+ return E.template isA<ErrT>();
+ }
+
+ template <typename HandlerT>
+ static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+ assert(appliesTo(*E) && "Applying incorrect handler");
+ return H(static_cast<ErrT &>(*E));
+ }
+};
+
+// Specialization functions of the form 'void (const ErrT&)'.
+template <typename ErrT> class ErrorHandlerTraits<void (&)(ErrT &)> {
+public:
+ static bool appliesTo(const ErrorInfoBase &E) {
+ return E.template isA<ErrT>();
+ }
+
+ template <typename HandlerT>
+ static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+ assert(appliesTo(*E) && "Applying incorrect handler");
+ H(static_cast<ErrT &>(*E));
+ return Error::success();
+ }
+};
+
+/// Specialization for functions of the form 'Error (std::unique_ptr<ErrT>)'.
+template <typename ErrT>
+class ErrorHandlerTraits<Error (&)(std::unique_ptr<ErrT>)> {
+public:
+ static bool appliesTo(const ErrorInfoBase &E) {
+ return E.template isA<ErrT>();
+ }
+
+ template <typename HandlerT>
+ static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+ assert(appliesTo(*E) && "Applying incorrect handler");
+ std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release()));
+ return H(std::move(SubE));
+ }
+};
+
+/// Specialization for functions of the form 'void (std::unique_ptr<ErrT>)'.
+template <typename ErrT>
+class ErrorHandlerTraits<void (&)(std::unique_ptr<ErrT>)> {
+public:
+ static bool appliesTo(const ErrorInfoBase &E) {
+ return E.template isA<ErrT>();
+ }
+
+ template <typename HandlerT>
+ static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+ assert(appliesTo(*E) && "Applying incorrect handler");
+ std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release()));
+ H(std::move(SubE));
+ return Error::success();
+ }
+};
+
+// Specialization for member functions of the form 'RetT (const ErrT&)'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(ErrT &)>
+ : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+// Specialization for member functions of the form 'RetT (const ErrT&) const'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(ErrT &) const>
+ : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+// Specialization for member functions of the form 'RetT (const ErrT&)'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(const ErrT &)>
+ : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+// Specialization for member functions of the form 'RetT (const ErrT&) const'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(const ErrT &) const>
+ : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+/// Specialization for member functions of the form
+/// 'RetT (std::unique_ptr<ErrT>)'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>)>
+ : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
+
+/// Specialization for member functions of the form
+/// 'RetT (std::unique_ptr<ErrT>) const'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>) const>
+ : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
+
+inline Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload) {
+ return Error(std::move(Payload));
+}
+
+template <typename HandlerT, typename... HandlerTs>
+Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload,
+ HandlerT &&Handler, HandlerTs &&... Handlers) {
+ if (ErrorHandlerTraits<HandlerT>::appliesTo(*Payload))
+ return ErrorHandlerTraits<HandlerT>::apply(std::forward<HandlerT>(Handler),
+ std::move(Payload));
+ return handleErrorImpl(std::move(Payload),
+ std::forward<HandlerTs>(Handlers)...);
+}
+
+/// Pass the ErrorInfo(s) contained in E to their respective handlers. Any
+/// unhandled errors (or Errors returned by handlers) are re-concatenated and
+/// returned.
+/// Because this function returns an error, its result must also be checked
+/// or returned. If you intend to handle all errors use handleAllErrors
+/// (which returns void, and will abort() on unhandled errors) instead.
+template <typename... HandlerTs>
+Error handleErrors(Error E, HandlerTs &&... Hs) {
+ if (!E)
+ return Error::success();
+
+ std::unique_ptr<ErrorInfoBase> Payload = E.takePayload();
+
+ if (Payload->isA<ErrorList>()) {
+ ErrorList &List = static_cast<ErrorList &>(*Payload);
+ Error R;
+ for (auto &P : List.Payloads)
+ R = ErrorList::join(
+ std::move(R),
+ handleErrorImpl(std::move(P), std::forward<HandlerTs>(Hs)...));
+ return R;
+ }
+
+ return handleErrorImpl(std::move(Payload), std::forward<HandlerTs>(Hs)...);
+}
+
+/// Behaves the same as handleErrors, except that it requires that all
+/// errors be handled by the given handlers. If any unhandled error remains
+/// after the handlers have run, report_fatal_error() will be called.
+template <typename... HandlerTs>
+void handleAllErrors(Error E, HandlerTs &&... Handlers) {
+ cantFail(handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...));
+}
+
+/// Check that E is a non-error, then drop it.
+/// If E is an error report_fatal_error will be called.
+inline void handleAllErrors(Error E) {
+ cantFail(std::move(E));
+}
+
+/// Handle any errors (if present) in an Expected<T>, then try a recovery path.
+///
+/// If the incoming value is a success value it is returned unmodified. If it
+/// is a failure value then it the contained error is passed to handleErrors.
+/// If handleErrors is able to handle the error then the RecoveryPath functor
+/// is called to supply the final result. If handleErrors is not able to
+/// handle all errors then the unhandled errors are returned.
+///
+/// This utility enables the follow pattern:
+///
+/// @code{.cpp}
+/// enum FooStrategy { Aggressive, Conservative };
+/// Expected<Foo> foo(FooStrategy S);
+///
+/// auto ResultOrErr =
+/// handleExpected(
+/// foo(Aggressive),
+/// []() { return foo(Conservative); },
+/// [](AggressiveStrategyError&) {
+/// // Implicitly conusme this - we'll recover by using a conservative
+/// // strategy.
+/// });
+///
+/// @endcode
+template <typename T, typename RecoveryFtor, typename... HandlerTs>
+Expected<T> handleExpected(Expected<T> ValOrErr, RecoveryFtor &&RecoveryPath,
+ HandlerTs &&... Handlers) {
+ if (ValOrErr)
+ return ValOrErr;
+
+ if (auto Err = handleErrors(ValOrErr.takeError(),
+ std::forward<HandlerTs>(Handlers)...))
+ return std::move(Err);
+
+ return RecoveryPath();
+}
+
+/// Log all errors (if any) in E to OS. If there are any errors, ErrorBanner
+/// will be printed before the first one is logged. A newline will be printed
+/// after each error.
+///
+/// This is useful in the base level of your program to allow clean termination
+/// (allowing clean deallocation of resources, etc.), while reporting error
+/// information to the user.
+void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner);
+
+/// Write all error messages (if any) in E to a string. The newline character
+/// is used to separate error messages.
+inline std::string toString(Error E) {
+ SmallVector<std::string, 2> Errors;
+ handleAllErrors(std::move(E), [&Errors](const ErrorInfoBase &EI) {
+ Errors.push_back(EI.message());
+ });
+ return join(Errors.begin(), Errors.end(), "\n");
+}
+
+/// Consume a Error without doing anything. This method should be used
+/// only where an error can be considered a reasonable and expected return
+/// value.
+///
+/// Uses of this method are potentially indicative of design problems: If it's
+/// legitimate to do nothing while processing an "error", the error-producer
+/// might be more clearly refactored to return an Optional<T>.
+inline void consumeError(Error Err) {
+ handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {});
+}
+
+/// Helper for Errors used as out-parameters.
+///
+/// This helper is for use with the Error-as-out-parameter idiom, where an error
+/// is passed to a function or method by reference, rather than being returned.
+/// In such cases it is helpful to set the checked bit on entry to the function
+/// so that the error can be written to (unchecked Errors abort on assignment)
+/// and clear the checked bit on exit so that clients cannot accidentally forget
+/// to check the result. This helper performs these actions automatically using
+/// RAII:
+///
+/// @code{.cpp}
+/// Result foo(Error &Err) {
+/// ErrorAsOutParameter ErrAsOutParam(&Err); // 'Checked' flag set
+/// // <body of foo>
+/// // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed.
+/// }
+/// @endcode
+///
+/// ErrorAsOutParameter takes an Error* rather than Error& so that it can be
+/// used with optional Errors (Error pointers that are allowed to be null). If
+/// ErrorAsOutParameter took an Error reference, an instance would have to be
+/// created inside every condition that verified that Error was non-null. By
+/// taking an Error pointer we can just create one instance at the top of the
+/// function.
+class ErrorAsOutParameter {
+public:
+ ErrorAsOutParameter(Error *Err) : Err(Err) {
+ // Raise the checked bit if Err is success.
+ if (Err)
+ (void)!!*Err;
+ }
+
+ ~ErrorAsOutParameter() {
+ // Clear the checked bit.
+ if (Err && !*Err)
+ *Err = Error::success();
+ }
+
+private:
+ Error *Err;
+};
+
/// Helper for Expected<T>s used as out-parameters.
///
/// See ErrorAsOutParameter.
@@ -1032,71 +1150,6 @@ private:
std::function<int(const Error &)> GetExitCode;
};
-/// Report a serious error, calling any installed error handler. See
-/// ErrorHandling.h.
-LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err,
- bool gen_crash_diag = true);
-
-/// Report a fatal error if Err is a failure value.
-///
-/// This function can be used to wrap calls to fallible functions ONLY when it
-/// is known that the Error will always be a success value. E.g.
-///
-/// @code{.cpp}
-/// // foo only attempts the fallible operation if DoFallibleOperation is
-/// // true. If DoFallibleOperation is false then foo always returns
-/// // Error::success().
-/// Error foo(bool DoFallibleOperation);
-///
-/// cantFail(foo(false));
-/// @endcode
-inline void cantFail(Error Err) {
- if (Err)
- llvm_unreachable("Failure value returned from cantFail wrapped call");
-}
-
-/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and
-/// returns the contained value.
-///
-/// This function can be used to wrap calls to fallible functions ONLY when it
-/// is known that the Error will always be a success value. E.g.
-///
-/// @code{.cpp}
-/// // foo only attempts the fallible operation if DoFallibleOperation is
-/// // true. If DoFallibleOperation is false then foo always returns an int.
-/// Expected<int> foo(bool DoFallibleOperation);
-///
-/// int X = cantFail(foo(false));
-/// @endcode
-template <typename T>
-T cantFail(Expected<T> ValOrErr) {
- if (ValOrErr)
- return std::move(*ValOrErr);
- else
- llvm_unreachable("Failure value returned from cantFail wrapped call");
-}
-
-/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and
-/// returns the contained reference.
-///
-/// This function can be used to wrap calls to fallible functions ONLY when it
-/// is known that the Error will always be a success value. E.g.
-///
-/// @code{.cpp}
-/// // foo only attempts the fallible operation if DoFallibleOperation is
-/// // true. If DoFallibleOperation is false then foo always returns a Bar&.
-/// Expected<Bar&> foo(bool DoFallibleOperation);
-///
-/// Bar &X = cantFail(foo(false));
-/// @endcode
-template <typename T>
-T& cantFail(Expected<T&> ValOrErr) {
- if (ValOrErr)
- return *ValOrErr;
- else
- llvm_unreachable("Failure value returned from cantFail wrapped call");
-}
-
} // end namespace llvm
#endif // LLVM_SUPPORT_ERROR_H
diff --git a/include/llvm/Support/FileOutputBuffer.h b/include/llvm/Support/FileOutputBuffer.h
index 2c054c75374b..6aed423a01e3 100644
--- a/include/llvm/Support/FileOutputBuffer.h
+++ b/include/llvm/Support/FileOutputBuffer.h
@@ -17,7 +17,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DataTypes.h"
-#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
namespace llvm {
@@ -30,7 +30,6 @@ namespace llvm {
/// not committed, the file will be deleted in the FileOutputBuffer destructor.
class FileOutputBuffer {
public:
-
enum {
F_executable = 1 /// set the 'x' bit on the resulting file
};
@@ -38,52 +37,37 @@ public:
/// Factory method to create an OutputBuffer object which manages a read/write
/// buffer of the specified size. When committed, the buffer will be written
/// to the file at the specified path.
- static ErrorOr<std::unique_ptr<FileOutputBuffer>>
+ static Expected<std::unique_ptr<FileOutputBuffer>>
create(StringRef FilePath, size_t Size, unsigned Flags = 0);
/// Returns a pointer to the start of the buffer.
- uint8_t *getBufferStart() {
- return (uint8_t*)Region->data();
- }
+ virtual uint8_t *getBufferStart() const = 0;
/// Returns a pointer to the end of the buffer.
- uint8_t *getBufferEnd() {
- return (uint8_t*)Region->data() + Region->size();
- }
+ virtual uint8_t *getBufferEnd() const = 0;
/// Returns size of the buffer.
- size_t getBufferSize() const {
- return Region->size();
- }
+ virtual size_t getBufferSize() const = 0;
/// Returns path where file will show up if buffer is committed.
- StringRef getPath() const {
- return FinalPath;
- }
+ StringRef getPath() const { return FinalPath; }
/// Flushes the content of the buffer to its file and deallocates the
/// buffer. If commit() is not called before this object's destructor
/// is called, the file is deleted in the destructor. The optional parameter
/// is used if it turns out you want the file size to be smaller than
/// initially requested.
- std::error_code commit();
+ virtual Error commit() = 0;
/// If this object was previously committed, the destructor just deletes
/// this object. If this object was not committed, the destructor
/// deallocates the buffer and the target file is never written.
- ~FileOutputBuffer();
-
-private:
- FileOutputBuffer(const FileOutputBuffer &) = delete;
- FileOutputBuffer &operator=(const FileOutputBuffer &) = delete;
+ virtual ~FileOutputBuffer() {}
- FileOutputBuffer(std::unique_ptr<llvm::sys::fs::mapped_file_region> R,
- StringRef Path, StringRef TempPath, bool IsRegular);
+protected:
+ FileOutputBuffer(StringRef Path) : FinalPath(Path) {}
- std::unique_ptr<llvm::sys::fs::mapped_file_region> Region;
- SmallString<128> FinalPath;
- SmallString<128> TempPath;
- bool IsRegular;
+ std::string FinalPath;
};
} // end namespace llvm
diff --git a/include/llvm/Support/FileSystem.h b/include/llvm/Support/FileSystem.h
index 21c5fcdb7145..b1683ba5ddb3 100644
--- a/include/llvm/Support/FileSystem.h
+++ b/include/llvm/Support/FileSystem.h
@@ -31,6 +31,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Chrono.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MD5.h"
@@ -141,65 +142,48 @@ public:
uint64_t getFile() const { return File; }
};
-/// file_status - Represents the result of a call to stat and friends. It has
-/// a platform-specific member to store the result.
-class file_status
-{
- friend bool equivalent(file_status A, file_status B);
-
+/// Represents the result of a call to directory_iterator::status(). This is a
+/// subset of the information returned by a regular sys::fs::status() call, and
+/// represents the information provided by Windows FileFirstFile/FindNextFile.
+class basic_file_status {
+protected:
#if defined(LLVM_ON_UNIX)
- dev_t fs_st_dev = 0;
- nlink_t fs_st_nlinks = 0;
- ino_t fs_st_ino = 0;
time_t fs_st_atime = 0;
time_t fs_st_mtime = 0;
uid_t fs_st_uid = 0;
gid_t fs_st_gid = 0;
off_t fs_st_size = 0;
#elif defined (LLVM_ON_WIN32)
- uint32_t NumLinks = 0;
uint32_t LastAccessedTimeHigh = 0;
uint32_t LastAccessedTimeLow = 0;
uint32_t LastWriteTimeHigh = 0;
uint32_t LastWriteTimeLow = 0;
- uint32_t VolumeSerialNumber = 0;
uint32_t FileSizeHigh = 0;
uint32_t FileSizeLow = 0;
- uint32_t FileIndexHigh = 0;
- uint32_t FileIndexLow = 0;
#endif
file_type Type = file_type::status_error;
perms Perms = perms_not_known;
public:
- #if defined(LLVM_ON_UNIX)
- file_status() = default;
+ basic_file_status() = default;
- file_status(file_type Type) : Type(Type) {}
+ explicit basic_file_status(file_type Type) : Type(Type) {}
- 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)
- : fs_st_dev(Dev), fs_st_nlinks(Links), fs_st_ino(Ino), fs_st_atime(ATime),
- fs_st_mtime(MTime), fs_st_uid(UID), fs_st_gid(GID), fs_st_size(Size),
- Type(Type), Perms(Perms) {}
- #elif defined(LLVM_ON_WIN32)
- file_status() = default;
-
- file_status(file_type Type) : Type(Type) {}
-
- file_status(file_type Type, perms Perms, uint32_t LinkCount,
- uint32_t LastAccessTimeHigh, uint32_t LastAccessTimeLow,
- uint32_t LastWriteTimeHigh, uint32_t LastWriteTimeLow,
- uint32_t VolumeSerialNumber, uint32_t FileSizeHigh,
- uint32_t FileSizeLow, uint32_t FileIndexHigh,
- uint32_t FileIndexLow)
- : NumLinks(LinkCount), LastAccessedTimeHigh(LastAccessTimeHigh),
+ #if defined(LLVM_ON_UNIX)
+ basic_file_status(file_type Type, perms Perms, time_t ATime, time_t MTime,
+ 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_size(Size), Type(Type), Perms(Perms) {}
+#elif defined(LLVM_ON_WIN32)
+ basic_file_status(file_type Type, perms Perms, uint32_t LastAccessTimeHigh,
+ uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh,
+ uint32_t LastWriteTimeLow, uint32_t FileSizeHigh,
+ uint32_t FileSizeLow)
+ : LastAccessedTimeHigh(LastAccessTimeHigh),
LastAccessedTimeLow(LastAccessTimeLow),
LastWriteTimeHigh(LastWriteTimeHigh),
- LastWriteTimeLow(LastWriteTimeLow),
- VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh),
- FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh),
- FileIndexLow(FileIndexLow), Type(Type), Perms(Perms) {}
+ LastWriteTimeLow(LastWriteTimeLow), FileSizeHigh(FileSizeHigh),
+ FileSizeLow(FileSizeLow), Type(Type), Perms(Perms) {}
#endif
// getters
@@ -207,8 +191,6 @@ public:
perms permissions() const { return Perms; }
TimePoint<> getLastAccessedTime() const;
TimePoint<> getLastModificationTime() const;
- UniqueID getUniqueID() const;
- uint32_t getLinkCount() const;
#if defined(LLVM_ON_UNIX)
uint32_t getUser() const { return fs_st_uid; }
@@ -233,6 +215,49 @@ public:
void permissions(perms p) { Perms = p; }
};
+/// Represents the result of a call to sys::fs::status().
+class file_status : public basic_file_status {
+ friend bool equivalent(file_status A, file_status B);
+
+ #if defined(LLVM_ON_UNIX)
+ dev_t fs_st_dev = 0;
+ nlink_t fs_st_nlinks = 0;
+ ino_t fs_st_ino = 0;
+ #elif defined (LLVM_ON_WIN32)
+ uint32_t NumLinks = 0;
+ uint32_t VolumeSerialNumber = 0;
+ uint32_t FileIndexHigh = 0;
+ uint32_t FileIndexLow = 0;
+ #endif
+
+public:
+ file_status() = default;
+
+ explicit file_status(file_type Type) : basic_file_status(Type) {}
+
+ #if defined(LLVM_ON_UNIX)
+ file_status(file_type Type, perms Perms, dev_t Dev, nlink_t Links, ino_t Ino,
+ time_t ATime, time_t MTime, uid_t UID, gid_t GID, off_t Size)
+ : basic_file_status(Type, Perms, ATime, MTime, UID, GID, Size),
+ fs_st_dev(Dev), fs_st_nlinks(Links), fs_st_ino(Ino) {}
+ #elif defined(LLVM_ON_WIN32)
+ file_status(file_type Type, perms Perms, uint32_t LinkCount,
+ uint32_t LastAccessTimeHigh, uint32_t LastAccessTimeLow,
+ uint32_t LastWriteTimeHigh, uint32_t LastWriteTimeLow,
+ uint32_t VolumeSerialNumber, uint32_t FileSizeHigh,
+ uint32_t FileSizeLow, uint32_t FileIndexHigh,
+ uint32_t FileIndexLow)
+ : basic_file_status(Type, Perms, LastAccessTimeHigh, LastAccessTimeLow,
+ LastWriteTimeHigh, LastWriteTimeLow, FileSizeHigh,
+ FileSizeLow),
+ NumLinks(LinkCount), VolumeSerialNumber(VolumeSerialNumber),
+ FileIndexHigh(FileIndexHigh), FileIndexLow(FileIndexLow) {}
+ #endif
+
+ UniqueID getUniqueID() const;
+ uint32_t getLinkCount() const;
+};
+
/// @}
/// @name Physical Operators
/// @{
@@ -343,7 +368,11 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting = true);
/// platform-specific error code.
std::error_code remove_directories(const Twine &path, bool IgnoreErrors = true);
-/// @brief Rename \a from to \a to. Files are renamed as if by POSIX rename().
+/// @brief Rename \a from to \a to.
+///
+/// Files are renamed as if by POSIX rename(), except that on Windows there may
+/// be a short interval of time during which the destination file does not
+/// exist.
///
/// @param from The path to rename from.
/// @param to The path to rename to. This is created.
@@ -379,10 +408,10 @@ ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path);
/// @brief Does file exist?
///
-/// @param status A file_status previously returned from stat.
+/// @param status A basic_file_status previously returned from stat.
/// @returns True if the file represented by status exists, false if it does
/// not.
-bool exists(file_status status);
+bool exists(const basic_file_status &status);
enum class AccessMode { Exist, Write, Execute };
@@ -481,9 +510,9 @@ file_type get_file_type(const Twine &Path, bool Follow = true);
/// @brief Does status represent a directory?
///
-/// @param status A file_status previously returned from status.
+/// @param status A basic_file_status previously returned from status.
/// @returns status.type() == file_type::directory_file.
-bool is_directory(file_status status);
+bool is_directory(const basic_file_status &status);
/// @brief Is path a directory?
///
@@ -503,9 +532,9 @@ inline bool is_directory(const Twine &Path) {
/// @brief Does status represent a regular file?
///
-/// @param status A file_status previously returned from status.
+/// @param status A basic_file_status previously returned from status.
/// @returns status_known(status) && status.type() == file_type::regular_file.
-bool is_regular_file(file_status status);
+bool is_regular_file(const basic_file_status &status);
/// @brief Is path a regular file?
///
@@ -527,9 +556,9 @@ inline bool is_regular_file(const Twine &Path) {
/// @brief Does status represent a symlink file?
///
-/// @param status A file_status previously returned from status.
+/// @param status A basic_file_status previously returned from status.
/// @returns status_known(status) && status.type() == file_type::symlink_file.
-bool is_symlink_file(file_status status);
+bool is_symlink_file(const basic_file_status &status);
/// @brief Is path a symlink file?
///
@@ -552,9 +581,9 @@ inline bool is_symlink_file(const Twine &Path) {
/// @brief Does this status represent something that exists but is not a
/// directory or regular file?
///
-/// @param status A file_status previously returned from status.
+/// @param status A basic_file_status previously returned from status.
/// @returns exists(s) && !is_regular_file(s) && !is_directory(s)
-bool is_other(file_status status);
+bool is_other(const basic_file_status &status);
/// @brief Is path something that exists but is not a directory,
/// regular file, or symlink?
@@ -627,7 +656,7 @@ std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time);
///
/// @param s Input file status.
/// @returns True if status() != status_error.
-bool status_known(file_status s);
+bool status_known(const basic_file_status &s);
/// @brief Is status available?
///
@@ -637,6 +666,29 @@ bool status_known(file_status s);
/// platform-specific error_code.
std::error_code status_known(const Twine &path, bool &result);
+enum OpenFlags : unsigned {
+ F_None = 0,
+
+ /// F_Excl - When opening a file, this flag makes raw_fd_ostream
+ /// report an error if the file already exists.
+ F_Excl = 1,
+
+ /// F_Append - When opening a file, if it already exists append to the
+ /// existing file instead of returning an error. This may not be specified
+ /// with F_Excl.
+ F_Append = 2,
+
+ /// The file should be opened in text mode on platforms that make this
+ /// distinction.
+ F_Text = 4,
+
+ /// Open the file for read and write.
+ F_RW = 8,
+
+ /// Delete the file on close. Only makes a difference on windows.
+ F_Delete = 16
+};
+
/// @brief Create a uniquely named file.
///
/// Generates a unique path suitable for a temporary file and then opens it as a
@@ -660,12 +712,51 @@ std::error_code status_known(const Twine &path, bool &result);
/// otherwise a platform-specific error_code.
std::error_code createUniqueFile(const Twine &Model, int &ResultFD,
SmallVectorImpl<char> &ResultPath,
- unsigned Mode = all_read | all_write);
+ unsigned Mode = all_read | all_write,
+ sys::fs::OpenFlags Flags = sys::fs::F_RW);
/// @brief Simpler version for clients that don't want an open file.
std::error_code createUniqueFile(const Twine &Model,
SmallVectorImpl<char> &ResultPath);
+/// Represents a temporary file.
+///
+/// The temporary file must be eventually discarded or given a final name and
+/// kept.
+///
+/// The destructor doesn't implicitly discard because there is no way to
+/// properly handle errors in a destructor.
+class TempFile {
+ bool Done = false;
+ TempFile(StringRef Name, int FD);
+
+public:
+ /// This creates a temporary file with createUniqueFile and schedules it for
+ /// deletion with sys::RemoveFileOnSignal.
+ static Expected<TempFile> create(const Twine &Model,
+ unsigned Mode = all_read | all_write);
+ TempFile(TempFile &&Other);
+ TempFile &operator=(TempFile &&Other);
+
+ // Name of the temporary file.
+ std::string TmpName;
+
+ // The open file descriptor.
+ int FD = -1;
+
+ // Keep this with the given name.
+ Error keep(const Twine &Name);
+
+ // Keep this with the temporary name.
+ Error keep();
+
+ // Delete the file.
+ Error discard();
+
+ // This checks that keep or delete was called.
+ ~TempFile();
+};
+
/// @brief Create a file in the system temporary directory.
///
/// The filename is of the form prefix-random_chars.suffix. Since the directory
@@ -676,7 +767,8 @@ std::error_code createUniqueFile(const Twine &Model,
/// running the assembler.
std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
int &ResultFD,
- SmallVectorImpl<char> &ResultPath);
+ SmallVectorImpl<char> &ResultPath,
+ sys::fs::OpenFlags Flags = sys::fs::F_RW);
/// @brief Simpler version for clients that don't want an open file.
std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
@@ -685,32 +777,6 @@ std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
std::error_code createUniqueDirectory(const Twine &Prefix,
SmallVectorImpl<char> &ResultPath);
-/// @brief Fetch a path to an open file, as specified by a file descriptor
-///
-/// @param FD File descriptor to a currently open file
-/// @param ResultPath The buffer into which to write the path
-std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath);
-
-enum OpenFlags : unsigned {
- F_None = 0,
-
- /// F_Excl - When opening a file, this flag makes raw_fd_ostream
- /// report an error if the file already exists.
- F_Excl = 1,
-
- /// F_Append - When opening a file, if it already exists append to the
- /// existing file instead of returning an error. This may not be specified
- /// with F_Excl.
- F_Append = 2,
-
- /// The file should be opened in text mode on platforms that make this
- /// distinction.
- F_Text = 4,
-
- /// Open the file for read and write.
- F_RW = 8
-};
-
inline OpenFlags operator|(OpenFlags A, OpenFlags B) {
return OpenFlags(unsigned(A) | unsigned(B));
}
@@ -751,7 +817,7 @@ public:
private:
/// Platform-specific mapping state.
- uint64_t Size;
+ size_t Size;
void *Mapping;
std::error_code init(int FD, uint64_t Offset, mapmode Mode);
@@ -764,12 +830,12 @@ public:
/// \param fd An open file descriptor to map. mapped_file_region takes
/// ownership if closefd is true. It must have been opended in the correct
/// mode.
- mapped_file_region(int fd, mapmode mode, uint64_t length, uint64_t offset,
+ mapped_file_region(int fd, mapmode mode, size_t length, uint64_t offset,
std::error_code &ec);
~mapped_file_region();
- uint64_t size() const;
+ size_t size() const;
char *data() const;
/// Get a const view of the data. Modifying this memory has undefined
@@ -795,24 +861,25 @@ std::string getMainExecutable(const char *argv0, void *MainExecAddr);
class directory_entry {
std::string Path;
bool FollowSymlinks;
- mutable file_status Status;
+ basic_file_status Status;
public:
explicit directory_entry(const Twine &path, bool follow_symlinks = true,
- file_status st = file_status())
+ basic_file_status st = basic_file_status())
: Path(path.str()), FollowSymlinks(follow_symlinks), Status(st) {}
directory_entry() = default;
- void assign(const Twine &path, file_status st = file_status()) {
+ void assign(const Twine &path, basic_file_status st = basic_file_status()) {
Path = path.str();
Status = st;
}
- void replace_filename(const Twine &filename, file_status st = file_status());
+ void replace_filename(const Twine &filename,
+ basic_file_status st = basic_file_status());
const std::string &path() const { return Path; }
- std::error_code status(file_status &result) const;
+ ErrorOr<basic_file_status> status() const;
bool operator==(const directory_entry& rhs) const { return Path == rhs.Path; }
bool operator!=(const directory_entry& rhs) const { return !(*this == rhs); }
@@ -931,9 +998,9 @@ public:
if (State->HasNoPushRequest)
State->HasNoPushRequest = false;
else {
- file_status st;
- if ((ec = State->Stack.top()->status(st))) return *this;
- if (is_directory(st)) {
+ ErrorOr<basic_file_status> st = State->Stack.top()->status();
+ if (!st) return *this;
+ if (is_directory(*st)) {
State->Stack.push(directory_iterator(*State->Stack.top(), ec, Follow));
if (ec) return *this;
if (State->Stack.top() != end_itr) {
diff --git a/include/llvm/Support/FormatVariadic.h b/include/llvm/Support/FormatVariadic.h
index 408c6d8b2e0d..8c08a7d9488f 100644
--- a/include/llvm/Support/FormatVariadic.h
+++ b/include/llvm/Support/FormatVariadic.h
@@ -230,9 +230,8 @@ public:
// For a given parameter of type T, the following steps are executed in order
// until a match is found:
//
-// 1. If the parameter is of class type, and contains a method
-// void format(raw_ostream &Stream, StringRef Options)
-// Then this method is invoked to produce the formatted output. The
+// 1. If the parameter is of class type, and inherits from format_adapter,
+// Then format() is invoked on it to produce the formatted output. The
// implementation should write the formatted text into `Stream`.
// 2. If there is a suitable template specialization of format_provider<>
// for type T containing a method whose signature is:
@@ -259,6 +258,13 @@ inline auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object<decltype(
std::make_tuple(detail::build_format_adapter(std::forward<Ts>(Vals))...));
}
+// Allow a formatv_object to be formatted (no options supported).
+template <typename T> struct format_provider<formatv_object<T>> {
+ static void format(const formatv_object<T> &V, raw_ostream &OS, StringRef) {
+ OS << V;
+ }
+};
+
} // end namespace llvm
#endif // LLVM_SUPPORT_FORMATVARIADIC_H
diff --git a/include/llvm/Support/FormatVariadicDetails.h b/include/llvm/Support/FormatVariadicDetails.h
index b4a564ffc26c..9b60462209dc 100644
--- a/include/llvm/Support/FormatVariadicDetails.h
+++ b/include/llvm/Support/FormatVariadicDetails.h
@@ -31,7 +31,7 @@ template <typename T> class provider_format_adapter : public format_adapter {
T Item;
public:
- explicit provider_format_adapter(T &&Item) : Item(Item) {}
+ explicit provider_format_adapter(T &&Item) : Item(std::forward<T>(Item)) {}
void format(llvm::raw_ostream &S, StringRef Options) override {
format_provider<typename std::decay<T>::type>::format(Item, S, Options);
diff --git a/include/llvm/Support/GCOV.h b/include/llvm/Support/GCOV.h
deleted file mode 100644
index 02016e7dbd62..000000000000
--- a/include/llvm/Support/GCOV.h
+++ /dev/null
@@ -1,460 +0,0 @@
-//===- GCOV.h - LLVM coverage tool ------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This header provides the interface to read and write coverage files that
-// use 'gcov' format.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_SUPPORT_GCOV_H
-#define LLVM_SUPPORT_GCOV_H
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/MapVector.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/iterator.h"
-#include "llvm/ADT/iterator_range.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <utility>
-
-namespace llvm {
-
-class GCOVFunction;
-class GCOVBlock;
-class FileInfo;
-
-namespace GCOV {
-
-enum GCOVVersion { V402, V404, V704 };
-
-/// \brief A struct for passing gcov options between functions.
-struct Options {
- Options(bool A, bool B, bool C, bool F, bool P, bool U, bool L, bool N)
- : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
- PreservePaths(P), UncondBranch(U), LongFileNames(L), NoOutput(N) {}
-
- bool AllBlocks;
- bool BranchInfo;
- bool BranchCount;
- bool FuncCoverage;
- bool PreservePaths;
- bool UncondBranch;
- bool LongFileNames;
- bool NoOutput;
-};
-
-} // end namespace GCOV
-
-/// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
-/// read operations.
-class GCOVBuffer {
-public:
- GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
-
- /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
- bool readGCNOFormat() {
- StringRef File = Buffer->getBuffer().slice(0, 4);
- if (File != "oncg") {
- errs() << "Unexpected file type: " << File << ".\n";
- return false;
- }
- Cursor = 4;
- return true;
- }
-
- /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
- bool readGCDAFormat() {
- StringRef File = Buffer->getBuffer().slice(0, 4);
- if (File != "adcg") {
- errs() << "Unexpected file type: " << File << ".\n";
- return false;
- }
- Cursor = 4;
- return true;
- }
-
- /// readGCOVVersion - Read GCOV version.
- bool readGCOVVersion(GCOV::GCOVVersion &Version) {
- StringRef VersionStr = Buffer->getBuffer().slice(Cursor, Cursor + 4);
- if (VersionStr == "*204") {
- Cursor += 4;
- Version = GCOV::V402;
- return true;
- }
- if (VersionStr == "*404") {
- Cursor += 4;
- Version = GCOV::V404;
- return true;
- }
- if (VersionStr == "*704") {
- Cursor += 4;
- Version = GCOV::V704;
- return true;
- }
- errs() << "Unexpected version: " << VersionStr << ".\n";
- return false;
- }
-
- /// readFunctionTag - If cursor points to a function tag then increment the
- /// cursor and return true otherwise return false.
- bool readFunctionTag() {
- StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
- if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
- Tag[3] != '\1') {
- return false;
- }
- Cursor += 4;
- return true;
- }
-
- /// readBlockTag - If cursor points to a block tag then increment the
- /// cursor and return true otherwise return false.
- bool readBlockTag() {
- StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
- if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x41' ||
- Tag[3] != '\x01') {
- return false;
- }
- Cursor += 4;
- return true;
- }
-
- /// readEdgeTag - If cursor points to an edge tag then increment the
- /// cursor and return true otherwise return false.
- bool readEdgeTag() {
- StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
- if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x43' ||
- Tag[3] != '\x01') {
- return false;
- }
- Cursor += 4;
- return true;
- }
-
- /// readLineTag - If cursor points to a line tag then increment the
- /// cursor and return true otherwise return false.
- bool readLineTag() {
- StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
- if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x45' ||
- Tag[3] != '\x01') {
- return false;
- }
- Cursor += 4;
- return true;
- }
-
- /// readArcTag - If cursor points to an gcda arc tag then increment the
- /// cursor and return true otherwise return false.
- bool readArcTag() {
- StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
- if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\xa1' ||
- Tag[3] != '\1') {
- return false;
- }
- Cursor += 4;
- return true;
- }
-
- /// readObjectTag - If cursor points to an object summary tag then increment
- /// the cursor and return true otherwise return false.
- bool readObjectTag() {
- StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
- if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
- Tag[3] != '\xa1') {
- return false;
- }
- Cursor += 4;
- return true;
- }
-
- /// readProgramTag - If cursor points to a program summary tag then increment
- /// the cursor and return true otherwise return false.
- bool readProgramTag() {
- StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
- if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
- Tag[3] != '\xa3') {
- return false;
- }
- Cursor += 4;
- return true;
- }
-
- bool readInt(uint32_t &Val) {
- if (Buffer->getBuffer().size() < Cursor + 4) {
- errs() << "Unexpected end of memory buffer: " << Cursor + 4 << ".\n";
- return false;
- }
- StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor + 4);
- Cursor += 4;
- Val = *(const uint32_t *)(Str.data());
- return true;
- }
-
- bool readInt64(uint64_t &Val) {
- uint32_t Lo, Hi;
- if (!readInt(Lo) || !readInt(Hi))
- return false;
- Val = ((uint64_t)Hi << 32) | Lo;
- return true;
- }
-
- bool readString(StringRef &Str) {
- uint32_t Len = 0;
- // Keep reading until we find a non-zero length. This emulates gcov's
- // behaviour, which appears to do the same.
- while (Len == 0)
- if (!readInt(Len))
- return false;
- Len *= 4;
- if (Buffer->getBuffer().size() < Cursor + Len) {
- errs() << "Unexpected end of memory buffer: " << Cursor + Len << ".\n";
- return false;
- }
- Str = Buffer->getBuffer().slice(Cursor, Cursor + Len).split('\0').first;
- Cursor += Len;
- return true;
- }
-
- uint64_t getCursor() const { return Cursor; }
- void advanceCursor(uint32_t n) { Cursor += n * 4; }
-
-private:
- MemoryBuffer *Buffer;
- uint64_t Cursor = 0;
-};
-
-/// GCOVFile - Collects coverage information for one pair of coverage file
-/// (.gcno and .gcda).
-class GCOVFile {
-public:
- GCOVFile() = default;
-
- bool readGCNO(GCOVBuffer &Buffer);
- bool readGCDA(GCOVBuffer &Buffer);
- uint32_t getChecksum() const { return Checksum; }
- void print(raw_ostream &OS) const;
- void dump() const;
- void collectLineCounts(FileInfo &FI);
-
-private:
- bool GCNOInitialized = false;
- GCOV::GCOVVersion Version;
- uint32_t Checksum = 0;
- SmallVector<std::unique_ptr<GCOVFunction>, 16> Functions;
- uint32_t RunCount = 0;
- uint32_t ProgramCount = 0;
-};
-
-/// GCOVEdge - Collects edge information.
-struct GCOVEdge {
- GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D) {}
-
- GCOVBlock &Src;
- GCOVBlock &Dst;
- uint64_t Count = 0;
-};
-
-/// GCOVFunction - Collects function information.
-class GCOVFunction {
-public:
- using BlockIterator = pointee_iterator<SmallVectorImpl<
- std::unique_ptr<GCOVBlock>>::const_iterator>;
-
- GCOVFunction(GCOVFile &P) : Parent(P) {}
-
- bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
- bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
- StringRef getName() const { return Name; }
- StringRef getFilename() const { return Filename; }
- size_t getNumBlocks() const { return Blocks.size(); }
- uint64_t getEntryCount() const;
- uint64_t getExitCount() const;
-
- BlockIterator block_begin() const { return Blocks.begin(); }
- BlockIterator block_end() const { return Blocks.end(); }
- iterator_range<BlockIterator> blocks() const {
- return make_range(block_begin(), block_end());
- }
-
- void print(raw_ostream &OS) const;
- void dump() const;
- void collectLineCounts(FileInfo &FI);
-
-private:
- GCOVFile &Parent;
- uint32_t Ident = 0;
- uint32_t Checksum;
- uint32_t LineNumber = 0;
- StringRef Name;
- StringRef Filename;
- SmallVector<std::unique_ptr<GCOVBlock>, 16> Blocks;
- SmallVector<std::unique_ptr<GCOVEdge>, 16> Edges;
-};
-
-/// GCOVBlock - Collects block information.
-class GCOVBlock {
- struct EdgeWeight {
- EdgeWeight(GCOVBlock *D) : Dst(D) {}
-
- GCOVBlock *Dst;
- uint64_t Count = 0;
- };
-
- struct SortDstEdgesFunctor {
- bool operator()(const GCOVEdge *E1, const GCOVEdge *E2) {
- return E1->Dst.Number < E2->Dst.Number;
- }
- };
-
-public:
- using EdgeIterator = SmallVectorImpl<GCOVEdge *>::const_iterator;
-
- GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N) {}
- ~GCOVBlock();
-
- const GCOVFunction &getParent() const { return Parent; }
- void addLine(uint32_t N) { Lines.push_back(N); }
- uint32_t getLastLine() const { return Lines.back(); }
- void addCount(size_t DstEdgeNo, uint64_t N);
- uint64_t getCount() const { return Counter; }
-
- void addSrcEdge(GCOVEdge *Edge) {
- assert(&Edge->Dst == this); // up to caller to ensure edge is valid
- SrcEdges.push_back(Edge);
- }
-
- void addDstEdge(GCOVEdge *Edge) {
- assert(&Edge->Src == this); // up to caller to ensure edge is valid
- // Check if adding this edge causes list to become unsorted.
- if (DstEdges.size() && DstEdges.back()->Dst.Number > Edge->Dst.Number)
- DstEdgesAreSorted = false;
- DstEdges.push_back(Edge);
- }
-
- size_t getNumSrcEdges() const { return SrcEdges.size(); }
- size_t getNumDstEdges() const { return DstEdges.size(); }
- void sortDstEdges();
-
- EdgeIterator src_begin() const { return SrcEdges.begin(); }
- EdgeIterator src_end() const { return SrcEdges.end(); }
- iterator_range<EdgeIterator> srcs() const {
- return make_range(src_begin(), src_end());
- }
-
- EdgeIterator dst_begin() const { return DstEdges.begin(); }
- EdgeIterator dst_end() const { return DstEdges.end(); }
- iterator_range<EdgeIterator> dsts() const {
- return make_range(dst_begin(), dst_end());
- }
-
- void print(raw_ostream &OS) const;
- void dump() const;
- void collectLineCounts(FileInfo &FI);
-
-private:
- GCOVFunction &Parent;
- uint32_t Number;
- uint64_t Counter = 0;
- bool DstEdgesAreSorted = true;
- SmallVector<GCOVEdge *, 16> SrcEdges;
- SmallVector<GCOVEdge *, 16> DstEdges;
- SmallVector<uint32_t, 16> Lines;
-};
-
-class FileInfo {
- // It is unlikely--but possible--for multiple functions to be on the same
- // line.
- // Therefore this typedef allows LineData.Functions to store multiple
- // functions
- // per instance. This is rare, however, so optimize for the common case.
- using FunctionVector = SmallVector<const GCOVFunction *, 1>;
- using FunctionLines = DenseMap<uint32_t, FunctionVector>;
- using BlockVector = SmallVector<const GCOVBlock *, 4>;
- using BlockLines = DenseMap<uint32_t, BlockVector>;
-
- struct LineData {
- LineData() = default;
-
- BlockLines Blocks;
- FunctionLines Functions;
- uint32_t LastLine = 0;
- };
-
- struct GCOVCoverage {
- GCOVCoverage(StringRef Name) : Name(Name) {}
-
- StringRef Name;
-
- uint32_t LogicalLines = 0;
- uint32_t LinesExec = 0;
-
- uint32_t Branches = 0;
- uint32_t BranchesExec = 0;
- uint32_t BranchesTaken = 0;
- };
-
-public:
- FileInfo(const GCOV::Options &Options) : Options(Options) {}
-
- void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) {
- if (Line > LineInfo[Filename].LastLine)
- LineInfo[Filename].LastLine = Line;
- LineInfo[Filename].Blocks[Line - 1].push_back(Block);
- }
-
- void addFunctionLine(StringRef Filename, uint32_t Line,
- const GCOVFunction *Function) {
- if (Line > LineInfo[Filename].LastLine)
- LineInfo[Filename].LastLine = Line;
- LineInfo[Filename].Functions[Line - 1].push_back(Function);
- }
-
- void setRunCount(uint32_t Runs) { RunCount = Runs; }
- void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
- void print(raw_ostream &OS, StringRef MainFilename, StringRef GCNOFile,
- StringRef GCDAFile);
-
-private:
- std::string getCoveragePath(StringRef Filename, StringRef MainFilename);
- std::unique_ptr<raw_ostream> openCoveragePath(StringRef CoveragePath);
- void printFunctionSummary(raw_ostream &OS, const FunctionVector &Funcs) const;
- void printBlockInfo(raw_ostream &OS, const GCOVBlock &Block,
- uint32_t LineIndex, uint32_t &BlockNo) const;
- void printBranchInfo(raw_ostream &OS, const GCOVBlock &Block,
- GCOVCoverage &Coverage, uint32_t &EdgeNo);
- void printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo,
- uint64_t Count) const;
-
- void printCoverage(raw_ostream &OS, const GCOVCoverage &Coverage) const;
- void printFuncCoverage(raw_ostream &OS) const;
- void printFileCoverage(raw_ostream &OS) const;
-
- const GCOV::Options &Options;
- StringMap<LineData> LineInfo;
- uint32_t RunCount = 0;
- uint32_t ProgramCount = 0;
-
- using FileCoverageList = SmallVector<std::pair<std::string, GCOVCoverage>, 4>;
- using FuncCoverageMap = MapVector<const GCOVFunction *, GCOVCoverage>;
-
- FileCoverageList FileCoverages;
- FuncCoverageMap FuncCoverages;
-};
-
-} // end namespace llvm
-
-#endif // LLVM_SUPPORT_GCOV_H
diff --git a/include/llvm/Support/GenericDomTree.h b/include/llvm/Support/GenericDomTree.h
index 706320fed9a7..635c87a106f0 100644
--- a/include/llvm/Support/GenericDomTree.h
+++ b/include/llvm/Support/GenericDomTree.h
@@ -14,8 +14,8 @@
/// graph types.
///
/// Unlike ADT/* graph algorithms, generic dominator tree has more requirements
-/// on the graph's NodeRef. The NodeRef should be a pointer and, depending on
-/// the implementation, e.g. NodeRef->getParent() return the parent node.
+/// on the graph's NodeRef. The NodeRef should be a pointer and,
+/// NodeRef->getParent() must return the parent node that is also a pointer.
///
/// FIXME: Maybe GenericDomTree needs a TreeTraits, instead of GraphTraits.
///
@@ -24,12 +24,6 @@
#ifndef LLVM_SUPPORT_GENERICDOMTREE_H
#define LLVM_SUPPORT_GENERICDOMTREE_H
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/GraphTraits.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
@@ -38,6 +32,13 @@
#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 {
@@ -45,7 +46,7 @@ template <typename NodeT, bool IsPostDom>
class DominatorTreeBase;
namespace DomTreeBuilder {
-template <class DomTreeT>
+template <typename DomTreeT>
struct SemiNCAInfo;
} // namespace DomTreeBuilder
@@ -187,17 +188,51 @@ void PrintDomTree(const DomTreeNodeBase<NodeT> *N, raw_ostream &O,
namespace DomTreeBuilder {
// The routines below are provided in a separate header but referenced here.
-template <typename DomTreeT, typename FuncT>
-void Calculate(DomTreeT &DT, FuncT &F);
+template <typename DomTreeT>
+void Calculate(DomTreeT &DT);
-template <class DomTreeT>
+template <typename DomTreeT>
void InsertEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
typename DomTreeT::NodePtr To);
-template <class DomTreeT>
+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);
+
template <typename DomTreeT>
bool Verify(const DomTreeT &DT);
} // namespace DomTreeBuilder
@@ -208,14 +243,30 @@ bool Verify(const DomTreeT &DT);
/// various graphs in the LLVM IR or in the code generator.
template <typename NodeT, bool IsPostDom>
class DominatorTreeBase {
+ public:
+ static_assert(std::is_pointer<typename GraphTraits<NodeT *>::NodeRef>::value,
+ "Currently DominatorTreeBase supports only pointer nodes");
+ using NodeType = NodeT;
+ using NodePtr = NodeT *;
+ using ParentPtr = decltype(std::declval<NodeT *>()->getParent());
+ static_assert(std::is_pointer<ParentPtr>::value,
+ "Currently NodeT's parent must be a pointer type");
+ using ParentType = typename std::remove_pointer<ParentPtr>::type;
+ static constexpr bool IsPostDominator = IsPostDom;
+
+ using UpdateType = DomTreeBuilder::Update<NodePtr>;
+ using UpdateKind = DomTreeBuilder::UpdateKind;
+ static constexpr UpdateKind Insert = UpdateKind::Insert;
+ static constexpr UpdateKind Delete = UpdateKind::Delete;
+
protected:
- std::vector<NodeT *> Roots;
+ // Dominators always have a single root, postdominators can have more.
+ SmallVector<NodeT *, IsPostDom ? 4 : 1> Roots;
using DomTreeNodeMapType =
DenseMap<NodeT *, std::unique_ptr<DomTreeNodeBase<NodeT>>>;
DomTreeNodeMapType DomTreeNodes;
DomTreeNodeBase<NodeT> *RootNode;
- using ParentPtr = decltype(std::declval<NodeT *>()->getParent());
ParentPtr Parent = nullptr;
mutable bool DFSInfoValid = false;
@@ -224,12 +275,6 @@ class DominatorTreeBase {
friend struct DomTreeBuilder::SemiNCAInfo<DominatorTreeBase>;
public:
- static_assert(std::is_pointer<typename GraphTraits<NodeT *>::NodeRef>::value,
- "Currently DominatorTreeBase supports only pointer nodes");
- using NodeType = NodeT;
- using NodePtr = NodeT *;
- static constexpr bool IsPostDominator = IsPostDom;
-
DominatorTreeBase() {}
DominatorTreeBase(DominatorTreeBase &&Arg)
@@ -260,7 +305,7 @@ class DominatorTreeBase {
/// multiple blocks if we are computing post dominators. For forward
/// dominators, this will always be a single block (the entry node).
///
- const std::vector<NodeT *> &getRoots() const { return Roots; }
+ const SmallVectorImpl<NodeT *> &getRoots() const { return Roots; }
/// isPostDominator - Returns true if analysis based of postdoms
///
@@ -412,14 +457,15 @@ class DominatorTreeBase {
}
/// findNearestCommonDominator - Find nearest common dominator basic block
- /// for basic block A and B. If there is no such block then return NULL.
+ /// for basic block A and B. If there is no such block then return nullptr.
NodeT *findNearestCommonDominator(NodeT *A, NodeT *B) const {
+ assert(A && B && "Pointers are not valid");
assert(A->getParent() == B->getParent() &&
"Two blocks are not in same function");
// If either A or B is a entry block then it is nearest common dominator
// (for forward-dominators).
- if (!this->isPostDominator()) {
+ if (!isPostDominator()) {
NodeT &Entry = A->getParent()->front();
if (A == &Entry || B == &Entry)
return &Entry;
@@ -457,6 +503,41 @@ class DominatorTreeBase {
// API to update (Post)DominatorTree information based on modifications to
// the CFG...
+ /// Inform the dominator tree about a sequence of CFG edge insertions and
+ /// deletions and perform a batch update on the tree.
+ ///
+ /// This function should be used when there were multiple CFG updates after
+ /// the last dominator tree update. It takes care of performing the updates
+ /// in sync with the CFG and optimizes away the redundant operations that
+ /// cancel each other.
+ /// The functions expects the sequence of updates to be balanced. Eg.:
+ /// - {{Insert, A, B}, {Delete, A, B}, {Insert, A, B}} is fine, because
+ /// logically it results in a single insertions.
+ /// - {{Insert, A, B}, {Insert, A, B}} is invalid, because it doesn't make
+ /// sense to insert the same edge twice.
+ ///
+ /// What's more, the functions assumes that it's safe to ask every node in the
+ /// CFG about its children and inverse children. This implies that deletions
+ /// of CFG edges must not delete the CFG nodes before calling this function.
+ ///
+ /// Batch updates should be generally faster when performing longer sequences
+ /// of updates than calling insertEdge/deleteEdge manually multiple times, as
+ /// it can reorder the updates and remove redundant ones internally.
+ /// The batch updater is also able to detect sequences of zero and exactly one
+ /// update -- it's optimized to do less work in these cases.
+ ///
+ /// Note that for postdominators it automatically takes care of applying
+ /// updates on reverse edges internally (so there's no need to swap the
+ /// From and To pointers when constructing DominatorTree::UpdateType).
+ /// The type of updates is the same for DomTreeBase<T> and PostDomTreeBase<T>
+ /// with the same template parameter T.
+ ///
+ /// \param Updates An unordered sequence of updates to perform.
+ ///
+ void applyUpdates(ArrayRef<UpdateType> Updates) {
+ DomTreeBuilder::ApplyUpdates(*this, Updates);
+ }
+
/// Inform the dominator tree about a CFG edge insertion and update the tree.
///
/// This function has to be called just before or just after making the update
@@ -476,11 +557,10 @@ class DominatorTreeBase {
/// Inform the dominator tree about a CFG edge deletion and update the tree.
///
- /// This function has to be called just after making the update
- /// on the actual CFG. There cannot be any other updates that the dominator
- /// tree doesn't know about. The only exception is when the deletion that the
- /// tree is informed about makes some (domominator) subtree unreachable -- in
- /// this case, it is fine to perform deletions within this subtree.
+ /// This function has to be called just after making the update on the actual
+ /// CFG. An internal functions checks if the edge doesn't exist in the CFG in
+ /// DEBUG mode. There cannot be any other updates that the
+ /// dominator tree doesn't know about.
///
/// Note that for postdominators it automatically takes care of deleting
/// a reverse edge internally (so there's no need to swap the parameters).
@@ -559,11 +639,12 @@ class DominatorTreeBase {
assert(Node && "Removing node that isn't in dominator tree.");
assert(Node->getChildren().empty() && "Node is not a leaf node.");
+ DFSInfoValid = false;
+
// Remove node from immediate dominator's children list.
DomTreeNodeBase<NodeT> *IDom = Node->getIDom();
if (IDom) {
- typename std::vector<DomTreeNodeBase<NodeT> *>::iterator I =
- find(IDom->Children, Node);
+ const auto I = find(IDom->Children, Node);
assert(I != IDom->Children.end() &&
"Not in immediate dominator children set!");
// I am no longer your child...
@@ -571,6 +652,15 @@ class DominatorTreeBase {
}
DomTreeNodes.erase(BB);
+
+ if (!IsPostDom) return;
+
+ // Remember to update PostDominatorTree roots.
+ auto RIt = llvm::find(Roots, BB);
+ if (RIt != Roots.end()) {
+ std::swap(*RIt, Roots.back());
+ Roots.pop_back();
+ }
}
/// splitBlock - BB is split and now it has one successor. Update dominator
@@ -586,7 +676,7 @@ class DominatorTreeBase {
///
void print(raw_ostream &O) const {
O << "=============================--------------------------------\n";
- if (this->isPostDominator())
+ if (IsPostDominator)
O << "Inorder PostDominator Tree: ";
else
O << "Inorder Dominator Tree: ";
@@ -596,6 +686,14 @@ class DominatorTreeBase {
// The postdom tree can have a null root if there are no returns.
if (getRootNode()) PrintDomTree<NodeT>(getRootNode(), O, 1);
+ if (IsPostDominator) {
+ O << "Roots: ";
+ for (const NodePtr Block : Roots) {
+ Block->printAsOperand(O, false);
+ O << " ";
+ }
+ O << "\n";
+ }
}
public:
@@ -607,28 +705,25 @@ public:
return;
}
- unsigned DFSNum = 0;
-
SmallVector<std::pair<const DomTreeNodeBase<NodeT> *,
typename DomTreeNodeBase<NodeT>::const_iterator>,
32> WorkStack;
const DomTreeNodeBase<NodeT> *ThisRoot = getRootNode();
-
+ assert((!Parent || ThisRoot) && "Empty constructed DomTree");
if (!ThisRoot)
return;
- // Even in the case of multiple exits that form the post dominator root
- // nodes, do not iterate over all exits, but start from the virtual root
- // node. Otherwise bbs, that are not post dominated by any exit but by the
- // virtual root node, will never be assigned a DFS number.
- WorkStack.push_back(std::make_pair(ThisRoot, ThisRoot->begin()));
+ // Both dominators and postdominators have a single root node. In the case
+ // case of PostDominatorTree, this node is a virtual root.
+ WorkStack.push_back({ThisRoot, ThisRoot->begin()});
+
+ unsigned DFSNum = 0;
ThisRoot->DFSNumIn = DFSNum++;
while (!WorkStack.empty()) {
const DomTreeNodeBase<NodeT> *Node = WorkStack.back().first;
- typename DomTreeNodeBase<NodeT>::const_iterator ChildIt =
- WorkStack.back().second;
+ const auto ChildIt = WorkStack.back().second;
// If we visited all of the children of this node, "recurse" back up the
// stack setting the DFOutNum.
@@ -640,7 +735,7 @@ public:
const DomTreeNodeBase<NodeT> *Child = *ChildIt;
++WorkStack.back().second;
- WorkStack.push_back(std::make_pair(Child, Child->begin()));
+ WorkStack.push_back({Child, Child->begin()});
Child->DFSNumIn = DFSNum++;
}
}
@@ -650,23 +745,9 @@ public:
}
/// recalculate - compute a dominator tree for the given function
- template <class FT> void recalculate(FT &F) {
- using TraitsTy = GraphTraits<FT *>;
- reset();
- Parent = &F;
-
- if (!IsPostDominator) {
- // Initialize root
- NodeT *entry = TraitsTy::getEntryNode(&F);
- addRoot(entry);
- } else {
- // Initialize the roots list
- for (auto *Node : nodes(&F))
- if (TraitsTy::child_begin(Node) == TraitsTy::child_end(Node))
- addRoot(Node);
- }
-
- DomTreeBuilder::Calculate(*this, F);
+ void recalculate(ParentType &Func) {
+ Parent = &Func;
+ DomTreeBuilder::Calculate(*this);
}
/// verify - check parent and sibling property
diff --git a/include/llvm/Support/GenericDomTreeConstruction.h b/include/llvm/Support/GenericDomTreeConstruction.h
index be90afa4c3c8..8f801662d0fb 100644
--- a/include/llvm/Support/GenericDomTreeConstruction.h
+++ b/include/llvm/Support/GenericDomTreeConstruction.h
@@ -21,8 +21,8 @@
/// faster than the almost-linear O(n*alpha(n)) version, even for large CFGs.
///
/// The file uses the Depth Based Search algorithm to perform incremental
-/// upates (insertion and deletions). The implemented algorithm is based on this
-/// publication:
+/// updates (insertion and deletions). The implemented algorithm is based on
+/// this publication:
///
/// An Experimental Study of Dynamic Dominators
/// Loukas Georgiadis, et al., April 12 2016, pp. 5-7, 9-10:
@@ -34,8 +34,10 @@
#define LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H
#include <queue>
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/GenericDomTree.h"
@@ -45,25 +47,12 @@
namespace llvm {
namespace DomTreeBuilder {
-template <typename NodePtr, bool Inverse>
-struct ChildrenGetter {
- static auto Get(NodePtr N) -> decltype(reverse(children<NodePtr>(N))) {
- return reverse(children<NodePtr>(N));
- }
-};
-
-template <typename NodePtr>
-struct ChildrenGetter<NodePtr, true> {
- static auto Get(NodePtr N) -> decltype(inverse_children<NodePtr>(N)) {
- return inverse_children<NodePtr>(N);
- }
-};
-
template <typename DomTreeT>
struct SemiNCAInfo {
using NodePtr = typename DomTreeT::NodePtr;
using NodeT = typename DomTreeT::NodeType;
using TreeNodePtr = DomTreeNodeBase<NodeT> *;
+ using RootsT = decltype(DomTreeT::Roots);
static constexpr bool IsPostDom = DomTreeT::IsPostDominator;
// Information record used by Semi-NCA during tree construction.
@@ -81,11 +70,99 @@ struct SemiNCAInfo {
std::vector<NodePtr> NumToNode = {nullptr};
DenseMap<NodePtr, InfoRec> NodeToInfo;
+ using UpdateT = typename DomTreeT::UpdateType;
+ struct BatchUpdateInfo {
+ SmallVector<UpdateT, 4> Updates;
+ using NodePtrAndKind = PointerIntPair<NodePtr, 1, UpdateKind>;
+
+ // In order to be able to walk a CFG that is out of sync with the CFG
+ // DominatorTree last knew about, use the list of updates to reconstruct
+ // previous CFG versions of the current CFG. For each node, we store a set
+ // of its virtually added/deleted future successors and predecessors.
+ // Note that these children are from the future relative to what the
+ // DominatorTree knows about -- using them to gets us some snapshot of the
+ // CFG from the past (relative to the state of the CFG).
+ DenseMap<NodePtr, SmallDenseSet<NodePtrAndKind, 4>> FutureSuccessors;
+ DenseMap<NodePtr, SmallDenseSet<NodePtrAndKind, 4>> FuturePredecessors;
+ // Remembers if the whole tree was recalculated at some point during the
+ // current batch update.
+ bool IsRecalculated = false;
+ };
+
+ BatchUpdateInfo *BatchUpdates;
+ using BatchUpdatePtr = BatchUpdateInfo *;
+
+ // If BUI is a nullptr, then there's no batch update in progress.
+ SemiNCAInfo(BatchUpdatePtr BUI) : BatchUpdates(BUI) {}
+
void clear() {
NumToNode = {nullptr}; // Restore to initial state with a dummy start node.
NodeToInfo.clear();
+ // Don't reset the pointer to BatchUpdateInfo here -- if there's an update
+ // in progress, we need this information to continue it.
}
+ template <bool Inverse>
+ struct ChildrenGetter {
+ using ResultTy = SmallVector<NodePtr, 8>;
+
+ static ResultTy Get(NodePtr N, std::integral_constant<bool, false>) {
+ auto RChildren = reverse(children<NodePtr>(N));
+ return ResultTy(RChildren.begin(), RChildren.end());
+ }
+
+ static ResultTy Get(NodePtr N, std::integral_constant<bool, true>) {
+ auto IChildren = inverse_children<NodePtr>(N);
+ return ResultTy(IChildren.begin(), IChildren.end());
+ }
+
+ using Tag = std::integral_constant<bool, Inverse>;
+
+ // The function below is the core part of the batch updater. It allows the
+ // Depth Based Search algorithm to perform incremental updates in lockstep
+ // with updates to the CFG. We emulated lockstep CFG updates by getting its
+ // next snapshots by reverse-applying future updates.
+ static ResultTy Get(NodePtr N, BatchUpdatePtr BUI) {
+ ResultTy Res = Get(N, Tag());
+ // If there's no batch update in progress, simply return node's children.
+ if (!BUI) return Res;
+
+ // CFG children are actually its *most current* children, and we have to
+ // reverse-apply the future updates to get the node's children at the
+ // point in time the update was performed.
+ auto &FutureChildren = (Inverse != IsPostDom) ? BUI->FuturePredecessors
+ : BUI->FutureSuccessors;
+ auto FCIt = FutureChildren.find(N);
+ if (FCIt == FutureChildren.end()) return Res;
+
+ for (auto ChildAndKind : FCIt->second) {
+ const NodePtr Child = ChildAndKind.getPointer();
+ const UpdateKind UK = ChildAndKind.getInt();
+
+ // Reverse-apply the future update.
+ if (UK == UpdateKind::Insert) {
+ // If there's an insertion in the future, it means that the edge must
+ // exist in the current CFG, but was not present in it before.
+ assert(llvm::find(Res, Child) != Res.end()
+ && "Expected child not found in the CFG");
+ Res.erase(std::remove(Res.begin(), Res.end(), Child), Res.end());
+ DEBUG(dbgs() << "\tHiding edge " << BlockNamePrinter(N) << " -> "
+ << BlockNamePrinter(Child) << "\n");
+ } else {
+ // If there's an deletion in the future, it means that the edge cannot
+ // exist in the current CFG, but existed in it before.
+ assert(llvm::find(Res, Child) == Res.end() &&
+ "Unexpected child found in the CFG");
+ DEBUG(dbgs() << "\tShowing virtual edge " << BlockNamePrinter(N)
+ << " -> " << BlockNamePrinter(Child) << "\n");
+ Res.push_back(Child);
+ }
+ }
+
+ return Res;
+ }
+ };
+
NodePtr getIDom(NodePtr BB) const {
auto InfoIt = NodeToInfo.find(BB);
if (InfoIt == NodeToInfo.end()) return nullptr;
@@ -131,7 +208,11 @@ struct SemiNCAInfo {
// Custom DFS implementation which can skip nodes based on a provided
// predicate. It also collects ReverseChildren so that we don't have to spend
// time getting predecessors in SemiNCA.
- template <bool Inverse, typename DescendCondition>
+ //
+ // If IsReverse is set to true, the DFS walk will be performed backwards
+ // relative to IsPostDom -- using reverse edges for dominators and forward
+ // edges for postdominators.
+ template <bool IsReverse = false, typename DescendCondition>
unsigned runDFS(NodePtr V, unsigned LastNum, DescendCondition Condition,
unsigned AttachToNum) {
assert(V);
@@ -148,10 +229,12 @@ struct SemiNCAInfo {
BBInfo.Label = BB;
NumToNode.push_back(BB);
- for (const NodePtr Succ : ChildrenGetter<NodePtr, Inverse>::Get(BB)) {
+ constexpr bool Direction = IsReverse != IsPostDom; // XOR.
+ for (const NodePtr Succ :
+ ChildrenGetter<Direction>::Get(BB, BatchUpdates)) {
const auto SIT = NodeToInfo.find(Succ);
// Don't visit nodes more than once but remember to collect
- // RerverseChildren.
+ // ReverseChildren.
if (SIT != NodeToInfo.end() && SIT->second.DFSNum != 0) {
if (Succ != BB) SIT->second.ReverseChildren.push_back(BB);
continue;
@@ -256,51 +339,244 @@ struct SemiNCAInfo {
}
}
- template <typename DescendCondition>
- unsigned doFullDFSWalk(const DomTreeT &DT, DescendCondition DC) {
- unsigned Num = 0;
+ // PostDominatorTree always has a virtual root that represents a virtual CFG
+ // node that serves as a single exit from the function. All the other exits
+ // (CFG nodes with terminators and nodes in infinite loops are logically
+ // connected to this virtual CFG exit node).
+ // This functions maps a nullptr CFG node to the virtual root tree node.
+ void addVirtualRoot() {
+ assert(IsPostDom && "Only postdominators have a virtual root");
+ assert(NumToNode.size() == 1 && "SNCAInfo must be freshly constructed");
- if (DT.Roots.size() > 1) {
- auto &BBInfo = NodeToInfo[nullptr];
- BBInfo.DFSNum = BBInfo.Semi = ++Num;
- BBInfo.Label = nullptr;
+ auto &BBInfo = NodeToInfo[nullptr];
+ BBInfo.DFSNum = BBInfo.Semi = 1;
+ BBInfo.Label = nullptr;
- NumToNode.push_back(nullptr); // NumToNode[n] = V;
+ NumToNode.push_back(nullptr); // NumToNode[1] = nullptr;
+ }
+
+ // For postdominators, nodes with no forward successors are trivial roots that
+ // are always selected as tree roots. Roots with forward successors correspond
+ // to CFG nodes within infinite loops.
+ static bool HasForwardSuccessors(const NodePtr N, BatchUpdatePtr BUI) {
+ assert(N && "N must be a valid node");
+ return !ChildrenGetter<false>::Get(N, BUI).empty();
+ }
+
+ static NodePtr GetEntryNode(const DomTreeT &DT) {
+ assert(DT.Parent && "Parent not set");
+ return GraphTraits<typename DomTreeT::ParentPtr>::getEntryNode(DT.Parent);
+ }
+
+ // Finds all roots without relaying on the set of roots already stored in the
+ // tree.
+ // We define roots to be some non-redundant set of the CFG nodes
+ static RootsT FindRoots(const DomTreeT &DT, BatchUpdatePtr BUI) {
+ assert(DT.Parent && "Parent pointer is not set");
+ RootsT Roots;
+
+ // For dominators, function entry CFG node is always a tree root node.
+ if (!IsPostDom) {
+ Roots.push_back(GetEntryNode(DT));
+ return Roots;
}
- if (DT.isPostDominator()) {
- for (auto *Root : DT.Roots) Num = runDFS<true>(Root, Num, DC, 1);
- } else {
- assert(DT.Roots.size() == 1);
- Num = runDFS<false>(DT.Roots[0], Num, DC, Num);
+ SemiNCAInfo SNCA(BUI);
+
+ // PostDominatorTree always has a virtual root.
+ SNCA.addVirtualRoot();
+ unsigned Num = 1;
+
+ DEBUG(dbgs() << "\t\tLooking for trivial roots\n");
+
+ // Step #1: Find all the trivial roots that are going to will definitely
+ // remain tree roots.
+ unsigned Total = 0;
+ // It may happen that there are some new nodes in the CFG that are result of
+ // the ongoing batch update, but we cannot really pretend that they don't
+ // exist -- we won't see any outgoing or incoming edges to them, so it's
+ // fine to discover them here, as they would end up appearing in the CFG at
+ // some point anyway.
+ for (const NodePtr N : nodes(DT.Parent)) {
+ ++Total;
+ // If it has no *successors*, it is definitely a root.
+ if (!HasForwardSuccessors(N, BUI)) {
+ Roots.push_back(N);
+ // Run DFS not to walk this part of CFG later.
+ Num = SNCA.runDFS(N, Num, AlwaysDescend, 1);
+ DEBUG(dbgs() << "Found a new trivial root: " << BlockNamePrinter(N)
+ << "\n");
+ DEBUG(dbgs() << "Last visited node: "
+ << BlockNamePrinter(SNCA.NumToNode[Num]) << "\n");
+ }
}
- return Num;
+ DEBUG(dbgs() << "\t\tLooking for non-trivial roots\n");
+
+ // Step #2: Find all non-trivial root candidates. Those are CFG nodes that
+ // are reverse-unreachable were not visited by previous DFS walks (i.e. CFG
+ // nodes in infinite loops).
+ bool HasNonTrivialRoots = false;
+ // Accounting for the virtual exit, see if we had any reverse-unreachable
+ // nodes.
+ if (Total + 1 != Num) {
+ HasNonTrivialRoots = true;
+ // Make another DFS pass over all other nodes to find the
+ // reverse-unreachable blocks, and find the furthest paths we'll be able
+ // to make.
+ // Note that this looks N^2, but it's really 2N worst case, if every node
+ // is unreachable. This is because we are still going to only visit each
+ // unreachable node once, we may just visit it in two directions,
+ // depending on how lucky we get.
+ SmallPtrSet<NodePtr, 4> ConnectToExitBlock;
+ for (const NodePtr I : nodes(DT.Parent)) {
+ if (SNCA.NodeToInfo.count(I) == 0) {
+ DEBUG(dbgs() << "\t\t\tVisiting node " << BlockNamePrinter(I)
+ << "\n");
+ // Find the furthest away we can get by following successors, then
+ // follow them in reverse. This gives us some reasonable answer about
+ // the post-dom tree inside any infinite loop. In particular, it
+ // guarantees we get to the farthest away point along *some*
+ // path. This also matches the GCC's behavior.
+ // If we really wanted a totally complete picture of dominance inside
+ // this infinite loop, we could do it with SCC-like algorithms to find
+ // the lowest and highest points in the infinite loop. In theory, it
+ // would be nice to give the canonical backedge for the loop, but it's
+ // expensive and does not always lead to a minimal set of roots.
+ DEBUG(dbgs() << "\t\t\tRunning forward DFS\n");
+
+ const unsigned NewNum = SNCA.runDFS<true>(I, Num, AlwaysDescend, Num);
+ const NodePtr FurthestAway = SNCA.NumToNode[NewNum];
+ DEBUG(dbgs() << "\t\t\tFound a new furthest away node "
+ << "(non-trivial root): "
+ << BlockNamePrinter(FurthestAway) << "\n");
+ ConnectToExitBlock.insert(FurthestAway);
+ Roots.push_back(FurthestAway);
+ DEBUG(dbgs() << "\t\t\tPrev DFSNum: " << Num << ", new DFSNum: "
+ << NewNum << "\n\t\t\tRemoving DFS info\n");
+ for (unsigned i = NewNum; i > Num; --i) {
+ const NodePtr N = SNCA.NumToNode[i];
+ DEBUG(dbgs() << "\t\t\t\tRemoving DFS info for "
+ << BlockNamePrinter(N) << "\n");
+ SNCA.NodeToInfo.erase(N);
+ SNCA.NumToNode.pop_back();
+ }
+ const unsigned PrevNum = Num;
+ DEBUG(dbgs() << "\t\t\tRunning reverse DFS\n");
+ Num = SNCA.runDFS(FurthestAway, Num, AlwaysDescend, 1);
+ for (unsigned i = PrevNum + 1; i <= Num; ++i)
+ DEBUG(dbgs() << "\t\t\t\tfound node "
+ << BlockNamePrinter(SNCA.NumToNode[i]) << "\n");
+ }
+ }
+ }
+
+ DEBUG(dbgs() << "Total: " << Total << ", Num: " << Num << "\n");
+ DEBUG(dbgs() << "Discovered CFG nodes:\n");
+ DEBUG(for (size_t i = 0; i <= Num; ++i) dbgs()
+ << i << ": " << BlockNamePrinter(SNCA.NumToNode[i]) << "\n");
+
+ assert((Total + 1 == Num) && "Everything should have been visited");
+
+ // Step #3: If we found some non-trivial roots, make them non-redundant.
+ if (HasNonTrivialRoots) RemoveRedundantRoots(DT, BUI, Roots);
+
+ DEBUG(dbgs() << "Found roots: ");
+ DEBUG(for (auto *Root : Roots) dbgs() << BlockNamePrinter(Root) << " ");
+ DEBUG(dbgs() << "\n");
+
+ return Roots;
}
- void calculateFromScratch(DomTreeT &DT, const unsigned NumBlocks) {
+ // This function only makes sense for postdominators.
+ // We define roots to be some set of CFG nodes where (reverse) DFS walks have
+ // to start in order to visit all the CFG nodes (including the
+ // reverse-unreachable ones).
+ // When the search for non-trivial roots is done it may happen that some of
+ // the non-trivial roots are reverse-reachable from other non-trivial roots,
+ // which makes them redundant. This function removes them from the set of
+ // input roots.
+ static void RemoveRedundantRoots(const DomTreeT &DT, BatchUpdatePtr BUI,
+ RootsT &Roots) {
+ assert(IsPostDom && "This function is for postdominators only");
+ DEBUG(dbgs() << "Removing redundant roots\n");
+
+ SemiNCAInfo SNCA(BUI);
+
+ for (unsigned i = 0; i < Roots.size(); ++i) {
+ auto &Root = Roots[i];
+ // Trivial roots are always non-redundant.
+ if (!HasForwardSuccessors(Root, BUI)) continue;
+ DEBUG(dbgs() << "\tChecking if " << BlockNamePrinter(Root)
+ << " remains a root\n");
+ SNCA.clear();
+ // Do a forward walk looking for the other roots.
+ const unsigned Num = SNCA.runDFS<true>(Root, 0, AlwaysDescend, 0);
+ // Skip the start node and begin from the second one (note that DFS uses
+ // 1-based indexing).
+ for (unsigned x = 2; x <= Num; ++x) {
+ const NodePtr N = SNCA.NumToNode[x];
+ // If we wound another root in a (forward) DFS walk, remove the current
+ // root from the set of roots, as it is reverse-reachable from the other
+ // one.
+ if (llvm::find(Roots, N) != Roots.end()) {
+ DEBUG(dbgs() << "\tForward DFS walk found another root "
+ << BlockNamePrinter(N) << "\n\tRemoving root "
+ << BlockNamePrinter(Root) << "\n");
+ std::swap(Root, Roots.back());
+ Roots.pop_back();
+
+ // Root at the back takes the current root's place.
+ // Start the next loop iteration with the same index.
+ --i;
+ break;
+ }
+ }
+ }
+ }
+
+ template <typename DescendCondition>
+ void doFullDFSWalk(const DomTreeT &DT, DescendCondition DC) {
+ if (!IsPostDom) {
+ assert(DT.Roots.size() == 1 && "Dominators should have a singe root");
+ runDFS(DT.Roots[0], 0, DC, 0);
+ return;
+ }
+
+ addVirtualRoot();
+ unsigned Num = 1;
+ for (const NodePtr Root : DT.Roots) Num = runDFS(Root, Num, DC, 0);
+ }
+
+ static void CalculateFromScratch(DomTreeT &DT, BatchUpdatePtr BUI) {
+ auto *Parent = DT.Parent;
+ DT.reset();
+ DT.Parent = Parent;
+ SemiNCAInfo SNCA(nullptr); // Since we are rebuilding the whole tree,
+ // there's no point doing it incrementally.
+
// Step #0: Number blocks in depth-first order and initialize variables used
// in later stages of the algorithm.
- const unsigned LastDFSNum = doFullDFSWalk(DT, AlwaysDescend);
+ DT.Roots = FindRoots(DT, nullptr);
+ SNCA.doFullDFSWalk(DT, AlwaysDescend);
- runSemiNCA(DT);
+ SNCA.runSemiNCA(DT);
+ if (BUI) {
+ BUI->IsRecalculated = true;
+ DEBUG(dbgs() << "DomTree recalculated, skipping future batch updates\n");
+ }
if (DT.Roots.empty()) return;
- // Add a node for the root. This node might be the actual root, if there is
- // one exit block, or it may be the virtual exit (denoted by
- // (BasicBlock *)0) which postdominates all real exits if there are multiple
- // exit blocks, or an infinite loop.
- // It might be that some blocks did not get a DFS number (e.g., blocks of
- // infinite loops). In these cases an artificial exit node is required.
- const bool MultipleRoots = DT.Roots.size() > 1 || (DT.isPostDominator() &&
- LastDFSNum != NumBlocks);
- NodePtr Root = !MultipleRoots ? DT.Roots[0] : nullptr;
+ // Add a node for the root. If the tree is a PostDominatorTree it will be
+ // the virtual exit (denoted by (BasicBlock *) nullptr) which postdominates
+ // all real exits (including multiple exit blocks, infinite loops).
+ NodePtr Root = IsPostDom ? nullptr : DT.Roots[0];
DT.RootNode = (DT.DomTreeNodes[Root] =
llvm::make_unique<DomTreeNodeBase<NodeT>>(Root, nullptr))
.get();
- attachNewSubtree(DT, DT.RootNode);
+ SNCA.attachNewSubtree(DT, DT.RootNode);
}
void attachNewSubtree(DomTreeT& DT, const TreeNodePtr AttachTo) {
@@ -317,11 +593,11 @@ struct SemiNCAInfo {
NodePtr ImmDom = getIDom(W);
- // Get or calculate the node for the immediate dominator
+ // Get or calculate the node for the immediate dominator.
TreeNodePtr IDomNode = getNodeForBlock(ImmDom, DT);
// Add a new tree node for this BasicBlock, and link it as a child of
- // IDomNode
+ // IDomNode.
DT.DomTreeNodes[W] = IDomNode->addChild(
llvm::make_unique<DomTreeNodeBase<NodeT>>(W, IDomNode));
}
@@ -357,31 +633,105 @@ struct SemiNCAInfo {
SmallVector<TreeNodePtr, 8> VisitedNotAffectedQueue;
};
- static void InsertEdge(DomTreeT &DT, const NodePtr From, const NodePtr To) {
- assert(From && To && "Cannot connect nullptrs");
+ static void InsertEdge(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const NodePtr From, const NodePtr To) {
+ assert((From || IsPostDom) &&
+ "From has to be a valid CFG node or a virtual root");
+ assert(To && "Cannot be a nullptr");
DEBUG(dbgs() << "Inserting edge " << BlockNamePrinter(From) << " -> "
<< BlockNamePrinter(To) << "\n");
- const TreeNodePtr FromTN = DT.getNode(From);
-
- // Ignore edges from unreachable nodes.
- if (!FromTN) return;
+ TreeNodePtr FromTN = DT.getNode(From);
+
+ if (!FromTN) {
+ // Ignore edges from unreachable nodes for (forward) dominators.
+ if (!IsPostDom) return;
+
+ // The unreachable node becomes a new root -- a tree node for it.
+ TreeNodePtr VirtualRoot = DT.getNode(nullptr);
+ FromTN =
+ (DT.DomTreeNodes[From] = VirtualRoot->addChild(
+ llvm::make_unique<DomTreeNodeBase<NodeT>>(From, VirtualRoot)))
+ .get();
+ DT.Roots.push_back(From);
+ }
DT.DFSInfoValid = false;
const TreeNodePtr ToTN = DT.getNode(To);
if (!ToTN)
- InsertUnreachable(DT, FromTN, To);
+ InsertUnreachable(DT, BUI, FromTN, To);
else
- InsertReachable(DT, FromTN, ToTN);
+ InsertReachable(DT, BUI, FromTN, ToTN);
+ }
+
+ // Determines if some existing root becomes reverse-reachable after the
+ // insertion. Rebuilds the whole tree if that situation happens.
+ static bool UpdateRootsBeforeInsertion(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr From,
+ const TreeNodePtr To) {
+ assert(IsPostDom && "This function is only for postdominators");
+ // Destination node is not attached to the virtual root, so it cannot be a
+ // root.
+ if (!DT.isVirtualRoot(To->getIDom())) return false;
+
+ auto RIt = llvm::find(DT.Roots, To->getBlock());
+ if (RIt == DT.Roots.end())
+ return false; // To is not a root, nothing to update.
+
+ DEBUG(dbgs() << "\t\tAfter the insertion, " << BlockNamePrinter(To)
+ << " is no longer a root\n\t\tRebuilding the tree!!!\n");
+
+ CalculateFromScratch(DT, BUI);
+ return true;
+ }
+
+ // Updates the set of roots after insertion or deletion. This ensures that
+ // roots are the same when after a series of updates and when the tree would
+ // be built from scratch.
+ static void UpdateRootsAfterUpdate(DomTreeT &DT, const BatchUpdatePtr BUI) {
+ assert(IsPostDom && "This function is only for postdominators");
+
+ // The tree has only trivial roots -- nothing to update.
+ if (std::none_of(DT.Roots.begin(), DT.Roots.end(), [BUI](const NodePtr N) {
+ return HasForwardSuccessors(N, BUI);
+ }))
+ return;
+
+ // Recalculate the set of roots.
+ DT.Roots = FindRoots(DT, BUI);
+ for (const NodePtr R : DT.Roots) {
+ const TreeNodePtr TN = DT.getNode(R);
+ // A CFG node was selected as a tree root, but the corresponding tree node
+ // is not connected to the virtual root. This is because the incremental
+ // algorithm does not really know or use the set of roots and can make a
+ // different (implicit) decision about which nodes within an infinite loop
+ // becomes a root.
+ if (DT.isVirtualRoot(TN->getIDom())) {
+ DEBUG(dbgs() << "Root " << BlockNamePrinter(R)
+ << " is not virtual root's child\n"
+ << "The entire tree needs to be rebuilt\n");
+ // It should be possible to rotate the subtree instead of recalculating
+ // the whole tree, but this situation happens extremely rarely in
+ // practice.
+ CalculateFromScratch(DT, BUI);
+ return;
+ }
+ }
}
// Handles insertion to a node already in the dominator tree.
- static void InsertReachable(DomTreeT &DT, const TreeNodePtr From,
- const TreeNodePtr To) {
+ static void InsertReachable(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr From, const TreeNodePtr To) {
DEBUG(dbgs() << "\tReachable " << BlockNamePrinter(From->getBlock())
<< " -> " << BlockNamePrinter(To->getBlock()) << "\n");
+ if (IsPostDom && UpdateRootsBeforeInsertion(DT, BUI, From, To)) return;
+ // DT.findNCD expects both pointers to be valid. When From is a virtual
+ // root, then its CFG block pointer is a nullptr, so we have to 'compute'
+ // the NCD manually.
const NodePtr NCDBlock =
- DT.findNearestCommonDominator(From->getBlock(), To->getBlock());
+ (From->getBlock() && To->getBlock())
+ ? DT.findNearestCommonDominator(From->getBlock(), To->getBlock())
+ : nullptr;
assert(NCDBlock || DT.isPostDominator());
const TreeNodePtr NCD = DT.getNode(NCDBlock);
assert(NCD);
@@ -410,53 +760,61 @@ struct SemiNCAInfo {
II.AffectedQueue.push_back(CurrentNode);
// Discover and collect affected successors of the current node.
- VisitInsertion(DT, CurrentNode, CurrentNode->getLevel(), NCD, II);
+ VisitInsertion(DT, BUI, CurrentNode, CurrentNode->getLevel(), NCD, II);
}
// Finish by updating immediate dominators and levels.
- UpdateInsertion(DT, NCD, II);
+ UpdateInsertion(DT, BUI, NCD, II);
}
// Visits an affected node and collect its affected successors.
- static void VisitInsertion(DomTreeT &DT, const TreeNodePtr TN,
- const unsigned RootLevel, const TreeNodePtr NCD,
- InsertionInfo &II) {
+ static void VisitInsertion(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr TN, const unsigned RootLevel,
+ const TreeNodePtr NCD, InsertionInfo &II) {
const unsigned NCDLevel = NCD->getLevel();
DEBUG(dbgs() << "Visiting " << BlockNamePrinter(TN) << "\n");
- assert(TN->getBlock());
- for (const NodePtr Succ :
- ChildrenGetter<NodePtr, IsPostDom>::Get(TN->getBlock())) {
- const TreeNodePtr SuccTN = DT.getNode(Succ);
- assert(SuccTN && "Unreachable successor found at reachable insertion");
- const unsigned SuccLevel = SuccTN->getLevel();
-
- DEBUG(dbgs() << "\tSuccessor " << BlockNamePrinter(Succ)
- << ", level = " << SuccLevel << "\n");
-
- // Succ dominated by subtree From -- not affected.
- // (Based on the lemma 2.5 from the second paper.)
- if (SuccLevel > RootLevel) {
- DEBUG(dbgs() << "\t\tDominated by subtree From\n");
- if (II.Visited.count(SuccTN) != 0) continue;
-
- DEBUG(dbgs() << "\t\tMarking visited not affected "
- << BlockNamePrinter(Succ) << "\n");
- II.Visited.insert(SuccTN);
- II.VisitedNotAffectedQueue.push_back(SuccTN);
- VisitInsertion(DT, SuccTN, RootLevel, NCD, II);
- } else if ((SuccLevel > NCDLevel + 1) && II.Affected.count(SuccTN) == 0) {
- DEBUG(dbgs() << "\t\tMarking affected and adding "
- << BlockNamePrinter(Succ) << " to a Bucket\n");
- II.Affected.insert(SuccTN);
- II.Bucket.push({SuccLevel, SuccTN});
+ SmallVector<TreeNodePtr, 8> Stack = {TN};
+ assert(TN->getBlock() && II.Visited.count(TN) && "Preconditions!");
+
+ do {
+ TreeNodePtr Next = Stack.pop_back_val();
+
+ for (const NodePtr Succ :
+ ChildrenGetter<IsPostDom>::Get(Next->getBlock(), BUI)) {
+ const TreeNodePtr SuccTN = DT.getNode(Succ);
+ assert(SuccTN && "Unreachable successor found at reachable insertion");
+ const unsigned SuccLevel = SuccTN->getLevel();
+
+ DEBUG(dbgs() << "\tSuccessor " << BlockNamePrinter(Succ)
+ << ", level = " << SuccLevel << "\n");
+
+ // Succ dominated by subtree From -- not affected.
+ // (Based on the lemma 2.5 from the second paper.)
+ if (SuccLevel > RootLevel) {
+ DEBUG(dbgs() << "\t\tDominated by subtree From\n");
+ if (II.Visited.count(SuccTN) != 0)
+ continue;
+
+ DEBUG(dbgs() << "\t\tMarking visited not affected "
+ << BlockNamePrinter(Succ) << "\n");
+ II.Visited.insert(SuccTN);
+ II.VisitedNotAffectedQueue.push_back(SuccTN);
+ Stack.push_back(SuccTN);
+ } else if ((SuccLevel > NCDLevel + 1) &&
+ II.Affected.count(SuccTN) == 0) {
+ DEBUG(dbgs() << "\t\tMarking affected and adding "
+ << BlockNamePrinter(Succ) << " to a Bucket\n");
+ II.Affected.insert(SuccTN);
+ II.Bucket.push({SuccLevel, SuccTN});
+ }
}
- }
+ } while (!Stack.empty());
}
// Updates immediate dominators and levels after insertion.
- static void UpdateInsertion(DomTreeT &DT, const TreeNodePtr NCD,
- InsertionInfo &II) {
+ static void UpdateInsertion(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr NCD, InsertionInfo &II) {
DEBUG(dbgs() << "Updating NCD = " << BlockNamePrinter(NCD) << "\n");
for (const TreeNodePtr TN : II.AffectedQueue) {
@@ -466,6 +824,7 @@ struct SemiNCAInfo {
}
UpdateLevelsAfterInsertion(II);
+ if (IsPostDom) UpdateRootsAfterUpdate(DT, BUI);
}
static void UpdateLevelsAfterInsertion(InsertionInfo &II) {
@@ -480,36 +839,35 @@ struct SemiNCAInfo {
}
// Handles insertion to previously unreachable nodes.
- static void InsertUnreachable(DomTreeT &DT, const TreeNodePtr From,
- const NodePtr To) {
+ static void InsertUnreachable(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr From, const NodePtr To) {
DEBUG(dbgs() << "Inserting " << BlockNamePrinter(From)
<< " -> (unreachable) " << BlockNamePrinter(To) << "\n");
// Collect discovered edges to already reachable nodes.
SmallVector<std::pair<NodePtr, TreeNodePtr>, 8> DiscoveredEdgesToReachable;
// Discover and connect nodes that became reachable with the insertion.
- ComputeUnreachableDominators(DT, To, From, DiscoveredEdgesToReachable);
+ ComputeUnreachableDominators(DT, BUI, To, From, DiscoveredEdgesToReachable);
DEBUG(dbgs() << "Inserted " << BlockNamePrinter(From)
<< " -> (prev unreachable) " << BlockNamePrinter(To) << "\n");
- DEBUG(DT.print(dbgs()));
-
// Used the discovered edges and inset discovered connecting (incoming)
// edges.
for (const auto &Edge : DiscoveredEdgesToReachable) {
DEBUG(dbgs() << "\tInserting discovered connecting edge "
<< BlockNamePrinter(Edge.first) << " -> "
<< BlockNamePrinter(Edge.second) << "\n");
- InsertReachable(DT, DT.getNode(Edge.first), Edge.second);
+ InsertReachable(DT, BUI, DT.getNode(Edge.first), Edge.second);
}
}
// Connects nodes that become reachable with an insertion.
static void ComputeUnreachableDominators(
- DomTreeT &DT, const NodePtr Root, const TreeNodePtr Incoming,
+ DomTreeT &DT, const BatchUpdatePtr BUI, const NodePtr Root,
+ const TreeNodePtr Incoming,
SmallVectorImpl<std::pair<NodePtr, TreeNodePtr>>
- &DiscoveredConnectingEdges) {
+ &DiscoveredConnectingEdges) {
assert(!DT.getNode(Root) && "Root must not be reachable");
// Visit only previously unreachable nodes.
@@ -522,50 +880,16 @@ struct SemiNCAInfo {
return false;
};
- SemiNCAInfo SNCA;
- SNCA.runDFS<IsPostDom>(Root, 0, UnreachableDescender, 0);
+ SemiNCAInfo SNCA(BUI);
+ SNCA.runDFS(Root, 0, UnreachableDescender, 0);
SNCA.runSemiNCA(DT);
SNCA.attachNewSubtree(DT, Incoming);
DEBUG(dbgs() << "After adding unreachable nodes\n");
- DEBUG(DT.print(dbgs()));
}
- // Checks if the tree contains all reachable nodes in the input graph.
- bool verifyReachability(const DomTreeT &DT) {
- clear();
- doFullDFSWalk(DT, AlwaysDescend);
-
- for (auto &NodeToTN : DT.DomTreeNodes) {
- const TreeNodePtr TN = NodeToTN.second.get();
- const NodePtr BB = TN->getBlock();
-
- // Virtual root has a corresponding virtual CFG node.
- if (DT.isVirtualRoot(TN)) continue;
-
- if (NodeToInfo.count(BB) == 0) {
- errs() << "DomTree node " << BlockNamePrinter(BB)
- << " not found by DFS walk!\n";
- errs().flush();
-
- return false;
- }
- }
-
- for (const NodePtr N : NumToNode) {
- if (N && !DT.getNode(N)) {
- errs() << "CFG node " << BlockNamePrinter(N)
- << " not found in the DomTree!\n";
- errs().flush();
-
- return false;
- }
- }
-
- return true;
- }
-
- static void DeleteEdge(DomTreeT &DT, const NodePtr From, const NodePtr To) {
+ static void DeleteEdge(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const NodePtr From, const NodePtr To) {
assert(From && To && "Cannot disconnect nullptrs");
DEBUG(dbgs() << "Deleting edge " << BlockNamePrinter(From) << " -> "
<< BlockNamePrinter(To) << "\n");
@@ -574,8 +898,8 @@ struct SemiNCAInfo {
// Ensure that the edge was in fact deleted from the CFG before informing
// the DomTree about it.
// The check is O(N), so run it only in debug configuration.
- auto IsSuccessor = [](const NodePtr SuccCandidate, const NodePtr Of) {
- auto Successors = ChildrenGetter<NodePtr, IsPostDom>::Get(Of);
+ auto IsSuccessor = [BUI](const NodePtr SuccCandidate, const NodePtr Of) {
+ auto Successors = ChildrenGetter<IsPostDom>::Get(Of, BUI);
return llvm::find(Successors, SuccCandidate) != Successors.end();
};
(void)IsSuccessor;
@@ -587,27 +911,37 @@ struct SemiNCAInfo {
if (!FromTN) return;
const TreeNodePtr ToTN = DT.getNode(To);
- assert(ToTN && "To already unreachable -- there is no edge to delete");
+ if (!ToTN) {
+ DEBUG(dbgs() << "\tTo (" << BlockNamePrinter(To)
+ << ") already unreachable -- there is no edge to delete\n");
+ return;
+ }
+
const NodePtr NCDBlock = DT.findNearestCommonDominator(From, To);
const TreeNodePtr NCD = DT.getNode(NCDBlock);
// To dominates From -- nothing to do.
if (ToTN == NCD) return;
+ DT.DFSInfoValid = false;
+
const TreeNodePtr ToIDom = ToTN->getIDom();
DEBUG(dbgs() << "\tNCD " << BlockNamePrinter(NCD) << ", ToIDom "
<< BlockNamePrinter(ToIDom) << "\n");
// To remains reachable after deletion.
// (Based on the caption under Figure 4. from the second paper.)
- if (FromTN != ToIDom || HasProperSupport(DT, ToTN))
- DeleteReachable(DT, FromTN, ToTN);
+ if (FromTN != ToIDom || HasProperSupport(DT, BUI, ToTN))
+ DeleteReachable(DT, BUI, FromTN, ToTN);
else
- DeleteUnreachable(DT, ToTN);
+ DeleteUnreachable(DT, BUI, ToTN);
+
+ if (IsPostDom) UpdateRootsAfterUpdate(DT, BUI);
}
// Handles deletions that leave destination nodes reachable.
- static void DeleteReachable(DomTreeT &DT, const TreeNodePtr FromTN,
+ static void DeleteReachable(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr FromTN,
const TreeNodePtr ToTN) {
DEBUG(dbgs() << "Deleting reachable " << BlockNamePrinter(FromTN) << " -> "
<< BlockNamePrinter(ToTN) << "\n");
@@ -625,7 +959,7 @@ struct SemiNCAInfo {
// scratch.
if (!PrevIDomSubTree) {
DEBUG(dbgs() << "The entire tree needs to be rebuilt\n");
- DT.recalculate(*DT.Parent);
+ CalculateFromScratch(DT, BUI);
return;
}
@@ -637,8 +971,8 @@ struct SemiNCAInfo {
DEBUG(dbgs() << "\tTop of subtree: " << BlockNamePrinter(ToIDomTN) << "\n");
- SemiNCAInfo SNCA;
- SNCA.runDFS<IsPostDom>(ToIDom, 0, DescendBelow, 0);
+ SemiNCAInfo SNCA(BUI);
+ SNCA.runDFS(ToIDom, 0, DescendBelow, 0);
DEBUG(dbgs() << "\tRunning Semi-NCA\n");
SNCA.runSemiNCA(DT, Level);
SNCA.reattachExistingSubtree(DT, PrevIDomSubTree);
@@ -646,10 +980,11 @@ struct SemiNCAInfo {
// Checks if a node has proper support, as defined on the page 3 and later
// explained on the page 7 of the second paper.
- static bool HasProperSupport(DomTreeT &DT, const TreeNodePtr TN) {
+ static bool HasProperSupport(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr TN) {
DEBUG(dbgs() << "IsReachableFromIDom " << BlockNamePrinter(TN) << "\n");
for (const NodePtr Pred :
- ChildrenGetter<NodePtr, !IsPostDom>::Get(TN->getBlock())) {
+ ChildrenGetter<!IsPostDom>::Get(TN->getBlock(), BUI)) {
DEBUG(dbgs() << "\tPred " << BlockNamePrinter(Pred) << "\n");
if (!DT.getNode(Pred)) continue;
@@ -669,12 +1004,24 @@ struct SemiNCAInfo {
// Handle deletions that make destination node unreachable.
// (Based on the lemma 2.7 from the second paper.)
- static void DeleteUnreachable(DomTreeT &DT, const TreeNodePtr ToTN) {
+ static void DeleteUnreachable(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr ToTN) {
DEBUG(dbgs() << "Deleting unreachable subtree " << BlockNamePrinter(ToTN)
<< "\n");
assert(ToTN);
assert(ToTN->getBlock());
+ if (IsPostDom) {
+ // Deletion makes a region reverse-unreachable and creates a new root.
+ // Simulate that by inserting an edge from the virtual root to ToTN and
+ // adding it as a new root.
+ DEBUG(dbgs() << "\tDeletion made a region reverse-unreachable\n");
+ DEBUG(dbgs() << "\tAdding new root " << BlockNamePrinter(ToTN) << "\n");
+ DT.Roots.push_back(ToTN->getBlock());
+ InsertReachable(DT, BUI, DT.getNode(nullptr), ToTN);
+ return;
+ }
+
SmallVector<NodePtr, 16> AffectedQueue;
const unsigned Level = ToTN->getLevel();
@@ -690,13 +1037,13 @@ struct SemiNCAInfo {
return false;
};
- SemiNCAInfo SNCA;
+ SemiNCAInfo SNCA(BUI);
unsigned LastDFSNum =
- SNCA.runDFS<IsPostDom>(ToTN->getBlock(), 0, DescendAndCollect, 0);
+ SNCA.runDFS(ToTN->getBlock(), 0, DescendAndCollect, 0);
TreeNodePtr MinNode = ToTN;
- // Identify the top of the subtree to rebuilt by finding the NCD of all
+ // Identify the top of the subtree to rebuild by finding the NCD of all
// the affected nodes.
for (const NodePtr N : AffectedQueue) {
const TreeNodePtr TN = DT.getNode(N);
@@ -715,7 +1062,7 @@ struct SemiNCAInfo {
// Root reached, rebuild the whole tree from scratch.
if (!MinNode->getIDom()) {
DEBUG(dbgs() << "The entire tree needs to be rebuilt\n");
- DT.recalculate(*DT.Parent);
+ CalculateFromScratch(DT, BUI);
return;
}
@@ -744,7 +1091,7 @@ struct SemiNCAInfo {
const TreeNodePtr ToTN = DT.getNode(To);
return ToTN && ToTN->getLevel() > MinLevel;
};
- SNCA.runDFS<IsPostDom>(MinNode->getBlock(), 0, DescendBelow, 0);
+ SNCA.runDFS(MinNode->getBlock(), 0, DescendBelow, 0);
DEBUG(dbgs() << "Previous IDom(MinNode) = " << BlockNamePrinter(PrevIDom)
<< "\nRunning Semi-NCA\n");
@@ -771,9 +1118,222 @@ struct SemiNCAInfo {
}
//~~
+ //===--------------------- DomTree Batch Updater --------------------------===
+ //~~
+
+ static void ApplyUpdates(DomTreeT &DT, ArrayRef<UpdateT> Updates) {
+ const size_t NumUpdates = Updates.size();
+ if (NumUpdates == 0)
+ return;
+
+ // Take the fast path for a single update and avoid running the batch update
+ // machinery.
+ if (NumUpdates == 1) {
+ const auto &Update = Updates.front();
+ if (Update.getKind() == UpdateKind::Insert)
+ DT.insertEdge(Update.getFrom(), Update.getTo());
+ else
+ DT.deleteEdge(Update.getFrom(), Update.getTo());
+
+ return;
+ }
+
+ BatchUpdateInfo BUI;
+ LegalizeUpdates(Updates, BUI.Updates);
+
+ const size_t NumLegalized = BUI.Updates.size();
+ BUI.FutureSuccessors.reserve(NumLegalized);
+ BUI.FuturePredecessors.reserve(NumLegalized);
+
+ // Use the legalized future updates to initialize future successors and
+ // predecessors. Note that these sets will only decrease size over time, as
+ // the next CFG snapshots slowly approach the actual (current) CFG.
+ for (UpdateT &U : BUI.Updates) {
+ BUI.FutureSuccessors[U.getFrom()].insert({U.getTo(), U.getKind()});
+ BUI.FuturePredecessors[U.getTo()].insert({U.getFrom(), U.getKind()});
+ }
+
+ DEBUG(dbgs() << "About to apply " << NumLegalized << " updates\n");
+ DEBUG(if (NumLegalized < 32) for (const auto &U
+ : reverse(BUI.Updates)) dbgs()
+ << '\t' << U << "\n");
+ DEBUG(dbgs() << "\n");
+
+ // If the DominatorTree was recalculated at some point, stop the batch
+ // updates. Full recalculations ignore batch updates and look at the actual
+ // CFG.
+ for (size_t i = 0; i < NumLegalized && !BUI.IsRecalculated; ++i)
+ 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) {
+ 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);
+ }
+
+ std::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();
+ DEBUG(dbgs() << "Applying update: " << CurrentUpdate << "\n");
+
+ // Move to the next snapshot of the CFG by removing the reverse-applied
+ // current update.
+ auto &FS = BUI.FutureSuccessors[CurrentUpdate.getFrom()];
+ FS.erase({CurrentUpdate.getTo(), CurrentUpdate.getKind()});
+ if (FS.empty()) BUI.FutureSuccessors.erase(CurrentUpdate.getFrom());
+
+ auto &FP = BUI.FuturePredecessors[CurrentUpdate.getTo()];
+ FP.erase({CurrentUpdate.getFrom(), CurrentUpdate.getKind()});
+ if (FP.empty()) BUI.FuturePredecessors.erase(CurrentUpdate.getTo());
+
+ if (CurrentUpdate.getKind() == UpdateKind::Insert)
+ InsertEdge(DT, &BUI, CurrentUpdate.getFrom(), CurrentUpdate.getTo());
+ else
+ DeleteEdge(DT, &BUI, CurrentUpdate.getFrom(), CurrentUpdate.getTo());
+ }
+
+ //~~
//===--------------- DomTree correctness verification ---------------------===
//~~
+ // Check if the tree has correct roots. A DominatorTree always has a single
+ // root which is the function's entry node. A PostDominatorTree can have
+ // multiple roots - one for each node with no successors and for infinite
+ // loops.
+ bool verifyRoots(const DomTreeT &DT) {
+ if (!DT.Parent && !DT.Roots.empty()) {
+ errs() << "Tree has no parent but has roots!\n";
+ errs().flush();
+ return false;
+ }
+
+ if (!IsPostDom) {
+ if (DT.Roots.empty()) {
+ errs() << "Tree doesn't have a root!\n";
+ errs().flush();
+ return false;
+ }
+
+ if (DT.getRoot() != GetEntryNode(DT)) {
+ errs() << "Tree's root is not its parent's entry node!\n";
+ errs().flush();
+ return false;
+ }
+ }
+
+ RootsT ComputedRoots = FindRoots(DT, nullptr);
+ if (DT.Roots.size() != ComputedRoots.size() ||
+ !std::is_permutation(DT.Roots.begin(), DT.Roots.end(),
+ ComputedRoots.begin())) {
+ errs() << "Tree has different roots than freshly computed ones!\n";
+ errs() << "\tPDT roots: ";
+ for (const NodePtr N : DT.Roots) errs() << BlockNamePrinter(N) << ", ";
+ errs() << "\n\tComputed roots: ";
+ for (const NodePtr N : ComputedRoots)
+ errs() << BlockNamePrinter(N) << ", ";
+ errs() << "\n";
+ errs().flush();
+ return false;
+ }
+
+ return true;
+ }
+
+ // Checks if the tree contains all reachable nodes in the input graph.
+ bool verifyReachability(const DomTreeT &DT) {
+ clear();
+ doFullDFSWalk(DT, AlwaysDescend);
+
+ for (auto &NodeToTN : DT.DomTreeNodes) {
+ const TreeNodePtr TN = NodeToTN.second.get();
+ const NodePtr BB = TN->getBlock();
+
+ // Virtual root has a corresponding virtual CFG node.
+ if (DT.isVirtualRoot(TN)) continue;
+
+ if (NodeToInfo.count(BB) == 0) {
+ errs() << "DomTree node " << BlockNamePrinter(BB)
+ << " not found by DFS walk!\n";
+ errs().flush();
+
+ return false;
+ }
+ }
+
+ for (const NodePtr N : NumToNode) {
+ if (N && !DT.getNode(N)) {
+ errs() << "CFG node " << BlockNamePrinter(N)
+ << " not found in the DomTree!\n";
+ errs().flush();
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
// Check if for every parent with a level L in the tree all of its children
// have level L + 1.
static bool VerifyLevels(const DomTreeT &DT) {
@@ -805,35 +1365,97 @@ struct SemiNCAInfo {
return true;
}
- // Checks if for every edge From -> To in the graph
- // NCD(From, To) == IDom(To) or To.
- bool verifyNCD(const DomTreeT &DT) {
- clear();
- doFullDFSWalk(DT, AlwaysDescend);
+ // Check if the computed DFS numbers are correct. Note that DFS info may not
+ // be valid, and when that is the case, we don't verify the numbers.
+ static bool VerifyDFSNumbers(const DomTreeT &DT) {
+ if (!DT.DFSInfoValid || !DT.Parent)
+ return true;
- for (auto &BlockToInfo : NodeToInfo) {
- auto &Info = BlockToInfo.second;
+ const NodePtr RootBB = IsPostDom ? nullptr : DT.getRoots()[0];
+ const TreeNodePtr Root = DT.getNode(RootBB);
- const NodePtr From = NumToNode[Info.Parent];
- if (!From) continue;
+ auto PrintNodeAndDFSNums = [](const TreeNodePtr TN) {
+ errs() << BlockNamePrinter(TN) << " {" << TN->getDFSNumIn() << ", "
+ << TN->getDFSNumOut() << '}';
+ };
- const NodePtr To = BlockToInfo.first;
- const TreeNodePtr ToTN = DT.getNode(To);
- assert(ToTN);
-
- const NodePtr NCD = DT.findNearestCommonDominator(From, To);
- const TreeNodePtr NCDTN = DT.getNode(NCD);
- const TreeNodePtr ToIDom = ToTN->getIDom();
- if (NCDTN != ToTN && NCDTN != ToIDom) {
- errs() << "NearestCommonDominator verification failed:\n\tNCD(From:"
- << BlockNamePrinter(From) << ", To:" << BlockNamePrinter(To)
- << ") = " << BlockNamePrinter(NCD)
- << ",\t (should be To or IDom[To]: " << BlockNamePrinter(ToIDom)
- << ")\n";
+ // Verify the root's DFS In number. Although DFS numbering would also work
+ // if we started from some other value, we assume 0-based numbering.
+ if (Root->getDFSNumIn() != 0) {
+ errs() << "DFSIn number for the tree root is not:\n\t";
+ PrintNodeAndDFSNums(Root);
+ errs() << '\n';
+ errs().flush();
+ return false;
+ }
+
+ // For each tree node verify if children's DFS numbers cover their parent's
+ // DFS numbers with no gaps.
+ for (const auto &NodeToTN : DT.DomTreeNodes) {
+ const TreeNodePtr Node = NodeToTN.second.get();
+
+ // Handle tree leaves.
+ if (Node->getChildren().empty()) {
+ if (Node->getDFSNumIn() + 1 != Node->getDFSNumOut()) {
+ errs() << "Tree leaf should have DFSOut = DFSIn + 1:\n\t";
+ PrintNodeAndDFSNums(Node);
+ errs() << '\n';
+ errs().flush();
+ return false;
+ }
+
+ continue;
+ }
+
+ // 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());
+ std::sort(Children.begin(), Children.end(),
+ [](const TreeNodePtr Ch1, const TreeNodePtr Ch2) {
+ return Ch1->getDFSNumIn() < Ch2->getDFSNumIn();
+ });
+
+ auto PrintChildrenError = [Node, &Children, PrintNodeAndDFSNums](
+ const TreeNodePtr FirstCh, const TreeNodePtr SecondCh) {
+ assert(FirstCh);
+
+ errs() << "Incorrect DFS numbers for:\n\tParent ";
+ PrintNodeAndDFSNums(Node);
+
+ errs() << "\n\tChild ";
+ PrintNodeAndDFSNums(FirstCh);
+
+ if (SecondCh) {
+ errs() << "\n\tSecond child ";
+ PrintNodeAndDFSNums(SecondCh);
+ }
+
+ errs() << "\nAll children: ";
+ for (const TreeNodePtr Ch : Children) {
+ PrintNodeAndDFSNums(Ch);
+ errs() << ", ";
+ }
+
+ errs() << '\n';
errs().flush();
+ };
+ if (Children.front()->getDFSNumIn() != Node->getDFSNumIn() + 1) {
+ PrintChildrenError(Children.front(), nullptr);
return false;
}
+
+ if (Children.back()->getDFSNumOut() + 1 != Node->getDFSNumOut()) {
+ PrintChildrenError(Children.back(), nullptr);
+ return false;
+ }
+
+ for (size_t i = 0, e = Children.size() - 1; i != e; ++i) {
+ if (Children[i]->getDFSNumOut() + 1 != Children[i + 1]->getDFSNumIn()) {
+ PrintChildrenError(Children[i], Children[i + 1]);
+ return false;
+ }
+ }
}
return true;
@@ -888,6 +1510,8 @@ struct SemiNCAInfo {
const NodePtr BB = TN->getBlock();
if (!BB || TN->getChildren().empty()) continue;
+ DEBUG(dbgs() << "Verifying parent property of node "
+ << BlockNamePrinter(TN) << "\n");
clear();
doFullDFSWalk(DT, [BB](NodePtr From, NodePtr To) {
return From != BB && To != BB;
@@ -945,33 +1569,37 @@ struct SemiNCAInfo {
}
};
-
-template <class DomTreeT, class FuncT>
-void Calculate(DomTreeT &DT, FuncT &F) {
- SemiNCAInfo<DomTreeT> SNCA;
- SNCA.calculateFromScratch(DT, GraphTraits<FuncT *>::size(&F));
+template <class DomTreeT>
+void Calculate(DomTreeT &DT) {
+ SemiNCAInfo<DomTreeT>::CalculateFromScratch(DT, nullptr);
}
template <class DomTreeT>
void InsertEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
typename DomTreeT::NodePtr To) {
if (DT.isPostDominator()) std::swap(From, To);
- SemiNCAInfo<DomTreeT>::InsertEdge(DT, From, To);
+ SemiNCAInfo<DomTreeT>::InsertEdge(DT, nullptr, From, To);
}
template <class DomTreeT>
void DeleteEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
typename DomTreeT::NodePtr To) {
if (DT.isPostDominator()) std::swap(From, To);
- SemiNCAInfo<DomTreeT>::DeleteEdge(DT, From, To);
+ SemiNCAInfo<DomTreeT>::DeleteEdge(DT, nullptr, From, To);
+}
+
+template <class DomTreeT>
+void ApplyUpdates(DomTreeT &DT,
+ ArrayRef<typename DomTreeT::UpdateType> Updates) {
+ SemiNCAInfo<DomTreeT>::ApplyUpdates(DT, Updates);
}
template <class DomTreeT>
bool Verify(const DomTreeT &DT) {
- SemiNCAInfo<DomTreeT> SNCA;
- return SNCA.verifyReachability(DT) && SNCA.VerifyLevels(DT) &&
- SNCA.verifyNCD(DT) && SNCA.verifyParentProperty(DT) &&
- SNCA.verifySiblingProperty(DT);
+ SemiNCAInfo<DomTreeT> SNCA(nullptr);
+ return SNCA.verifyRoots(DT) && SNCA.verifyReachability(DT) &&
+ SNCA.VerifyLevels(DT) && SNCA.verifyParentProperty(DT) &&
+ SNCA.verifySiblingProperty(DT) && SNCA.VerifyDFSNumbers(DT);
}
} // namespace DomTreeBuilder
diff --git a/include/llvm/Support/Host.h b/include/llvm/Support/Host.h
index be93dd99032e..a4b0a340c568 100644
--- a/include/llvm/Support/Host.h
+++ b/include/llvm/Support/Host.h
@@ -15,7 +15,6 @@
#define LLVM_SUPPORT_HOST_H
#include "llvm/ADT/StringMap.h"
-#include "llvm/Support/MemoryBuffer.h"
#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__)
#include <endian.h>
@@ -92,6 +91,7 @@ constexpr bool IsBigEndianHost = false;
StringRef getHostCPUNameForPowerPC(const StringRef &ProcCpuinfoContent);
StringRef getHostCPUNameForARM(const StringRef &ProcCpuinfoContent);
StringRef getHostCPUNameForS390x(const StringRef &ProcCpuinfoContent);
+ StringRef getHostCPUNameForBPF();
}
}
}
diff --git a/include/llvm/Support/KnownBits.h b/include/llvm/Support/KnownBits.h
index 2c77d40559b9..7a4de3e5ff12 100644
--- a/include/llvm/Support/KnownBits.h
+++ b/include/llvm/Support/KnownBits.h
@@ -25,7 +25,7 @@ struct KnownBits {
APInt One;
private:
- // Internal constructor for creating a ConstantRange from two APInts.
+ // Internal constructor for creating a KnownBits from two APInts.
KnownBits(APInt Zero, APInt One)
: Zero(std::move(Zero)), One(std::move(One)) {}
@@ -193,6 +193,10 @@ public:
unsigned countMaxPopulation() const {
return getBitWidth() - Zero.countPopulation();
}
+
+ /// Compute known bits resulting from adding LHS and RHS.
+ static KnownBits computeForAddSub(bool Add, bool NSW, const KnownBits &LHS,
+ KnownBits RHS);
};
} // end namespace llvm
diff --git a/include/llvm/Support/LEB128.h b/include/llvm/Support/LEB128.h
index 29640db69218..6af6e9f34474 100644
--- a/include/llvm/Support/LEB128.h
+++ b/include/llvm/Support/LEB128.h
@@ -21,23 +21,25 @@ namespace llvm {
/// Utility function to encode a SLEB128 value to an output stream.
inline void encodeSLEB128(int64_t Value, raw_ostream &OS,
- unsigned Padding = 0) {
+ unsigned PadTo = 0) {
bool More;
+ unsigned Count = 0;
do {
uint8_t Byte = Value & 0x7f;
// NOTE: this assumes that this signed shift is an arithmetic right shift.
Value >>= 7;
More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) ||
((Value == -1) && ((Byte & 0x40) != 0))));
- if (More || Padding != 0)
+ Count++;
+ if (More || Count < PadTo)
Byte |= 0x80; // Mark this byte to show that more bytes will follow.
OS << char(Byte);
} while (More);
// Pad with 0x80 and emit a terminating byte at the end.
- if (Padding != 0) {
+ if (Count < PadTo) {
uint8_t PadValue = Value < 0 ? 0x7f : 0x00;
- for (; Padding != 1; --Padding)
+ for (; Count < PadTo - 1; ++Count)
OS << char(PadValue | 0x80);
OS << char(PadValue);
}
@@ -45,8 +47,9 @@ inline void encodeSLEB128(int64_t Value, raw_ostream &OS,
/// Utility function to encode a SLEB128 value to a buffer. Returns
/// the length in bytes of the encoded value.
-inline unsigned encodeSLEB128(int64_t Value, uint8_t *p, unsigned Padding = 0) {
+inline unsigned encodeSLEB128(int64_t Value, uint8_t *p, unsigned PadTo = 0) {
uint8_t *orig_p = p;
+ unsigned Count = 0;
bool More;
do {
uint8_t Byte = Value & 0x7f;
@@ -54,15 +57,16 @@ inline unsigned encodeSLEB128(int64_t Value, uint8_t *p, unsigned Padding = 0) {
Value >>= 7;
More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) ||
((Value == -1) && ((Byte & 0x40) != 0))));
- if (More || Padding != 0)
+ Count++;
+ if (More || Count < PadTo)
Byte |= 0x80; // Mark this byte to show that more bytes will follow.
*p++ = Byte;
} while (More);
// Pad with 0x80 and emit a terminating byte at the end.
- if (Padding != 0) {
+ if (Count < PadTo) {
uint8_t PadValue = Value < 0 ? 0x7f : 0x00;
- for (; Padding != 1; --Padding)
+ for (; Count < PadTo - 1; ++Count)
*p++ = (PadValue | 0x80);
*p++ = PadValue;
}
@@ -71,42 +75,48 @@ inline unsigned encodeSLEB128(int64_t Value, uint8_t *p, unsigned Padding = 0) {
/// Utility function to encode a ULEB128 value to an output stream.
inline void encodeULEB128(uint64_t Value, raw_ostream &OS,
- unsigned Padding = 0) {
+ unsigned PadTo = 0) {
+ unsigned Count = 0;
do {
uint8_t Byte = Value & 0x7f;
Value >>= 7;
- if (Value != 0 || Padding != 0)
+ Count++;
+ if (Value != 0 || Count < PadTo)
Byte |= 0x80; // Mark this byte to show that more bytes will follow.
OS << char(Byte);
} while (Value != 0);
// Pad with 0x80 and emit a null byte at the end.
- if (Padding != 0) {
- for (; Padding != 1; --Padding)
+ if (Count < PadTo) {
+ for (; Count < PadTo - 1; ++Count)
OS << '\x80';
OS << '\x00';
+ Count++;
}
}
/// Utility function to encode a ULEB128 value to a buffer. Returns
/// the length in bytes of the encoded value.
inline unsigned encodeULEB128(uint64_t Value, uint8_t *p,
- unsigned Padding = 0) {
+ unsigned PadTo = 0) {
uint8_t *orig_p = p;
+ unsigned Count = 0;
do {
uint8_t Byte = Value & 0x7f;
Value >>= 7;
- if (Value != 0 || Padding != 0)
+ Count++;
+ if (Value != 0 || Count < PadTo)
Byte |= 0x80; // Mark this byte to show that more bytes will follow.
*p++ = Byte;
} while (Value != 0);
// Pad with 0x80 and emit a null byte at the end.
- if (Padding != 0) {
- for (; Padding != 1; --Padding)
+ if (Count < PadTo) {
+ for (; Count < PadTo - 1; ++Count)
*p++ = '\x80';
*p++ = '\x00';
}
+
return (unsigned)(p - orig_p);
}
diff --git a/include/llvm/Support/LockFileManager.h b/include/llvm/Support/LockFileManager.h
index 13d252425b93..1e417bdd5b25 100644
--- a/include/llvm/Support/LockFileManager.h
+++ b/include/llvm/Support/LockFileManager.h
@@ -11,6 +11,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
#include <system_error>
#include <utility> // for std::pair
@@ -53,10 +54,10 @@ public:
private:
SmallString<128> FileName;
SmallString<128> LockFileName;
- SmallString<128> UniqueLockFileName;
+ Optional<sys::fs::TempFile> UniqueLockFile;
Optional<std::pair<std::string, int> > Owner;
- Optional<std::error_code> Error;
+ std::error_code ErrorCode;
std::string ErrorDiagMsg;
LockFileManager(const LockFileManager &) = delete;
@@ -88,8 +89,8 @@ public:
std::string getErrorMessage() const;
/// \brief Set error and error message
- void setError(std::error_code &EC, StringRef ErrorMsg = "") {
- Error = EC;
+ void setError(const std::error_code &EC, StringRef ErrorMsg = "") {
+ ErrorCode = EC;
ErrorDiagMsg = ErrorMsg.str();
}
};
diff --git a/include/llvm/Support/LowLevelTypeImpl.h b/include/llvm/Support/LowLevelTypeImpl.h
index c79dd0c29507..099fa4618997 100644
--- a/include/llvm/Support/LowLevelTypeImpl.h
+++ b/include/llvm/Support/LowLevelTypeImpl.h
@@ -137,51 +137,6 @@ public:
return scalar(getScalarSizeInBits());
}
- /// Get a low-level type with half the size of the original, by halving the
- /// size of the scalar type involved. For example `s32` will become `s16`,
- /// `<2 x s32>` will become `<2 x s16>`.
- LLT halfScalarSize() const {
- assert(!IsPointer && getScalarSizeInBits() > 1 &&
- getScalarSizeInBits() % 2 == 0 && "cannot half size of this type");
- return LLT{/*isPointer=*/false, IsVector ? true : false,
- IsVector ? getNumElements() : (uint16_t)0,
- getScalarSizeInBits() / 2, /*AddressSpace=*/0};
- }
-
- /// Get a low-level type with twice the size of the original, by doubling the
- /// size of the scalar type involved. For example `s32` will become `s64`,
- /// `<2 x s32>` will become `<2 x s64>`.
- LLT doubleScalarSize() const {
- assert(!IsPointer && "cannot change size of this type");
- return LLT{/*isPointer=*/false, IsVector ? true : false,
- IsVector ? getNumElements() : (uint16_t)0,
- getScalarSizeInBits() * 2, /*AddressSpace=*/0};
- }
-
- /// Get a low-level type with half the size of the original, by halving the
- /// number of vector elements of the scalar type involved. The source must be
- /// a vector type with an even number of elements. For example `<4 x s32>`
- /// will become `<2 x s32>`, `<2 x s32>` will become `s32`.
- LLT halfElements() const {
- assert(isVector() && getNumElements() % 2 == 0 && "cannot half odd vector");
- if (getNumElements() == 2)
- return scalar(getScalarSizeInBits());
-
- return LLT{/*isPointer=*/false, /*isVector=*/true,
- (uint16_t)(getNumElements() / 2), getScalarSizeInBits(),
- /*AddressSpace=*/0};
- }
-
- /// Get a low-level type with twice the size of the original, by doubling the
- /// number of vector elements of the scalar type involved. The source must be
- /// a vector type. For example `<2 x s32>` will become `<4 x s32>`. Doubling
- /// the number of elements in sN produces <2 x sN>.
- LLT doubleElements() const {
- return LLT{IsPointer ? true : false, /*isVector=*/true,
- (uint16_t)(getNumElements() * 2), getScalarSizeInBits(),
- IsPointer ? getAddressSpace() : 0};
- }
-
void print(raw_ostream &OS) const;
bool operator==(const LLT &RHS) const {
diff --git a/include/llvm/Support/MathExtras.h b/include/llvm/Support/MathExtras.h
index fd29865c8475..a37a16784e2a 100644
--- a/include/llvm/Support/MathExtras.h
+++ b/include/llvm/Support/MathExtras.h
@@ -424,7 +424,7 @@ constexpr inline bool isPowerOf2_32(uint32_t Value) {
/// Return true if the argument is a power of two > 0 (64 bit edition.)
constexpr inline bool isPowerOf2_64(uint64_t Value) {
- return Value && !(Value & (Value - int64_t(1L)));
+ return Value && !(Value & (Value - 1));
}
/// Return a byte-swapped representation of the 16-bit argument.
@@ -687,6 +687,11 @@ template <uint64_t Align> constexpr inline uint64_t alignTo(uint64_t Value) {
return (Value + Align - 1) / Align * Align;
}
+/// Returns the integer ceil(Numerator / Denominator).
+inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
+ return alignTo(Numerator, Denominator) / Denominator;
+}
+
/// \c alignTo for contexts where a constant expression is required.
/// \sa alignTo
///
diff --git a/include/llvm/Support/Memory.h b/include/llvm/Support/Memory.h
index 8103aea2fa25..3140dc6eef42 100644
--- a/include/llvm/Support/Memory.h
+++ b/include/llvm/Support/Memory.h
@@ -109,51 +109,10 @@ namespace sys {
static std::error_code protectMappedMemory(const MemoryBlock &Block,
unsigned Flags);
- /// This method allocates a block of Read/Write/Execute memory that is
- /// suitable for executing dynamically generated code (e.g. JIT). An
- /// attempt to allocate \p NumBytes bytes of virtual memory is made.
- /// \p NearBlock may point to an existing allocation in which case
- /// an attempt is made to allocate more memory near the existing block.
- ///
- /// On success, this returns a non-null memory block, otherwise it returns
- /// a null memory block and fills in *ErrMsg.
- ///
- /// @brief Allocate Read/Write/Execute memory.
- static MemoryBlock AllocateRWX(size_t NumBytes,
- const MemoryBlock *NearBlock,
- std::string *ErrMsg = nullptr);
-
- /// This method releases a block of Read/Write/Execute memory that was
- /// allocated with the AllocateRWX method. It should not be used to
- /// release any memory block allocated any other way.
- ///
- /// On success, this returns false, otherwise it returns true and fills
- /// in *ErrMsg.
- /// @brief Release Read/Write/Execute memory.
- static bool ReleaseRWX(MemoryBlock &block, std::string *ErrMsg = nullptr);
-
/// InvalidateInstructionCache - Before the JIT can run a block of code
/// that has been emitted it must invalidate the instruction cache on some
/// platforms.
static void InvalidateInstructionCache(const void *Addr, size_t Len);
-
- /// setExecutable - Before the JIT can run a block of code, it has to be
- /// given read and executable privilege. Return true if it is already r-x
- /// or the system is able to change its previlege.
- static bool setExecutable(MemoryBlock &M, std::string *ErrMsg = nullptr);
-
- /// setWritable - When adding to a block of code, the JIT may need
- /// to mark a block of code as RW since the protections are on page
- /// boundaries, and the JIT internal allocations are not page aligned.
- static bool setWritable(MemoryBlock &M, std::string *ErrMsg = nullptr);
-
- /// setRangeExecutable - Mark the page containing a range of addresses
- /// as executable.
- static bool setRangeExecutable(const void *Addr, size_t Size);
-
- /// setRangeWritable - Mark the page containing a range of addresses
- /// as writable.
- static bool setRangeWritable(const void *Addr, size_t Size);
};
/// Owning version of MemoryBlock.
diff --git a/include/llvm/Support/MemoryBuffer.h b/include/llvm/Support/MemoryBuffer.h
index 73f0251a6b6e..59c93f15d7b8 100644
--- a/include/llvm/Support/MemoryBuffer.h
+++ b/include/llvm/Support/MemoryBuffer.h
@@ -136,7 +136,8 @@ public:
/// Map a subrange of the specified file as a MemoryBuffer.
static ErrorOr<std::unique_ptr<MemoryBuffer>>
- getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset, bool IsVolatile = false);
+ getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset,
+ bool IsVolatile = false);
//===--------------------------------------------------------------------===//
// Provided for performance analysis.
diff --git a/include/llvm/Support/Parallel.h b/include/llvm/Support/Parallel.h
index e36e0cc29e14..6bc0a6bbaf2b 100644
--- a/include/llvm/Support/Parallel.h
+++ b/include/llvm/Support/Parallel.h
@@ -158,11 +158,11 @@ void parallel_for_each(IterTy Begin, IterTy End, FuncTy Fn) {
TaskSize = 1;
TaskGroup TG;
- while (TaskSize <= std::distance(Begin, End)) {
+ while (TaskSize < std::distance(Begin, End)) {
TG.spawn([=, &Fn] { std::for_each(Begin, Begin + TaskSize, Fn); });
Begin += TaskSize;
}
- TG.spawn([=, &Fn] { std::for_each(Begin, End, Fn); });
+ std::for_each(Begin, End, Fn);
}
template <class IndexTy, class FuncTy>
@@ -179,10 +179,8 @@ void parallel_for_each_n(IndexTy Begin, IndexTy End, FuncTy Fn) {
Fn(J);
});
}
- TG.spawn([=, &Fn] {
- for (IndexTy J = I; J < End; ++J)
- Fn(J);
- });
+ for (IndexTy J = I; J < End; ++J)
+ Fn(J);
}
#endif
diff --git a/include/llvm/Support/PointerLikeTypeTraits.h b/include/llvm/Support/PointerLikeTypeTraits.h
index 521a49684e45..794230d606a4 100644
--- a/include/llvm/Support/PointerLikeTypeTraits.h
+++ b/include/llvm/Support/PointerLikeTypeTraits.h
@@ -22,11 +22,7 @@ namespace llvm {
/// A traits type that is used to handle pointer types and things that are just
/// wrappers for pointers as a uniform entity.
-template <typename T> class PointerLikeTypeTraits {
- // getAsVoidPointer
- // getFromVoidPointer
- // getNumLowBitsAvailable
-};
+template <typename T> struct PointerLikeTypeTraits;
namespace detail {
/// A tiny meta function to compute the log2 of a compile time constant.
@@ -34,19 +30,36 @@ template <size_t N>
struct ConstantLog2
: std::integral_constant<size_t, ConstantLog2<N / 2>::value + 1> {};
template <> struct ConstantLog2<1> : std::integral_constant<size_t, 0> {};
-}
+
+// Provide a trait to check if T is pointer-like.
+template <typename T, typename U = void> struct HasPointerLikeTypeTraits {
+ static const bool value = false;
+};
+
+// sizeof(T) is valid only for a complete T.
+template <typename T> struct HasPointerLikeTypeTraits<
+ T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> {
+ static const bool value = true;
+};
+
+template <typename T> struct IsPointerLike {
+ static const bool value = HasPointerLikeTypeTraits<T>::value;
+};
+
+template <typename T> struct IsPointerLike<T *> {
+ static const bool value = true;
+};
+} // namespace detail
// Provide PointerLikeTypeTraits for non-cvr pointers.
-template <typename T> class PointerLikeTypeTraits<T *> {
-public:
+template <typename T> struct PointerLikeTypeTraits<T *> {
static inline void *getAsVoidPointer(T *P) { return P; }
static inline T *getFromVoidPointer(void *P) { return static_cast<T *>(P); }
enum { NumLowBitsAvailable = detail::ConstantLog2<alignof(T)>::value };
};
-template <> class PointerLikeTypeTraits<void *> {
-public:
+template <> struct PointerLikeTypeTraits<void *> {
static inline void *getAsVoidPointer(void *P) { return P; }
static inline void *getFromVoidPointer(void *P) { return P; }
@@ -61,10 +74,9 @@ public:
};
// Provide PointerLikeTypeTraits for const things.
-template <typename T> class PointerLikeTypeTraits<const T> {
+template <typename T> struct PointerLikeTypeTraits<const T> {
typedef PointerLikeTypeTraits<T> NonConst;
-public:
static inline const void *getAsVoidPointer(const T P) {
return NonConst::getAsVoidPointer(P);
}
@@ -75,10 +87,9 @@ public:
};
// Provide PointerLikeTypeTraits for const pointers.
-template <typename T> class PointerLikeTypeTraits<const T *> {
+template <typename T> struct PointerLikeTypeTraits<const T *> {
typedef PointerLikeTypeTraits<T *> NonConst;
-public:
static inline const void *getAsVoidPointer(const T *P) {
return NonConst::getAsVoidPointer(const_cast<T *>(P));
}
@@ -89,8 +100,7 @@ public:
};
// Provide PointerLikeTypeTraits for uintptr_t.
-template <> class PointerLikeTypeTraits<uintptr_t> {
-public:
+template <> struct PointerLikeTypeTraits<uintptr_t> {
static inline void *getAsVoidPointer(uintptr_t P) {
return reinterpret_cast<void *>(P);
}
diff --git a/include/llvm/Support/Printable.h b/include/llvm/Support/Printable.h
index 28e875e8ff5e..cb55d41316e3 100644
--- a/include/llvm/Support/Printable.h
+++ b/include/llvm/Support/Printable.h
@@ -42,7 +42,7 @@ public:
: Print(std::move(Print)) {}
};
-static inline raw_ostream &operator<<(raw_ostream &OS, const Printable &P) {
+inline raw_ostream &operator<<(raw_ostream &OS, const Printable &P) {
P.Print(OS);
return OS;
}
diff --git a/include/llvm/Support/Process.h b/include/llvm/Support/Process.h
index 780c7e2ddd6f..82b0d9f6ba28 100644
--- a/include/llvm/Support/Process.h
+++ b/include/llvm/Support/Process.h
@@ -80,9 +80,15 @@ public:
/// This function searches for an existing file in the list of directories
/// in a PATH like environment variable, and returns the first file found,
/// according to the order of the entries in the PATH like environment
- /// variable.
- static Optional<std::string> FindInEnvPath(const std::string& EnvName,
- const std::string& FileName);
+ /// variable. If an ignore list is specified, then any folder which is in
+ /// the PATH like environment variable but is also in IgnoreList is not
+ /// considered.
+ static Optional<std::string> FindInEnvPath(StringRef EnvName,
+ StringRef FileName,
+ ArrayRef<std::string> IgnoreList);
+
+ static Optional<std::string> FindInEnvPath(StringRef EnvName,
+ StringRef FileName);
/// This function returns a SmallVector containing the arguments passed from
/// the operating system to the program. This function expects to be handed
diff --git a/include/llvm/Support/Program.h b/include/llvm/Support/Program.h
index 055f016d8243..06fd35078145 100644
--- a/include/llvm/Support/Program.h
+++ b/include/llvm/Support/Program.h
@@ -15,12 +15,12 @@
#define LLVM_SUPPORT_PROGRAM_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorOr.h"
#include <system_error>
namespace llvm {
-class StringRef;
-
namespace sys {
/// This is the OS-specific separator for PATH like environment variables:
@@ -69,7 +69,7 @@ struct ProcessInfo {
/// \returns The fully qualified path to the first \p Name in \p Paths if it
/// exists. \p Name if \p Name has slashes in it. Otherwise an error.
ErrorOr<std::string>
- findProgramByName(StringRef Name, ArrayRef<StringRef> Paths = None);
+ findProgramByName(StringRef Name, ArrayRef<StringRef> Paths = {});
// These functions change the specified standard stream (stdin or stdout) to
// binary mode. They return errc::success if the specified stream
@@ -84,33 +84,33 @@ struct ProcessInfo {
/// This function waits for the program to finish, so should be avoided in
/// library functions that aren't expected to block. Consider using
/// ExecuteNoWait() instead.
- /// @returns an integer result code indicating the status of the program.
+ /// \returns an integer result code indicating the status of the program.
/// A zero or positive value indicates the result code of the program.
/// -1 indicates failure to execute
/// -2 indicates a crash during execution or timeout
int ExecuteAndWait(
StringRef Program, ///< Path of the program to be executed. It is
///< presumed this is the result of the findProgramByName method.
- const char **args, ///< A vector of strings that are passed to the
+ const char **Args, ///< A vector of strings that are passed to the
///< program. The first element should be the name of the program.
///< The list *must* be terminated by a null char* entry.
- const char **env = nullptr, ///< An optional vector of strings to use for
+ const char **Env = nullptr, ///< An optional vector of strings to use for
///< the program's environment. If not provided, the current program's
///< environment will be used.
- const StringRef **redirects = nullptr, ///< An optional array of pointers
- ///< to paths. If the array is null, no redirection is done. The array
- ///< should have a size of at least three. The inferior process's
- ///< stdin(0), stdout(1), and stderr(2) will be redirected to the
- ///< corresponding paths.
- ///< When an empty path is passed in, the corresponding file
- ///< descriptor will be disconnected (ie, /dev/null'd) in a portable
- ///< way.
- unsigned secondsToWait = 0, ///< If non-zero, this specifies the amount
+ ArrayRef<Optional<StringRef>> Redirects = {}, ///<
+ ///< An array of optional paths. Should have a size of zero or three.
+ ///< If the array is empty, no redirections are performed.
+ ///< Otherwise, the inferior process's stdin(0), stdout(1), and stderr(2)
+ ///< will be redirected to the corresponding paths, if the optional path
+ ///< is present (not \c llvm::None).
+ ///< When an empty path is passed in, the corresponding file descriptor
+ ///< will be disconnected (ie, /dev/null'd) in a portable way.
+ unsigned SecondsToWait = 0, ///< If non-zero, this specifies the amount
///< of time to wait for the child process to exit. If the time
///< expires, the child is killed and this call returns. If zero,
///< this function will wait until the child finishes or forever if
///< it doesn't.
- unsigned memoryLimit = 0, ///< If non-zero, this specifies max. amount
+ unsigned MemoryLimit = 0, ///< If non-zero, this specifies max. amount
///< of memory can be allocated by process. If memory usage will be
///< higher limit, the child is killed and this call returns. If zero
///< - no memory limit.
@@ -122,17 +122,20 @@ struct ProcessInfo {
/// Similar to ExecuteAndWait, but returns immediately.
/// @returns The \see ProcessInfo of the newly launced process.
- /// \note On Microsoft Windows systems, users will need to either call \see
- /// Wait until the process finished execution or win32 CloseHandle() API on
- /// ProcessInfo.ProcessHandle to avoid memory leaks.
- ProcessInfo
- ExecuteNoWait(StringRef Program, const char **args, const char **env = nullptr,
- const StringRef **redirects = nullptr, unsigned memoryLimit = 0,
- std::string *ErrMsg = nullptr, bool *ExecutionFailed = nullptr);
+ /// \note On Microsoft Windows systems, users will need to either call
+ /// \see Wait until the process finished execution or win32 CloseHandle() API
+ /// on ProcessInfo.ProcessHandle to avoid memory leaks.
+ ProcessInfo ExecuteNoWait(StringRef Program, const char **Args,
+ const char **Env = nullptr,
+ ArrayRef<Optional<StringRef>> Redirects = {},
+ unsigned MemoryLimit = 0,
+ std::string *ErrMsg = nullptr,
+ bool *ExecutionFailed = nullptr);
/// Return true if the given arguments fit within system-specific
/// argument length limits.
- bool commandLineFitsWithinSystemLimits(StringRef Program, ArrayRef<const char*> Args);
+ bool commandLineFitsWithinSystemLimits(StringRef Program,
+ ArrayRef<const char *> Args);
/// File encoding options when writing contents that a non-UTF8 tool will
/// read (on Windows systems). For UNIX, we always use UTF-8.
diff --git a/include/llvm/Support/ReverseIteration.h b/include/llvm/Support/ReverseIteration.h
index cb97b60f06dd..5e0238d81c4c 100644
--- a/include/llvm/Support/ReverseIteration.h
+++ b/include/llvm/Support/ReverseIteration.h
@@ -2,16 +2,18 @@
#define LLVM_SUPPORT_REVERSEITERATION_H
#include "llvm/Config/abi-breaking.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
namespace llvm {
-#if LLVM_ENABLE_ABI_BREAKING_CHECKS
-template <class T = void> struct ReverseIterate { static bool value; };
+
+template<class T = void *>
+bool shouldReverseIterate() {
#if LLVM_ENABLE_REVERSE_ITERATION
-template <class T> bool ReverseIterate<T>::value = true;
+ return detail::IsPointerLike<T>::value;
#else
-template <class T> bool ReverseIterate<T>::value = false;
-#endif
+ return false;
#endif
}
+}
#endif
diff --git a/include/llvm/Support/ScaledNumber.h b/include/llvm/Support/ScaledNumber.h
index 910174732994..cfbdbc751617 100644
--- a/include/llvm/Support/ScaledNumber.h
+++ b/include/llvm/Support/ScaledNumber.h
@@ -504,13 +504,13 @@ private:
static_assert(Width <= 64, "invalid integer width for digits");
private:
- DigitsType Digits;
- int16_t Scale;
+ DigitsType Digits = 0;
+ int16_t Scale = 0;
public:
- ScaledNumber() : Digits(0), Scale(0) {}
+ ScaledNumber() = default;
- ScaledNumber(DigitsType Digits, int16_t Scale)
+ constexpr ScaledNumber(DigitsType Digits, int16_t Scale)
: Digits(Digits), Scale(Scale) {}
private:
diff --git a/include/llvm/Support/SourceMgr.h b/include/llvm/Support/SourceMgr.h
index 399f8dcd76fc..c08bf858760a 100644
--- a/include/llvm/Support/SourceMgr.h
+++ b/include/llvm/Support/SourceMgr.h
@@ -43,7 +43,8 @@ public:
enum DiagKind {
DK_Error,
DK_Warning,
- DK_Note
+ DK_Remark,
+ DK_Note,
};
/// Clients that want to handle their own diagnostics in a custom way can
diff --git a/include/llvm/Support/SpecialCaseList.h b/include/llvm/Support/SpecialCaseList.h
index ce693c501312..fd62fc48047b 100644
--- a/include/llvm/Support/SpecialCaseList.h
+++ b/include/llvm/Support/SpecialCaseList.h
@@ -8,15 +8,19 @@
//
// This is a utility class used to parse user-provided text files with
// "special case lists" for code sanitizers. Such files are used to
-// define "ABI list" for DataFlowSanitizer and blacklists for another sanitizers
+// define an "ABI list" for DataFlowSanitizer and blacklists for sanitizers
// like AddressSanitizer or UndefinedBehaviorSanitizer.
//
-// Empty lines and lines starting with "#" are ignored. All the rest lines
-// should have the form:
-// section:wildcard_expression[=category]
+// Empty lines and lines starting with "#" are ignored. Sections are defined
+// using a '[section_name]' header and can be used to specify sanitizers the
+// entries below it apply to. Section names are regular expressions, and
+// entries without a section header match all sections (e.g. an '[*]' header
+// is assumed.)
+// The remaining lines should have the form:
+// prefix:wildcard_expression[=category]
// If category is not specified, it is assumed to be empty string.
-// Definitions of "section" and "category" are sanitizer-specific. For example,
-// sanitizer blacklists support sections "src", "fun" and "global".
+// Definitions of "prefix" and "category" are sanitizer-specific. For example,
+// sanitizer blacklists support prefixes "src", "fun" and "global".
// Wildcard expressions define, respectively, source files, functions or
// globals which shouldn't be instrumented.
// Examples of categories:
@@ -26,6 +30,7 @@
// detection for certain globals or source files.
// Full special case list file example:
// ---
+// [address]
// # Blacklisted items:
// fun:*_ZN4base6subtle*
// global:*global_with_bad_access_or_initialization*
@@ -34,14 +39,13 @@
// src:file_with_tricky_code.cc
// src:ignore-global-initializers-issues.cc=init
//
+// [dataflow]
// # Functions with pure functional semantics:
// fun:cos=functional
// fun:sin=functional
// ---
// Note that the wild card is in fact an llvm::Regex, but * is automatically
// replaced with .*
-// This is similar to the "ignore" feature of ThreadSanitizer.
-// http://code.google.com/p/data-race-test/wiki/ThreadSanitizerIgnores
//
//===----------------------------------------------------------------------===//
@@ -49,6 +53,9 @@
#define LLVM_SUPPORT_SPECIALCASELIST_H
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/TrigramIndex.h"
#include <string>
#include <vector>
@@ -76,26 +83,70 @@ public:
/// Returns true, if special case list contains a line
/// \code
- /// @Section:<E>=@Category
+ /// @Prefix:<E>=@Category
/// \endcode
- /// and @Query satisfies a wildcard expression <E>.
- bool inSection(StringRef Section, StringRef Query,
+ /// where @Query satisfies wildcard expression <E> in a given @Section.
+ bool inSection(StringRef Section, StringRef Prefix, StringRef Query,
StringRef Category = StringRef()) const;
-private:
+ /// Returns the line number corresponding to the special case list entry if
+ /// the special case list contains a line
+ /// \code
+ /// @Prefix:<E>=@Category
+ /// \endcode
+ /// where @Query satisfies wildcard expression <E> in a given @Section.
+ /// Returns zero if there is no blacklist entry corresponding to this
+ /// expression.
+ unsigned inSectionBlame(StringRef Section, StringRef Prefix, StringRef Query,
+ StringRef Category = StringRef()) const;
+
+protected:
+ // Implementations of the create*() functions that can also be used by derived
+ // classes.
+ bool createInternal(const std::vector<std::string> &Paths,
+ std::string &Error);
+ bool createInternal(const MemoryBuffer *MB, std::string &Error);
+
+ SpecialCaseList() = default;
SpecialCaseList(SpecialCaseList const &) = delete;
SpecialCaseList &operator=(SpecialCaseList const &) = delete;
- struct Entry;
- StringMap<StringMap<Entry>> Entries;
- StringMap<StringMap<std::string>> Regexps;
- bool IsCompiled;
+ /// Represents a set of regular expressions. Regular expressions which are
+ /// "literal" (i.e. no regex metacharacters) are stored in Strings. The
+ /// reason for doing so is efficiency; StringMap is much faster at matching
+ /// literal strings than Regex.
+ class Matcher {
+ public:
+ bool insert(std::string Regexp, unsigned LineNumber, std::string &REError);
+ // Returns the line number in the source file that this query matches to.
+ // Returns zero if no match is found.
+ unsigned match(StringRef Query) const;
+
+ private:
+ StringMap<unsigned> Strings;
+ TrigramIndex Trigrams;
+ std::vector<std::pair<std::unique_ptr<Regex>, unsigned>> RegExes;
+ };
+
+ using SectionEntries = StringMap<StringMap<Matcher>>;
+
+ struct Section {
+ Section(std::unique_ptr<Matcher> M) : SectionMatcher(std::move(M)){};
+
+ std::unique_ptr<Matcher> SectionMatcher;
+ SectionEntries Entries;
+ };
+
+ std::vector<Section> Sections;
- SpecialCaseList();
/// Parses just-constructed SpecialCaseList entries from a memory buffer.
- bool parse(const MemoryBuffer *MB, std::string &Error);
- /// compile() should be called once, after parsing all the memory buffers.
- void compile();
+ bool parse(const MemoryBuffer *MB, StringMap<size_t> &SectionsMap,
+ std::string &Error);
+
+ // Helper method for derived classes to search by Prefix, Query, and Category
+ // once they have already resolved a section entry.
+ unsigned inSectionBlame(const SectionEntries &Entries, StringRef Prefix,
+ StringRef Query, StringRef Category) const;
};
} // namespace llvm
diff --git a/include/llvm/Support/TarWriter.h b/include/llvm/Support/TarWriter.h
index 44bdcaf2c465..639f61b53892 100644
--- a/include/llvm/Support/TarWriter.h
+++ b/include/llvm/Support/TarWriter.h
@@ -11,6 +11,7 @@
#define LLVM_SUPPORT_TAR_WRITER_H
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/raw_ostream.h"
@@ -26,6 +27,7 @@ private:
TarWriter(int FD, StringRef BaseDir);
raw_fd_ostream OS;
std::string BaseDir;
+ StringSet<> Files;
};
}
diff --git a/include/llvm/Support/TargetParser.h b/include/llvm/Support/TargetParser.h
index e13582f6a6d3..13b7befb8ce4 100644
--- a/include/llvm/Support/TargetParser.h
+++ b/include/llvm/Support/TargetParser.h
@@ -31,61 +31,61 @@ class StringRef;
// back-end to TableGen to create these clean tables.
namespace ARM {
-// 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
};
-// FPU Version
-enum FPUVersion {
- FV_NONE = 0,
- FV_VFPV2,
- FV_VFPV3,
- FV_VFPV3_FP16,
- FV_VFPV4,
- FV_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 NeonSupportLevel {
- NS_None = 0, ///< No Neon
- NS_Neon, ///< Neon
- NS_Crypto ///< Neon with Crypto
+enum class NeonSupportLevel {
+ None = 0, ///< No Neon
+ Neon, ///< Neon
+ Crypto ///< Neon with Crypto
};
-// An FPU name restricts the FPU in one of three ways:
-enum FPURestriction {
- FR_None = 0, ///< No restriction
- FR_D16, ///< Only 16 D registers
- FR_SP_D16 ///< Only single-precision instructions, with 16 D registers
+// FPU names.
+enum FPUKind {
+#define ARM_FPU(NAME, KIND, VERSION, NEON_SUPPORT, RESTRICTION) KIND,
+#include "ARMTargetParser.def"
+ FK_LAST
};
// Arch names.
-enum ArchKind {
+enum class ArchKind {
#define ARM_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) ID,
#include "ARMTargetParser.def"
- AK_LAST
};
// Arch extension modifiers for CPUs.
enum ArchExtKind : unsigned {
- AEK_INVALID = 0x0,
- AEK_NONE = 0x1,
- AEK_CRC = 0x2,
- AEK_CRYPTO = 0x4,
- AEK_FP = 0x8,
- AEK_HWDIVTHUMB = 0x10,
- AEK_HWDIVARM = 0x20,
- AEK_MP = 0x40,
- AEK_SIMD = 0x80,
- AEK_SEC = 0x100,
- AEK_VIRT = 0x200,
- AEK_DSP = 0x400,
- AEK_FP16 = 0x800,
- AEK_RAS = 0x1000,
- AEK_SVE = 0x2000,
+ 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,
// Unsupported extensions.
AEK_OS = 0x8000000,
AEK_IWMMXT = 0x10000000,
@@ -95,22 +95,22 @@ enum ArchExtKind : unsigned {
};
// ISA kinds.
-enum ISAKind { IK_INVALID = 0, IK_ARM, IK_THUMB, IK_AARCH64 };
+enum class ISAKind { INVALID = 0, ARM, THUMB, AARCH64 };
// Endianness
// FIXME: BE8 vs. BE32?
-enum EndianKind { EK_INVALID = 0, EK_LITTLE, EK_BIG };
+enum class EndianKind { INVALID = 0, LITTLE, BIG };
// v6/v7/v8 Profile
-enum ProfileKind { PK_INVALID = 0, PK_A, PK_R, PK_M };
+enum class ProfileKind { INVALID = 0, A, R, M };
StringRef getCanonicalArchName(StringRef Arch);
// Information by ID
StringRef getFPUName(unsigned FPUKind);
-unsigned getFPUVersion(unsigned FPUKind);
-unsigned getFPUNeonSupportLevel(unsigned FPUKind);
-unsigned getFPURestriction(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);
@@ -118,28 +118,28 @@ bool getHWDivFeatures(unsigned HWDivKind, std::vector<StringRef> &Features);
bool getExtensionFeatures(unsigned Extensions,
std::vector<StringRef> &Features);
-StringRef getArchName(unsigned ArchKind);
-unsigned getArchAttr(unsigned ArchKind);
-StringRef getCPUAttr(unsigned ArchKind);
-StringRef getSubArch(unsigned ArchKind);
+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, unsigned ArchKind);
-unsigned getDefaultExtensions(StringRef CPU, unsigned ArchKind);
+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);
-unsigned parseArch(StringRef Arch);
+ArchKind parseArch(StringRef Arch);
unsigned parseArchExt(StringRef ArchExt);
-unsigned parseCPUArch(StringRef CPU);
-unsigned parseArchISA(StringRef Arch);
-unsigned parseArchEndian(StringRef Arch);
-unsigned parseArchProfile(StringRef Arch);
+ArchKind parseCPUArch(StringRef CPU);
+ISAKind parseArchISA(StringRef Arch);
+EndianKind parseArchEndian(StringRef Arch);
+ProfileKind parseArchProfile(StringRef Arch);
unsigned parseArchVersion(StringRef Arch);
StringRef computeDefaultTargetABI(const Triple &TT, StringRef CPU);
@@ -153,62 +153,108 @@ namespace AArch64 {
enum class ArchKind {
#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) ID,
#include "AArch64TargetParser.def"
- AK_LAST
};
// Arch extension modifiers for CPUs.
enum ArchExtKind : unsigned {
- AEK_INVALID = 0x0,
- AEK_NONE = 0x1,
- AEK_CRC = 0x2,
- AEK_CRYPTO = 0x4,
- AEK_FP = 0x8,
- AEK_SIMD = 0x10,
- AEK_FP16 = 0x20,
- AEK_PROFILE = 0x40,
- AEK_RAS = 0x80,
- AEK_LSE = 0x100,
- AEK_SVE = 0x200
+ 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
};
StringRef getCanonicalArchName(StringRef Arch);
// Information by ID
StringRef getFPUName(unsigned FPUKind);
-unsigned getFPUVersion(unsigned FPUKind);
-unsigned getFPUNeonSupportLevel(unsigned FPUKind);
-unsigned getFPURestriction(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(unsigned ArchKind, std::vector<StringRef> &Features);
+bool getArchFeatures(ArchKind AK, std::vector<StringRef> &Features);
-StringRef getArchName(unsigned ArchKind);
-unsigned getArchAttr(unsigned ArchKind);
-StringRef getCPUAttr(unsigned ArchKind);
-StringRef getSubArch(unsigned ArchKind);
+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, unsigned ArchKind);
-unsigned getDefaultExtensions(StringRef CPU, unsigned ArchKind);
+unsigned getDefaultFPU(StringRef CPU, ArchKind AK);
+unsigned getDefaultExtensions(StringRef CPU, ArchKind AK);
StringRef getDefaultCPU(StringRef Arch);
// Parser
unsigned parseFPU(StringRef FPU);
-unsigned parseArch(StringRef Arch);
+AArch64::ArchKind parseArch(StringRef Arch);
unsigned parseArchExt(StringRef ArchExt);
-unsigned parseCPUArch(StringRef CPU);
-unsigned parseArchISA(StringRef Arch);
-unsigned parseArchEndian(StringRef Arch);
-unsigned parseArchProfile(StringRef Arch);
+ArchKind parseCPUArch(StringRef CPU);
+ARM::ISAKind parseArchISA(StringRef Arch);
+ARM::EndianKind parseArchEndian(StringRef Arch);
+ARM::ProfileKind parseArchProfile(StringRef Arch);
unsigned parseArchVersion(StringRef Arch);
} // namespace AArch64
+
+namespace X86 {
+
+// This should be kept in sync with libcc/compiler-rt as its included by clang
+// as a proxy for what's in libgcc/compiler-rt.
+enum ProcessorVendors : unsigned {
+ VENDOR_DUMMY,
+#define X86_VENDOR(ENUM, STRING) \
+ ENUM,
+#include "llvm/Support/X86TargetParser.def"
+ VENDOR_OTHER
+};
+
+// This should be kept in sync with libcc/compiler-rt as its included by clang
+// as a proxy for what's in libgcc/compiler-rt.
+enum ProcessorTypes : unsigned {
+ CPU_TYPE_DUMMY,
+#define X86_CPU_TYPE(ARCHNAME, ENUM) \
+ ENUM,
+#include "llvm/Support/X86TargetParser.def"
+ CPU_TYPE_MAX
+};
+
+// This should be kept in sync with libcc/compiler-rt as its included by clang
+// as a proxy for what's in libgcc/compiler-rt.
+enum ProcessorSubtypes : unsigned {
+ CPU_SUBTYPE_DUMMY,
+#define X86_CPU_SUBTYPE(ARCHNAME, ENUM) \
+ ENUM,
+#include "llvm/Support/X86TargetParser.def"
+ CPU_SUBTYPE_MAX
+};
+
+// This should be kept in sync with libcc/compiler-rt as it should be used
+// by clang as a proxy for what's in libgcc/compiler-rt.
+enum ProcessorFeatures {
+#define X86_FEATURE(VAL, ENUM) \
+ ENUM = VAL,
+#include "llvm/Support/X86TargetParser.def"
+
+};
+
+} // namespace X86
+
} // namespace llvm
#endif
diff --git a/include/llvm/Support/TargetRegistry.h b/include/llvm/Support/TargetRegistry.h
index 8454b27b6f04..bd096e2f74f6 100644
--- a/include/llvm/Support/TargetRegistry.h
+++ b/include/llvm/Support/TargetRegistry.h
@@ -67,15 +67,21 @@ MCStreamer *createAsmStreamer(MCContext &Ctx,
MCAsmBackend *TAB, bool ShowInst);
/// Takes ownership of \p TAB and \p CE.
-MCStreamer *createELFStreamer(MCContext &Ctx, MCAsmBackend &TAB,
- raw_pwrite_stream &OS, MCCodeEmitter *CE,
+MCStreamer *createELFStreamer(MCContext &Ctx,
+ std::unique_ptr<MCAsmBackend> &&TAB,
+ raw_pwrite_stream &OS,
+ std::unique_ptr<MCCodeEmitter> &&CE,
bool RelaxAll);
-MCStreamer *createMachOStreamer(MCContext &Ctx, MCAsmBackend &TAB,
- raw_pwrite_stream &OS, MCCodeEmitter *CE,
+MCStreamer *createMachOStreamer(MCContext &Ctx,
+ std::unique_ptr<MCAsmBackend> &&TAB,
+ raw_pwrite_stream &OS,
+ std::unique_ptr<MCCodeEmitter> &&CE,
bool RelaxAll, bool DWARFMustBeAtTheEnd,
bool LabelSections = false);
-MCStreamer *createWasmStreamer(MCContext &Ctx, MCAsmBackend &TAB,
- raw_pwrite_stream &OS, MCCodeEmitter *CE,
+MCStreamer *createWasmStreamer(MCContext &Ctx,
+ std::unique_ptr<MCAsmBackend> &&TAB,
+ raw_pwrite_stream &OS,
+ std::unique_ptr<MCCodeEmitter> &&CE,
bool RelaxAll);
MCRelocationInfo *createMCRelocationInfo(const Triple &TT, MCContext &Ctx);
@@ -101,19 +107,16 @@ public:
using MCAsmInfoCtorFnTy = MCAsmInfo *(*)(const MCRegisterInfo &MRI,
const Triple &TT);
- using MCAdjustCodeGenOptsFnTy = void (*)(const Triple &TT, Reloc::Model RM,
- CodeModel::Model &CM);
-
using MCInstrInfoCtorFnTy = MCInstrInfo *(*)();
using MCInstrAnalysisCtorFnTy = MCInstrAnalysis *(*)(const MCInstrInfo *Info);
using MCRegInfoCtorFnTy = MCRegisterInfo *(*)(const Triple &TT);
using MCSubtargetInfoCtorFnTy = MCSubtargetInfo *(*)(const Triple &TT,
StringRef CPU,
StringRef Features);
- using TargetMachineCtorTy = TargetMachine *(*)(
- const Target &T, const Triple &TT, StringRef CPU, StringRef Features,
- const TargetOptions &Options, Optional<Reloc::Model> RM,
- CodeModel::Model CM, CodeGenOpt::Level OL);
+ using TargetMachineCtorTy = TargetMachine
+ *(*)(const Target &T, const Triple &TT, StringRef CPU, StringRef Features,
+ const TargetOptions &Options, Optional<Reloc::Model> RM,
+ Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT);
// If it weren't for layering issues (this header is in llvm/Support, but
// depends on MC?) this should take the Streamer by value rather than rvalue
// reference.
@@ -137,26 +140,26 @@ public:
using MCCodeEmitterCtorTy = MCCodeEmitter *(*)(const MCInstrInfo &II,
const MCRegisterInfo &MRI,
MCContext &Ctx);
- using ELFStreamerCtorTy = MCStreamer *(*)(const Triple &T, MCContext &Ctx,
- MCAsmBackend &TAB,
- raw_pwrite_stream &OS,
- MCCodeEmitter *Emitter,
- bool RelaxAll);
- using MachOStreamerCtorTy = MCStreamer *(*)(MCContext &Ctx, MCAsmBackend &TAB,
- raw_pwrite_stream &OS,
- MCCodeEmitter *Emitter,
- bool RelaxAll,
- bool DWARFMustBeAtTheEnd);
- using COFFStreamerCtorTy = MCStreamer *(*)(MCContext &Ctx, MCAsmBackend &TAB,
- raw_pwrite_stream &OS,
- MCCodeEmitter *Emitter,
- bool RelaxAll,
- bool IncrementalLinkerCompatible);
- using WasmStreamerCtorTy = MCStreamer *(*)(const Triple &T, MCContext &Ctx,
- MCAsmBackend &TAB,
- raw_pwrite_stream &OS,
- MCCodeEmitter *Emitter,
- bool RelaxAll);
+ using ELFStreamerCtorTy =
+ MCStreamer *(*)(const Triple &T, MCContext &Ctx,
+ std::unique_ptr<MCAsmBackend> &&TAB,
+ raw_pwrite_stream &OS,
+ std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll);
+ using MachOStreamerCtorTy =
+ MCStreamer *(*)(MCContext &Ctx, std::unique_ptr<MCAsmBackend> &&TAB,
+ raw_pwrite_stream &OS,
+ std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll,
+ bool DWARFMustBeAtTheEnd);
+ using COFFStreamerCtorTy =
+ MCStreamer *(*)(MCContext &Ctx, std::unique_ptr<MCAsmBackend> &&TAB,
+ raw_pwrite_stream &OS,
+ std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll,
+ bool IncrementalLinkerCompatible);
+ using WasmStreamerCtorTy =
+ MCStreamer *(*)(const Triple &T, MCContext &Ctx,
+ std::unique_ptr<MCAsmBackend> &&TAB,
+ raw_pwrite_stream &OS,
+ std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll);
using NullTargetStreamerCtorTy = MCTargetStreamer *(*)(MCStreamer &S);
using AsmTargetStreamerCtorTy = MCTargetStreamer *(*)(
MCStreamer &S, formatted_raw_ostream &OS, MCInstPrinter *InstPrint,
@@ -184,6 +187,10 @@ private:
/// ShortDesc - A short description of the target.
const char *ShortDesc;
+ /// BackendName - The name of the backend implementation. This must match the
+ /// name of the 'def X : Target ...' in TableGen.
+ const char *BackendName;
+
/// HasJIT - Whether this target supports the JIT.
bool HasJIT;
@@ -191,8 +198,6 @@ private:
/// registered.
MCAsmInfoCtorFnTy MCAsmInfoCtorFn;
- MCAdjustCodeGenOptsFnTy MCAdjustCodeGenOptsFn;
-
/// MCInstrInfoCtorFn - Constructor function for this target's MCInstrInfo,
/// if registered.
MCInstrInfoCtorFnTy MCInstrInfoCtorFn;
@@ -278,6 +283,9 @@ public:
/// getShortDescription - Get a short description of the target.
const char *getShortDescription() const { return ShortDesc; }
+ /// getBackendName - Get the backend name.
+ const char *getBackendName() const { return BackendName; }
+
/// @}
/// @name Feature Predicates
/// @{
@@ -312,12 +320,6 @@ public:
return MCAsmInfoCtorFn(MRI, Triple(TheTriple));
}
- void adjustCodeGenOpts(const Triple &TT, Reloc::Model RM,
- CodeModel::Model &CM) const {
- if (MCAdjustCodeGenOptsFn)
- MCAdjustCodeGenOptsFn(TT, RM, CM);
- }
-
/// createMCInstrInfo - Create a MCInstrInfo implementation.
///
MCInstrInfo *createMCInstrInfo() const {
@@ -365,15 +367,17 @@ public:
/// feature set; it should always be provided. Generally this should be
/// either the target triple from the module, or the target triple of the
/// host if that does not exist.
- TargetMachine *
- createTargetMachine(StringRef TT, StringRef CPU, StringRef Features,
- const TargetOptions &Options, Optional<Reloc::Model> RM,
- CodeModel::Model CM = CodeModel::Default,
- CodeGenOpt::Level OL = CodeGenOpt::Default) const {
+ TargetMachine *createTargetMachine(StringRef TT, StringRef CPU,
+ StringRef Features,
+ const TargetOptions &Options,
+ Optional<Reloc::Model> RM,
+ Optional<CodeModel::Model> CM = None,
+ CodeGenOpt::Level OL = CodeGenOpt::Default,
+ bool JIT = false) const {
if (!TargetMachineCtorFn)
return nullptr;
return TargetMachineCtorFn(*this, Triple(TT), CPU, Features, Options, RM,
- CM, OL);
+ CM, OL, JIT);
}
/// createMCAsmBackend - Create a target specific assembly parser.
@@ -444,8 +448,9 @@ public:
/// \param Emitter The target independent assembler object.Takes ownership.
/// \param RelaxAll Relax all fixups?
MCStreamer *createMCObjectStreamer(const Triple &T, MCContext &Ctx,
- MCAsmBackend &TAB, raw_pwrite_stream &OS,
- MCCodeEmitter *Emitter,
+ std::unique_ptr<MCAsmBackend> &&TAB,
+ raw_pwrite_stream &OS,
+ std::unique_ptr<MCCodeEmitter> &&Emitter,
const MCSubtargetInfo &STI, bool RelaxAll,
bool IncrementalLinkerCompatible,
bool DWARFMustBeAtTheEnd) const {
@@ -455,28 +460,32 @@ public:
llvm_unreachable("Unknown object format");
case Triple::COFF:
assert(T.isOSWindows() && "only Windows COFF is supported");
- S = COFFStreamerCtorFn(Ctx, TAB, OS, Emitter, RelaxAll,
- IncrementalLinkerCompatible);
+ S = COFFStreamerCtorFn(Ctx, std::move(TAB), OS, std::move(Emitter),
+ RelaxAll, IncrementalLinkerCompatible);
break;
case Triple::MachO:
if (MachOStreamerCtorFn)
- S = MachOStreamerCtorFn(Ctx, TAB, OS, Emitter, RelaxAll,
- DWARFMustBeAtTheEnd);
+ S = MachOStreamerCtorFn(Ctx, std::move(TAB), OS, std::move(Emitter),
+ RelaxAll, DWARFMustBeAtTheEnd);
else
- S = createMachOStreamer(Ctx, TAB, OS, Emitter, RelaxAll,
- DWARFMustBeAtTheEnd);
+ S = createMachOStreamer(Ctx, std::move(TAB), OS, std::move(Emitter),
+ RelaxAll, DWARFMustBeAtTheEnd);
break;
case Triple::ELF:
if (ELFStreamerCtorFn)
- S = ELFStreamerCtorFn(T, Ctx, TAB, OS, Emitter, RelaxAll);
+ S = ELFStreamerCtorFn(T, Ctx, std::move(TAB), OS, std::move(Emitter),
+ RelaxAll);
else
- S = createELFStreamer(Ctx, TAB, OS, Emitter, RelaxAll);
+ S = createELFStreamer(Ctx, std::move(TAB), OS, std::move(Emitter),
+ RelaxAll);
break;
case Triple::Wasm:
if (WasmStreamerCtorFn)
- S = WasmStreamerCtorFn(T, Ctx, TAB, OS, Emitter, RelaxAll);
+ S = WasmStreamerCtorFn(T, Ctx, std::move(TAB), OS, std::move(Emitter),
+ RelaxAll);
else
- S = createWasmStreamer(Ctx, TAB, OS, Emitter, RelaxAll);
+ S = createWasmStreamer(Ctx, std::move(TAB), OS, std::move(Emitter),
+ RelaxAll);
break;
}
if (ObjectTargetStreamerCtorFn)
@@ -599,7 +608,7 @@ struct TargetRegistry {
/// printRegisteredTargetsForVersion - Print the registered targets
/// appropriately for inclusion in a tool's version output.
- static void printRegisteredTargetsForVersion();
+ static void printRegisteredTargetsForVersion(raw_ostream &OS);
/// @name Registry Access
/// @{
@@ -643,10 +652,15 @@ struct TargetRegistry {
/// @param Name - The target name. This should be a static string.
/// @param ShortDesc - A short target description. This should be a static
/// string.
+ /// @param BackendName - The name of the backend. This should be a static
+ /// string that is the same for all targets that share a backend
+ /// implementation and must match the name used in the 'def X : Target ...' in
+ /// TableGen.
/// @param ArchMatchFn - The arch match checking function for this target.
/// @param HasJIT - Whether the target supports JIT code
/// generation.
static void RegisterTarget(Target &T, const char *Name, const char *ShortDesc,
+ const char *BackendName,
Target::ArchMatchFnTy ArchMatchFn,
bool HasJIT = false);
@@ -663,11 +677,6 @@ struct TargetRegistry {
T.MCAsmInfoCtorFn = Fn;
}
- static void registerMCAdjustCodeGenOpts(Target &T,
- Target::MCAdjustCodeGenOptsFnTy Fn) {
- T.MCAdjustCodeGenOptsFn = Fn;
- }
-
/// RegisterMCInstrInfo - Register a MCInstrInfo implementation for the
/// given target.
///
@@ -881,13 +890,15 @@ struct TargetRegistry {
/// }
/// extern "C" void LLVMInitializeFooTargetInfo() {
/// RegisterTarget<Triple::foo> X(getTheFooTarget(), "foo", "Foo
-/// description");
+/// description", "Foo" /* Backend Name */);
/// }
template <Triple::ArchType TargetArchType = Triple::UnknownArch,
bool HasJIT = false>
struct RegisterTarget {
- RegisterTarget(Target &T, const char *Name, const char *Desc) {
- TargetRegistry::RegisterTarget(T, Name, Desc, &getArchMatch, HasJIT);
+ RegisterTarget(Target &T, const char *Name, const char *Desc,
+ const char *BackendName) {
+ TargetRegistry::RegisterTarget(T, Name, Desc, BackendName, &getArchMatch,
+ HasJIT);
}
static bool getArchMatch(Triple::ArchType Arch) {
@@ -929,12 +940,6 @@ struct RegisterMCAsmInfoFn {
}
};
-struct RegisterMCAdjustCodeGenOptsFn {
- RegisterMCAdjustCodeGenOptsFn(Target &T, Target::MCAdjustCodeGenOptsFnTy Fn) {
- TargetRegistry::registerMCAdjustCodeGenOpts(T, Fn);
- }
-};
-
/// RegisterMCInstrInfo - Helper template for registering a target instruction
/// info implementation. This invokes the static "Create" method on the class
/// to actually do the construction. Usage:
@@ -1080,12 +1085,11 @@ template <class TargetMachineImpl> struct RegisterTargetMachine {
}
private:
- static TargetMachine *Allocator(const Target &T, const Triple &TT,
- StringRef CPU, StringRef FS,
- const TargetOptions &Options,
- Optional<Reloc::Model> RM,
- CodeModel::Model CM, CodeGenOpt::Level OL) {
- return new TargetMachineImpl(T, TT, CPU, FS, Options, RM, CM, OL);
+ static TargetMachine *
+ Allocator(const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
+ const TargetOptions &Options, Optional<Reloc::Model> RM,
+ Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT) {
+ return new TargetMachineImpl(T, TT, CPU, FS, Options, RM, CM, OL, JIT);
}
};
diff --git a/include/llvm/Support/ThreadPool.h b/include/llvm/Support/ThreadPool.h
index 9ada946c6dae..fb8255900510 100644
--- a/include/llvm/Support/ThreadPool.h
+++ b/include/llvm/Support/ThreadPool.h
@@ -38,8 +38,8 @@ public:
using TaskTy = std::function<void()>;
using PackagedTaskTy = std::packaged_task<void()>;
- /// Construct a pool with the number of core available on the system (or
- /// whatever the value returned by std::thread::hardware_concurrency() is).
+ /// Construct a pool with the number of threads found by
+ /// hardware_concurrency().
ThreadPool();
/// Construct a pool of \p ThreadCount threads
diff --git a/include/llvm/Support/Threading.h b/include/llvm/Support/Threading.h
index 03963a24c107..6d813bccb93f 100644
--- a/include/llvm/Support/Threading.h
+++ b/include/llvm/Support/Threading.h
@@ -131,6 +131,14 @@ void llvm_execute_on_thread(void (*UserFn)(void *), void *UserData,
/// Returns 1 when LLVM is configured with LLVM_ENABLE_THREADS=OFF
unsigned heavyweight_hardware_concurrency();
+ /// Get the number of threads that the current program can execute
+ /// concurrently. On some systems std::thread::hardware_concurrency() returns
+ /// the total number of cores, without taking affinity into consideration.
+ /// Returns 1 when LLVM is configured with LLVM_ENABLE_THREADS=OFF.
+ /// Fallback to std::thread::hardware_concurrency() if sched_getaffinity is
+ /// not available.
+ unsigned hardware_concurrency();
+
/// \brief Return the current thread id, as used in various OS system calls.
/// Note that not all platforms guarantee that the value returned will be
/// unique across the entire system, so portable code should not assume
diff --git a/include/llvm/Support/ToolOutputFile.h b/include/llvm/Support/ToolOutputFile.h
index 1be26c2cb58b..b41ca5a6edaa 100644
--- a/include/llvm/Support/ToolOutputFile.h
+++ b/include/llvm/Support/ToolOutputFile.h
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines the tool_output_file class.
+// This file defines the ToolOutputFile class.
//
//===----------------------------------------------------------------------===//
@@ -21,9 +21,9 @@ namespace llvm {
/// This class contains a raw_fd_ostream and adds a few extra features commonly
/// needed for compiler-like tool output files:
/// - The file is automatically deleted if the process is killed.
-/// - The file is automatically deleted when the tool_output_file
+/// - The file is automatically deleted when the ToolOutputFile
/// object is destroyed unless the client calls keep().
-class tool_output_file {
+class ToolOutputFile {
/// This class is declared before the raw_fd_ostream so that it is constructed
/// before the raw_fd_ostream is constructed and destructed after the
/// raw_fd_ostream is destructed. It installs cleanups in its constructor and
@@ -45,10 +45,10 @@ class tool_output_file {
public:
/// This constructor's arguments are passed to to raw_fd_ostream's
/// constructor.
- tool_output_file(StringRef Filename, std::error_code &EC,
- sys::fs::OpenFlags Flags);
+ ToolOutputFile(StringRef Filename, std::error_code &EC,
+ sys::fs::OpenFlags Flags);
- tool_output_file(StringRef Filename, int FD);
+ ToolOutputFile(StringRef Filename, int FD);
/// Return the contained raw_fd_ostream.
raw_fd_ostream &os() { return OS; }
diff --git a/include/llvm/Support/X86TargetParser.def b/include/llvm/Support/X86TargetParser.def
new file mode 100644
index 000000000000..5c8c576b1027
--- /dev/null
+++ b/include/llvm/Support/X86TargetParser.def
@@ -0,0 +1,155 @@
+//===- X86TargetParser.def - X86 target parsing defines ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides defines to build up the X86 target parser's logic.
+//
+//===----------------------------------------------------------------------===//
+
+// NOTE: NO INCLUDE GUARD DESIRED!
+
+#ifndef X86_VENDOR
+#define X86_VENDOR(ENUM, STR)
+#endif
+X86_VENDOR(VENDOR_INTEL, "intel")
+X86_VENDOR(VENDOR_AMD, "amd")
+#undef X86_VENDOR
+
+// This macro is used to implement CPU types that have an alias. As of now
+// there is only ever one alias.
+#ifndef X86_CPU_TYPE_COMPAT_WITH_ALIAS
+#define X86_CPU_TYPE_COMPAT_WITH_ALIAS(ARCHNAME, ENUM, STR, ALIAS) X86_CPU_TYPE_COMPAT(ARCHNAME, ENUM, STR)
+#endif
+
+// This macro is used for cpu types present in compiler-rt/libgcc.
+#ifndef X86_CPU_TYPE_COMPAT
+#define X86_CPU_TYPE_COMPAT(ARCHNAME, ENUM, STR) X86_CPU_TYPE(ARCHNAME, ENUM)
+#endif
+
+#ifndef X86_CPU_TYPE
+#define X86_CPU_TYPE(ARCHNAME, ENUM)
+#endif
+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")
+// Entries below this are not in libgcc/compiler-rt.
+X86_CPU_TYPE ("i386", INTEL_i386)
+X86_CPU_TYPE ("i486", INTEL_i486)
+X86_CPU_TYPE ("pentium", INTEL_PENTIUM)
+X86_CPU_TYPE ("pentium-mmx", INTEL_PENTIUM_MMX)
+X86_CPU_TYPE ("pentiumpro", INTEL_PENTIUM_PRO)
+X86_CPU_TYPE ("pentium2", INTEL_PENTIUM_II)
+X86_CPU_TYPE ("pentium3", INTEL_PENTIUM_III)
+X86_CPU_TYPE ("pentium4", INTEL_PENTIUM_IV)
+X86_CPU_TYPE ("pentium-m", INTEL_PENTIUM_M)
+X86_CPU_TYPE ("yonah", INTEL_CORE_DUO)
+X86_CPU_TYPE ("nocona", INTEL_NOCONA)
+X86_CPU_TYPE ("prescott", INTEL_PRESCOTT)
+X86_CPU_TYPE ("i486", AMD_i486)
+X86_CPU_TYPE ("pentium", AMDPENTIUM)
+X86_CPU_TYPE ("athlon", AMD_ATHLON)
+X86_CPU_TYPE ("athlon-xp", AMD_ATHLON_XP)
+X86_CPU_TYPE ("k8", AMD_K8)
+X86_CPU_TYPE ("k8-sse3", AMD_K8SSE3)
+X86_CPU_TYPE ("goldmont", INTEL_GOLDMONT)
+#undef X86_CPU_TYPE_COMPAT_WITH_ALIAS
+#undef X86_CPU_TYPE_COMPAT
+#undef X86_CPU_TYPE
+
+// This macro is used for cpu subtypes present in compiler-rt/libgcc.
+#ifndef X86_CPU_SUBTYPE_COMPAT
+#define X86_CPU_SUBTYPE_COMPAT(ARCHNAME, ENUM, STR) X86_CPU_SUBTYPE(ARCHNAME, ENUM)
+#endif
+
+#ifndef X86_CPU_SUBTYPE
+#define X86_CPU_SUBTYPE(ARCHNAME, ENUM)
+#endif
+
+X86_CPU_SUBTYPE_COMPAT("nehalem", INTEL_COREI7_NEHALEM, "nehalem")
+X86_CPU_SUBTYPE_COMPAT("westmere", INTEL_COREI7_WESTMERE, "westmere")
+X86_CPU_SUBTYPE_COMPAT("sandybridge", INTEL_COREI7_SANDYBRIDGE, "sandybridge")
+X86_CPU_SUBTYPE_COMPAT("amdfam10", AMDFAM10H_BARCELONA, "barcelona")
+X86_CPU_SUBTYPE_COMPAT("amdfam10", AMDFAM10H_SHANGHAI, "shanghai")
+X86_CPU_SUBTYPE_COMPAT("amdfam10", AMDFAM10H_ISTANBUL, "istanbul")
+X86_CPU_SUBTYPE_COMPAT("bdver1", AMDFAM15H_BDVER1, "bdver1")
+X86_CPU_SUBTYPE_COMPAT("bdver2", AMDFAM15H_BDVER2, "bdver2")
+X86_CPU_SUBTYPE_COMPAT("bdver3", AMDFAM15H_BDVER3, "bdver3")
+X86_CPU_SUBTYPE_COMPAT("bdver4", AMDFAM15H_BDVER4, "bdver4")
+X86_CPU_SUBTYPE_COMPAT("znver1", AMDFAM17H_ZNVER1, "znver1")
+X86_CPU_SUBTYPE_COMPAT("ivybridge", INTEL_COREI7_IVYBRIDGE, "ivybridge")
+X86_CPU_SUBTYPE_COMPAT("haswell", INTEL_COREI7_HASWELL, "haswell")
+X86_CPU_SUBTYPE_COMPAT("broadwell", INTEL_COREI7_BROADWELL, "broadwell")
+X86_CPU_SUBTYPE_COMPAT("skylake", INTEL_COREI7_SKYLAKE, "skylake")
+X86_CPU_SUBTYPE_COMPAT("skylake-avx512", INTEL_COREI7_SKYLAKE_AVX512, "skylake-avx512")
+X86_CPU_SUBTYPE_COMPAT("cannonlake", INTEL_COREI7_CANNONLAKE, "cannonlake")
+// Entries below this are not in libgcc/compiler-rt.
+X86_CPU_SUBTYPE ("core2", INTEL_CORE2_65)
+X86_CPU_SUBTYPE ("penryn", INTEL_CORE2_45)
+X86_CPU_SUBTYPE ("k6", AMDPENTIUM_K6)
+X86_CPU_SUBTYPE ("k6-2", AMDPENTIUM_K62)
+X86_CPU_SUBTYPE ("k6-3", AMDPENTIUM_K63)
+X86_CPU_SUBTYPE ("geode", AMDPENTIUM_GEODE)
+#undef X86_CPU_SUBTYPE_COMPAT
+#undef X86_CPU_SUBTYPE
+
+
+// This macro is used for cpu types present in compiler-rt/libgcc.
+#ifndef X86_FEATURE_COMPAT
+#define X86_FEATURE_COMPAT(VAL, ENUM, STR) X86_FEATURE(VAL, ENUM)
+#endif
+
+#ifndef X86_FEATURE
+#define X86_FEATURE(VAL, ENUM)
+#endif
+X86_FEATURE_COMPAT( 0, FEATURE_CMOV, "cmov")
+X86_FEATURE_COMPAT( 1, FEATURE_MMX, "mmx")
+X86_FEATURE_COMPAT( 2, FEATURE_POPCNT, "popcnt")
+X86_FEATURE_COMPAT( 3, FEATURE_SSE, "sse")
+X86_FEATURE_COMPAT( 4, FEATURE_SSE2, "sse2")
+X86_FEATURE_COMPAT( 5, FEATURE_SSE3, "sse3")
+X86_FEATURE_COMPAT( 6, FEATURE_SSSE3, "ssse3")
+X86_FEATURE_COMPAT( 7, FEATURE_SSE4_1, "sse4.1")
+X86_FEATURE_COMPAT( 8, FEATURE_SSE4_2, "sse4.2")
+X86_FEATURE_COMPAT( 9, FEATURE_AVX, "avx")
+X86_FEATURE_COMPAT(10, FEATURE_AVX2, "avx2")
+X86_FEATURE_COMPAT(11, FEATURE_SSE4_A, "sse4a")
+X86_FEATURE_COMPAT(12, FEATURE_FMA4, "fma4")
+X86_FEATURE_COMPAT(13, FEATURE_XOP, "xop")
+X86_FEATURE_COMPAT(14, FEATURE_FMA, "fma")
+X86_FEATURE_COMPAT(15, FEATURE_AVX512F, "avx512f")
+X86_FEATURE_COMPAT(16, FEATURE_BMI, "bmi")
+X86_FEATURE_COMPAT(17, FEATURE_BMI2, "bmi2")
+X86_FEATURE_COMPAT(18, FEATURE_AES, "aes")
+X86_FEATURE_COMPAT(19, FEATURE_PCLMUL, "pclmul")
+X86_FEATURE_COMPAT(20, FEATURE_AVX512VL, "avx512vl")
+X86_FEATURE_COMPAT(21, FEATURE_AVX512BW, "avx512bw")
+X86_FEATURE_COMPAT(22, FEATURE_AVX512DQ, "avx512dq")
+X86_FEATURE_COMPAT(23, FEATURE_AVX512CD, "avx512cd")
+X86_FEATURE_COMPAT(24, FEATURE_AVX512ER, "avx512er")
+X86_FEATURE_COMPAT(25, FEATURE_AVX512PF, "avx512pf")
+X86_FEATURE_COMPAT(26, FEATURE_AVX512VBMI, "avx512vbmi")
+X86_FEATURE_COMPAT(27, FEATURE_AVX512IFMA, "avx512ifma")
+X86_FEATURE_COMPAT(28, FEATURE_AVX5124VNNIW, "avx5124vnniw")
+X86_FEATURE_COMPAT(29, FEATURE_AVX5124FMAPS, "avx5124fmaps")
+X86_FEATURE_COMPAT(30, FEATURE_AVX512VPOPCNTDQ, "avx512vpopcntdq")
+// 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)
+#undef X86_FEATURE_COMPAT
+#undef X86_FEATURE
diff --git a/include/llvm/Support/YAMLParser.h b/include/llvm/Support/YAMLParser.h
index 549da3ccad51..c907a99ddb59 100644
--- a/include/llvm/Support/YAMLParser.h
+++ b/include/llvm/Support/YAMLParser.h
@@ -291,9 +291,11 @@ public:
Node *getValue();
void skip() override {
- getKey()->skip();
- if (Node *Val = getValue())
- Val->skip();
+ if (Node *Key = getKey()) {
+ Key->skip();
+ if (Node *Val = getValue())
+ Val->skip();
+ }
}
static bool classof(const Node *N) {
@@ -572,13 +574,15 @@ public:
document_iterator() = default;
document_iterator(std::unique_ptr<Document> &D) : Doc(&D) {}
- bool operator==(const document_iterator &Other) {
+ bool operator==(const document_iterator &Other) const {
if (isAtEnd() || Other.isAtEnd())
return isAtEnd() && Other.isAtEnd();
return Doc == Other.Doc;
}
- bool operator!=(const document_iterator &Other) { return !(*this == Other); }
+ bool operator!=(const document_iterator &Other) const {
+ return !(*this == Other);
+ }
document_iterator operator++() {
assert(Doc && "incrementing iterator past the end.");
diff --git a/include/llvm/Support/YAMLTraits.h b/include/llvm/Support/YAMLTraits.h
index 71fdf47f1979..83b097a199d6 100644
--- a/include/llvm/Support/YAMLTraits.h
+++ b/include/llvm/Support/YAMLTraits.h
@@ -12,6 +12,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@@ -117,6 +118,11 @@ struct ScalarBitSetTraits {
// static void bitset(IO &io, T &value);
};
+/// Describe which type of quotes should be used when quoting is necessary.
+/// Some non-printable characters need to be double-quoted, while some others
+/// are fine with simple-quoting, and some don't need any quoting.
+enum class QuotingType { None, Single, Double };
+
/// This class should be specialized by type that requires custom conversion
/// to/from a yaml scalar. For example:
///
@@ -131,7 +137,7 @@ struct ScalarBitSetTraits {
/// // return empty string on success, or error string
/// return StringRef();
/// }
-/// static bool mustQuote(StringRef) { return true; }
+/// static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
/// };
template<typename T>
struct ScalarTraits {
@@ -145,7 +151,7 @@ struct ScalarTraits {
//static StringRef input(StringRef scalar, void *ctxt, T &value);
//
// Function to determine if the value should be quoted.
- //static bool mustQuote(StringRef);
+ //static QuotingType mustQuote(StringRef);
};
/// This class should be specialized by type that requires custom conversion
@@ -270,7 +276,7 @@ struct has_ScalarTraits
{
using Signature_input = StringRef (*)(StringRef, void*, T&);
using Signature_output = void (*)(const T&, void*, raw_ostream&);
- using Signature_mustQuote = bool (*)(StringRef);
+ using Signature_mustQuote = QuotingType (*)(StringRef);
template <typename U>
static char test(SameType<Signature_input, &U::input> *,
@@ -495,28 +501,66 @@ inline bool isBool(StringRef S) {
S.equals("false") || S.equals("False") || S.equals("FALSE");
}
-inline bool needsQuotes(StringRef S) {
+// 5.1. Character Set
+// The allowed character range explicitly excludes the C0 control block #x0-#x1F
+// (except for TAB #x9, LF #xA, and CR #xD which are allowed), DEL #x7F, the C1
+// control block #x80-#x9F (except for NEL #x85 which is allowed), the surrogate
+// block #xD800-#xDFFF, #xFFFE, and #xFFFF.
+inline QuotingType needsQuotes(StringRef S) {
if (S.empty())
- return true;
+ return QuotingType::Single;
if (isspace(S.front()) || isspace(S.back()))
- return true;
+ return QuotingType::Single;
if (S.front() == ',')
- return true;
-
- static const char ScalarSafeChars[] =
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-/^., \t";
- if (S.find_first_not_of(ScalarSafeChars) != StringRef::npos)
- return true;
-
+ return QuotingType::Single;
if (isNull(S))
- return true;
+ return QuotingType::Single;
if (isBool(S))
- return true;
+ return QuotingType::Single;
if (isNumeric(S))
- return true;
+ return QuotingType::Single;
+
+ QuotingType MaxQuotingNeeded = QuotingType::None;
+ for (unsigned char C : S) {
+ // Alphanum is safe.
+ if (isAlnum(C))
+ continue;
+
+ switch (C) {
+ // Safe scalar characters.
+ case '_':
+ case '-':
+ case '/':
+ case '^':
+ case '.':
+ case ',':
+ case ' ':
+ // TAB (0x9), LF (0xA), CR (0xD) and NEL (0x85) are allowed.
+ case 0x9:
+ case 0xA:
+ case 0xD:
+ case 0x85:
+ continue;
+ // DEL (0x7F) are excluded from the allowed character range.
+ case 0x7F:
+ return QuotingType::Double;
+ default: {
+ // C0 control block (0x0 - 0x1F) is excluded from the allowed character
+ // range.
+ if (C <= 0x1F)
+ return QuotingType::Double;
+ // C1 control block (0x80 - 0x9F) is excluded from the allowed character
+ // range.
+ if (C >= 0x80 && C <= 0x9F)
+ return QuotingType::Double;
+
+ // The character is not safe, at least simple quoting needed.
+ MaxQuotingNeeded = QuotingType::Single;
+ }
+ }
+ }
- return false;
+ return MaxQuotingNeeded;
}
template <typename T, typename Context>
@@ -581,7 +625,7 @@ public:
virtual bool bitSetMatch(const char*, bool) = 0;
virtual void endBitSetScalar() = 0;
- virtual void scalarString(StringRef &, bool) = 0;
+ virtual void scalarString(StringRef &, QuotingType) = 0;
virtual void blockScalarString(StringRef &) = 0;
virtual void setError(const Twine &) = 0;
@@ -911,91 +955,91 @@ template<>
struct ScalarTraits<bool> {
static void output(const bool &, void* , raw_ostream &);
static StringRef input(StringRef, void *, bool &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<StringRef> {
static void output(const StringRef &, void *, raw_ostream &);
static StringRef input(StringRef, void *, StringRef &);
- static bool mustQuote(StringRef S) { return needsQuotes(S); }
+ static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
};
template<>
struct ScalarTraits<std::string> {
static void output(const std::string &, void *, raw_ostream &);
static StringRef input(StringRef, void *, std::string &);
- static bool mustQuote(StringRef S) { return needsQuotes(S); }
+ static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
};
template<>
struct ScalarTraits<uint8_t> {
static void output(const uint8_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, uint8_t &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<uint16_t> {
static void output(const uint16_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, uint16_t &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<uint32_t> {
static void output(const uint32_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, uint32_t &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<uint64_t> {
static void output(const uint64_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, uint64_t &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<int8_t> {
static void output(const int8_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, int8_t &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<int16_t> {
static void output(const int16_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, int16_t &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<int32_t> {
static void output(const int32_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, int32_t &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<int64_t> {
static void output(const int64_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, int64_t &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<float> {
static void output(const float &, void *, raw_ostream &);
static StringRef input(StringRef, void *, float &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<double> {
static void output(const double &, void *, raw_ostream &);
static StringRef input(StringRef, void *, double &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
// For endian types, we just use the existing ScalarTraits for the underlying
@@ -1019,7 +1063,7 @@ struct ScalarTraits<support::detail::packed_endian_specific_integral<
return R;
}
- static bool mustQuote(StringRef Str) {
+ static QuotingType mustQuote(StringRef Str) {
return ScalarTraits<value_type>::mustQuote(Str);
}
};
@@ -1148,7 +1192,7 @@ private:
bool beginBitSetScalar(bool &) override;
bool bitSetMatch(const char *, bool ) override;
void endBitSetScalar() override;
- void scalarString(StringRef &, bool) override;
+ void scalarString(StringRef &, QuotingType) override;
void blockScalarString(StringRef &) override;
void setError(const Twine &message) override;
bool canElideEmptySequence() override;
@@ -1293,7 +1337,7 @@ public:
bool beginBitSetScalar(bool &) override;
bool bitSetMatch(const char *, bool ) override;
void endBitSetScalar() override;
- void scalarString(StringRef &, bool) override;
+ void scalarString(StringRef &, QuotingType) override;
void blockScalarString(StringRef &) override;
void setError(const Twine &message) override;
bool canElideEmptySequence() override;
@@ -1371,28 +1415,28 @@ template<>
struct ScalarTraits<Hex8> {
static void output(const Hex8 &, void *, raw_ostream &);
static StringRef input(StringRef, void *, Hex8 &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<Hex16> {
static void output(const Hex16 &, void *, raw_ostream &);
static StringRef input(StringRef, void *, Hex16 &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<Hex32> {
static void output(const Hex32 &, void *, raw_ostream &);
static StringRef input(StringRef, void *, Hex32 &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<Hex64> {
static void output(const Hex64 &, void *, raw_ostream &);
static StringRef input(StringRef, void *, Hex64 &);
- static bool mustQuote(StringRef) { return false; }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
// Define non-member operator>> so that Input can stream in a document list.
@@ -1681,7 +1725,7 @@ template <typename T> struct StdMapStringCustomMappingTraitsImpl {
template <> struct ScalarTraits<Type> { \
static void output(const Type &Value, void *ctx, raw_ostream &Out); \
static StringRef input(StringRef Scalar, void *ctxt, Type &Value); \
- static bool mustQuote(StringRef) { return MustQuote; } \
+ static QuotingType mustQuote(StringRef) { return MustQuote; } \
}; \
} \
}
diff --git a/include/llvm/Support/raw_ostream.h b/include/llvm/Support/raw_ostream.h
index e644a5bda5ef..d11f5a837796 100644
--- a/include/llvm/Support/raw_ostream.h
+++ b/include/llvm/Support/raw_ostream.h
@@ -213,6 +213,10 @@ public:
/// Output \p N in hexadecimal, without any prefix or padding.
raw_ostream &write_hex(unsigned long long N);
+ /// Output a formatted UUID with dash separators.
+ using uuid_t = uint8_t[16];
+ raw_ostream &write_uuid(const uuid_t UUID);
+
/// Output \p Str, turning '\\', '\t', '\n', '"', and anything that doesn't
/// satisfy std::isprint into an escape sequence.
raw_ostream &write_escaped(StringRef Str, bool UseHexEscapes = false);
@@ -358,9 +362,7 @@ class raw_fd_ostream : public raw_pwrite_stream {
int FD;
bool ShouldClose;
- /// Error This flag is true if an error of any kind has been detected.
- ///
- bool Error;
+ std::error_code EC;
uint64_t pos;
@@ -379,7 +381,7 @@ class raw_fd_ostream : public raw_pwrite_stream {
size_t preferred_buffer_size() const override;
/// Set the flag indicating that an output error has been encountered.
- void error_detected() { Error = true; }
+ void error_detected(std::error_code EC) { this->EC = EC; }
public:
/// Open the specified file for writing. If an error occurs, information
@@ -388,15 +390,14 @@ public:
/// \p Flags allows optional flags to control how the file will be opened.
///
/// As a special case, if Filename is "-", then the stream will use
- /// STDOUT_FILENO instead of opening a file. Note that it will still consider
- /// itself to own the file descriptor. In particular, it will close the
- /// file descriptor when it is done (this is necessary to detect
- /// output errors).
+ /// STDOUT_FILENO instead of opening a file. This will not close the stdout
+ /// descriptor.
raw_fd_ostream(StringRef Filename, std::error_code &EC,
sys::fs::OpenFlags Flags);
/// FD is the file descriptor that this writes to. If ShouldClose is true,
- /// this closes the file when the stream is destroyed.
+ /// this closes the file when the stream is destroyed. If FD is for stdout or
+ /// stderr, it will not be closed.
raw_fd_ostream(int fd, bool shouldClose, bool unbuffered=false);
~raw_fd_ostream() override;
@@ -421,13 +422,13 @@ public:
bool has_colors() const override;
+ std::error_code error() const { return EC; }
+
/// Return the value of the flag in this raw_fd_ostream indicating whether an
/// output error has been encountered.
/// This doesn't implicitly flush any pending output. Also, it doesn't
/// guarantee to detect all errors unless the stream has been closed.
- bool has_error() const {
- return Error;
- }
+ bool has_error() const { return bool(EC); }
/// Set the flag read by has_error() to false. If the error flag is set at the
/// time when this raw_ostream's destructor is called, report_fatal_error is
@@ -438,9 +439,7 @@ public:
/// Unless explicitly silenced."
/// - from The Zen of Python, by Tim Peters
///
- void clear_error() {
- Error = false;
- }
+ void clear_error() { EC = std::error_code(); }
};
/// This returns a reference to a raw_ostream for standard output. Use it like: