summaryrefslogtreecommitdiff
path: root/include/llvm/Support
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/Support')
-rw-r--r--include/llvm/Support/AArch64TargetParser.def13
-rw-r--r--include/llvm/Support/ARMAttributeParser.h140
-rw-r--r--include/llvm/Support/ARMBuildAttributes.h14
-rw-r--r--include/llvm/Support/ARMTargetParser.def6
-rw-r--r--include/llvm/Support/Allocator.h50
-rw-r--r--include/llvm/Support/Atomic.h5
-rw-r--r--include/llvm/Support/BinaryByteStream.h192
-rw-r--r--include/llvm/Support/BinaryItemStream.h95
-rw-r--r--include/llvm/Support/BinaryStream.h78
-rw-r--r--include/llvm/Support/BinaryStreamArray.h320
-rw-r--r--include/llvm/Support/BinaryStreamError.h48
-rw-r--r--include/llvm/Support/BinaryStreamReader.h234
-rw-r--r--include/llvm/Support/BinaryStreamRef.h174
-rw-r--r--include/llvm/Support/BinaryStreamWriter.h166
-rw-r--r--include/llvm/Support/CMakeLists.txt54
-rw-r--r--include/llvm/Support/CachePruning.h79
-rw-r--r--include/llvm/Support/Casting.h70
-rw-r--r--include/llvm/Support/Chrono.h95
-rw-r--r--include/llvm/Support/CommandLine.h8
-rw-r--r--include/llvm/Support/Compiler.h7
-rw-r--r--include/llvm/Support/Compression.h24
-rw-r--r--include/llvm/Support/Debug.h28
-rw-r--r--include/llvm/Support/DebugCounter.h165
-rw-r--r--include/llvm/Support/Dwarf.def87
-rw-r--r--include/llvm/Support/Dwarf.h13
-rw-r--r--include/llvm/Support/DynamicLibrary.h9
-rw-r--r--include/llvm/Support/ELF.h36
-rw-r--r--include/llvm/Support/Endian.h89
-rw-r--r--include/llvm/Support/Error.h102
-rw-r--r--include/llvm/Support/FileSystem.h274
-rw-r--r--include/llvm/Support/FormatAdapters.h3
-rw-r--r--include/llvm/Support/FormatProviders.h22
-rw-r--r--include/llvm/Support/FormatVariadic.h2
-rw-r--r--include/llvm/Support/GCOV.h67
-rw-r--r--include/llvm/Support/GenericDomTree.h76
-rw-r--r--include/llvm/Support/GenericDomTreeConstruction.h142
-rw-r--r--include/llvm/Support/Host.h12
-rw-r--r--include/llvm/Support/LEB128.h72
-rw-r--r--include/llvm/Support/LowLevelTypeImpl.h202
-rw-r--r--include/llvm/Support/MD5.h59
-rw-r--r--include/llvm/Support/MachO.def4
-rw-r--r--include/llvm/Support/MachO.h102
-rw-r--r--include/llvm/Support/MathExtras.h4
-rw-r--r--include/llvm/Support/MemoryBuffer.h20
-rw-r--r--include/llvm/Support/Path.h80
-rw-r--r--include/llvm/Support/PointerLikeTypeTraits.h14
-rw-r--r--include/llvm/Support/RWMutex.h25
-rw-r--r--include/llvm/Support/SMLoc.h4
-rw-r--r--include/llvm/Support/SourceMgr.h57
-rw-r--r--include/llvm/Support/TargetParser.h2
-rw-r--r--include/llvm/Support/TargetRegistry.h71
-rw-r--r--include/llvm/Support/ThreadPool.h15
-rw-r--r--include/llvm/Support/Threading.h104
-rw-r--r--include/llvm/Support/Timer.h4
-rw-r--r--include/llvm/Support/TrailingObjects.h7
-rw-r--r--include/llvm/Support/UniqueLock.h18
-rw-r--r--include/llvm/Support/Wasm.h145
-rw-r--r--include/llvm/Support/WasmRelocs/WebAssembly.def13
-rw-r--r--include/llvm/Support/YAMLTraits.h15
-rw-r--r--include/llvm/Support/thread.h14
-rw-r--r--include/llvm/Support/type_traits.h9
61 files changed, 3457 insertions, 602 deletions
diff --git a/include/llvm/Support/AArch64TargetParser.def b/include/llvm/Support/AArch64TargetParser.def
index c4416f099de1a..46d253bf0ec77 100644
--- a/include/llvm/Support/AArch64TargetParser.def
+++ b/include/llvm/Support/AArch64TargetParser.def
@@ -73,8 +73,17 @@ AARCH64_CPU_NAME("falkor", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO))
AARCH64_CPU_NAME("kryo", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO))
-AARCH64_CPU_NAME("vulcan", AK_ARMV8_1A, FK_CRYPTO_NEON_FP_ARMV8, false,
- (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO))
+AARCH64_CPU_NAME("thunderx2t99", AK_ARMV8_1A, FK_CRYPTO_NEON_FP_ARMV8, false,
+ (AArch64::AEK_SIMD | AArch64::AEK_LSE | AArch64::AEK_CRC |
+ AArch64::AEK_CRYPTO))
+AARCH64_CPU_NAME("thunderx", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+ (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_PROFILE))
+AARCH64_CPU_NAME("thunderxt88", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+ (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_PROFILE))
+AARCH64_CPU_NAME("thunderxt81", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+ (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_PROFILE))
+AARCH64_CPU_NAME("thunderxt83", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+ (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_PROFILE))
// Invalid CPU
AARCH64_CPU_NAME("invalid", AK_INVALID, FK_INVALID, true, AArch64::AEK_INVALID)
#undef AARCH64_CPU_NAME
diff --git a/include/llvm/Support/ARMAttributeParser.h b/include/llvm/Support/ARMAttributeParser.h
new file mode 100644
index 0000000000000..919f39721f866
--- /dev/null
+++ b/include/llvm/Support/ARMAttributeParser.h
@@ -0,0 +1,140 @@
+//===--- ARMAttributeParser.h - ARM Attribute Information Printer ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ARMATTRIBUTEPARSER_H
+#define LLVM_SUPPORT_ARMATTRIBUTEPARSER_H
+
+#include "ARMBuildAttributes.h"
+#include "ScopedPrinter.h"
+
+#include <map>
+
+namespace llvm {
+class StringRef;
+
+class ARMAttributeParser {
+ ScopedPrinter *SW;
+
+ std::map<unsigned, unsigned> Attributes;
+
+ struct DisplayHandler {
+ ARMBuildAttrs::AttrType Attribute;
+ void (ARMAttributeParser::*Routine)(ARMBuildAttrs::AttrType,
+ const uint8_t *, uint32_t &);
+ };
+ static const DisplayHandler DisplayRoutines[];
+
+ uint64_t ParseInteger(const uint8_t *Data, uint32_t &Offset);
+ StringRef ParseString(const uint8_t *Data, uint32_t &Offset);
+
+ void IntegerAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void StringAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+
+ void PrintAttribute(unsigned Tag, unsigned Value, StringRef ValueDesc);
+
+ void CPU_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void CPU_arch_profile(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ARM_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void THUMB_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void FP_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void WMMX_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void Advanced_SIMD_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void PCS_config(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_PCS_R9_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_PCS_RW_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_PCS_RO_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_PCS_GOT_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_PCS_wchar_t(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_FP_rounding(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_FP_denormal(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_FP_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_FP_user_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_FP_number_model(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_align_needed(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_align_preserved(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_enum_size(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_HardFP_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_VFP_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_WMMX_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_optimization_goals(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_FP_optimization_goals(ARMBuildAttrs::AttrType Tag,
+ const uint8_t *Data, uint32_t &Offset);
+ void compatibility(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void CPU_unaligned_access(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void FP_HP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_FP_16bit_format(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void MPextension_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void DIV_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void DSP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void T2EE_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void Virtualization_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void nodefaults(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+
+ void ParseAttributeList(const uint8_t *Data, uint32_t &Offset,
+ uint32_t Length);
+ void ParseIndexList(const uint8_t *Data, uint32_t &Offset,
+ SmallVectorImpl<uint8_t> &IndexList);
+ void ParseSubsection(const uint8_t *Data, uint32_t Length);
+public:
+ ARMAttributeParser(ScopedPrinter *SW) : SW(SW) {}
+
+ ARMAttributeParser() : SW(nullptr) { }
+
+ void Parse(ArrayRef<uint8_t> Section, bool isLittle);
+
+ bool hasAttribute(unsigned Tag) const {
+ return Attributes.count(Tag);
+ }
+
+ unsigned getAttributeValue(unsigned Tag) const {
+ return Attributes.find(Tag)->second;
+ }
+};
+
+}
+
+#endif
+
diff --git a/include/llvm/Support/ARMBuildAttributes.h b/include/llvm/Support/ARMBuildAttributes.h
index e25445790b0c8..6c83e447cb245 100644
--- a/include/llvm/Support/ARMBuildAttributes.h
+++ b/include/llvm/Support/ARMBuildAttributes.h
@@ -176,14 +176,25 @@ enum {
WCharWidth2Bytes = 2, // sizeof(wchar_t) == 2
WCharWidth4Bytes = 4, // sizeof(wchar_t) == 4
+ // Tag_ABI_align_needed, (=24), uleb128
+ Align8Byte = 1,
+ Align4Byte = 2,
+ AlignReserved = 3,
+
+ // Tag_ABI_align_needed, (=25), uleb128
+ AlignNotPreserved = 0,
+ AlignPreserve8Byte = 1,
+ AlignPreserveAll = 2,
+
// Tag_ABI_FP_denormal, (=20), uleb128
PositiveZero = 0,
IEEEDenormals = 1,
PreserveFPSign = 2, // sign when flushed-to-zero is preserved
// Tag_ABI_FP_number_model, (=23), uleb128
+ AllowIEEENormal = 1,
AllowRTABI = 2, // numbers, infinities, and one quiet NaN (see [RTABI])
- AllowIEE754 = 3, // this code to use all the IEEE 754-defined FP encodings
+ AllowIEEE754 = 3, // this code to use all the IEEE 754-defined FP encodings
// Tag_ABI_enum_size, (=26), uleb128
EnumProhibited = 0, // The user prohibited the use of enums when building
@@ -208,6 +219,7 @@ enum {
// Tag_FP_16bit_format, (=38), uleb128
FP16FormatIEEE = 1,
+ FP16VFP3 = 2,
// Tag_MPextension_use, (=42), uleb128
AllowMP = 1, // Allow use of MP extensions
diff --git a/include/llvm/Support/ARMTargetParser.def b/include/llvm/Support/ARMTargetParser.def
index 58cb6381a9aba..18bf9af432262 100644
--- a/include/llvm/Support/ARMTargetParser.def
+++ b/include/llvm/Support/ARMTargetParser.def
@@ -76,6 +76,9 @@ ARM_ARCH("armv6-m", AK_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,
FK_NEON, ARM::AEK_DSP)
+ARM_ARCH("armv7ve", AK_ARMV7VE, "7VE", "v7ve", ARMBuildAttrs::CPUArch::v7,
+ FK_NEON, (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT |
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIV | ARM::AEK_DSP))
ARM_ARCH("armv7-r", AK_ARMV7R, "7-R", "v7r", ARMBuildAttrs::CPUArch::v7,
FK_NONE, (ARM::AEK_HWDIV | ARM::AEK_DSP))
ARM_ARCH("armv7-m", AK_ARMV7M, "7-M", "v7m", ARMBuildAttrs::CPUArch::v7,
@@ -229,6 +232,8 @@ 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, true, ARM::AEK_CRC)
@@ -239,6 +244,7 @@ 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)
// 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)
diff --git a/include/llvm/Support/Allocator.h b/include/llvm/Support/Allocator.h
index c71759abd7d21..a5e662f4c588a 100644
--- a/include/llvm/Support/Allocator.h
+++ b/include/llvm/Support/Allocator.h
@@ -1,4 +1,4 @@
-//===--- Allocator.h - Simple memory allocation abstraction -----*- C++ -*-===//
+//===- Allocator.h - Simple memory allocation abstraction -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -144,19 +144,18 @@ public:
"that objects larger than a slab go into their own memory "
"allocation.");
- BumpPtrAllocatorImpl()
- : CurPtr(nullptr), End(nullptr), BytesAllocated(0), Allocator() {}
+ BumpPtrAllocatorImpl() = default;
+
template <typename T>
BumpPtrAllocatorImpl(T &&Allocator)
- : CurPtr(nullptr), End(nullptr), BytesAllocated(0),
- Allocator(std::forward<T &&>(Allocator)) {}
+ : Allocator(std::forward<T &&>(Allocator)) {}
// Manually implement a move constructor as we must clear the old allocator's
// slabs as a matter of correctness.
BumpPtrAllocatorImpl(BumpPtrAllocatorImpl &&Old)
: CurPtr(Old.CurPtr), End(Old.End), Slabs(std::move(Old.Slabs)),
CustomSizedSlabs(std::move(Old.CustomSizedSlabs)),
- BytesAllocated(Old.BytesAllocated),
+ BytesAllocated(Old.BytesAllocated), RedZoneSize(Old.RedZoneSize),
Allocator(std::move(Old.Allocator)) {
Old.CurPtr = Old.End = nullptr;
Old.BytesAllocated = 0;
@@ -176,6 +175,7 @@ public:
CurPtr = RHS.CurPtr;
End = RHS.End;
BytesAllocated = RHS.BytesAllocated;
+ RedZoneSize = RHS.RedZoneSize;
Slabs = std::move(RHS.Slabs);
CustomSizedSlabs = std::move(RHS.CustomSizedSlabs);
Allocator = std::move(RHS.Allocator);
@@ -218,10 +218,16 @@ public:
size_t Adjustment = alignmentAdjustment(CurPtr, Alignment);
assert(Adjustment + Size >= Size && "Adjustment + Size must not overflow");
+ size_t SizeToAllocate = Size;
+#if LLVM_ADDRESS_SANITIZER_BUILD
+ // Add trailing bytes as a "red zone" under ASan.
+ SizeToAllocate += RedZoneSize;
+#endif
+
// Check if we have enough space.
- if (Adjustment + Size <= size_t(End - CurPtr)) {
+ if (Adjustment + SizeToAllocate <= size_t(End - CurPtr)) {
char *AlignedPtr = CurPtr + Adjustment;
- CurPtr = AlignedPtr + Size;
+ CurPtr = AlignedPtr + SizeToAllocate;
// Update the allocation point of this memory block in MemorySanitizer.
// Without this, MemorySanitizer messages for values originated from here
// will point to the allocation of the entire slab.
@@ -232,7 +238,7 @@ public:
}
// If Size is really big, allocate a separate slab for it.
- size_t PaddedSize = Size + Alignment - 1;
+ size_t PaddedSize = SizeToAllocate + Alignment - 1;
if (PaddedSize > SizeThreshold) {
void *NewSlab = Allocator.Allocate(PaddedSize, 0);
// We own the new slab and don't want anyone reading anyting other than
@@ -251,10 +257,10 @@ public:
// Otherwise, start a new slab and try again.
StartNewSlab();
uintptr_t AlignedAddr = alignAddr(CurPtr, Alignment);
- assert(AlignedAddr + Size <= (uintptr_t)End &&
+ assert(AlignedAddr + SizeToAllocate <= (uintptr_t)End &&
"Unable to allocate memory!");
char *AlignedPtr = (char*)AlignedAddr;
- CurPtr = AlignedPtr + Size;
+ CurPtr = AlignedPtr + SizeToAllocate;
__msan_allocated_memory(AlignedPtr, Size);
__asan_unpoison_memory_region(AlignedPtr, Size);
return AlignedPtr;
@@ -283,6 +289,10 @@ public:
size_t getBytesAllocated() const { return BytesAllocated; }
+ void setRedZoneSize(size_t NewSize) {
+ RedZoneSize = NewSize;
+ }
+
void PrintStats() const {
detail::printBumpPtrAllocatorStats(Slabs.size(), BytesAllocated,
getTotalMemory());
@@ -292,10 +302,10 @@ private:
/// \brief The current pointer into the current slab.
///
/// This points to the next free byte in the slab.
- char *CurPtr;
+ char *CurPtr = nullptr;
/// \brief The end of the current slab.
- char *End;
+ char *End = nullptr;
/// \brief The slabs allocated so far.
SmallVector<void *, 4> Slabs;
@@ -306,7 +316,11 @@ private:
/// \brief How many bytes we've allocated.
///
/// Used so that we can compute how much space was wasted.
- size_t BytesAllocated;
+ size_t BytesAllocated = 0;
+
+ /// \brief The number of bytes to put between allocations when running under
+ /// a sanitizer.
+ size_t RedZoneSize = 1;
/// \brief The allocator instance we use to get slabs of memory.
AllocatorT Allocator;
@@ -357,7 +371,7 @@ private:
};
/// \brief The standard BumpPtrAllocator which just uses the default template
-/// paramaters.
+/// parameters.
typedef BumpPtrAllocatorImpl<> BumpPtrAllocator;
/// \brief A BumpPtrAllocator that allows only elements of a specific type to be
@@ -369,7 +383,11 @@ template <typename T> class SpecificBumpPtrAllocator {
BumpPtrAllocator Allocator;
public:
- SpecificBumpPtrAllocator() = default;
+ SpecificBumpPtrAllocator() {
+ // Because SpecificBumpPtrAllocator walks the memory to call destructors,
+ // it can't have red zones between allocations.
+ Allocator.setRedZoneSize(0);
+ }
SpecificBumpPtrAllocator(SpecificBumpPtrAllocator &&Old)
: Allocator(std::move(Old.Allocator)) {}
~SpecificBumpPtrAllocator() { DestroyAll(); }
diff --git a/include/llvm/Support/Atomic.h b/include/llvm/Support/Atomic.h
index d03714b009c51..552313f0c2412 100644
--- a/include/llvm/Support/Atomic.h
+++ b/include/llvm/Support/Atomic.h
@@ -20,6 +20,11 @@
#include "llvm/Support/DataTypes.h"
+// Windows will at times define MemoryFence.
+#ifdef MemoryFence
+#undef MemoryFence
+#endif
+
namespace llvm {
namespace sys {
void MemoryFence();
diff --git a/include/llvm/Support/BinaryByteStream.h b/include/llvm/Support/BinaryByteStream.h
new file mode 100644
index 0000000000000..694be28e07e16
--- /dev/null
+++ b/include/llvm/Support/BinaryByteStream.h
@@ -0,0 +1,192 @@
+//===- BinaryByteStream.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===//
+// A BinaryStream which stores data in a single continguous memory buffer.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H
+#define LLVM_SUPPORT_BINARYBYTESTREAM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/BinaryStream.h"
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+
+namespace llvm {
+
+/// \brief An implementation of BinaryStream which holds its entire data set
+/// in a single contiguous buffer. BinaryByteStream guarantees that no read
+/// operation will ever incur a copy. Note that BinaryByteStream does not
+/// own the underlying buffer.
+class BinaryByteStream : public BinaryStream {
+public:
+ BinaryByteStream() = default;
+ BinaryByteStream(ArrayRef<uint8_t> Data, llvm::support::endianness Endian)
+ : Endian(Endian), Data(Data) {}
+ BinaryByteStream(StringRef Data, llvm::support::endianness Endian)
+ : Endian(Endian), Data(Data.bytes_begin(), Data.bytes_end()) {}
+
+ llvm::support::endianness getEndian() const override { return Endian; }
+
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) override {
+ if (auto EC = checkOffset(Offset, Size))
+ return EC;
+ Buffer = Data.slice(Offset, Size);
+ return Error::success();
+ }
+
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) override {
+ if (auto EC = checkOffset(Offset, 1))
+ return EC;
+ Buffer = Data.slice(Offset);
+ return Error::success();
+ }
+
+ uint32_t getLength() override { return Data.size(); }
+
+ ArrayRef<uint8_t> data() const { return Data; }
+
+ StringRef str() const {
+ const char *CharData = reinterpret_cast<const char *>(Data.data());
+ return StringRef(CharData, Data.size());
+ }
+
+protected:
+ llvm::support::endianness Endian;
+ ArrayRef<uint8_t> Data;
+};
+
+/// \brief An implementation of BinaryStream whose data is backed by an llvm
+/// MemoryBuffer object. MemoryBufferByteStream owns the MemoryBuffer in
+/// question. As with BinaryByteStream, reading from a MemoryBufferByteStream
+/// will never cause a copy.
+class MemoryBufferByteStream : public BinaryByteStream {
+public:
+ MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer,
+ llvm::support::endianness Endian)
+ : BinaryByteStream(Buffer->getBuffer(), Endian),
+ MemBuffer(std::move(Buffer)) {}
+
+ std::unique_ptr<MemoryBuffer> MemBuffer;
+};
+
+/// \brief An implementation of BinaryStream which holds its entire data set
+/// in a single contiguous buffer. As with BinaryByteStream, the mutable
+/// version also guarantees that no read operation will ever incur a copy,
+/// and similarly it does not own the underlying buffer.
+class MutableBinaryByteStream : public WritableBinaryStream {
+public:
+ MutableBinaryByteStream() = default;
+ MutableBinaryByteStream(MutableArrayRef<uint8_t> Data,
+ llvm::support::endianness Endian)
+ : Data(Data), ImmutableStream(Data, Endian) {}
+
+ llvm::support::endianness getEndian() const override {
+ return ImmutableStream.getEndian();
+ }
+
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) override {
+ return ImmutableStream.readBytes(Offset, Size, Buffer);
+ }
+
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) override {
+ return ImmutableStream.readLongestContiguousChunk(Offset, Buffer);
+ }
+
+ uint32_t getLength() override { return ImmutableStream.getLength(); }
+
+ Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override {
+ if (Buffer.empty())
+ return Error::success();
+
+ if (auto EC = checkOffset(Offset, Buffer.size()))
+ return EC;
+
+ uint8_t *DataPtr = const_cast<uint8_t *>(Data.data());
+ ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size());
+ return Error::success();
+ }
+
+ Error commit() override { return Error::success(); }
+
+ MutableArrayRef<uint8_t> data() const { return Data; }
+
+private:
+ MutableArrayRef<uint8_t> Data;
+ BinaryByteStream ImmutableStream;
+};
+
+/// \brief An implementation of WritableBinaryStream backed by an llvm
+/// FileOutputBuffer.
+class FileBufferByteStream : public WritableBinaryStream {
+private:
+ class StreamImpl : public MutableBinaryByteStream {
+ public:
+ StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer,
+ llvm::support::endianness Endian)
+ : MutableBinaryByteStream(
+ MutableArrayRef<uint8_t>(Buffer->getBufferStart(),
+ Buffer->getBufferEnd()),
+ Endian),
+ FileBuffer(std::move(Buffer)) {}
+
+ Error commit() override {
+ if (FileBuffer->commit())
+ return make_error<BinaryStreamError>(
+ stream_error_code::filesystem_error);
+ return Error::success();
+ }
+
+ private:
+ std::unique_ptr<FileOutputBuffer> FileBuffer;
+ };
+
+public:
+ FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer,
+ llvm::support::endianness Endian)
+ : Impl(std::move(Buffer), Endian) {}
+
+ llvm::support::endianness getEndian() const override {
+ return Impl.getEndian();
+ }
+
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) override {
+ return Impl.readBytes(Offset, Size, Buffer);
+ }
+
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) override {
+ return Impl.readLongestContiguousChunk(Offset, Buffer);
+ }
+
+ uint32_t getLength() override { return Impl.getLength(); }
+
+ Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) override {
+ return Impl.writeBytes(Offset, Data);
+ }
+
+ Error commit() override { return Impl.commit(); }
+
+private:
+ StreamImpl Impl;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_BYTESTREAM_H
diff --git a/include/llvm/Support/BinaryItemStream.h b/include/llvm/Support/BinaryItemStream.h
new file mode 100644
index 0000000000000..f4b319217819e
--- /dev/null
+++ b/include/llvm/Support/BinaryItemStream.h
@@ -0,0 +1,95 @@
+//===- BinaryItemStream.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYITEMSTREAM_H
+#define LLVM_SUPPORT_BINARYITEMSTREAM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/BinaryStream.h"
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/Error.h"
+#include <cstddef>
+#include <cstdint>
+
+namespace llvm {
+
+template <typename T> struct BinaryItemTraits {
+ static size_t length(const T &Item) = delete;
+ static ArrayRef<uint8_t> bytes(const T &Item) = delete;
+};
+
+/// BinaryItemStream represents a sequence of objects stored in some kind of
+/// external container but for which it is useful to view as a stream of
+/// contiguous bytes. An example of this might be if you have a collection of
+/// records and you serialize each one into a buffer, and store these serialized
+/// records in a container. The pointers themselves are not laid out
+/// contiguously in memory, but we may wish to read from or write to these
+/// records as if they were.
+template <typename T, typename Traits = BinaryItemTraits<T>>
+class BinaryItemStream : public BinaryStream {
+public:
+ explicit BinaryItemStream(llvm::support::endianness Endian)
+ : Endian(Endian) {}
+
+ llvm::support::endianness getEndian() const override { return Endian; }
+
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) override {
+ auto ExpectedIndex = translateOffsetIndex(Offset);
+ if (!ExpectedIndex)
+ return ExpectedIndex.takeError();
+ const auto &Item = Items[*ExpectedIndex];
+ if (auto EC = checkOffset(Offset, Size))
+ return EC;
+ if (Size > Traits::length(Item))
+ return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
+ Buffer = Traits::bytes(Item).take_front(Size);
+ return Error::success();
+ }
+
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) override {
+ auto ExpectedIndex = translateOffsetIndex(Offset);
+ if (!ExpectedIndex)
+ return ExpectedIndex.takeError();
+ Buffer = Traits::bytes(Items[*ExpectedIndex]);
+ return Error::success();
+ }
+
+ void setItems(ArrayRef<T> ItemArray) { Items = ItemArray; }
+
+ uint32_t getLength() override {
+ uint32_t Size = 0;
+ for (const auto &Item : Items)
+ Size += Traits::length(Item);
+ return Size;
+ }
+
+private:
+ Expected<uint32_t> translateOffsetIndex(uint32_t Offset) const {
+ uint32_t CurrentOffset = 0;
+ uint32_t CurrentIndex = 0;
+ for (const auto &Item : Items) {
+ if (CurrentOffset >= Offset)
+ break;
+ CurrentOffset += Traits::length(Item);
+ ++CurrentIndex;
+ }
+ if (CurrentOffset != Offset)
+ return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
+ return CurrentIndex;
+ }
+
+ llvm::support::endianness Endian;
+ ArrayRef<T> Items;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYITEMSTREAM_H
diff --git a/include/llvm/Support/BinaryStream.h b/include/llvm/Support/BinaryStream.h
new file mode 100644
index 0000000000000..a227117e063e9
--- /dev/null
+++ b/include/llvm/Support/BinaryStream.h
@@ -0,0 +1,78 @@
+//===- BinaryStream.h - Base interface for a stream of data -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYSTREAM_H
+#define LLVM_SUPPORT_BINARYSTREAM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+
+namespace llvm {
+
+/// \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
+/// implementation. Since implementations may not necessarily store data in a
+/// single contiguous buffer (or even in memory at all), in such cases a it may
+/// be necessary for an implementation to cache such a buffer so that it can
+/// return it.
+class BinaryStream {
+public:
+ virtual ~BinaryStream() = default;
+
+ virtual llvm::support::endianness getEndian() const = 0;
+
+ /// \brief Given an offset into the stream and a number of bytes, attempt to
+ /// read the bytes and set the output ArrayRef to point to data owned by the
+ /// stream.
+ virtual Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) = 0;
+
+ /// \brief Given an offset into the stream, read as much as possible without
+ /// copying any data.
+ virtual Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) = 0;
+
+ /// \brief Return the number of bytes of data in this stream.
+ virtual uint32_t getLength() = 0;
+
+protected:
+ Error checkOffset(uint32_t Offset, uint32_t DataSize) {
+ if (Offset > getLength())
+ return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
+ if (getLength() < DataSize + Offset)
+ return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
+ return Error::success();
+ }
+};
+
+/// \brief A BinaryStream which can be read from as well as written to. Note
+/// that writing to a BinaryStream always necessitates copying from the input
+/// buffer to the stream's backing store. Streams are assumed to be buffered
+/// so that to be portable it is necessary to call commit() on the stream when
+/// all data has been written.
+class WritableBinaryStream : public BinaryStream {
+public:
+ ~WritableBinaryStream() override = default;
+
+ /// \brief Attempt to write the given bytes into the stream at the desired
+ /// offset. This will always necessitate a copy. Cannot shrink or grow the
+ /// stream, only writes into existing allocated space.
+ virtual Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) = 0;
+
+ /// \brief For buffered streams, commits changes to the backing store.
+ virtual Error commit() = 0;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYSTREAM_H
diff --git a/include/llvm/Support/BinaryStreamArray.h b/include/llvm/Support/BinaryStreamArray.h
new file mode 100644
index 0000000000000..3b1301d3cc0bd
--- /dev/null
+++ b/include/llvm/Support/BinaryStreamArray.h
@@ -0,0 +1,320 @@
+//===- BinaryStreamArray.h - Array backed by an arbitrary stream *- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYSTREAMARRAY_H
+#define LLVM_SUPPORT_BINARYSTREAMARRAY_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/Error.h"
+#include <cassert>
+#include <cstdint>
+
+/// Lightweight arrays that are backed by an arbitrary BinaryStream. This file
+/// provides two different array implementations.
+///
+/// VarStreamArray - Arrays of variable length records. The user specifies
+/// an Extractor type that can extract a record from a given offset and
+/// return the number of bytes consumed by the record.
+///
+/// FixedStreamArray - Arrays of fixed length records. This is similar in
+/// spirit to ArrayRef<T>, but since it is backed by a BinaryStream, the
+/// elements of the array need not be laid out in contiguous memory.
+namespace llvm {
+
+/// VarStreamArrayExtractor is intended to be specialized to provide customized
+/// extraction logic. On input it receives a BinaryStreamRef pointing to the
+/// beginning of the next record, but where the length of the record is not yet
+/// known. Upon completion, it should return an appropriate Error instance if
+/// a record could not be extracted, or if one could be extracted it should
+/// return success and set Len to the number of bytes this record occupied in
+/// the underlying stream, and it should fill out the fields of the value type
+/// Item appropriately to represent the current record.
+///
+/// You can specialize this template for your own custom value types to avoid
+/// having to specify a second template argument to VarStreamArray (documented
+/// below).
+template <typename T> struct VarStreamArrayExtractor {
+ // Method intentionally deleted. You must provide an explicit specialization
+ // with the following method implemented.
+ Error operator()(BinaryStreamRef Stream, uint32_t &Len,
+ T &Item) const = delete;
+};
+
+/// VarStreamArray represents an array of variable length records backed by a
+/// stream. This could be a contiguous sequence of bytes in memory, it could
+/// be a file on disk, or it could be a PDB stream where bytes are stored as
+/// discontiguous blocks in a file. Usually it is desirable to treat arrays
+/// as contiguous blocks of memory, but doing so with large PDB files, for
+/// example, could mean allocating huge amounts of memory just to allow
+/// re-ordering of stream data to be contiguous before iterating over it. By
+/// abstracting this out, we need not duplicate this memory, and we can
+/// iterate over arrays in arbitrarily formatted streams. Elements are parsed
+/// lazily on iteration, so there is no upfront cost associated with building
+/// or copying a VarStreamArray, no matter how large it may be.
+///
+/// You create a VarStreamArray by specifying a ValueType and an Extractor type.
+/// If you do not specify an Extractor type, you are expected to specialize
+/// VarStreamArrayExtractor<T> for your ValueType.
+///
+/// By default an Extractor is default constructed in the class, but in some
+/// cases you might find it useful for an Extractor to maintain state across
+/// extractions. In this case you can provide your own Extractor through a
+/// secondary constructor. The following examples show various ways of
+/// creating a VarStreamArray.
+///
+/// // Will use VarStreamArrayExtractor<MyType> as the extractor.
+/// VarStreamArray<MyType> MyTypeArray;
+///
+/// // Will use a default-constructed MyExtractor as the extractor.
+/// VarStreamArray<MyType, MyExtractor> MyTypeArray2;
+///
+/// // Will use the specific instance of MyExtractor provided.
+/// // MyExtractor need not be default-constructible in this case.
+/// MyExtractor E(SomeContext);
+/// VarStreamArray<MyType, MyExtractor> MyTypeArray3(E);
+///
+template <typename ValueType, typename Extractor> class VarStreamArrayIterator;
+
+template <typename ValueType,
+ typename Extractor = VarStreamArrayExtractor<ValueType>>
+
+class VarStreamArray {
+ friend class VarStreamArrayIterator<ValueType, Extractor>;
+
+public:
+ typedef VarStreamArrayIterator<ValueType, Extractor> Iterator;
+
+ VarStreamArray() = default;
+ explicit VarStreamArray(const Extractor &E) : E(E) {}
+
+ explicit VarStreamArray(BinaryStreamRef Stream) : Stream(Stream) {}
+ VarStreamArray(BinaryStreamRef Stream, const Extractor &E)
+ : Stream(Stream), E(E) {}
+
+ VarStreamArray(const VarStreamArray<ValueType, Extractor> &Other)
+ : Stream(Other.Stream), E(Other.E) {}
+
+ Iterator begin(bool *HadError = nullptr) const {
+ return Iterator(*this, E, HadError);
+ }
+
+ Iterator end() const { return Iterator(E); }
+
+ const Extractor &getExtractor() const { return E; }
+
+ BinaryStreamRef getUnderlyingStream() const { return Stream; }
+
+private:
+ BinaryStreamRef Stream;
+ Extractor E;
+};
+
+template <typename ValueType, typename Extractor>
+class VarStreamArrayIterator
+ : public iterator_facade_base<VarStreamArrayIterator<ValueType, Extractor>,
+ std::forward_iterator_tag, ValueType> {
+ typedef VarStreamArrayIterator<ValueType, Extractor> IterType;
+ typedef VarStreamArray<ValueType, Extractor> ArrayType;
+
+public:
+ VarStreamArrayIterator(const ArrayType &Array, const Extractor &E,
+ bool *HadError = nullptr)
+ : IterRef(Array.Stream), Array(&Array), HadError(HadError), Extract(E) {
+ if (IterRef.getLength() == 0)
+ moveToEnd();
+ else {
+ auto EC = Extract(IterRef, ThisLen, ThisValue);
+ if (EC) {
+ consumeError(std::move(EC));
+ markError();
+ }
+ }
+ }
+ VarStreamArrayIterator() = default;
+ explicit VarStreamArrayIterator(const Extractor &E) : Extract(E) {}
+ ~VarStreamArrayIterator() = default;
+
+ bool operator==(const IterType &R) const {
+ if (Array && R.Array) {
+ // Both have a valid array, make sure they're same.
+ assert(Array == R.Array);
+ return IterRef == R.IterRef;
+ }
+
+ // Both iterators are at the end.
+ if (!Array && !R.Array)
+ return true;
+
+ // One is not at the end and one is.
+ return false;
+ }
+
+ const ValueType &operator*() const {
+ assert(Array && !HasError);
+ return ThisValue;
+ }
+
+ IterType &operator+=(unsigned N) {
+ for (unsigned I = 0; I < N; ++I) {
+ // We are done with the current record, discard it so that we are
+ // positioned at the next record.
+ IterRef = IterRef.drop_front(ThisLen);
+ if (IterRef.getLength() == 0) {
+ // There is nothing after the current record, we must make this an end
+ // iterator.
+ moveToEnd();
+ } else {
+ // There is some data after the current record.
+ auto EC = Extract(IterRef, ThisLen, ThisValue);
+ if (EC) {
+ consumeError(std::move(EC));
+ markError();
+ } else if (ThisLen == 0) {
+ // An empty record? Make this an end iterator.
+ moveToEnd();
+ }
+ }
+ }
+ return *this;
+ }
+
+private:
+ void moveToEnd() {
+ Array = nullptr;
+ ThisLen = 0;
+ }
+ void markError() {
+ moveToEnd();
+ HasError = true;
+ if (HadError != nullptr)
+ *HadError = true;
+ }
+
+ ValueType ThisValue;
+ BinaryStreamRef IterRef;
+ const ArrayType *Array{nullptr};
+ uint32_t ThisLen{0};
+ bool HasError{false};
+ bool *HadError{nullptr};
+ Extractor Extract;
+};
+
+template <typename T> class FixedStreamArrayIterator;
+
+/// FixedStreamArray is similar to VarStreamArray, except with each record
+/// having a fixed-length. As with VarStreamArray, there is no upfront
+/// cost associated with building or copying a FixedStreamArray, as the
+/// memory for each element is not read from the backing stream until that
+/// element is iterated.
+template <typename T> class FixedStreamArray {
+ friend class FixedStreamArrayIterator<T>;
+
+public:
+ FixedStreamArray() = default;
+ explicit FixedStreamArray(BinaryStreamRef Stream) : Stream(Stream) {
+ assert(Stream.getLength() % sizeof(T) == 0);
+ }
+
+ bool operator==(const FixedStreamArray<T> &Other) const {
+ return Stream == Other.Stream;
+ }
+
+ bool operator!=(const FixedStreamArray<T> &Other) const {
+ return !(*this == Other);
+ }
+
+ FixedStreamArray &operator=(const FixedStreamArray &) = default;
+
+ const T &operator[](uint32_t Index) const {
+ assert(Index < size());
+ uint32_t Off = Index * sizeof(T);
+ ArrayRef<uint8_t> Data;
+ if (auto EC = Stream.readBytes(Off, sizeof(T), Data)) {
+ assert(false && "Unexpected failure reading from stream");
+ // This should never happen since we asserted that the stream length was
+ // an exact multiple of the element size.
+ consumeError(std::move(EC));
+ }
+ assert(llvm::alignmentAdjustment(Data.data(), alignof(T)) == 0);
+ return *reinterpret_cast<const T *>(Data.data());
+ }
+
+ uint32_t size() const { return Stream.getLength() / sizeof(T); }
+
+ bool empty() const { return size() == 0; }
+
+ FixedStreamArrayIterator<T> begin() const {
+ return FixedStreamArrayIterator<T>(*this, 0);
+ }
+
+ FixedStreamArrayIterator<T> end() const {
+ return FixedStreamArrayIterator<T>(*this, size());
+ }
+
+ BinaryStreamRef getUnderlyingStream() const { return Stream; }
+
+private:
+ BinaryStreamRef Stream;
+};
+
+template <typename T>
+class FixedStreamArrayIterator
+ : public iterator_facade_base<FixedStreamArrayIterator<T>,
+ std::random_access_iterator_tag, T> {
+
+public:
+ FixedStreamArrayIterator(const FixedStreamArray<T> &Array, uint32_t Index)
+ : Array(Array), Index(Index) {}
+
+ FixedStreamArrayIterator<T> &
+ operator=(const FixedStreamArrayIterator<T> &Other) {
+ Array = Other.Array;
+ Index = Other.Index;
+ return *this;
+ }
+
+ const T &operator*() const { return Array[Index]; }
+
+ bool operator==(const FixedStreamArrayIterator<T> &R) const {
+ assert(Array == R.Array);
+ return (Index == R.Index) && (Array == R.Array);
+ }
+
+ FixedStreamArrayIterator<T> &operator+=(std::ptrdiff_t N) {
+ Index += N;
+ return *this;
+ }
+
+ FixedStreamArrayIterator<T> &operator-=(std::ptrdiff_t N) {
+ assert(Index >= N);
+ Index -= N;
+ return *this;
+ }
+
+ std::ptrdiff_t operator-(const FixedStreamArrayIterator<T> &R) const {
+ assert(Array == R.Array);
+ assert(Index >= R.Index);
+ return Index - R.Index;
+ }
+
+ bool operator<(const FixedStreamArrayIterator<T> &RHS) const {
+ assert(Array == RHS.Array);
+ return Index < RHS.Index;
+ }
+
+private:
+ FixedStreamArray<T> Array;
+ uint32_t Index;
+};
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYSTREAMARRAY_H
diff --git a/include/llvm/Support/BinaryStreamError.h b/include/llvm/Support/BinaryStreamError.h
new file mode 100644
index 0000000000000..7d9699d536391
--- /dev/null
+++ b/include/llvm/Support/BinaryStreamError.h
@@ -0,0 +1,48 @@
+//===- BinaryStreamError.h - Error extensions for Binary Streams *- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYSTREAMERROR_H
+#define LLVM_SUPPORT_BINARYSTREAMERROR_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+#include <string>
+
+namespace llvm {
+enum class stream_error_code {
+ unspecified,
+ stream_too_short,
+ invalid_array_size,
+ invalid_offset,
+ filesystem_error
+};
+
+/// Base class for errors originating when parsing raw PDB files
+class BinaryStreamError : public ErrorInfo<BinaryStreamError> {
+public:
+ static char ID;
+ explicit BinaryStreamError(stream_error_code C);
+ explicit BinaryStreamError(StringRef Context);
+ BinaryStreamError(stream_error_code C, StringRef Context);
+
+ void log(raw_ostream &OS) const override;
+ std::error_code convertToErrorCode() const override;
+
+ StringRef getErrorMessage() const;
+
+ stream_error_code getErrorCode() const { return Code; }
+
+private:
+ std::string ErrMsg;
+ stream_error_code Code;
+};
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYSTREAMERROR_H
diff --git a/include/llvm/Support/BinaryStreamReader.h b/include/llvm/Support/BinaryStreamReader.h
new file mode 100644
index 0000000000000..d994fa0f49d0b
--- /dev/null
+++ b/include/llvm/Support/BinaryStreamReader.h
@@ -0,0 +1,234 @@
+//===- BinaryStreamReader.h - Reads objects from a binary stream *- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYSTREAMREADER_H
+#define LLVM_SUPPORT_BINARYSTREAMREADER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/BinaryStreamArray.h"
+#include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/type_traits.h"
+
+#include <string>
+#include <type_traits>
+
+namespace llvm {
+
+/// \brief Provides read only access to a subclass of `BinaryStream`. Provides
+/// bounds checking and helpers for writing certain common data types such as
+/// null-terminated strings, integers in various flavors of endianness, etc.
+/// Can be subclassed to provide reading of custom datatypes, although no
+/// are overridable.
+class BinaryStreamReader {
+public:
+ explicit BinaryStreamReader(BinaryStreamRef Stream);
+ virtual ~BinaryStreamReader() {}
+
+ /// Read as much as possible from the underlying string at the current offset
+ /// without invoking a copy, and set \p Buffer to the resulting data slice.
+ /// Updates the stream's offset to point after the newly read data.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer);
+
+ /// Read \p Size bytes from the underlying stream at the current offset and
+ /// and set \p Buffer to the resulting data slice. Whether a copy occurs
+ /// depends on the implementation of the underlying stream. Updates the
+ /// stream's offset to point after the newly read data.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size);
+
+ /// Read an integer of the specified endianness into \p Dest and update the
+ /// stream's offset. The data is always copied from the stream's underlying
+ /// buffer into \p Dest. Updates the stream's offset to point after the newly
+ /// read data.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ template <typename T> Error readInteger(T &Dest) {
+ static_assert(std::is_integral<T>::value,
+ "Cannot call readInteger with non-integral value!");
+
+ ArrayRef<uint8_t> Bytes;
+ if (auto EC = readBytes(Bytes, sizeof(T)))
+ return EC;
+
+ Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
+ Bytes.data(), Stream.getEndian());
+ return Error::success();
+ }
+
+ /// Similar to readInteger.
+ template <typename T> Error readEnum(T &Dest) {
+ static_assert(std::is_enum<T>::value,
+ "Cannot call readEnum with non-enum value!");
+ typename std::underlying_type<T>::type N;
+ if (auto EC = readInteger(N))
+ return EC;
+ Dest = static_cast<T>(N);
+ return Error::success();
+ }
+
+ /// Read a null terminated string from \p Dest. Whether a copy occurs depends
+ /// on the implementation of the underlying stream. Updates the stream's
+ /// offset to point after the newly read data.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readCString(StringRef &Dest);
+
+ /// Read a \p Length byte string into \p Dest. Whether a copy occurs depends
+ /// on the implementation of the underlying stream. Updates the stream's
+ /// offset to point after the newly read data.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readFixedString(StringRef &Dest, uint32_t Length);
+
+ /// Read the entire remainder of the underlying stream into \p Ref. This is
+ /// equivalent to calling getUnderlyingStream().slice(Offset). Updates the
+ /// stream's offset to point to the end of the stream. Never causes a copy.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readStreamRef(BinaryStreamRef &Ref);
+
+ /// Read \p Length bytes from the underlying stream into \p Ref. This is
+ /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
+ /// Updates the stream's offset to point after the newly read object. Never
+ /// causes a copy.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readStreamRef(BinaryStreamRef &Ref, uint32_t Length);
+
+ /// Get a pointer to an object of type T from the underlying stream, as if by
+ /// memcpy, and store the result into \p Dest. It is up to the caller to
+ /// ensure that objects of type T can be safely treated in this manner.
+ /// Updates the stream's offset to point after the newly read object. Whether
+ /// a copy occurs depends upon the implementation of the underlying
+ /// stream.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ template <typename T> Error readObject(const T *&Dest) {
+ ArrayRef<uint8_t> Buffer;
+ if (auto EC = readBytes(Buffer, sizeof(T)))
+ return EC;
+ Dest = reinterpret_cast<const T *>(Buffer.data());
+ return Error::success();
+ }
+
+ /// Get a reference to a \p NumElements element array of objects of type T
+ /// from the underlying stream as if by memcpy, and store the resulting array
+ /// slice into \p array. It is up to the caller to ensure that objects of
+ /// type T can be safely treated in this manner. Updates the stream's offset
+ /// to point after the newly read object. Whether a copy occurs depends upon
+ /// the implementation of the underlying stream.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ template <typename T>
+ Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
+ ArrayRef<uint8_t> Bytes;
+ if (NumElements == 0) {
+ Array = ArrayRef<T>();
+ return Error::success();
+ }
+
+ if (NumElements > UINT32_MAX / sizeof(T))
+ return make_error<BinaryStreamError>(
+ stream_error_code::invalid_array_size);
+
+ if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
+ return EC;
+
+ assert(alignmentAdjustment(Bytes.data(), alignof(T)) == 0 &&
+ "Reading at invalid alignment!");
+
+ Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
+ return Error::success();
+ }
+
+ /// Read a VarStreamArray of size \p Size bytes and store the result into
+ /// \p Array. Updates the stream's offset to point after the newly read
+ /// array. Never causes a copy (although iterating the elements of the
+ /// VarStreamArray may, depending upon the implementation of the underlying
+ /// stream).
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ template <typename T, typename U>
+ Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) {
+ BinaryStreamRef S;
+ if (auto EC = readStreamRef(S, Size))
+ return EC;
+ Array = VarStreamArray<T, U>(S, Array.getExtractor());
+ return Error::success();
+ }
+
+ /// Read a FixedStreamArray of \p NumItems elements and store the result into
+ /// \p Array. Updates the stream's offset to point after the newly read
+ /// array. Never causes a copy (although iterating the elements of the
+ /// FixedStreamArray may, depending upon the implementation of the underlying
+ /// stream).
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ template <typename T>
+ Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) {
+ if (NumItems == 0) {
+ Array = FixedStreamArray<T>();
+ return Error::success();
+ }
+
+ if (NumItems > UINT32_MAX / sizeof(T))
+ return make_error<BinaryStreamError>(
+ stream_error_code::invalid_array_size);
+
+ BinaryStreamRef View;
+ if (auto EC = readStreamRef(View, NumItems * sizeof(T)))
+ return EC;
+
+ Array = FixedStreamArray<T>(View);
+ return Error::success();
+ }
+
+ bool empty() const { return bytesRemaining() == 0; }
+ void setOffset(uint32_t Off) { Offset = Off; }
+ uint32_t getOffset() const { return Offset; }
+ uint32_t getLength() const { return Stream.getLength(); }
+ uint32_t bytesRemaining() const { return getLength() - getOffset(); }
+
+ /// Advance the stream's offset by \p Amount bytes.
+ ///
+ /// \returns a success error code if at least \p Amount bytes remain in the
+ /// stream, otherwise returns an appropriate error code.
+ Error skip(uint32_t Amount);
+
+ /// Examine the next byte of the underlying stream without advancing the
+ /// stream's offset. If the stream is empty the behavior is undefined.
+ ///
+ /// \returns the next byte in the stream.
+ uint8_t peek() const;
+
+private:
+ BinaryStreamRef Stream;
+ uint32_t Offset;
+};
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYSTREAMREADER_H
diff --git a/include/llvm/Support/BinaryStreamRef.h b/include/llvm/Support/BinaryStreamRef.h
new file mode 100644
index 0000000000000..23ce02fd7ca41
--- /dev/null
+++ b/include/llvm/Support/BinaryStreamRef.h
@@ -0,0 +1,174 @@
+//===- BinaryStreamRef.h - A copyable reference to a stream -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYSTREAMREF_H
+#define LLVM_SUPPORT_BINARYSTREAMREF_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/BinaryStream.h"
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cstdint>
+
+namespace llvm {
+
+/// Common stuff for mutable and immutable StreamRefs.
+template <class StreamType, class RefType> class BinaryStreamRefBase {
+public:
+ BinaryStreamRefBase() : Stream(nullptr), ViewOffset(0), Length(0) {}
+ BinaryStreamRefBase(StreamType &Stream, uint32_t Offset, uint32_t Length)
+ : Stream(&Stream), ViewOffset(Offset), Length(Length) {}
+
+ llvm::support::endianness getEndian() const { return Stream->getEndian(); }
+
+ uint32_t getLength() const { return Length; }
+ const StreamType *getStream() const { return Stream; }
+
+ /// Return a new BinaryStreamRef with the first \p N elements removed.
+ RefType drop_front(uint32_t N) const {
+ if (!Stream)
+ return RefType();
+
+ N = std::min(N, Length);
+ return RefType(*Stream, ViewOffset + N, Length - N);
+ }
+
+ /// Return a new BinaryStreamRef with only the first \p N elements remaining.
+ RefType keep_front(uint32_t N) const {
+ if (!Stream)
+ return RefType();
+ N = std::min(N, Length);
+ return RefType(*Stream, ViewOffset, N);
+ }
+
+ /// Return a new BinaryStreamRef with the first \p Offset elements removed,
+ /// and retaining exactly \p Len elements.
+ RefType slice(uint32_t Offset, uint32_t Len) const {
+ return drop_front(Offset).keep_front(Len);
+ }
+
+ bool operator==(const RefType &Other) const {
+ if (Stream != Other.Stream)
+ return false;
+ if (ViewOffset != Other.ViewOffset)
+ return false;
+ if (Length != Other.Length)
+ return false;
+ return true;
+ }
+
+protected:
+ Error checkOffset(uint32_t Offset, uint32_t DataSize) const {
+ if (Offset > getLength())
+ return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
+ if (getLength() < DataSize + Offset)
+ return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
+ return Error::success();
+ }
+
+ StreamType *Stream;
+ uint32_t ViewOffset;
+ uint32_t Length;
+};
+
+/// \brief BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It
+/// provides copy-semantics and read only access to a "window" of the underlying
+/// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream. That is to
+/// say, it does not inherit and override the methods of BinaryStream. In
+/// general, you should not pass around pointers or references to BinaryStreams
+/// and use inheritance to achieve polymorphism. Instead, you should pass
+/// around BinaryStreamRefs by value and achieve polymorphism that way.
+class BinaryStreamRef
+ : public BinaryStreamRefBase<BinaryStream, BinaryStreamRef> {
+public:
+ BinaryStreamRef() = default;
+ BinaryStreamRef(BinaryStream &Stream)
+ : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {}
+ BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, uint32_t Length)
+ : BinaryStreamRefBase(Stream, Offset, Length) {}
+
+ // Use BinaryStreamRef.slice() instead.
+ BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset,
+ uint32_t Length) = delete;
+
+ /// Given an Offset into this StreamRef and a Size, return a reference to a
+ /// buffer owned by the stream.
+ ///
+ /// \returns a success error code if the entire range of data is within the
+ /// bounds of this BinaryStreamRef's view and the implementation could read
+ /// the data, and an appropriate error code otherwise.
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) const {
+ if (auto EC = checkOffset(Offset, Size))
+ return EC;
+
+ return Stream->readBytes(ViewOffset + Offset, Size, Buffer);
+ }
+
+ /// Given an Offset into this BinaryStreamRef, return a reference to the
+ /// largest buffer the stream could support without necessitating a copy.
+ ///
+ /// \returns a success error code if implementation could read the data,
+ /// and an appropriate error code otherwise.
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) const {
+ if (auto EC = checkOffset(Offset, 1))
+ return EC;
+
+ if (auto EC =
+ Stream->readLongestContiguousChunk(ViewOffset + Offset, Buffer))
+ return EC;
+ // This StreamRef might refer to a smaller window over a larger stream. In
+ // that case we will have read out more bytes than we should return, because
+ // we should not read past the end of the current view.
+ uint32_t MaxLength = Length - Offset;
+ if (Buffer.size() > MaxLength)
+ Buffer = Buffer.slice(0, MaxLength);
+ return Error::success();
+ }
+};
+
+class WritableBinaryStreamRef
+ : public BinaryStreamRefBase<WritableBinaryStream,
+ WritableBinaryStreamRef> {
+public:
+ WritableBinaryStreamRef() = default;
+ WritableBinaryStreamRef(WritableBinaryStream &Stream)
+ : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {}
+ WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset,
+ uint32_t Length)
+ : BinaryStreamRefBase(Stream, Offset, Length) {}
+
+ // Use WritableBinaryStreamRef.slice() instead.
+ WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint32_t Offset,
+ uint32_t Length) = delete;
+
+ /// Given an Offset into this WritableBinaryStreamRef and some input data,
+ /// writes the data to the underlying stream.
+ ///
+ /// \returns a success error code if the data could fit within the underlying
+ /// stream at the specified location and the implementation could write the
+ /// data, and an appropriate error code otherwise.
+ Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const {
+ if (auto EC = checkOffset(Offset, Data.size()))
+ return EC;
+
+ return Stream->writeBytes(ViewOffset + Offset, Data);
+ }
+
+ operator BinaryStreamRef() { return BinaryStreamRef(*Stream); }
+
+ /// \brief For buffered streams, commits changes to the backing store.
+ Error commit() { return Stream->commit(); }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYSTREAMREF_H
diff --git a/include/llvm/Support/BinaryStreamWriter.h b/include/llvm/Support/BinaryStreamWriter.h
new file mode 100644
index 0000000000000..64f26b24543df
--- /dev/null
+++ b/include/llvm/Support/BinaryStreamWriter.h
@@ -0,0 +1,166 @@
+//===- BinaryStreamWriter.h - Writes objects to a BinaryStream ---*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYSTREAMWRITER_H
+#define LLVM_SUPPORT_BINARYSTREAMWRITER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/BinaryStreamArray.h"
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+#include <type_traits>
+
+namespace llvm {
+
+/// \brief Provides write only access to a subclass of `WritableBinaryStream`.
+/// Provides bounds checking and helpers for writing certain common data types
+/// such as null-terminated strings, integers in various flavors of endianness,
+/// etc. Can be subclassed to provide reading and writing of custom datatypes,
+/// although no methods are overridable.
+class BinaryStreamWriter {
+public:
+ BinaryStreamWriter() = default;
+ explicit BinaryStreamWriter(WritableBinaryStreamRef Stream);
+ virtual ~BinaryStreamWriter() {}
+
+ /// Write the bytes specified in \p Buffer to the underlying stream.
+ /// On success, updates the offset so that subsequent writes will occur
+ /// at the next unwritten position.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ Error writeBytes(ArrayRef<uint8_t> Buffer);
+
+ /// Write the the integer \p Value to the underlying stream in the
+ /// specified endianness. On success, updates the offset so that
+ /// subsequent writes occur at the next unwritten position.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ template <typename T> Error writeInteger(T Value) {
+ static_assert(std::is_integral<T>::value,
+ "Cannot call writeInteger with non-integral value!");
+ uint8_t Buffer[sizeof(T)];
+ llvm::support::endian::write<T, llvm::support::unaligned>(
+ Buffer, Value, Stream.getEndian());
+ return writeBytes(Buffer);
+ }
+
+ /// Similar to writeInteger
+ template <typename T> Error writeEnum(T Num) {
+ static_assert(std::is_enum<T>::value,
+ "Cannot call writeEnum with non-Enum type");
+
+ using U = typename std::underlying_type<T>::type;
+ return writeInteger<U>(static_cast<U>(Num));
+ }
+
+ /// Write the the string \p Str to the underlying stream followed by a null
+ /// terminator. On success, updates the offset so that subsequent writes
+ /// occur at the next unwritten position. \p Str need not be null terminated
+ /// on input.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ Error writeCString(StringRef Str);
+
+ /// Write the the string \p Str to the underlying stream without a null
+ /// terminator. On success, updates the offset so that subsequent writes
+ /// occur at the next unwritten position.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ Error writeFixedString(StringRef Str);
+
+ /// Efficiently reads all data from \p Ref, and writes it to this stream.
+ /// This operation will not invoke any copies of the source data, regardless
+ /// of the source stream's implementation.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ Error writeStreamRef(BinaryStreamRef Ref);
+
+ /// Efficiently reads \p Size bytes from \p Ref, and writes it to this stream.
+ /// This operation will not invoke any copies of the source data, regardless
+ /// of the source stream's implementation.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ Error writeStreamRef(BinaryStreamRef Ref, uint32_t Size);
+
+ /// Writes the object \p Obj to the underlying stream, as if by using memcpy.
+ /// It is up to the caller to ensure that type of \p Obj can be safely copied
+ /// in this fashion, as no checks are made to ensure that this is safe.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ template <typename T> Error writeObject(const T &Obj) {
+ static_assert(!std::is_pointer<T>::value,
+ "writeObject should not be used with pointers, to write "
+ "the pointed-to value dereference the pointer before calling "
+ "writeObject");
+ return writeBytes(
+ ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&Obj), sizeof(T)));
+ }
+
+ /// Writes an array of objects of type T to the underlying stream, as if by
+ /// using memcpy. It is up to the caller to ensure that type of \p Obj can
+ /// be safely copied in this fashion, as no checks are made to ensure that
+ /// this is safe.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ template <typename T> Error writeArray(ArrayRef<T> Array) {
+ if (Array.empty())
+ return Error::success();
+ if (Array.size() > UINT32_MAX / sizeof(T))
+ return make_error<BinaryStreamError>(
+ stream_error_code::invalid_array_size);
+
+ return writeBytes(
+ ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Array.data()),
+ Array.size() * sizeof(T)));
+ }
+
+ /// Writes all data from the array \p Array to the underlying stream.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ template <typename T, typename U>
+ Error writeArray(VarStreamArray<T, U> Array) {
+ return writeStreamRef(Array.getUnderlyingStream());
+ }
+
+ /// Writes all elements from the array \p Array to the underlying stream.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ template <typename T> Error writeArray(FixedStreamArray<T> Array) {
+ return writeStreamRef(Array.getUnderlyingStream());
+ }
+
+ void setOffset(uint32_t Off) { Offset = Off; }
+ uint32_t getOffset() const { return Offset; }
+ uint32_t getLength() const { return Stream.getLength(); }
+ uint32_t bytesRemaining() const { return getLength() - getOffset(); }
+ Error padToAlignment(uint32_t Align);
+
+protected:
+ WritableBinaryStreamRef Stream;
+ uint32_t Offset = 0;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYSTREAMWRITER_H
diff --git a/include/llvm/Support/CMakeLists.txt b/include/llvm/Support/CMakeLists.txt
new file mode 100644
index 0000000000000..b4b9937057451
--- /dev/null
+++ b/include/llvm/Support/CMakeLists.txt
@@ -0,0 +1,54 @@
+# 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)
+ 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)
+ if(git_result EQUAL 0)
+ string(STRIP "${git_dir}" git_dir)
+ set(${out_var} "${git_dir}/logs/HEAD")
+ else()
+ find_first_existing_file(${out_var}
+ "${path}/.svn/wc.db" # SVN 1.7
+ "${path}/.svn/entries" # SVN 1.6
+ )
+ endif()
+endmacro()
+
+find_first_existing_vc_file(llvm_vc "${LLVM_MAIN_SRC_DIR}")
+
+# The VC revision include that we want to generate.
+set(version_inc "${CMAKE_CURRENT_BINARY_DIR}/VCSRevision.h")
+
+set(get_svn_script "${LLVM_CMAKE_PATH}/GenerateVersionFromCVS.cmake")
+
+if(DEFINED llvm_vc)
+ # Create custom target to generate the VC revision include.
+ add_custom_command(OUTPUT "${version_inc}"
+ DEPENDS "${llvm_vc}" "${get_svn_script}"
+ COMMAND
+ ${CMAKE_COMMAND} "-DSOURCE_DIR=${LLVM_MAIN_SRC_DIR}"
+ "-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}" "")
+endif()
+
+add_custom_target(llvm_vcsrevision_h DEPENDS "${version_inc}")
diff --git a/include/llvm/Support/CachePruning.h b/include/llvm/Support/CachePruning.h
index 954fd8ae7ffbb..e826938878e50 100644
--- a/include/llvm/Support/CachePruning.h
+++ b/include/llvm/Support/CachePruning.h
@@ -20,51 +20,44 @@
namespace llvm {
-/// Handle pruning a directory provided a path and some options to control what
-/// to prune.
-class CachePruning {
-public:
- /// Prepare to prune \p Path.
- CachePruning(StringRef Path) : Path(Path) {}
-
- /// Define the pruning interval. This is intended to be used to avoid scanning
- /// the directory too often. It does not impact the decision of which file to
- /// prune. A value of 0 forces the scan to occurs.
- CachePruning &setPruningInterval(std::chrono::seconds PruningInterval) {
- Interval = PruningInterval;
- return *this;
- }
-
- /// Define the expiration for a file. When a file hasn't been accessed for
- /// \p ExpireAfter seconds, it is removed from the cache. A value of 0 disable
- /// the expiration-based pruning.
- CachePruning &setEntryExpiration(std::chrono::seconds ExpireAfter) {
- Expiration = ExpireAfter;
- return *this;
- }
-
- /// Define the maximum size for the cache directory, in terms of percentage of
- /// the available space on the the disk. Set to 100 to indicate no limit, 50
- /// to indicate that the cache size will not be left over half the
- /// available disk space. A value over 100 will be reduced to 100. A value of
- /// 0 disable the size-based pruning.
- CachePruning &setMaxSize(unsigned Percentage) {
- PercentageOfAvailableSpace = std::min(100u, Percentage);
- return *this;
- }
-
- /// Peform pruning using the supplied options, returns true if pruning
- /// occured, i.e. if PruningInterval was expired.
- bool prune();
-
-private:
- // Options that matches the setters above.
- std::string Path;
- std::chrono::seconds Expiration = std::chrono::seconds::zero();
- std::chrono::seconds Interval = std::chrono::seconds::zero();
- unsigned PercentageOfAvailableSpace = 0;
+template <typename T> class Expected;
+
+/// Policy for the pruneCache() function. A default constructed
+/// CachePruningPolicy provides a reasonable default policy.
+struct CachePruningPolicy {
+ /// The pruning interval. This is intended to be used to avoid scanning the
+ /// directory too often. It does not impact the decision of which file to
+ /// prune. A value of 0 forces the scan to occur.
+ std::chrono::seconds Interval = std::chrono::seconds(1200);
+
+ /// The expiration for a file. When a file hasn't been accessed for Expiration
+ /// seconds, it is removed from the cache. A value of 0 disables the
+ /// expiration-based pruning.
+ std::chrono::seconds Expiration = std::chrono::hours(7 * 24); // 1w
+
+ /// The maximum size for the cache directory, in terms of percentage of the
+ /// available space on the the disk. Set to 100 to indicate no limit, 50 to
+ /// indicate that the cache size will not be left over half the available disk
+ /// space. A value over 100 will be reduced to 100. A value of 0 disables the
+ /// size-based pruning.
+ unsigned PercentageOfAvailableSpace = 75;
};
+/// Parse the given string as a cache pruning policy. Defaults are taken from a
+/// default constructed CachePruningPolicy object.
+/// For example: "prune_interval=30s:prune_after=24h:cache_size=50%"
+/// which means a pruning interval of 30 seconds, expiration time of 24 hours
+/// and maximum cache size of 50% of available disk space.
+Expected<CachePruningPolicy> parseCachePruningPolicy(StringRef PolicyStr);
+
+/// Peform pruning using the supplied policy, returns true if pruning
+/// occured, i.e. if Policy.Interval was expired.
+///
+/// As a safeguard against data loss if the user specifies the wrong directory
+/// as their cache directory, this function will ignore files not matching the
+/// pattern "llvmcache-*".
+bool pruneCache(StringRef Path, CachePruningPolicy Policy);
+
} // namespace llvm
#endif
diff --git a/include/llvm/Support/Casting.h b/include/llvm/Support/Casting.h
index a73047b2b557f..89d2af052dc16 100644
--- a/include/llvm/Support/Casting.h
+++ b/include/llvm/Support/Casting.h
@@ -18,6 +18,7 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/type_traits.h"
#include <cassert>
+#include <memory>
namespace llvm {
@@ -76,6 +77,14 @@ template <typename To, typename From> struct isa_impl_cl<To, const From> {
}
};
+template <typename To, typename From>
+struct isa_impl_cl<To, const std::unique_ptr<From>> {
+ static inline bool doit(const std::unique_ptr<From> &Val) {
+ assert(Val && "isa<> used on a null pointer");
+ return isa_impl_cl<To, From>::doit(*Val);
+ }
+};
+
template <typename To, typename From> struct isa_impl_cl<To, From*> {
static inline bool doit(const From *Val) {
assert(Val && "isa<> used on a null pointer");
@@ -161,6 +170,15 @@ template<class To, class From> struct cast_retty_impl<To, const From*const> {
typedef const To* ret_type; // Constant pointer arg case, return const Ty*
};
+template <class To, class From>
+struct cast_retty_impl<To, std::unique_ptr<From>> {
+private:
+ typedef typename cast_retty_impl<To, From *>::ret_type PointerType;
+ typedef typename std::remove_pointer<PointerType>::type ResultType;
+
+public:
+ typedef std::unique_ptr<ResultType> ret_type;
+};
template<class To, class From, class SimpleFrom>
struct cast_retty_wrap {
@@ -238,6 +256,16 @@ inline typename cast_retty<X, Y *>::ret_type cast(Y *Val) {
typename simplify_type<Y*>::SimpleType>::doit(Val);
}
+template <class X, class Y>
+inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type
+cast(std::unique_ptr<Y> &&Val) {
+ assert(isa<X>(Val.get()) && "cast<Ty>() argument of incompatible type!");
+ using ret_type = typename cast_retty<X, std::unique_ptr<Y>>::ret_type;
+ return ret_type(
+ cast_convert_val<X, Y *, typename simplify_type<Y *>::SimpleType>::doit(
+ Val.release()));
+}
+
// cast_or_null<X> - Functionally identical to cast, except that a null value is
// accepted.
//
@@ -271,6 +299,13 @@ cast_or_null(Y *Val) {
return cast<X>(Val);
}
+template <class X, class Y>
+inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type
+cast_or_null(std::unique_ptr<Y> &&Val) {
+ if (!Val)
+ return nullptr;
+ return cast<X>(std::move(Val));
+}
// dyn_cast<X> - Return the argument parameter cast to the specified type. This
// casting operator returns null if the argument is of the wrong type, so it can
@@ -323,6 +358,41 @@ dyn_cast_or_null(Y *Val) {
return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
}
+// unique_dyn_cast<X> - Given a unique_ptr<Y>, try to return a unique_ptr<X>,
+// taking ownership of the input pointer iff isa<X>(Val) is true. If the
+// cast is successful, From refers to nullptr on exit and the casted value
+// is returned. If the cast is unsuccessful, the function returns nullptr
+// and From is unchanged.
+template <class X, class Y>
+LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &Val)
+ -> decltype(cast<X>(Val)) {
+ if (!isa<X>(Val))
+ return nullptr;
+ return cast<X>(std::move(Val));
+}
+
+template <class X, class Y>
+LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &&Val)
+ -> decltype(cast<X>(Val)) {
+ return unique_dyn_cast<X, Y>(Val);
+}
+
+// dyn_cast_or_null<X> - Functionally identical to unique_dyn_cast, except that
+// a null value is accepted.
+template <class X, class Y>
+LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &Val)
+ -> decltype(cast<X>(Val)) {
+ if (!Val)
+ return nullptr;
+ return unique_dyn_cast<X, Y>(Val);
+}
+
+template <class X, class Y>
+LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &&Val)
+ -> decltype(cast<X>(Val)) {
+ return unique_dyn_cast_or_null<X, Y>(Val);
+}
+
} // End llvm namespace
#endif
diff --git a/include/llvm/Support/Chrono.h b/include/llvm/Support/Chrono.h
index 203439cab9192..6118ed0476edf 100644
--- a/include/llvm/Support/Chrono.h
+++ b/include/llvm/Support/Chrono.h
@@ -11,6 +11,7 @@
#define LLVM_SUPPORT_CHRONO_H
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/FormatProviders.h"
#include <chrono>
#include <ctime>
@@ -50,6 +51,100 @@ toTimePoint(std::time_t T) {
raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP);
+/// Implementation of format_provider<T> for duration types.
+///
+/// The options string of a duration type has the grammar:
+///
+/// duration_options ::= [unit][show_unit [number_options]]
+/// unit ::= `h`|`m`|`s`|`ms|`us`|`ns`
+/// show_unit ::= `+` | `-`
+/// number_options ::= options string for a integral or floating point type
+///
+/// Examples
+/// =================================
+/// | options | Input | Output |
+/// =================================
+/// | "" | 1s | 1 s |
+/// | "ms" | 1s | 1000 ms |
+/// | "ms-" | 1s | 1000 |
+/// | "ms-n" | 1s | 1,000 |
+/// | "" | 1.0s | 1.00 s |
+/// =================================
+///
+/// If the unit of the duration type is not one of the units specified above,
+/// it is still possible to format it, provided you explicitly request a
+/// display unit or you request that the unit is not displayed.
+
+namespace detail {
+template <typename Period> struct unit { static const char value[]; };
+template <typename Period> const char unit<Period>::value[] = "";
+
+template <> struct unit<std::ratio<3600>> { static const char value[]; };
+template <> struct unit<std::ratio<60>> { static const char value[]; };
+template <> struct unit<std::ratio<1>> { static const char value[]; };
+template <> struct unit<std::milli> { static const char value[]; };
+template <> struct unit<std::micro> { static const char value[]; };
+template <> struct unit<std::nano> { static const char value[]; };
+} // namespace detail
+
+template <typename Rep, typename Period>
+struct format_provider<std::chrono::duration<Rep, Period>> {
+private:
+ typedef std::chrono::duration<Rep, Period> Dur;
+ typedef typename std::conditional<
+ std::chrono::treat_as_floating_point<Rep>::value, double, intmax_t>::type
+ InternalRep;
+
+ template <typename AsPeriod> static InternalRep getAs(const Dur &D) {
+ using namespace std::chrono;
+ return duration_cast<duration<InternalRep, AsPeriod>>(D).count();
+ }
+
+ static std::pair<InternalRep, StringRef> consumeUnit(StringRef &Style,
+ const Dur &D) {
+ using namespace std::chrono;
+ if (Style.consume_front("ns"))
+ return {getAs<std::nano>(D), "ns"};
+ if (Style.consume_front("us"))
+ return {getAs<std::micro>(D), "us"};
+ if (Style.consume_front("ms"))
+ return {getAs<std::milli>(D), "ms"};
+ if (Style.consume_front("s"))
+ return {getAs<std::ratio<1>>(D), "s"};
+ if (Style.consume_front("m"))
+ return {getAs<std::ratio<60>>(D), "m"};
+ if (Style.consume_front("h"))
+ return {getAs<std::ratio<3600>>(D), "h"};
+ return {D.count(), detail::unit<Period>::value};
+ }
+
+ static bool consumeShowUnit(StringRef &Style) {
+ if (Style.empty())
+ return true;
+ if (Style.consume_front("-"))
+ return false;
+ if (Style.consume_front("+"))
+ return true;
+ assert(0 && "Unrecognised duration format");
+ return true;
+ }
+
+public:
+ static void format(const Dur &D, llvm::raw_ostream &Stream, StringRef Style) {
+ InternalRep count;
+ StringRef unit;
+ std::tie(count, unit) = consumeUnit(Style, D);
+ bool show_unit = consumeShowUnit(Style);
+
+ format_provider<InternalRep>::format(count, Stream, Style);
+
+ if (show_unit) {
+ assert(!unit.empty());
+ Stream << " " << unit;
+ }
+ }
+};
+
} // namespace llvm
#endif // LLVM_SUPPORT_CHRONO_H
diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h
index 8d4ac81d29429..ae32e20d6daba 100644
--- a/include/llvm/Support/CommandLine.h
+++ b/include/llvm/Support/CommandLine.h
@@ -50,9 +50,12 @@ namespace cl {
//===----------------------------------------------------------------------===//
// ParseCommandLineOptions - Command line option processing entry point.
//
+// Returns true on success. Otherwise, this will print the error message to
+// stderr and exit if \p Errs is not set (nullptr by default), or print the
+// error message to \p Errs and return false if \p Errs is provided.
bool ParseCommandLineOptions(int argc, const char *const *argv,
StringRef Overview = "",
- bool IgnoreErrors = false);
+ raw_ostream *Errs = nullptr);
//===----------------------------------------------------------------------===//
// ParseEnvironmentOptions - Environment variable option processing alternate
@@ -343,6 +346,9 @@ public:
virtual void printOptionValue(size_t GlobalWidth, bool Force) const = 0;
+ static void printHelpStr(StringRef HelpStr, size_t Indent,
+ size_t FirstLineIndentedBy);
+
virtual void getExtraOptionNames(SmallVectorImpl<StringRef> &) {}
// addOccurrence - Wrapper around handleOccurrence that enforces Flags.
diff --git a/include/llvm/Support/Compiler.h b/include/llvm/Support/Compiler.h
index 55148a490c298..a56bc93e111b6 100644
--- a/include/llvm/Support/Compiler.h
+++ b/include/llvm/Support/Compiler.h
@@ -343,7 +343,7 @@
/// int k;
/// long long l;
/// };
-/// LLVM_PACKED_END
+/// LLVM_PACKED_END
#ifdef _MSC_VER
# define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop))
# define LLVM_PACKED_START __pragma(pack(push, 1))
@@ -445,6 +445,9 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
/// \brief Mark debug helper function definitions like dump() that should not be
/// stripped from debug builds.
+/// Note that you should also surround dump() functions with
+/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always
+/// get stripped in release builds.
// FIXME: Move this to a private config.h as it's not usable in public headers.
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
@@ -461,7 +464,7 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
#define LLVM_PRETTY_FUNCTION __FUNCSIG__
#elif defined(__GNUC__) || defined(__clang__)
#define LLVM_PRETTY_FUNCTION __PRETTY_FUNCTION__
-#else
+#else
#define LLVM_PRETTY_FUNCTION __func__
#endif
diff --git a/include/llvm/Support/Compression.h b/include/llvm/Support/Compression.h
index 5bf7031fe9f90..2d191abe4b1af 100644
--- a/include/llvm/Support/Compression.h
+++ b/include/llvm/Support/Compression.h
@@ -18,6 +18,7 @@
namespace llvm {
template <typename T> class SmallVectorImpl;
+class Error;
class StringRef;
namespace zlib {
@@ -29,26 +30,17 @@ enum CompressionLevel {
BestSizeCompression
};
-enum Status {
- StatusOK,
- StatusUnsupported, // zlib is unavailable
- StatusOutOfMemory, // there was not enough memory
- StatusBufferTooShort, // there was not enough room in the output buffer
- StatusInvalidArg, // invalid input parameter
- StatusInvalidData // data was corrupted or incomplete
-};
-
bool isAvailable();
-Status compress(StringRef InputBuffer, SmallVectorImpl<char> &CompressedBuffer,
- CompressionLevel Level = DefaultCompression);
+Error compress(StringRef InputBuffer, SmallVectorImpl<char> &CompressedBuffer,
+ CompressionLevel Level = DefaultCompression);
-Status uncompress(StringRef InputBuffer, char *UncompressedBuffer,
- size_t &UncompressedSize);
+Error uncompress(StringRef InputBuffer, char *UncompressedBuffer,
+ size_t &UncompressedSize);
-Status uncompress(StringRef InputBuffer,
- SmallVectorImpl<char> &UncompressedBuffer,
- size_t UncompressedSize);
+Error uncompress(StringRef InputBuffer,
+ SmallVectorImpl<char> &UncompressedBuffer,
+ size_t UncompressedSize);
uint32_t crc32(StringRef Buffer);
diff --git a/include/llvm/Support/Debug.h b/include/llvm/Support/Debug.h
index 3465c403361f9..48e9e1bc167d3 100644
--- a/include/llvm/Support/Debug.h
+++ b/include/llvm/Support/Debug.h
@@ -33,11 +33,6 @@ namespace llvm {
class raw_ostream;
#ifndef NDEBUG
-/// DebugFlag - This boolean is set to true if the '-debug' command line option
-/// is specified. This should probably not be referenced directly, instead, use
-/// the DEBUG macro below.
-///
-extern bool DebugFlag;
/// isCurrentDebugType - Return true if the specified string is the debug type
/// specified on the command line, or if none was specified on the command line
@@ -77,6 +72,29 @@ void setCurrentDebugTypes(const char **Types, unsigned Count);
#define DEBUG_WITH_TYPE(TYPE, X) do { } while (false)
#endif
+/// This boolean is set to true if the '-debug' command line option
+/// is specified. This should probably not be referenced directly, instead, use
+/// the DEBUG macro below.
+///
+extern bool DebugFlag;
+
+/// \name Verification flags.
+///
+/// These flags turns on/off that are expensive and are turned off by default,
+/// unless macro EXPENSIVE_CHECKS is defined. The flags allow selectively
+/// turning the checks on without need to recompile.
+/// \{
+
+/// Enables verification of dominator trees.
+///
+extern bool VerifyDomInfo;
+
+/// Enables verification of loop info.
+///
+extern bool VerifyLoopInfo;
+
+///\}
+
/// EnableDebugBuffering - This defaults to false. If true, the debug
/// stream will install signal handlers to dump any buffered debug
/// output. It allows clients to selectively allow the debug stream
diff --git a/include/llvm/Support/DebugCounter.h b/include/llvm/Support/DebugCounter.h
new file mode 100644
index 0000000000000..9687cb7b9d95f
--- /dev/null
+++ b/include/llvm/Support/DebugCounter.h
@@ -0,0 +1,165 @@
+//===- llvm/Support/DebugCounter.h - Debug counter support ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief This file provides an implementation of debug counters. Debug
+/// counters are a tool that let you narrow down a miscompilation to a specific
+/// thing happening.
+///
+/// To give a use case: Imagine you have a file, very large, and you
+/// are trying to understand the minimal transformation that breaks it. Bugpoint
+/// and bisection is often helpful here in narrowing it down to a specific pass,
+/// but it's still a very large file, and a very complicated pass to try to
+/// debug. That is where debug counting steps in. You can instrument the pass
+/// with a debug counter before it does a certain thing, and depending on the
+/// counts, it will either execute that thing or not. The debug counter itself
+/// consists of a skip and a count. Skip is the number of times shouldExecute
+/// needs to be called before it returns true. Count is the number of times to
+/// return true once Skip is 0. So a skip=47, count=2 ,would skip the first 47
+/// executions by returning false from shouldExecute, then execute twice, and
+/// then return false again.
+/// Note that a counter set to a negative number will always execute.
+/// For a concrete example, during predicateinfo creation, the renaming pass
+/// replaces each use with a renamed use.
+////
+/// If I use DEBUG_COUNTER to create a counter called "predicateinfo", and
+/// variable name RenameCounter, and then instrument this renaming with a debug
+/// counter, like so:
+///
+/// if (!DebugCounter::shouldExecute(RenameCounter)
+/// <continue or return or whatever not executing looks like>
+///
+/// Now I can, from the command line, make it rename or not rename certain uses
+/// by setting the skip and count.
+/// So for example
+/// bin/opt -debug-counter=predicateinfo-skip=47,predicateinfo-count=1
+/// will skip renaming the first 47 uses, then rename one, then skip the rest.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DEBUGCOUNTER_H
+#define LLVM_SUPPORT_DEBUGCOUNTER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/UniqueVector.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+namespace llvm {
+
+class DebugCounter {
+public:
+ /// \brief Returns a reference to the singleton instance.
+ static DebugCounter &instance();
+
+ // Used by the command line option parser to push a new value it parsed.
+ void push_back(const std::string &);
+
+ // Register a counter with the specified name.
+ //
+ // FIXME: Currently, counter registration is required to happen before command
+ // line option parsing. The main reason to register counters is to produce a
+ // nice list of them on the command line, but i'm not sure this is worth it.
+ static unsigned registerCounter(StringRef Name, StringRef Desc) {
+ return instance().addCounter(Name, Desc);
+ }
+ inline static bool shouldExecute(unsigned CounterName) {
+// Compile to nothing when debugging is off
+#ifdef NDEBUG
+ return true;
+#else
+ auto &Us = instance();
+ auto Result = Us.Counters.find(CounterName);
+ if (Result != Us.Counters.end()) {
+ auto &CounterPair = Result->second;
+ // We only execute while the skip (first) is zero and the count (second)
+ // is non-zero.
+ // Negative counters always execute.
+ if (CounterPair.first < 0)
+ return true;
+ if (CounterPair.first != 0) {
+ --CounterPair.first;
+ return false;
+ }
+ if (CounterPair.second < 0)
+ return true;
+ if (CounterPair.second != 0) {
+ --CounterPair.second;
+ return true;
+ }
+ return false;
+ }
+ // Didn't find the counter, should we warn?
+ return true;
+#endif // NDEBUG
+ }
+
+ // Return true if a given counter had values set (either programatically or on
+ // the command line). This will return true even if those values are
+ // currently in a state where the counter will always execute.
+ static bool isCounterSet(unsigned ID) {
+ return instance().Counters.count(ID);
+ }
+
+ // Return the skip and count for a counter. This only works for set counters.
+ static std::pair<int, int> getCounterValue(unsigned ID) {
+ auto &Us = instance();
+ auto Result = Us.Counters.find(ID);
+ assert(Result != Us.Counters.end() && "Asking about a non-set counter");
+ return Result->second;
+ }
+
+ // Set a registered counter to a given value.
+ static void setCounterValue(unsigned ID, const std::pair<int, int> &Val) {
+ auto &Us = instance();
+ Us.Counters[ID] = Val;
+ }
+
+ // Dump or print the current counter set.
+ LLVM_DUMP_METHOD void dump() { print(dbgs()); }
+
+ void print(raw_ostream &OS);
+
+ // Get the counter ID for a given named counter, or return 0 if none is found.
+ unsigned getCounterId(const std::string &Name) const {
+ return RegisteredCounters.idFor(Name);
+ }
+
+ // Return the number of registered counters.
+ unsigned int getNumCounters() const { return RegisteredCounters.size(); }
+
+ // Return the name and description of the counter with the given ID.
+ std::pair<std::string, std::string> getCounterInfo(unsigned ID) const {
+ return std::make_pair(RegisteredCounters[ID], CounterDesc.lookup(ID));
+ }
+
+ // Iterate through the registered counters
+ typedef UniqueVector<std::string> CounterVector;
+ CounterVector::const_iterator begin() const {
+ return RegisteredCounters.begin();
+ }
+ CounterVector::const_iterator end() const { return RegisteredCounters.end(); }
+
+private:
+ unsigned addCounter(const std::string &Name, const std::string &Desc) {
+ unsigned Result = RegisteredCounters.insert(Name);
+ CounterDesc[Result] = Desc;
+ return Result;
+ }
+ DenseMap<unsigned, std::pair<long, long>> Counters;
+ DenseMap<unsigned, std::string> CounterDesc;
+ CounterVector RegisteredCounters;
+};
+
+#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC) \
+ static const unsigned VARNAME = \
+ DebugCounter::registerCounter(COUNTERNAME, DESC);
+
+} // namespace llvm
+#endif
diff --git a/include/llvm/Support/Dwarf.def b/include/llvm/Support/Dwarf.def
index 841fc7d4ae22e..fdbd8ea701166 100644
--- a/include/llvm/Support/Dwarf.def
+++ b/include/llvm/Support/Dwarf.def
@@ -19,7 +19,8 @@
defined HANDLE_DW_CC || defined HANDLE_DW_LNS || \
defined HANDLE_DW_LNE || defined HANDLE_DW_LNCT || \
defined HANDLE_DW_MACRO || defined HANDLE_DW_RLE || \
- defined HANDLE_DW_CFA || defined HANDLE_DW_APPLE_PROPERTY)
+ defined HANDLE_DW_CFA || defined HANDLE_DW_APPLE_PROPERTY || \
+ defined HANDLE_DW_UT)
#error "Missing macro definition of HANDLE_DW*"
#endif
@@ -87,6 +88,10 @@
#define HANDLE_DW_APPLE_PROPERTY(ID, NAME)
#endif
+#ifndef HANDLE_DW_UT
+#define HANDLE_DW_UT(ID, NAME)
+#endif
+
HANDLE_DW_TAG(0x0000, null)
HANDLE_DW_TAG(0x0001, array_type)
HANDLE_DW_TAG(0x0002, class_type)
@@ -135,6 +140,7 @@ HANDLE_DW_TAG(0x0032, try_block)
HANDLE_DW_TAG(0x0033, variant_part)
HANDLE_DW_TAG(0x0034, variable)
HANDLE_DW_TAG(0x0035, volatile_type)
+// New in DWARF v3:
HANDLE_DW_TAG(0x0036, dwarf_procedure)
HANDLE_DW_TAG(0x0037, restrict_type)
HANDLE_DW_TAG(0x0038, interface_type)
@@ -145,11 +151,11 @@ HANDLE_DW_TAG(0x003c, partial_unit)
HANDLE_DW_TAG(0x003d, imported_unit)
HANDLE_DW_TAG(0x003f, condition)
HANDLE_DW_TAG(0x0040, shared_type)
+// New in DWARF v4:
HANDLE_DW_TAG(0x0041, type_unit)
HANDLE_DW_TAG(0x0042, rvalue_reference_type)
HANDLE_DW_TAG(0x0043, template_alias)
-
-// New in DWARF v5.
+// New in DWARF v5:
HANDLE_DW_TAG(0x0044, coarray_type)
HANDLE_DW_TAG(0x0045, generic_subrange)
HANDLE_DW_TAG(0x0046, dynamic_type)
@@ -158,8 +164,7 @@ HANDLE_DW_TAG(0x0048, call_site)
HANDLE_DW_TAG(0x0049, call_site_parameter)
HANDLE_DW_TAG(0x004a, skeleton_unit)
HANDLE_DW_TAG(0x004b, immutable_type)
-
-// User-defined tags.
+// Vendor extensions:
HANDLE_DW_TAG(0x4081, MIPS_loop)
HANDLE_DW_TAG(0x4101, format_label)
HANDLE_DW_TAG(0x4102, function_template)
@@ -234,6 +239,7 @@ HANDLE_DW_AT(0x4a, use_location)
HANDLE_DW_AT(0x4b, variable_parameter)
HANDLE_DW_AT(0x4c, virtuality)
HANDLE_DW_AT(0x4d, vtable_elem_location)
+// New in DWARF v3:
HANDLE_DW_AT(0x4e, allocated)
HANDLE_DW_AT(0x4f, associated)
HANDLE_DW_AT(0x50, data_location)
@@ -261,14 +267,14 @@ HANDLE_DW_AT(0x65, endianity)
HANDLE_DW_AT(0x66, elemental)
HANDLE_DW_AT(0x67, pure)
HANDLE_DW_AT(0x68, recursive)
+// New in DWARF v4:
HANDLE_DW_AT(0x69, signature)
HANDLE_DW_AT(0x6a, main_subprogram)
HANDLE_DW_AT(0x6b, data_bit_offset)
HANDLE_DW_AT(0x6c, const_expr)
HANDLE_DW_AT(0x6d, enum_class)
HANDLE_DW_AT(0x6e, linkage_name)
-
-// New in DWARF 5:
+// New in DWARF v5:
HANDLE_DW_AT(0x6f, string_length_bit_size)
HANDLE_DW_AT(0x70, string_length_byte_size)
HANDLE_DW_AT(0x71, rank)
@@ -299,7 +305,7 @@ HANDLE_DW_AT(0x89, export_symbols)
HANDLE_DW_AT(0x8a, deleted)
HANDLE_DW_AT(0x8b, defaulted)
HANDLE_DW_AT(0x8c, loclists_base)
-
+// Vendor extensions:
HANDLE_DW_AT(0x2002, MIPS_loop_begin)
HANDLE_DW_AT(0x2003, MIPS_tail_loop_begin)
HANDLE_DW_AT(0x2004, MIPS_epilog_begin)
@@ -315,11 +321,9 @@ HANDLE_DW_AT(0x200d, MIPS_stride_elem)
HANDLE_DW_AT(0x200e, MIPS_ptr_dopetype)
HANDLE_DW_AT(0x200f, MIPS_allocatable_dopetype)
HANDLE_DW_AT(0x2010, MIPS_assumed_shape_dopetype)
-
// This one appears to have only been implemented by Open64 for
// fortran and may conflict with other extensions.
HANDLE_DW_AT(0x2011, MIPS_assumed_size)
-
// GNU extensions
HANDLE_DW_AT(0x2101, sf_names)
HANDLE_DW_AT(0x2102, src_info)
@@ -329,10 +333,8 @@ HANDLE_DW_AT(0x2105, body_begin)
HANDLE_DW_AT(0x2106, body_end)
HANDLE_DW_AT(0x2107, GNU_vector)
HANDLE_DW_AT(0x2110, GNU_template_name)
-
HANDLE_DW_AT(0x210f, GNU_odr_signature)
HANDLE_DW_AT(0x2119, GNU_macros)
-
// Extensions for Fission proposal.
HANDLE_DW_AT(0x2130, GNU_dwo_name)
HANDLE_DW_AT(0x2131, GNU_dwo_id)
@@ -341,7 +343,6 @@ HANDLE_DW_AT(0x2133, GNU_addr_base)
HANDLE_DW_AT(0x2134, GNU_pubnames)
HANDLE_DW_AT(0x2135, GNU_pubtypes)
HANDLE_DW_AT(0x2136, GNU_discriminator)
-
// Borland extensions.
HANDLE_DW_AT(0x3b11, BORLAND_property_read)
HANDLE_DW_AT(0x3b12, BORLAND_property_write)
@@ -360,12 +361,10 @@ HANDLE_DW_AT(0x3b28, BORLAND_Delphi_ABI)
HANDLE_DW_AT(0x3b29, BORLAND_Delphi_return)
HANDLE_DW_AT(0x3b30, BORLAND_Delphi_frameptr)
HANDLE_DW_AT(0x3b31, BORLAND_closure)
-
// LLVM project extensions.
HANDLE_DW_AT(0x3e00, LLVM_include_path)
HANDLE_DW_AT(0x3e01, LLVM_config_macros)
HANDLE_DW_AT(0x3e02, LLVM_isysroot)
-
// Apple extensions.
HANDLE_DW_AT(0x3fe1, APPLE_optimized)
HANDLE_DW_AT(0x3fe2, APPLE_flags)
@@ -403,26 +402,34 @@ HANDLE_DW_FORM(0x13, ref4)
HANDLE_DW_FORM(0x14, ref8)
HANDLE_DW_FORM(0x15, ref_udata)
HANDLE_DW_FORM(0x16, indirect)
+// New in DWARF v4:
HANDLE_DW_FORM(0x17, sec_offset)
HANDLE_DW_FORM(0x18, exprloc)
HANDLE_DW_FORM(0x19, flag_present)
-
-// New in DWARF v5.
+// This was defined out of sequence.
+HANDLE_DW_FORM(0x20, ref_sig8)
+// New in DWARF v5:
HANDLE_DW_FORM(0x1a, strx)
HANDLE_DW_FORM(0x1b, addrx)
-HANDLE_DW_FORM(0x1c, ref_sup)
+HANDLE_DW_FORM(0x1c, ref_sup4)
HANDLE_DW_FORM(0x1d, strp_sup)
HANDLE_DW_FORM(0x1e, data16)
HANDLE_DW_FORM(0x1f, line_strp)
-HANDLE_DW_FORM(0x20, ref_sig8)
HANDLE_DW_FORM(0x21, implicit_const)
HANDLE_DW_FORM(0x22, loclistx)
HANDLE_DW_FORM(0x23, rnglistx)
-
+HANDLE_DW_FORM(0x24, ref_sup8)
+HANDLE_DW_FORM(0x25, strx1)
+HANDLE_DW_FORM(0x26, strx2)
+HANDLE_DW_FORM(0x27, strx3)
+HANDLE_DW_FORM(0x28, strx4)
+HANDLE_DW_FORM(0x29, addrx1)
+HANDLE_DW_FORM(0x2a, addrx2)
+HANDLE_DW_FORM(0x2b, addrx3)
+HANDLE_DW_FORM(0x2c, addrx4)
// Extensions for Fission proposal
HANDLE_DW_FORM(0x1f01, GNU_addr_index)
HANDLE_DW_FORM(0x1f02, GNU_str_index)
-
// Alternate debug sections proposal (output of "dwz" tool).
HANDLE_DW_FORM(0x1f20, GNU_ref_alt)
HANDLE_DW_FORM(0x1f21, GNU_strp_alt)
@@ -462,7 +469,6 @@ HANDLE_DW_OP(0x24, shl)
HANDLE_DW_OP(0x25, shr)
HANDLE_DW_OP(0x26, shra)
HANDLE_DW_OP(0x27, xor)
-HANDLE_DW_OP(0x2f, skip)
HANDLE_DW_OP(0x28, bra)
HANDLE_DW_OP(0x29, eq)
HANDLE_DW_OP(0x2a, ge)
@@ -470,6 +476,7 @@ HANDLE_DW_OP(0x2b, gt)
HANDLE_DW_OP(0x2c, le)
HANDLE_DW_OP(0x2d, lt)
HANDLE_DW_OP(0x2e, ne)
+HANDLE_DW_OP(0x2f, skip)
HANDLE_DW_OP(0x30, lit0)
HANDLE_DW_OP(0x31, lit1)
HANDLE_DW_OP(0x32, lit2)
@@ -573,6 +580,7 @@ HANDLE_DW_OP(0x93, piece)
HANDLE_DW_OP(0x94, deref_size)
HANDLE_DW_OP(0x95, xderef_size)
HANDLE_DW_OP(0x96, nop)
+// New in DWARF v3:
HANDLE_DW_OP(0x97, push_object_address)
HANDLE_DW_OP(0x98, call2)
HANDLE_DW_OP(0x99, call4)
@@ -580,8 +588,10 @@ HANDLE_DW_OP(0x9a, call_ref)
HANDLE_DW_OP(0x9b, form_tls_address)
HANDLE_DW_OP(0x9c, call_frame_cfa)
HANDLE_DW_OP(0x9d, bit_piece)
+// New in DWARF v4:
HANDLE_DW_OP(0x9e, implicit_value)
HANDLE_DW_OP(0x9f, stack_value)
+// New in DWARF v5:
HANDLE_DW_OP(0xa0, implicit_pointer)
HANDLE_DW_OP(0xa1, addrx)
HANDLE_DW_OP(0xa2, constx)
@@ -592,11 +602,9 @@ HANDLE_DW_OP(0xa6, deref_type)
HANDLE_DW_OP(0xa7, xderef_type)
HANDLE_DW_OP(0xa8, convert)
HANDLE_DW_OP(0xa9, reinterpret)
-
-// Vendor extensions.
+// Vendor extensions:
// Extensions for GNU-style thread-local storage.
HANDLE_DW_OP(0xe0, GNU_push_tls_address)
-
// Extensions for Fission proposal.
HANDLE_DW_OP(0xfb, GNU_addr_index)
HANDLE_DW_OP(0xfc, GNU_const_index)
@@ -612,6 +620,7 @@ HANDLE_DW_LANG(0x0007, Fortran77)
HANDLE_DW_LANG(0x0008, Fortran90)
HANDLE_DW_LANG(0x0009, Pascal83)
HANDLE_DW_LANG(0x000a, Modula2)
+// New in DWARF v3:
HANDLE_DW_LANG(0x000b, Java)
HANDLE_DW_LANG(0x000c, C99)
HANDLE_DW_LANG(0x000d, Ada95)
@@ -621,9 +630,9 @@ HANDLE_DW_LANG(0x0010, ObjC)
HANDLE_DW_LANG(0x0011, ObjC_plus_plus)
HANDLE_DW_LANG(0x0012, UPC)
HANDLE_DW_LANG(0x0013, D)
-
-// New in DWARF 5:
+// New in DWARF v4:
HANDLE_DW_LANG(0x0014, Python)
+// New in DWARF v5:
HANDLE_DW_LANG(0x0015, OpenCL)
HANDLE_DW_LANG(0x0016, Go)
HANDLE_DW_LANG(0x0017, Modula3)
@@ -640,8 +649,8 @@ HANDLE_DW_LANG(0x0021, C_plus_plus_14)
HANDLE_DW_LANG(0x0022, Fortran03)
HANDLE_DW_LANG(0x0023, Fortran08)
HANDLE_DW_LANG(0x0024, RenderScript)
-
-// Vendor extensions.
+HANDLE_DW_LANG(0x0025, BLISS)
+// Vendor extensions:
HANDLE_DW_LANG(0x8001, Mips_Assembler)
HANDLE_DW_LANG(0x8e57, GOOGLE_RenderScript)
HANDLE_DW_LANG(0xb000, BORLAND_Delphi)
@@ -655,6 +664,7 @@ HANDLE_DW_ATE(0x05, signed)
HANDLE_DW_ATE(0x06, signed_char)
HANDLE_DW_ATE(0x07, unsigned)
HANDLE_DW_ATE(0x08, unsigned_char)
+// New in DWARF v3:
HANDLE_DW_ATE(0x09, imaginary_float)
HANDLE_DW_ATE(0x0a, packed_decimal)
HANDLE_DW_ATE(0x0b, numeric_string)
@@ -662,7 +672,9 @@ HANDLE_DW_ATE(0x0c, edited)
HANDLE_DW_ATE(0x0d, signed_fixed)
HANDLE_DW_ATE(0x0e, unsigned_fixed)
HANDLE_DW_ATE(0x0f, decimal_float)
+// New in DWARF v4:
HANDLE_DW_ATE(0x10, UTF)
+// New in DWARF v5:
HANDLE_DW_ATE(0x11, UCS)
HANDLE_DW_ATE(0x12, ASCII)
@@ -680,8 +692,10 @@ HANDLE_DW_DEFAULTED(0x02, out_of_class)
HANDLE_DW_CC(0x01, normal)
HANDLE_DW_CC(0x02, program)
HANDLE_DW_CC(0x03, nocall)
+// New in DWARF v5:
HANDLE_DW_CC(0x04, pass_by_reference)
HANDLE_DW_CC(0x05, pass_by_value)
+// Vendor extensions:
HANDLE_DW_CC(0x41, GNU_borland_fastcall_i386)
HANDLE_DW_CC(0xb0, BORLAND_safecall)
HANDLE_DW_CC(0xb1, BORLAND_stdcall)
@@ -696,6 +710,7 @@ HANDLE_DW_CC(0xc0, LLVM_vectorcall)
HANDLE_DW_LNE(0x01, end_sequence)
HANDLE_DW_LNE(0x02, set_address)
HANDLE_DW_LNE(0x03, define_file)
+// New in DWARF v4:
HANDLE_DW_LNE(0x04, set_discriminator)
// Line Number Standard Opcode Encodings.
@@ -709,6 +724,7 @@ HANDLE_DW_LNS(0x06, negate_stmt)
HANDLE_DW_LNS(0x07, set_basic_block)
HANDLE_DW_LNS(0x08, const_add_pc)
HANDLE_DW_LNS(0x09, fixed_advance_pc)
+// New in DWARF v3:
HANDLE_DW_LNS(0x0a, set_prologue_end)
HANDLE_DW_LNS(0x0b, set_epilogue_begin)
HANDLE_DW_LNS(0x0c, set_isa)
@@ -720,6 +736,7 @@ HANDLE_DW_LNCT(0x03, timestamp)
HANDLE_DW_LNCT(0x04, size)
HANDLE_DW_LNCT(0x05, MD5)
+// DWARF v5 Macro information.
HANDLE_DW_MACRO(0x01, define)
HANDLE_DW_MACRO(0x02, undef)
HANDLE_DW_MACRO(0x03, start_file)
@@ -733,7 +750,7 @@ HANDLE_DW_MACRO(0x0a, import_sup)
HANDLE_DW_MACRO(0x0b, define_strx)
HANDLE_DW_MACRO(0x0c, undef_strx)
-// Range list entry encoding values.
+// DWARF v5 Range List Entry encoding values.
HANDLE_DW_RLE(0x00, end_of_list)
HANDLE_DW_RLE(0x01, base_addressx)
HANDLE_DW_RLE(0x02, startx_endx)
@@ -762,6 +779,7 @@ HANDLE_DW_CFA(0x0b, restore_state)
HANDLE_DW_CFA(0x0c, def_cfa)
HANDLE_DW_CFA(0x0d, def_cfa_register)
HANDLE_DW_CFA(0x0e, def_cfa_offset)
+// New in DWARF v3:
HANDLE_DW_CFA(0x0f, def_cfa_expression)
HANDLE_DW_CFA(0x10, expression)
HANDLE_DW_CFA(0x11, offset_extended_sf)
@@ -770,6 +788,7 @@ HANDLE_DW_CFA(0x13, def_cfa_offset_sf)
HANDLE_DW_CFA(0x14, val_offset)
HANDLE_DW_CFA(0x15, val_offset_sf)
HANDLE_DW_CFA(0x16, val_expression)
+// Vendor extensions:
HANDLE_DW_CFA(0x1d, MIPS_advance_loc8)
HANDLE_DW_CFA(0x2d, GNU_window_save)
HANDLE_DW_CFA(0x2e, GNU_args_size)
@@ -792,6 +811,13 @@ HANDLE_DW_APPLE_PROPERTY(0x1000, nullability)
HANDLE_DW_APPLE_PROPERTY(0x2000, null_resettable)
HANDLE_DW_APPLE_PROPERTY(0x4000, class)
+// DWARF v5 Unit Types.
+HANDLE_DW_UT(0x01, compile)
+HANDLE_DW_UT(0x02, type)
+HANDLE_DW_UT(0x03, partial)
+HANDLE_DW_UT(0x04, skeleton)
+HANDLE_DW_UT(0x05, split_compile)
+HANDLE_DW_UT(0x06, split_type)
#undef HANDLE_DW_TAG
#undef HANDLE_DW_AT
@@ -809,3 +835,4 @@ HANDLE_DW_APPLE_PROPERTY(0x4000, class)
#undef HANDLE_DW_RLE
#undef HANDLE_DW_CFA
#undef HANDLE_DW_APPLE_PROPERTY
+#undef HANDLE_DW_UT
diff --git a/include/llvm/Support/Dwarf.h b/include/llvm/Support/Dwarf.h
index 8336b9df9df0d..84056682924eb 100644
--- a/include/llvm/Support/Dwarf.h
+++ b/include/llvm/Support/Dwarf.h
@@ -29,7 +29,7 @@ class StringRef;
namespace dwarf {
//===----------------------------------------------------------------------===//
-// Dwarf constants as gleaned from the DWARF Debugging Information Format V.4
+// DWARF constants as gleaned from the DWARF Debugging Information Format V.5
// reference manual http://www.dwarfstd.org/.
//
@@ -305,7 +305,15 @@ enum ApplePropertyAttributes {
#include "llvm/Support/Dwarf.def"
};
-// Constants for the DWARF5 Accelerator Table Proposal
+/// Constants for unit types in DWARF v5.
+enum UnitType : unsigned char {
+#define HANDLE_DW_UT(ID, NAME) DW_UT_##NAME = ID,
+#include "llvm/Support/Dwarf.def"
+ DW_UT_lo_user = 0x80,
+ DW_UT_hi_user = 0xff
+};
+
+// Constants for the DWARF v5 Accelerator Table Proposal
enum AcceleratorTable {
// Data layout descriptors.
DW_ATOM_null = 0u, // Marker as the end of a list of atoms.
@@ -373,6 +381,7 @@ StringRef LNExtendedString(unsigned Encoding);
StringRef MacinfoString(unsigned Encoding);
StringRef CallFrameString(unsigned Encoding);
StringRef ApplePropertyString(unsigned);
+StringRef UnitTypeString(unsigned);
StringRef AtomTypeString(unsigned Atom);
StringRef GDBIndexEntryKindString(GDBIndexEntryKind Kind);
StringRef GDBIndexEntryLinkageString(GDBIndexEntryLinkage Linkage);
diff --git a/include/llvm/Support/DynamicLibrary.h b/include/llvm/Support/DynamicLibrary.h
index a7d22212dbdb5..aa9bb8938ad3b 100644
--- a/include/llvm/Support/DynamicLibrary.h
+++ b/include/llvm/Support/DynamicLibrary.h
@@ -68,6 +68,15 @@ namespace sys {
static DynamicLibrary getPermanentLibrary(const char *filename,
std::string *errMsg = nullptr);
+ /// Registers an externally loaded library. The library will be unloaded
+ /// when the program terminates.
+ ///
+ /// It is safe to call this function multiple times for the same library.
+ ///
+ /// \returns An empty \p DynamicLibrary if the library was already loaded.
+ static DynamicLibrary addPermanentLibrary(void *handle,
+ std::string *errMsg = nullptr);
+
/// This function permanently loads the dynamic library at the given path.
/// Use this instead of getPermanentLibrary() when you won't need to get
/// symbols from the library itself.
diff --git a/include/llvm/Support/ELF.h b/include/llvm/Support/ELF.h
index 3ea4da81ad945..33f20a809d6ca 100644
--- a/include/llvm/Support/ELF.h
+++ b/include/llvm/Support/ELF.h
@@ -556,6 +556,7 @@ enum {
EF_HEXAGON_MACH_V5 = 0x00000004, // Hexagon V5
EF_HEXAGON_MACH_V55 = 0x00000005, // Hexagon V55
EF_HEXAGON_MACH_V60 = 0x00000060, // Hexagon V60
+ EF_HEXAGON_MACH_V62 = 0x00000062, // Hexagon V62
// Highest ISA version flags
EF_HEXAGON_ISA_MACH = 0x00000000, // Same as specified in bits[11:0]
@@ -566,6 +567,7 @@ enum {
EF_HEXAGON_ISA_V5 = 0x00000040, // Hexagon V5 ISA
EF_HEXAGON_ISA_V55 = 0x00000050, // Hexagon V55 ISA
EF_HEXAGON_ISA_V60 = 0x00000060, // Hexagon V60 ISA
+ EF_HEXAGON_ISA_V62 = 0x00000062, // Hexagon V62 ISA
};
// Hexagon-specific section indexes for common small data
@@ -703,6 +705,7 @@ enum : unsigned {
SHT_MIPS_REGINFO = 0x70000006, // Register usage information
SHT_MIPS_OPTIONS = 0x7000000d, // General options
+ SHT_MIPS_DWARF = 0x7000001e, // DWARF debugging section.
SHT_MIPS_ABIFLAGS = 0x7000002a, // ABI information.
SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type.
@@ -751,21 +754,21 @@ enum : unsigned {
// Start of target-specific flags.
- /// XCORE_SHF_CP_SECTION - All sections with the "c" flag are grouped
- /// together by the linker to form the constant pool and the cp register is
- /// set to the start of the constant pool by the boot code.
- XCORE_SHF_CP_SECTION = 0x800U,
-
- /// XCORE_SHF_DP_SECTION - All sections with the "d" flag are grouped
- /// together by the linker to form the data section and the dp register is
- /// set to the start of the section by the boot code.
- XCORE_SHF_DP_SECTION = 0x1000U,
-
SHF_MASKOS = 0x0ff00000,
// Bits indicating processor-specific flags.
SHF_MASKPROC = 0xf0000000,
+ /// All sections with the "d" flag are grouped together by the linker to form
+ /// the data section and the dp register is set to the start of the section by
+ /// the boot code.
+ XCORE_SHF_DP_SECTION = 0x10000000,
+
+ /// All sections with the "c" flag are grouped together by the linker to form
+ /// the constant pool and the cp register is set to the start of the constant
+ /// pool by the boot code.
+ XCORE_SHF_CP_SECTION = 0x20000000,
+
// If an object file section does not have this flag set, then it may not hold
// more than 2GB and can be freely referred to in objects using smaller code
// models. Otherwise, only objects using larger code models can refer to them.
@@ -1312,6 +1315,19 @@ enum { VER_NEED_NONE = 0, VER_NEED_CURRENT = 1 };
// SHT_NOTE section types
enum {
+ NT_FREEBSD_THRMISC = 7,
+ NT_FREEBSD_PROCSTAT_PROC = 8,
+ NT_FREEBSD_PROCSTAT_FILES = 9,
+ NT_FREEBSD_PROCSTAT_VMMAP = 10,
+ NT_FREEBSD_PROCSTAT_GROUPS = 11,
+ NT_FREEBSD_PROCSTAT_UMASK = 12,
+ NT_FREEBSD_PROCSTAT_RLIMIT = 13,
+ NT_FREEBSD_PROCSTAT_OSREL = 14,
+ NT_FREEBSD_PROCSTAT_PSSTRINGS = 15,
+ NT_FREEBSD_PROCSTAT_AUXV = 16,
+};
+
+enum {
NT_GNU_ABI_TAG = 1,
NT_GNU_HWCAP = 2,
NT_GNU_BUILD_ID = 3,
diff --git a/include/llvm/Support/Endian.h b/include/llvm/Support/Endian.h
index cbe3d67b1f9e6..06e089ffa166f 100644
--- a/include/llvm/Support/Endian.h
+++ b/include/llvm/Support/Endian.h
@@ -17,6 +17,8 @@
#include "llvm/Support/Host.h"
#include "llvm/Support/SwapByteOrder.h"
+#include <stdint.h>
+
namespace llvm {
namespace support {
enum endianness {big, little, native};
@@ -33,48 +35,71 @@ namespace detail {
} // end namespace detail
namespace endian {
+constexpr endianness system_endianness() {
+ return sys::IsBigEndianHost ? big : little;
+}
+
+template <typename value_type>
+inline value_type byte_swap(value_type value, endianness endian) {
+ if ((endian != native) && (endian != system_endianness()))
+ sys::swapByteOrder(value);
+ return value;
+}
+
/// Swap the bytes of value to match the given endianness.
template<typename value_type, endianness endian>
inline value_type byte_swap(value_type value) {
- if (endian != native && sys::IsBigEndianHost != (endian == big))
- sys::swapByteOrder(value);
- return value;
+ return byte_swap(value, endian);
}
/// Read a value of a particular endianness from memory.
-template<typename value_type,
- endianness endian,
- std::size_t alignment>
-inline value_type read(const void *memory) {
+template <typename value_type, std::size_t alignment>
+inline value_type read(const void *memory, endianness endian) {
value_type ret;
memcpy(&ret,
- LLVM_ASSUME_ALIGNED(memory,
- (detail::PickAlignment<value_type, alignment>::value)),
+ LLVM_ASSUME_ALIGNED(
+ memory, (detail::PickAlignment<value_type, alignment>::value)),
sizeof(value_type));
- return byte_swap<value_type, endian>(ret);
+ return byte_swap<value_type>(ret, endian);
+}
+
+template<typename value_type,
+ endianness endian,
+ std::size_t alignment>
+inline value_type read(const void *memory) {
+ return read<value_type, alignment>(memory, endian);
}
/// Read a value of a particular endianness from a buffer, and increment the
/// buffer past that value.
+template <typename value_type, std::size_t alignment, typename CharT>
+inline value_type readNext(const CharT *&memory, endianness endian) {
+ value_type ret = read<value_type, alignment>(memory, endian);
+ memory += sizeof(value_type);
+ return ret;
+}
+
template<typename value_type, endianness endian, std::size_t alignment,
typename CharT>
inline value_type readNext(const CharT *&memory) {
- value_type ret = read<value_type, endian, alignment>(memory);
- memory += sizeof(value_type);
- return ret;
+ return readNext<value_type, alignment, CharT>(memory, endian);
}
/// Write a value to memory with a particular endianness.
+template <typename value_type, std::size_t alignment>
+inline void write(void *memory, value_type value, endianness endian) {
+ value = byte_swap<value_type>(value, endian);
+ memcpy(LLVM_ASSUME_ALIGNED(
+ memory, (detail::PickAlignment<value_type, alignment>::value)),
+ &value, sizeof(value_type));
+}
+
template<typename value_type,
endianness endian,
std::size_t alignment>
inline void write(void *memory, value_type value) {
- value = byte_swap<value_type, endian>(value);
- memcpy(LLVM_ASSUME_ALIGNED(memory,
- (detail::PickAlignment<value_type, alignment>::value)),
- &value,
- sizeof(value_type));
+ write<value_type, alignment>(memory, value, endian);
}
template <typename value_type>
@@ -300,10 +325,24 @@ typedef detail::packed_endian_specific_integral
<int64_t, native, unaligned> unaligned_int64_t;
namespace endian {
+template <typename T> inline T read(const void *P, endianness E) {
+ return read<T, unaligned>(P, E);
+}
+
template <typename T, endianness E> inline T read(const void *P) {
return *(const detail::packed_endian_specific_integral<T, E, unaligned> *)P;
}
+inline uint16_t read16(const void *P, endianness E) {
+ return read<uint16_t>(P, E);
+}
+inline uint32_t read32(const void *P, endianness E) {
+ return read<uint32_t>(P, E);
+}
+inline uint64_t read64(const void *P, endianness E) {
+ return read<uint64_t>(P, E);
+}
+
template <endianness E> inline uint16_t read16(const void *P) {
return read<uint16_t, E>(P);
}
@@ -321,10 +360,24 @@ inline uint16_t read16be(const void *P) { return read16<big>(P); }
inline uint32_t read32be(const void *P) { return read32<big>(P); }
inline uint64_t read64be(const void *P) { return read64<big>(P); }
+template <typename T> inline void write(void *P, T V, endianness E) {
+ write<T, unaligned>(P, V, E);
+}
+
template <typename T, endianness E> inline void write(void *P, T V) {
*(detail::packed_endian_specific_integral<T, E, unaligned> *)P = V;
}
+inline void write16(void *P, uint16_t V, endianness E) {
+ write<uint16_t>(P, V, E);
+}
+inline void write32(void *P, uint32_t V, endianness E) {
+ write<uint32_t>(P, V, E);
+}
+inline void write64(void *P, uint64_t V, endianness E) {
+ write<uint64_t>(P, V, E);
+}
+
template <endianness E> inline void write16(void *P, uint16_t V) {
write<uint16_t, E>(P, V);
}
diff --git a/include/llvm/Support/Error.h b/include/llvm/Support/Error.h
index f13c9484b5fd5..a3482f5a58b53 100644
--- a/include/llvm/Support/Error.h
+++ b/include/llvm/Support/Error.h
@@ -64,6 +64,12 @@ public:
/// using std::error_code. It will be removed in the future.
virtual std::error_code convertToErrorCode() const = 0;
+ // Returns the class ID for this type.
+ static const void *classID() { return &ID; }
+
+ // Returns the class ID for the dynamic type of this ErrorInfoBase instance.
+ virtual const void *dynamicClassID() const = 0;
+
// Check whether this instance is a subclass of the class identified by
// ClassID.
virtual bool isA(const void *const ClassID) const {
@@ -75,9 +81,6 @@ public:
return isA(ErrorInfoT::classID());
}
- // Returns the class ID for this type.
- static const void *classID() { return &ID; }
-
private:
virtual void anchor();
@@ -233,6 +236,14 @@ public:
return getPtr() && getPtr()->isA(ErrT::classID());
}
+ /// Returns the dynamic class id of this error, or null if this is a success
+ /// value.
+ const void* dynamicClassID() const {
+ if (!getPtr())
+ return nullptr;
+ return getPtr()->dynamicClassID();
+ }
+
private:
void assertIsChecked() {
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
@@ -316,11 +327,14 @@ template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) {
template <typename ThisErrT, typename ParentErrT = ErrorInfoBase>
class ErrorInfo : public ParentErrT {
public:
+
+ static const void *classID() { return &ThisErrT::ID; }
+
+ const void *dynamicClassID() const override { return &ThisErrT::ID; }
+
bool isA(const void *const ClassID) const override {
return ClassID == classID() || ParentErrT::isA(ClassID);
}
-
- static const void *classID() { return &ThisErrT::ID; }
};
/// Special ErrorInfo subclass representing a list of ErrorInfos.
@@ -629,6 +643,7 @@ private:
/// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the
/// error class type.
template <class T> class LLVM_NODISCARD Expected {
+ template <class T1> friend class ExpectedAsOutParameter;
template <class OtherT> friend class Expected;
static const bool isRef = std::is_reference<T>::value;
typedef ReferenceStorage<typename std::remove_reference<T>::type> wrap;
@@ -737,7 +752,7 @@ public:
/// \brief Check that this Expected<T> is an error of type ErrT.
template <typename ErrT> bool errorIsA() const {
- return HasError && getErrorStorage()->template isA<ErrT>();
+ return HasError && (*getErrorStorage())->template isA<ErrT>();
}
/// \brief Take ownership of the stored error.
@@ -832,6 +847,18 @@ private:
return reinterpret_cast<error_type *>(ErrorStorage.buffer);
}
+ const error_type *getErrorStorage() const {
+ assert(HasError && "Cannot get error when a value exists!");
+ return reinterpret_cast<const error_type *>(ErrorStorage.buffer);
+ }
+
+ // Used by ExpectedAsOutParameter to reset the checked flag.
+ void setUnchecked() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ Unchecked = true;
+#endif
+ }
+
void assertIsChecked() {
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
if (Unchecked) {
@@ -858,6 +885,28 @@ private:
#endif
};
+/// Helper for Expected<T>s used as out-parameters.
+///
+/// See ErrorAsOutParameter.
+template <typename T>
+class ExpectedAsOutParameter {
+public:
+
+ ExpectedAsOutParameter(Expected<T> *ValOrErr)
+ : ValOrErr(ValOrErr) {
+ if (ValOrErr)
+ (void)!!*ValOrErr;
+ }
+
+ ~ExpectedAsOutParameter() {
+ if (ValOrErr)
+ ValOrErr->setUnchecked();
+ }
+
+private:
+ Expected<T> *ValOrErr;
+};
+
/// This class wraps a std::error_code in a Error.
///
/// This is useful if you're writing an interface that returns a Error
@@ -926,6 +975,8 @@ public:
void log(raw_ostream &OS) const override;
std::error_code convertToErrorCode() const override;
+ const std::string &getMessage() const { return Msg; }
+
private:
std::string Msg;
std::error_code EC;
@@ -985,6 +1036,45 @@ private:
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");
+}
+
} // end namespace llvm
#endif // LLVM_SUPPORT_ERROR_H
diff --git a/include/llvm/Support/FileSystem.h b/include/llvm/Support/FileSystem.h
index ad21d8af66e99..29515c231bc46 100644
--- a/include/llvm/Support/FileSystem.h
+++ b/include/llvm/Support/FileSystem.h
@@ -33,6 +33,7 @@
#include "llvm/Support/Chrono.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MD5.h"
#include <cassert>
#include <cstdint>
#include <ctime>
@@ -93,6 +94,7 @@ enum perms {
set_uid_on_exe = 04000,
set_gid_on_exe = 02000,
sticky_bit = 01000,
+ all_perms = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit,
perms_not_known = 0xFFFF
};
@@ -141,70 +143,61 @@ public:
/// a platform-specific member to store the result.
class file_status
{
+ friend bool equivalent(file_status A, file_status B);
+
#if defined(LLVM_ON_UNIX)
- dev_t fs_st_dev;
- ino_t fs_st_ino;
- time_t fs_st_atime;
- time_t fs_st_mtime;
- uid_t fs_st_uid;
- gid_t fs_st_gid;
- off_t fs_st_size;
+ 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 LastAccessedTimeHigh;
- uint32_t LastAccessedTimeLow;
- uint32_t LastWriteTimeHigh;
- uint32_t LastWriteTimeLow;
- uint32_t VolumeSerialNumber;
- uint32_t FileSizeHigh;
- uint32_t FileSizeLow;
- uint32_t FileIndexHigh;
- uint32_t FileIndexLow;
+ 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
- friend bool equivalent(file_status A, file_status B);
- file_type Type;
- perms Perms;
+ file_type Type = file_type::status_error;
+ perms Perms = perms_not_known;
public:
#if defined(LLVM_ON_UNIX)
- file_status()
- : fs_st_dev(0), fs_st_ino(0), fs_st_atime(0), fs_st_mtime(0),
- fs_st_uid(0), fs_st_gid(0), fs_st_size(0),
- Type(file_type::status_error), Perms(perms_not_known) {}
-
- file_status(file_type Type)
- : fs_st_dev(0), fs_st_ino(0), fs_st_atime(0), fs_st_mtime(0),
- fs_st_uid(0), fs_st_gid(0), fs_st_size(0), Type(Type),
- Perms(perms_not_known) {}
-
- file_status(file_type Type, perms Perms, dev_t Dev, ino_t Ino, time_t ATime,
- time_t MTime, uid_t UID, gid_t GID, off_t Size)
- : fs_st_dev(Dev), 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) {}
+ file_status() = default;
+
+ 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()
- : LastAccessedTimeHigh(0), LastAccessedTimeLow(0), LastWriteTimeHigh(0),
- LastWriteTimeLow(0), VolumeSerialNumber(0), FileSizeHigh(0),
- FileSizeLow(0), FileIndexHigh(0), FileIndexLow(0),
- Type(file_type::status_error), Perms(perms_not_known) {}
-
- file_status(file_type Type)
- : LastAccessedTimeHigh(0), LastAccessedTimeLow(0), LastWriteTimeHigh(0),
- LastWriteTimeLow(0), VolumeSerialNumber(0), FileSizeHigh(0),
- FileSizeLow(0), FileIndexHigh(0), FileIndexLow(0), Type(Type),
- Perms(perms_not_known) {}
-
- file_status(file_type Type, 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)
- : LastAccessedTimeHigh(LastAccessTimeHigh), LastAccessedTimeLow(LastAccessTimeLow),
+ 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),
+ LastAccessedTimeLow(LastAccessTimeLow),
LastWriteTimeHigh(LastWriteTimeHigh),
LastWriteTimeLow(LastWriteTimeLow),
VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh),
FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh),
- FileIndexLow(FileIndexLow), Type(Type), Perms(perms_not_known) {}
+ FileIndexLow(FileIndexLow), Type(Type), Perms(Perms) {}
#endif
// getters
@@ -213,6 +206,7 @@ public:
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; }
@@ -222,9 +216,11 @@ public:
uint32_t getUser() const {
return 9999; // Not applicable to Windows, so...
}
+
uint32_t getGroup() const {
return 9999; // Not applicable to Windows, so...
}
+
uint64_t getSize() const {
return (uint64_t(FileSizeHigh) << 32) + FileSizeLow;
}
@@ -271,12 +267,12 @@ struct file_magic {
return V != unknown;
}
- file_magic() : V(unknown) {}
+ file_magic() = default;
file_magic(Impl V) : V(V) {}
operator Impl() const { return V; }
private:
- Impl V;
+ Impl V = unknown;
};
/// @}
@@ -350,6 +346,16 @@ std::error_code create_link(const Twine &to, const Twine &from);
/// specific error_code.
std::error_code create_hard_link(const Twine &to, const Twine &from);
+/// @brief Collapse all . and .. patterns, resolve all symlinks, and optionally
+/// expand ~ expressions to the user's home directory.
+///
+/// @param path The path to resolve.
+/// @param output The location to store the resolved path.
+/// @param expand_tilde If true, resolves ~ expressions to the user's home
+/// directory.
+std::error_code real_path(const Twine &path, SmallVectorImpl<char> &output,
+ bool expand_tilde = false);
+
/// @brief Get the current path.
///
/// @param result Holds the current path on return.
@@ -357,6 +363,13 @@ std::error_code create_hard_link(const Twine &to, const Twine &from);
/// otherwise a platform-specific error_code.
std::error_code current_path(SmallVectorImpl<char> &result);
+/// @brief Set the current path.
+///
+/// @param path The path to set.
+/// @returns errc::success if the current path was successfully set,
+/// otherwise a platform-specific error_code.
+std::error_code set_current_path(const Twine &path);
+
/// @brief Remove path. Equivalent to POSIX remove().
///
/// @param path Input path.
@@ -365,6 +378,13 @@ std::error_code current_path(SmallVectorImpl<char> &result);
/// returns error if the file didn't exist.
std::error_code remove(const Twine &path, bool IgnoreNonExisting = true);
+/// @brief Recursively delete a directory.
+///
+/// @param path Input path.
+/// @returns errc::success if path has been removed or didn't exist, otherwise a
+/// platform-specific error code.
+std::error_code remove_directories(const Twine &path, bool IgnoreErrors = true);
+
/// @brief Rename \a from to \a to. Files are renamed as if by POSIX rename().
///
/// @param from The path to rename from.
@@ -385,6 +405,16 @@ std::error_code copy_file(const Twine &From, const Twine &To);
/// platform-specific error_code.
std::error_code resize_file(int FD, uint64_t Size);
+/// @brief Compute an MD5 hash of a file's contents.
+///
+/// @param FD Input file descriptor.
+/// @returns An MD5Result with the hash computed, if successful, otherwise a
+/// std::error_code.
+ErrorOr<MD5::MD5Result> md5_contents(int FD);
+
+/// @brief Version of compute_md5 that doesn't require an open file descriptor.
+ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path);
+
/// @}
/// @name Physical Observers
/// @{
@@ -457,6 +487,40 @@ inline bool equivalent(const Twine &A, const Twine &B) {
return !equivalent(A, B, result) && result;
}
+/// @brief Is the file mounted on a local filesystem?
+///
+/// @param path Input path.
+/// @param result Set to true if \a path is on fixed media such as a hard disk,
+/// false if it is not.
+/// @returns errc::success if result has been successfully set, otherwise a
+/// platform specific error_code.
+std::error_code is_local(const Twine &path, bool &result);
+
+/// @brief Version of is_local accepting an open file descriptor.
+std::error_code is_local(int FD, bool &result);
+
+/// @brief Simpler version of is_local for clients that don't need to
+/// differentiate between an error and false.
+inline bool is_local(const Twine &Path) {
+ bool Result;
+ return !is_local(Path, Result) && Result;
+}
+
+/// @brief Simpler version of is_local accepting an open file descriptor for
+/// clients that don't need to differentiate between an error and false.
+inline bool is_local(int FD) {
+ bool Result;
+ return !is_local(FD, Result) && Result;
+}
+
+/// @brief Does status represent a directory?
+///
+/// @param Path The path to get the type of.
+/// @param Follow For symbolic links, indicates whether to return the file type
+/// of the link itself, or of the target.
+/// @returns A value from the file_type enumeration indicating the type of file.
+file_type get_file_type(const Twine &Path, bool Follow = true);
+
/// @brief Does status represent a directory?
///
/// @param status A file_status previously returned from status.
@@ -466,8 +530,8 @@ bool is_directory(file_status status);
/// @brief Is path a directory?
///
/// @param path Input path.
-/// @param result Set to true if \a path is a directory, false if it is not.
-/// Undefined otherwise.
+/// @param result Set to true if \a path is a directory (after following
+/// symlinks, false if it is not. Undefined otherwise.
/// @returns errc::success if result has been successfully set, otherwise a
/// platform-specific error_code.
std::error_code is_directory(const Twine &path, bool &result);
@@ -488,8 +552,8 @@ bool is_regular_file(file_status status);
/// @brief Is path a regular file?
///
/// @param path Input path.
-/// @param result Set to true if \a path is a regular file, false if it is not.
-/// Undefined otherwise.
+/// @param result Set to true if \a path is a regular file (after following
+/// symlinks), false if it is not. Undefined otherwise.
/// @returns errc::success if result has been successfully set, otherwise a
/// platform-specific error_code.
std::error_code is_regular_file(const Twine &path, bool &result);
@@ -503,8 +567,32 @@ inline bool is_regular_file(const Twine &Path) {
return Result;
}
+/// @brief Does status represent a symlink file?
+///
+/// @param status A file_status previously returned from status.
+/// @returns status_known(status) && status.type() == file_type::symlink_file.
+bool is_symlink_file(file_status status);
+
+/// @brief Is path a symlink file?
+///
+/// @param path Input path.
+/// @param result Set to true if \a path is a symlink file, false if it is not.
+/// Undefined otherwise.
+/// @returns errc::success if result has been successfully set, otherwise a
+/// platform-specific error_code.
+std::error_code is_symlink_file(const Twine &path, bool &result);
+
+/// @brief Simpler version of is_symlink_file for clients that don't need to
+/// differentiate between an error and false.
+inline bool is_symlink_file(const Twine &Path) {
+ bool Result;
+ if (is_symlink_file(Path, Result))
+ return false;
+ return Result;
+}
+
/// @brief Does this status represent something that exists but is not a
-/// directory, regular file, or symlink?
+/// directory or regular file?
///
/// @param status A file_status previously returned from status.
/// @returns exists(s) && !is_regular_file(s) && !is_directory(s)
@@ -524,13 +612,37 @@ std::error_code is_other(const Twine &path, bool &result);
///
/// @param path Input path.
/// @param result Set to the file status.
+/// @param follow When true, follows symlinks. Otherwise, the symlink itself is
+/// statted.
/// @returns errc::success if result has been successfully set, otherwise a
/// platform-specific error_code.
-std::error_code status(const Twine &path, file_status &result);
+std::error_code status(const Twine &path, file_status &result,
+ bool follow = true);
/// @brief A version for when a file descriptor is already available.
std::error_code status(int FD, file_status &Result);
+/// @brief Set file permissions.
+///
+/// @param Path File to set permissions on.
+/// @param Permissions New file permissions.
+/// @returns errc::success if the permissions were successfully set, otherwise
+/// a platform-specific error_code.
+/// @note On Windows, all permissions except *_write are ignored. Using any of
+/// owner_write, group_write, or all_write will make the file writable.
+/// Otherwise, the file will be marked as read-only.
+std::error_code setPermissions(const Twine &Path, perms Permissions);
+
+/// @brief Get file permissions.
+///
+/// @param Path File to get permissions from.
+/// @returns the permissions if they were successfully retrieved, otherwise a
+/// platform-specific error_code.
+/// @note On Windows, if the file does not have the FILE_ATTRIBUTE_READONLY
+/// attribute, all_all will be returned. Otherwise, all_read | all_exe
+/// will be returned.
+ErrorOr<perms> getPermissions(const Twine &Path);
+
/// @brief Get file size.
///
/// @param Path Input path.
@@ -735,12 +847,13 @@ std::string getMainExecutable(const char *argv0, void *MainExecAddr);
/// called.
class directory_entry {
std::string Path;
+ bool FollowSymlinks;
mutable file_status Status;
public:
- explicit directory_entry(const Twine &path, file_status st = file_status())
- : Path(path.str())
- , Status(st) {}
+ explicit directory_entry(const Twine &path, bool follow_symlinks = true,
+ file_status st = file_status())
+ : Path(path.str()), FollowSymlinks(follow_symlinks), Status(st) {}
directory_entry() = default;
@@ -763,9 +876,10 @@ public:
};
namespace detail {
+
struct DirIterState;
- std::error_code directory_iterator_construct(DirIterState &, StringRef);
+ std::error_code directory_iterator_construct(DirIterState &, StringRef, bool);
std::error_code directory_iterator_increment(DirIterState &);
std::error_code directory_iterator_destruct(DirIterState &);
@@ -778,6 +892,7 @@ namespace detail {
intptr_t IterationHandle = 0;
directory_entry CurrentEntry;
};
+
} // end namespace detail
/// directory_iterator - Iterates through the entries in path. There is no
@@ -785,18 +900,24 @@ namespace detail {
/// it call report_fatal_error on error.
class directory_iterator {
std::shared_ptr<detail::DirIterState> State;
+ bool FollowSymlinks = true;
public:
- explicit directory_iterator(const Twine &path, std::error_code &ec) {
+ explicit directory_iterator(const Twine &path, std::error_code &ec,
+ bool follow_symlinks = true)
+ : FollowSymlinks(follow_symlinks) {
State = std::make_shared<detail::DirIterState>();
SmallString<128> path_storage;
- ec = detail::directory_iterator_construct(*State,
- path.toStringRef(path_storage));
+ ec = detail::directory_iterator_construct(
+ *State, path.toStringRef(path_storage), FollowSymlinks);
}
- explicit directory_iterator(const directory_entry &de, std::error_code &ec) {
+ explicit directory_iterator(const directory_entry &de, std::error_code &ec,
+ bool follow_symlinks = true)
+ : FollowSymlinks(follow_symlinks) {
State = std::make_shared<detail::DirIterState>();
- ec = detail::directory_iterator_construct(*State, de.path());
+ ec =
+ detail::directory_iterator_construct(*State, de.path(), FollowSymlinks);
}
/// Construct end iterator.
@@ -829,24 +950,29 @@ public:
};
namespace detail {
+
/// Keeps state for the recursive_directory_iterator.
struct RecDirIterState {
std::stack<directory_iterator, std::vector<directory_iterator>> Stack;
uint16_t Level = 0;
bool HasNoPushRequest = false;
};
+
} // end namespace detail
/// recursive_directory_iterator - Same as directory_iterator except for it
/// recurses down into child directories.
class recursive_directory_iterator {
std::shared_ptr<detail::RecDirIterState> State;
+ bool Follow;
public:
recursive_directory_iterator() = default;
- explicit recursive_directory_iterator(const Twine &path, std::error_code &ec)
- : State(std::make_shared<detail::RecDirIterState>()) {
- State->Stack.push(directory_iterator(path, ec));
+ explicit recursive_directory_iterator(const Twine &path, std::error_code &ec,
+ bool follow_symlinks = true)
+ : State(std::make_shared<detail::RecDirIterState>()),
+ Follow(follow_symlinks) {
+ State->Stack.push(directory_iterator(path, ec, Follow));
if (State->Stack.top() == directory_iterator())
State.reset();
}
@@ -861,7 +987,7 @@ public:
file_status st;
if ((ec = State->Stack.top()->status(st))) return *this;
if (is_directory(st)) {
- State->Stack.push(directory_iterator(*State->Stack.top(), ec));
+ State->Stack.push(directory_iterator(*State->Stack.top(), ec, Follow));
if (ec) return *this;
if (State->Stack.top() != end_itr) {
++State->Level;
diff --git a/include/llvm/Support/FormatAdapters.h b/include/llvm/Support/FormatAdapters.h
index 7bacd2e17135c..698e134b328de 100644
--- a/include/llvm/Support/FormatAdapters.h
+++ b/include/llvm/Support/FormatAdapters.h
@@ -22,9 +22,6 @@ protected:
explicit FormatAdapter(T &&Item) : Item(Item) {}
T Item;
-
- static_assert(!detail::uses_missing_provider<T>::value,
- "Item does not have a format provider!");
};
namespace detail {
diff --git a/include/llvm/Support/FormatProviders.h b/include/llvm/Support/FormatProviders.h
index 1f0768c3ab08b..4e57034ff98e9 100644
--- a/include/llvm/Support/FormatProviders.h
+++ b/include/llvm/Support/FormatProviders.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/FormatVariadicDetails.h"
#include "llvm/Support/NativeFormatting.h"
@@ -45,9 +46,8 @@ struct is_cstring
template <typename T>
struct use_string_formatter
- : public std::integral_constant<
- bool, is_one_of<T, llvm::StringRef, std::string>::value ||
- is_cstring<T>::value> {};
+ : public std::integral_constant<bool,
+ std::is_convertible<T, llvm::StringRef>::value> {};
template <typename T>
struct use_pointer_formatter
@@ -205,11 +205,22 @@ struct format_provider<
if (!Style.empty() && Style.getAsInteger(10, N)) {
assert(false && "Style is not a valid integer");
}
- llvm::StringRef S(V);
+ llvm::StringRef S = V;
Stream << S.substr(0, N);
}
};
+/// Implementation of format_provider<T> for llvm::Twine.
+///
+/// This follows the same rules as the string formatter.
+
+template <> struct format_provider<Twine> {
+ static void format(const Twine &V, llvm::raw_ostream &Stream,
+ StringRef Style) {
+ format_provider<std::string>::format(V.str(), Stream, Style);
+ }
+};
+
/// Implementation of format_provider<T> for characters.
///
/// The options string of a character type has the grammar:
@@ -359,8 +370,7 @@ template <typename IterT> class format_provider<llvm::iterator_range<IterT>> {
return Default;
}
- std::vector<const char *> Delims = {"[]", "<>", "()"};
- for (const char *D : Delims) {
+ for (const char *D : {"[]", "<>", "()"}) {
if (Style.front() != D[0])
continue;
size_t End = Style.find_first_of(D[1]);
diff --git a/include/llvm/Support/FormatVariadic.h b/include/llvm/Support/FormatVariadic.h
index e5f5c9615cb6b..3a4668687cc94 100644
--- a/include/llvm/Support/FormatVariadic.h
+++ b/include/llvm/Support/FormatVariadic.h
@@ -196,7 +196,7 @@ public:
// "}}" to print a literal '}'.
//
// ===Parameter Indexing===
-// `index` specifies the index of the paramter in the parameter pack to format
+// `index` specifies the index of the parameter in the parameter pack to format
// into the output. Note that it is possible to refer to the same parameter
// index multiple times in a given format string. This makes it possible to
// output the same value multiple times without passing it multiple times to the
diff --git a/include/llvm/Support/GCOV.h b/include/llvm/Support/GCOV.h
index f297fe609d2a0..73fddca8e35bb 100644
--- a/include/llvm/Support/GCOV.h
+++ b/include/llvm/Support/GCOV.h
@@ -63,7 +63,7 @@ struct Options {
/// read operations.
class GCOVBuffer {
public:
- GCOVBuffer(MemoryBuffer *B) : Buffer(B), Cursor(0) {}
+ GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
/// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
bool readGCNOFormat() {
@@ -234,39 +234,38 @@ public:
private:
MemoryBuffer *Buffer;
- uint64_t Cursor;
+ uint64_t Cursor = 0;
};
/// GCOVFile - Collects coverage information for one pair of coverage file
/// (.gcno and .gcda).
class GCOVFile {
public:
- GCOVFile()
- : GCNOInitialized(false), Checksum(0), RunCount(0),
- ProgramCount(0) {}
+ 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;
+ bool GCNOInitialized = false;
GCOV::GCOVVersion Version;
- uint32_t Checksum;
+ uint32_t Checksum = 0;
SmallVector<std::unique_ptr<GCOVFunction>, 16> Functions;
- uint32_t RunCount;
- uint32_t ProgramCount;
+ uint32_t RunCount = 0;
+ uint32_t ProgramCount = 0;
};
/// GCOVEdge - Collects edge information.
struct GCOVEdge {
- GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D), Count(0) {}
+ GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D) {}
GCOVBlock &Src;
GCOVBlock &Dst;
- uint64_t Count;
+ uint64_t Count = 0;
};
/// GCOVFunction - Collects function information.
@@ -275,7 +274,8 @@ public:
typedef pointee_iterator<SmallVectorImpl<
std::unique_ptr<GCOVBlock>>::const_iterator> BlockIterator;
- GCOVFunction(GCOVFile &P) : Parent(P), Ident(0), LineNumber(0) {}
+ GCOVFunction(GCOVFile &P) : Parent(P) {}
+
bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
StringRef getName() const { return Name; }
@@ -290,14 +290,15 @@ public:
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;
+ uint32_t Ident = 0;
uint32_t Checksum;
- uint32_t LineNumber;
+ uint32_t LineNumber = 0;
StringRef Name;
StringRef Filename;
SmallVector<std::unique_ptr<GCOVBlock>, 16> Blocks;
@@ -307,10 +308,10 @@ private:
/// GCOVBlock - Collects block information.
class GCOVBlock {
struct EdgeWeight {
- EdgeWeight(GCOVBlock *D) : Dst(D), Count(0) {}
+ EdgeWeight(GCOVBlock *D) : Dst(D) {}
GCOVBlock *Dst;
- uint64_t Count;
+ uint64_t Count = 0;
};
struct SortDstEdgesFunctor {
@@ -322,8 +323,7 @@ class GCOVBlock {
public:
typedef SmallVectorImpl<GCOVEdge *>::const_iterator EdgeIterator;
- GCOVBlock(GCOVFunction &P, uint32_t N)
- : Parent(P), Number(N), Counter(0), DstEdgesAreSorted(true) {}
+ GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N) {}
~GCOVBlock();
const GCOVFunction &getParent() const { return Parent; }
@@ -361,14 +361,15 @@ public:
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;
- bool DstEdgesAreSorted;
+ uint64_t Counter = 0;
+ bool DstEdgesAreSorted = true;
SmallVector<GCOVEdge *, 16> SrcEdges;
SmallVector<GCOVEdge *, 16> DstEdges;
SmallVector<uint32_t, 16> Lines;
@@ -386,30 +387,28 @@ class FileInfo {
typedef DenseMap<uint32_t, BlockVector> BlockLines;
struct LineData {
- LineData() : LastLine(0) {}
+ LineData() = default;
+
BlockLines Blocks;
FunctionLines Functions;
- uint32_t LastLine;
+ uint32_t LastLine = 0;
};
struct GCOVCoverage {
- GCOVCoverage(StringRef Name)
- : Name(Name), LogicalLines(0), LinesExec(0), Branches(0),
- BranchesExec(0), BranchesTaken(0) {}
+ GCOVCoverage(StringRef Name) : Name(Name) {}
StringRef Name;
- uint32_t LogicalLines;
- uint32_t LinesExec;
+ uint32_t LogicalLines = 0;
+ uint32_t LinesExec = 0;
- uint32_t Branches;
- uint32_t BranchesExec;
- uint32_t BranchesTaken;
+ uint32_t Branches = 0;
+ uint32_t BranchesExec = 0;
+ uint32_t BranchesTaken = 0;
};
public:
- FileInfo(const GCOV::Options &Options)
- : Options(Options), RunCount(0), ProgramCount(0) {}
+ FileInfo(const GCOV::Options &Options) : Options(Options) {}
void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) {
if (Line > LineInfo[Filename].LastLine)
@@ -446,8 +445,8 @@ private:
const GCOV::Options &Options;
StringMap<LineData> LineInfo;
- uint32_t RunCount;
- uint32_t ProgramCount;
+ uint32_t RunCount = 0;
+ uint32_t ProgramCount = 0;
typedef SmallVector<std::pair<std::string, GCOVCoverage>, 4> FileCoverageList;
typedef MapVector<const GCOVFunction *, GCOVCoverage> FuncCoverageMap;
diff --git a/include/llvm/Support/GenericDomTree.h b/include/llvm/Support/GenericDomTree.h
index 6e6ee40016440..20f3ffdf3aab7 100644
--- a/include/llvm/Support/GenericDomTree.h
+++ b/include/llvm/Support/GenericDomTree.h
@@ -13,7 +13,7 @@
/// dominance queries on the CFG, but is fully generic w.r.t. the underlying
/// graph types.
///
-/// Unlike ADT/* graph algorithms, generic dominator tree has more reuiqrement
+/// 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.
///
@@ -25,14 +25,19 @@
#define LLVM_SUPPORT_GENERICDOMTREE_H
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/GraphTraits.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <utility>
+#include <vector>
namespace llvm {
@@ -47,7 +52,7 @@ template <typename GT> struct DominatorTreeBaseTraits {
typename std::remove_pointer<typename GT::NodeRef>::type>;
};
-} // End namespace detail
+} // end namespace detail
template <typename GT>
using DominatorTreeBaseByGraphTraits =
@@ -59,13 +64,16 @@ template <class NodeT> class DominatorBase {
protected:
std::vector<NodeT *> Roots;
bool IsPostDominators;
+
explicit DominatorBase(bool isPostDom)
: Roots(), IsPostDominators(isPostDom) {}
+
DominatorBase(DominatorBase &&Arg)
: Roots(std::move(Arg.Roots)),
IsPostDominators(std::move(Arg.IsPostDominators)) {
Arg.Roots.clear();
}
+
DominatorBase &operator=(DominatorBase &&RHS) {
Roots = std::move(RHS.Roots);
IsPostDominators = std::move(RHS.IsPostDominators);
@@ -85,19 +93,21 @@ public:
bool isPostDominator() const { return IsPostDominators; }
};
-struct PostDominatorTree;
-
/// \brief Base class for the actual dominator tree node.
template <class NodeT> class DomTreeNodeBase {
+ friend struct PostDominatorTree;
+ template <class N> friend class DominatorTreeBase;
+
NodeT *TheBB;
DomTreeNodeBase<NodeT> *IDom;
std::vector<DomTreeNodeBase<NodeT> *> Children;
- mutable int DFSNumIn, DFSNumOut;
-
- template <class N> friend class DominatorTreeBase;
- friend struct PostDominatorTree;
+ mutable int DFSNumIn = -1;
+ mutable int DFSNumOut = -1;
public:
+ DomTreeNodeBase(NodeT *BB, DomTreeNodeBase<NodeT> *iDom)
+ : TheBB(BB), IDom(iDom) {}
+
typedef typename std::vector<DomTreeNodeBase<NodeT> *>::iterator iterator;
typedef typename std::vector<DomTreeNodeBase<NodeT> *>::const_iterator
const_iterator;
@@ -109,13 +119,11 @@ public:
NodeT *getBlock() const { return TheBB; }
DomTreeNodeBase<NodeT> *getIDom() const { return IDom; }
+
const std::vector<DomTreeNodeBase<NodeT> *> &getChildren() const {
return Children;
}
- DomTreeNodeBase(NodeT *BB, DomTreeNodeBase<NodeT> *iDom)
- : TheBB(BB), IDom(iDom), DFSNumIn(-1), DFSNumOut(-1) {}
-
std::unique_ptr<DomTreeNodeBase<NodeT>>
addChild(std::unique_ptr<DomTreeNodeBase<NodeT>> C) {
Children.push_back(C.get());
@@ -206,9 +214,6 @@ void Calculate(DominatorTreeBaseByGraphTraits<GraphTraits<N>> &DT, FuncT &F);
/// This class is a generic template over graph nodes. It is instantiated for
/// various graphs in the LLVM IR or in the code generator.
template <class NodeT> class DominatorTreeBase : public DominatorBase<NodeT> {
- DominatorTreeBase(const DominatorTreeBase &) = delete;
- DominatorTreeBase &operator=(const DominatorTreeBase &) = delete;
-
bool dominatedBySlowTreeWalk(const DomTreeNodeBase<NodeT> *A,
const DomTreeNodeBase<NodeT> *B) const {
assert(A != B);
@@ -239,16 +244,16 @@ protected:
DomTreeNodeMapType DomTreeNodes;
DomTreeNodeBase<NodeT> *RootNode;
- mutable bool DFSInfoValid;
- mutable unsigned int SlowQueries;
+ mutable bool DFSInfoValid = false;
+ mutable unsigned int SlowQueries = 0;
// Information record used during immediate dominators computation.
struct InfoRec {
- unsigned DFSNum;
- unsigned Parent;
- unsigned Semi;
- NodeT *Label;
+ unsigned DFSNum = 0;
+ unsigned Parent = 0;
+ unsigned Semi = 0;
+ NodeT *Label = nullptr;
- InfoRec() : DFSNum(0), Parent(0), Semi(0), Label(nullptr) {}
+ InfoRec() = default;
};
DenseMap<NodeT *, NodeT *> IDoms;
@@ -336,7 +341,7 @@ protected:
public:
explicit DominatorTreeBase(bool isPostDom)
- : DominatorBase<NodeT>(isPostDom), DFSInfoValid(false), SlowQueries(0) {}
+ : DominatorBase<NodeT>(isPostDom) {}
DominatorTreeBase(DominatorTreeBase &&Arg)
: DominatorBase<NodeT>(
@@ -348,6 +353,7 @@ public:
Vertex(std::move(Arg.Vertex)), Info(std::move(Arg.Info)) {
Arg.wipe();
}
+
DominatorTreeBase &operator=(DominatorTreeBase &&RHS) {
DominatorBase<NodeT>::operator=(
std::move(static_cast<DominatorBase<NodeT> &>(RHS)));
@@ -362,6 +368,9 @@ public:
return *this;
}
+ DominatorTreeBase(const DominatorTreeBase &) = delete;
+ DominatorTreeBase &operator=(const DominatorTreeBase &) = delete;
+
/// compare - Return false if the other dominator tree base matches this
/// dominator tree base. Otherwise return true.
bool compare(const DominatorTreeBase &Other) const {
@@ -684,6 +693,10 @@ protected:
unsigned LastLinked);
template <class GraphT>
+ friend unsigned ReverseDFSPass(DominatorTreeBaseByGraphTraits<GraphT> &DT,
+ typename GraphT::NodeRef V, unsigned N);
+
+ template <class GraphT>
friend unsigned DFSPass(DominatorTreeBaseByGraphTraits<GraphT> &DT,
typename GraphT::NodeRef V, unsigned N);
@@ -716,7 +729,6 @@ public:
/// updateDFSNumbers - Assign In and Out numbers to the nodes while walking
/// dominator tree in dfs order.
void updateDFSNumbers() const {
-
if (DFSInfoValid) {
SlowQueries = 0;
return;
@@ -778,11 +790,9 @@ public:
Calculate<FT, NodeT *>(*this, F);
} else {
// Initialize the roots list
- for (typename TraitsTy::nodes_iterator I = TraitsTy::nodes_begin(&F),
- E = TraitsTy::nodes_end(&F);
- I != E; ++I)
- if (TraitsTy::child_begin(*I) == TraitsTy::child_end(*I))
- addRoot(*I);
+ for (auto *Node : nodes(&F))
+ if (TraitsTy::child_begin(Node) == TraitsTy::child_end(Node))
+ addRoot(Node);
Calculate<FT, Inverse<NodeT *>>(*this, F);
}
@@ -815,6 +825,6 @@ bool DominatorTreeBase<NodeT>::properlyDominates(const NodeT *A,
getNode(const_cast<NodeT *>(B)));
}
-}
+} // end namespace llvm
-#endif
+#endif // LLVM_SUPPORT_GENERICDOMTREE_H
diff --git a/include/llvm/Support/GenericDomTreeConstruction.h b/include/llvm/Support/GenericDomTreeConstruction.h
index 54e55cc1a32e1..c1d757f3ab6a3 100644
--- a/include/llvm/Support/GenericDomTreeConstruction.h
+++ b/include/llvm/Support/GenericDomTreeConstruction.h
@@ -24,82 +24,77 @@
#ifndef LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H
#define LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H
+#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/GenericDomTree.h"
namespace llvm {
-template <class GraphT>
-unsigned DFSPass(DominatorTreeBaseByGraphTraits<GraphT> &DT,
- typename GraphT::NodeRef V, unsigned N) {
- // This is more understandable as a recursive algorithm, but we can't use the
- // recursive algorithm due to stack depth issues. Keep it here for
- // documentation purposes.
-#if 0
- InfoRec &VInfo = DT.Info[DT.Roots[i]];
- VInfo.DFSNum = VInfo.Semi = ++N;
- VInfo.Label = V;
-
- Vertex.push_back(V); // Vertex[n] = V;
-
- for (succ_iterator SI = succ_begin(V), E = succ_end(V); SI != E; ++SI) {
- InfoRec &SuccVInfo = DT.Info[*SI];
- if (SuccVInfo.Semi == 0) {
- SuccVInfo.Parent = V;
- N = DTDFSPass(DT, *SI, N);
- }
+// External storage for depth first iterator that reuses the info lookup map
+// domtree already has. We don't have a set, but a map instead, so we are
+// converting the one argument insert calls.
+template <class NodeRef, class InfoType> struct df_iterator_dom_storage {
+public:
+ typedef DenseMap<NodeRef, InfoType> BaseSet;
+ df_iterator_dom_storage(BaseSet &Storage) : Storage(Storage) {}
+
+ typedef typename BaseSet::iterator iterator;
+ std::pair<iterator, bool> insert(NodeRef N) {
+ return Storage.insert({N, InfoType()});
}
-#else
- bool IsChildOfArtificialExit = (N != 0);
+ void completed(NodeRef) {}
- SmallVector<
- std::pair<typename GraphT::NodeRef, typename GraphT::ChildIteratorType>,
- 32>
- Worklist;
- Worklist.push_back(std::make_pair(V, GraphT::child_begin(V)));
- while (!Worklist.empty()) {
- typename GraphT::NodeRef BB = Worklist.back().first;
- typename GraphT::ChildIteratorType NextSucc = Worklist.back().second;
+private:
+ BaseSet &Storage;
+};
+template <class GraphT>
+unsigned ReverseDFSPass(DominatorTreeBaseByGraphTraits<GraphT> &DT,
+ typename GraphT::NodeRef V, unsigned N) {
+ df_iterator_dom_storage<
+ typename GraphT::NodeRef,
+ typename DominatorTreeBaseByGraphTraits<GraphT>::InfoRec>
+ DFStorage(DT.Info);
+ bool IsChildOfArtificialExit = (N != 0);
+ for (auto I = idf_ext_begin(V, DFStorage), E = idf_ext_end(V, DFStorage);
+ I != E; ++I) {
+ typename GraphT::NodeRef BB = *I;
auto &BBInfo = DT.Info[BB];
+ BBInfo.DFSNum = BBInfo.Semi = ++N;
+ BBInfo.Label = BB;
+ // Set the parent to the top of the visited stack. The stack includes us,
+ // and is 1 based, so we subtract to account for both of these.
+ if (I.getPathLength() > 1)
+ BBInfo.Parent = DT.Info[I.getPath(I.getPathLength() - 2)].DFSNum;
+ DT.Vertex.push_back(BB); // Vertex[n] = V;
- // First time we visited this BB?
- if (NextSucc == GraphT::child_begin(BB)) {
- BBInfo.DFSNum = BBInfo.Semi = ++N;
- BBInfo.Label = BB;
-
- DT.Vertex.push_back(BB); // Vertex[n] = V;
-
- if (IsChildOfArtificialExit)
- BBInfo.Parent = 1;
-
- IsChildOfArtificialExit = false;
- }
-
- // store the DFS number of the current BB - the reference to BBInfo might
- // get invalidated when processing the successors.
- unsigned BBDFSNum = BBInfo.DFSNum;
-
- // If we are done with this block, remove it from the worklist.
- if (NextSucc == GraphT::child_end(BB)) {
- Worklist.pop_back();
- continue;
- }
-
- // Increment the successor number for the next time we get to it.
- ++Worklist.back().second;
-
- // Visit the successor next, if it isn't already visited.
- typename GraphT::NodeRef Succ = *NextSucc;
+ if (IsChildOfArtificialExit)
+ BBInfo.Parent = 1;
- auto &SuccVInfo = DT.Info[Succ];
- if (SuccVInfo.Semi == 0) {
- SuccVInfo.Parent = BBDFSNum;
- Worklist.push_back(std::make_pair(Succ, GraphT::child_begin(Succ)));
- }
+ IsChildOfArtificialExit = false;
}
-#endif
- return N;
+ return N;
+}
+template <class GraphT>
+unsigned DFSPass(DominatorTreeBaseByGraphTraits<GraphT> &DT,
+ typename GraphT::NodeRef V, unsigned N) {
+ df_iterator_dom_storage<
+ typename GraphT::NodeRef,
+ typename DominatorTreeBaseByGraphTraits<GraphT>::InfoRec>
+ DFStorage(DT.Info);
+ for (auto I = df_ext_begin(V, DFStorage), E = df_ext_end(V, DFStorage);
+ I != E; ++I) {
+ typename GraphT::NodeRef BB = *I;
+ auto &BBInfo = DT.Info[BB];
+ BBInfo.DFSNum = BBInfo.Semi = ++N;
+ BBInfo.Label = BB;
+ // Set the parent to the top of the visited stack. The stack includes us,
+ // and is 1 based, so we subtract to account for both of these.
+ if (I.getPathLength() > 1)
+ BBInfo.Parent = DT.Info[I.getPath(I.getPathLength() - 2)].DFSNum;
+ DT.Vertex.push_back(BB); // Vertex[n] = V;
+ }
+ return N;
}
template <class GraphT>
@@ -163,9 +158,13 @@ void Calculate(DominatorTreeBaseByGraphTraits<GraphTraits<NodeT>> &DT,
// Step #1: Number blocks in depth-first order and initialize variables used
// in later stages of the algorithm.
- for (unsigned i = 0, e = static_cast<unsigned>(DT.Roots.size());
- i != e; ++i)
- N = DFSPass<GraphT>(DT, DT.Roots[i], N);
+ if (DT.isPostDominator()){
+ for (unsigned i = 0, e = static_cast<unsigned>(DT.Roots.size());
+ i != e; ++i)
+ N = ReverseDFSPass<GraphT>(DT, DT.Roots[i], N);
+ } else {
+ N = DFSPass<GraphT>(DT, DT.Roots[0], N);
+ }
// 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.
@@ -201,17 +200,12 @@ void Calculate(DominatorTreeBaseByGraphTraits<GraphTraits<NodeT>> &DT,
// initialize the semi dominator to point to the parent node
WInfo.Semi = WInfo.Parent;
- typedef GraphTraits<Inverse<NodeT> > InvTraits;
- for (typename InvTraits::ChildIteratorType CI =
- InvTraits::child_begin(W),
- E = InvTraits::child_end(W); CI != E; ++CI) {
- typename InvTraits::NodeRef N = *CI;
- if (DT.Info.count(N)) { // Only if this predecessor is reachable!
+ for (const auto &N : inverse_children<NodeT>(W))
+ if (DT.Info.count(N)) { // Only if this predecessor is reachable!
unsigned SemiU = DT.Info[Eval<GraphT>(DT, N, i + 1)].Semi;
if (SemiU < WInfo.Semi)
WInfo.Semi = SemiU;
}
- }
// If V is a non-root vertex and sdom(V) = parent(V), then idom(V) is
// necessarily parent(V). In this case, set idom(V) here and avoid placing
diff --git a/include/llvm/Support/Host.h b/include/llvm/Support/Host.h
index 9df584c68c0d9..89986fdae9713 100644
--- a/include/llvm/Support/Host.h
+++ b/include/llvm/Support/Host.h
@@ -15,6 +15,7 @@
#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>
@@ -32,9 +33,9 @@ namespace llvm {
namespace sys {
#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
- static const bool IsBigEndianHost = true;
+constexpr bool IsBigEndianHost = true;
#else
- static const bool IsBigEndianHost = false;
+constexpr bool IsBigEndianHost = false;
#endif
static const bool IsLittleEndianHost = !IsBigEndianHost;
@@ -75,6 +76,13 @@ namespace sys {
/// from thread::hardware_concurrency(), which includes hyperthreads).
/// Returns -1 if unknown for the current host system.
int getHostNumPhysicalCores();
+
+ namespace detail {
+ /// Helper functions to extract HostCPUName from /proc/cpuinfo on linux.
+ StringRef getHostCPUNameForPowerPC(const StringRef &ProcCpuinfoContent);
+ StringRef getHostCPUNameForARM(const StringRef &ProcCpuinfoContent);
+ StringRef getHostCPUNameForS390x(const StringRef &ProcCpuinfoContent);
+ }
}
}
diff --git a/include/llvm/Support/LEB128.h b/include/llvm/Support/LEB128.h
index 6a95432ca2d93..ff775f3b7b364 100644
--- a/include/llvm/Support/LEB128.h
+++ b/include/llvm/Support/LEB128.h
@@ -20,7 +20,8 @@
namespace llvm {
/// Utility function to encode a SLEB128 value to an output stream.
-inline void encodeSLEB128(int64_t Value, raw_ostream &OS) {
+inline void encodeSLEB128(int64_t Value, raw_ostream &OS,
+ unsigned Padding = 0) {
bool More;
do {
uint8_t Byte = Value & 0x7f;
@@ -28,10 +29,45 @@ inline void encodeSLEB128(int64_t Value, raw_ostream &OS) {
Value >>= 7;
More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) ||
((Value == -1) && ((Byte & 0x40) != 0))));
- if (More)
+ if (More || Padding != 0)
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) {
+ uint8_t PadValue = Value < 0 ? 0x7f : 0x00;
+ for (; Padding != 1; --Padding)
+ OS << char(PadValue | 0x80);
+ OS << char(PadValue);
+ }
+}
+
+/// 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) {
+ uint8_t *orig_p = p;
+ bool More;
+ do {
+ uint8_t Byte = Value & 0x7f;
+ // NOTE: this assumes that this signed shift is an arithmetic right shift.
+ Value >>= 7;
+ More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) ||
+ ((Value == -1) && ((Byte & 0x40) != 0))));
+ if (More || Padding != 0)
+ 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) {
+ uint8_t PadValue = Value < 0 ? 0x7f : 0x00;
+ for (; Padding != 1; --Padding)
+ *p++ = (PadValue | 0x80);
+ *p++ = PadValue;
+ }
+ return (unsigned)(p - orig_p);
}
/// Utility function to encode a ULEB128 value to an output stream.
@@ -77,11 +113,30 @@ inline unsigned encodeULEB128(uint64_t Value, uint8_t *p,
/// Utility function to decode a ULEB128 value.
-inline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr) {
+inline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr,
+ const uint8_t *end = nullptr,
+ const char **error = nullptr) {
const uint8_t *orig_p = p;
uint64_t Value = 0;
unsigned Shift = 0;
+ if(error)
+ *error = nullptr;
do {
+ if(end && p == end){
+ if(error)
+ *error = "malformed uleb128, extends past end";
+ if (n)
+ *n = (unsigned)(p - orig_p);
+ return 0;
+ }
+ uint64_t Slice = *p & 0x7f;
+ if(Shift >= 64 || Slice << Shift >> Shift != Slice){
+ if(error)
+ *error = "uleb128 too big for uint64";
+ if (n)
+ *n = (unsigned)(p - orig_p);
+ return 0;
+ }
Value += uint64_t(*p & 0x7f) << Shift;
Shift += 7;
} while (*p++ >= 128);
@@ -91,12 +146,21 @@ inline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr) {
}
/// Utility function to decode a SLEB128 value.
-inline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr) {
+inline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr,
+ const uint8_t *end = nullptr,
+ const char **error = nullptr) {
const uint8_t *orig_p = p;
int64_t Value = 0;
unsigned Shift = 0;
uint8_t Byte;
do {
+ if(end && p == end){
+ if(error)
+ *error = "malformed sleb128, extends past end";
+ if (n)
+ *n = (unsigned)(p - orig_p);
+ return 0;
+ }
Byte = *p++;
Value |= ((Byte & 0x7f) << Shift);
Shift += 7;
diff --git a/include/llvm/Support/LowLevelTypeImpl.h b/include/llvm/Support/LowLevelTypeImpl.h
new file mode 100644
index 0000000000000..02df4d806f13b
--- /dev/null
+++ b/include/llvm/Support/LowLevelTypeImpl.h
@@ -0,0 +1,202 @@
+//== llvm/Support/LowLevelTypeImpl.h --------------------------- -*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// Implement a low-level type suitable for MachineInstr level instruction
+/// selection.
+///
+/// For a type attached to a MachineInstr, we only care about 2 details: total
+/// size and the number of vector lanes (if any). Accordingly, there are 4
+/// possible valid type-kinds:
+///
+/// * `sN` for scalars and aggregates
+/// * `<N x sM>` for vectors, which must have at least 2 elements.
+/// * `pN` for pointers
+///
+/// Other information required for correct selection is expected to be carried
+/// by the opcode, or non-type flags. For example the distinction between G_ADD
+/// and G_FADD for int/float or fast-math flags.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_LOWLEVELTYPEIMPL_H
+#define LLVM_SUPPORT_LOWLEVELTYPEIMPL_H
+
+#include <cassert>
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/CodeGen/MachineValueType.h"
+
+namespace llvm {
+
+class DataLayout;
+class Type;
+class raw_ostream;
+
+class LLT {
+public:
+ enum TypeKind : uint16_t {
+ Invalid,
+ Scalar,
+ Pointer,
+ Vector,
+ };
+
+ /// Get a low-level scalar or aggregate "bag of bits".
+ static LLT scalar(unsigned SizeInBits) {
+ assert(SizeInBits > 0 && "invalid scalar size");
+ return LLT{Scalar, 1, SizeInBits};
+ }
+
+ /// Get a low-level pointer in the given address space (defaulting to 0).
+ static LLT pointer(uint16_t AddressSpace, unsigned SizeInBits) {
+ return LLT{Pointer, AddressSpace, SizeInBits};
+ }
+
+ /// Get a low-level vector of some number of elements and element width.
+ /// \p NumElements must be at least 2.
+ static LLT vector(uint16_t NumElements, unsigned ScalarSizeInBits) {
+ assert(NumElements > 1 && "invalid number of vector elements");
+ return LLT{Vector, NumElements, ScalarSizeInBits};
+ }
+
+ /// Get a low-level vector of some number of elements and element type.
+ static LLT vector(uint16_t NumElements, LLT ScalarTy) {
+ assert(NumElements > 1 && "invalid number of vector elements");
+ assert(ScalarTy.isScalar() && "invalid vector element type");
+ return LLT{Vector, NumElements, ScalarTy.getSizeInBits()};
+ }
+
+ explicit LLT(TypeKind Kind, uint16_t NumElements, unsigned SizeInBits)
+ : SizeInBits(SizeInBits), ElementsOrAddrSpace(NumElements), Kind(Kind) {
+ assert((Kind != Vector || ElementsOrAddrSpace > 1) &&
+ "invalid number of vector elements");
+ }
+
+ explicit LLT() : SizeInBits(0), ElementsOrAddrSpace(0), Kind(Invalid) {}
+
+ explicit LLT(MVT VT);
+
+ bool isValid() const { return Kind != Invalid; }
+
+ bool isScalar() const { return Kind == Scalar; }
+
+ bool isPointer() const { return Kind == Pointer; }
+
+ bool isVector() const { return Kind == Vector; }
+
+ /// Returns the number of elements in a vector LLT. Must only be called on
+ /// vector types.
+ uint16_t getNumElements() const {
+ assert(isVector() && "cannot get number of elements on scalar/aggregate");
+ return ElementsOrAddrSpace;
+ }
+
+ /// Returns the total size of the type. Must only be called on sized types.
+ unsigned getSizeInBits() const {
+ if (isPointer() || isScalar())
+ return SizeInBits;
+ return SizeInBits * ElementsOrAddrSpace;
+ }
+
+ unsigned getScalarSizeInBits() const {
+ return SizeInBits;
+ }
+
+ unsigned getAddressSpace() const {
+ assert(isPointer() && "cannot get address space of non-pointer type");
+ return ElementsOrAddrSpace;
+ }
+
+ /// Returns the vector's element type. Only valid for vector types.
+ LLT getElementType() const {
+ assert(isVector() && "cannot get element type of scalar/aggregate");
+ return scalar(SizeInBits);
+ }
+
+ /// 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{Kind, ElementsOrAddrSpace, SizeInBits / 2};
+ }
+
+ /// 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{Kind, ElementsOrAddrSpace, SizeInBits * 2};
+ }
+
+ /// 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() && ElementsOrAddrSpace % 2 == 0 &&
+ "cannot half odd vector");
+ if (ElementsOrAddrSpace == 2)
+ return scalar(SizeInBits);
+
+ return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace / 2),
+ SizeInBits};
+ }
+
+ /// 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 {
+ assert(!isPointer() && "cannot double elements in pointer");
+ return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace * 2),
+ SizeInBits};
+ }
+
+ void print(raw_ostream &OS) const;
+
+ bool operator==(const LLT &RHS) const {
+ return Kind == RHS.Kind && SizeInBits == RHS.SizeInBits &&
+ ElementsOrAddrSpace == RHS.ElementsOrAddrSpace;
+ }
+
+ bool operator!=(const LLT &RHS) const { return !(*this == RHS); }
+
+ friend struct DenseMapInfo<LLT>;
+private:
+ unsigned SizeInBits;
+ uint16_t ElementsOrAddrSpace;
+ TypeKind Kind;
+};
+
+inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) {
+ Ty.print(OS);
+ return OS;
+}
+
+template<> struct DenseMapInfo<LLT> {
+ static inline LLT getEmptyKey() {
+ return LLT{LLT::Invalid, 0, -1u};
+ }
+ static inline LLT getTombstoneKey() {
+ return LLT{LLT::Invalid, 0, -2u};
+ }
+ static inline unsigned getHashValue(const LLT &Ty) {
+ uint64_t Val = ((uint64_t)Ty.SizeInBits << 32) |
+ ((uint64_t)Ty.ElementsOrAddrSpace << 16) | (uint64_t)Ty.Kind;
+ return DenseMapInfo<uint64_t>::getHashValue(Val);
+ }
+ static bool isEqual(const LLT &LHS, const LLT &RHS) {
+ return LHS == RHS;
+ }
+};
+
+}
+
+#endif // LLVM_SUPPORT_LOWLEVELTYPEIMPL_H
diff --git a/include/llvm/Support/MD5.h b/include/llvm/Support/MD5.h
index eb181bfe8a5c8..2c0dc76485f85 100644
--- a/include/llvm/Support/MD5.h
+++ b/include/llvm/Support/MD5.h
@@ -1,4 +1,4 @@
-/*
+/* -*- C++ -*-
* This code is derived from (original license follows):
*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
@@ -29,24 +29,55 @@
#define LLVM_SUPPORT_MD5_H
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/DataTypes.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Endian.h"
#include <array>
+#include <cstdint>
namespace llvm {
+
template <typename T> class ArrayRef;
class MD5 {
// Any 32-bit or wider unsigned integer data type will do.
typedef uint32_t MD5_u32plus;
- MD5_u32plus a, b, c, d;
- MD5_u32plus hi, lo;
+ MD5_u32plus a = 0x67452301;
+ MD5_u32plus b = 0xefcdab89;
+ MD5_u32plus c = 0x98badcfe;
+ MD5_u32plus d = 0x10325476;
+ MD5_u32plus hi = 0;
+ MD5_u32plus lo = 0;
uint8_t buffer[64];
MD5_u32plus block[16];
public:
- typedef uint8_t MD5Result[16];
+ struct MD5Result {
+ std::array<uint8_t, 16> Bytes;
+
+ operator std::array<uint8_t, 16>() const { return Bytes; }
+
+ const uint8_t &operator[](size_t I) const { return Bytes[I]; }
+ uint8_t &operator[](size_t I) { return Bytes[I]; }
+
+ SmallString<32> digest() const;
+
+ uint64_t low() const {
+ // Our MD5 implementation returns the result in little endian, so the low
+ // word is first.
+ using namespace support;
+ return endian::read<uint64_t, little, unaligned>(Bytes.data());
+ }
+
+ uint64_t high() const {
+ using namespace support;
+ return endian::read<uint64_t, little, unaligned>(Bytes.data() + 8);
+ }
+ std::pair<uint64_t, uint64_t> words() const {
+ using namespace support;
+ return std::make_pair(high(), low());
+ }
+ };
MD5();
@@ -70,18 +101,22 @@ private:
const uint8_t *body(ArrayRef<uint8_t> Data);
};
+inline bool operator==(const MD5::MD5Result &LHS, const MD5::MD5Result &RHS) {
+ return LHS.Bytes == RHS.Bytes;
+}
+
/// Helper to compute and return lower 64 bits of the given string's MD5 hash.
inline uint64_t MD5Hash(StringRef Str) {
+ using namespace support;
+
MD5 Hash;
Hash.update(Str);
- llvm::MD5::MD5Result Result;
+ MD5::MD5Result Result;
Hash.final(Result);
- // Return the least significant 8 bytes. Our MD5 implementation returns the
- // result in little endian, so we may need to swap bytes.
- using namespace llvm::support;
- return endian::read<uint64_t, little, unaligned>(Result);
+ // Return the least significant word.
+ return Result.low();
}
-}
+} // end namespace llvm
-#endif
+#endif // LLVM_SUPPORT_MD5_H
diff --git a/include/llvm/Support/MachO.def b/include/llvm/Support/MachO.def
index 57522897d0fca..95de48d2b19eb 100644
--- a/include/llvm/Support/MachO.def
+++ b/include/llvm/Support/MachO.def
@@ -73,6 +73,8 @@ HANDLE_LOAD_COMMAND(LC_LINKER_OPTION, 0x0000002Du, linker_option_command)
HANDLE_LOAD_COMMAND(LC_LINKER_OPTIMIZATION_HINT, 0x0000002Eu, linkedit_data_command)
HANDLE_LOAD_COMMAND(LC_VERSION_MIN_TVOS, 0x0000002Fu, version_min_command)
HANDLE_LOAD_COMMAND(LC_VERSION_MIN_WATCHOS, 0x00000030u, version_min_command)
+HANDLE_LOAD_COMMAND(LC_NOTE, 0x00000031u, note_command)
+HANDLE_LOAD_COMMAND(LC_BUILD_VERSION, 0x00000032u, build_version_command)
#endif
@@ -109,6 +111,8 @@ LOAD_COMMAND_STRUCT(thread_command)
LOAD_COMMAND_STRUCT(twolevel_hints_command)
LOAD_COMMAND_STRUCT(uuid_command)
LOAD_COMMAND_STRUCT(version_min_command)
+LOAD_COMMAND_STRUCT(note_command)
+LOAD_COMMAND_STRUCT(build_version_command)
#endif
diff --git a/include/llvm/Support/MachO.h b/include/llvm/Support/MachO.h
index 2b23c0f86448a..3d704292c260a 100644
--- a/include/llvm/Support/MachO.h
+++ b/include/llvm/Support/MachO.h
@@ -487,6 +487,22 @@ namespace llvm {
VM_PROT_EXECUTE = 0x4
};
+ // Values for platform field in build_version_command.
+ enum {
+ PLATFORM_MACOS = 1,
+ PLATFORM_IOS = 2,
+ PLATFORM_TVOS = 3,
+ PLATFORM_WATCHOS = 4,
+ PLATFORM_BRIDGEOS = 5
+ };
+
+ // Values for tools enum in build_tool_version.
+ enum {
+ TOOL_CLANG = 1,
+ TOOL_SWIFT = 2,
+ TOOL_LD = 3
+ };
+
// Structs from <mach-o/loader.h>
struct mach_header {
@@ -819,6 +835,29 @@ namespace llvm {
uint32_t sdk; // X.Y.Z is encoded in nibbles xxxx.yy.zz
};
+ struct note_command {
+ uint32_t cmd; // LC_NOTE
+ uint32_t cmdsize; // sizeof(struct note_command)
+ char data_owner[16]; // owner name for this LC_NOTE
+ uint64_t offset; // file offset of this data
+ uint64_t size; // length of data region
+ };
+
+ struct build_tool_version {
+ uint32_t tool; // enum for the tool
+ uint32_t version; // version of the tool
+ };
+
+ struct build_version_command {
+ uint32_t cmd; // LC_BUILD_VERSION
+ uint32_t cmdsize; // sizeof(struct build_version_command) +
+ // ntools * sizeof(struct build_tool_version)
+ uint32_t platform; // platform
+ uint32_t minos; // X.Y.Z is encoded in nibbles xxxx.yy.zz
+ uint32_t sdk; // X.Y.Z is encoded in nibbles xxxx.yy.zz
+ uint32_t ntools; // number of tool entries following this
+ };
+
struct dyld_info_command {
uint32_t cmd;
uint32_t cmdsize;
@@ -1266,6 +1305,27 @@ namespace llvm {
sys::swapByteOrder(C.sdk);
}
+ inline void swapStruct(note_command &C) {
+ sys::swapByteOrder(C.cmd);
+ sys::swapByteOrder(C.cmdsize);
+ sys::swapByteOrder(C.offset);
+ sys::swapByteOrder(C.size);
+ }
+
+ inline void swapStruct(build_version_command&C) {
+ sys::swapByteOrder(C.cmd);
+ sys::swapByteOrder(C.cmdsize);
+ sys::swapByteOrder(C.platform);
+ sys::swapByteOrder(C.minos);
+ sys::swapByteOrder(C.sdk);
+ sys::swapByteOrder(C.ntools);
+ }
+
+ inline void swapStruct(build_tool_version&C) {
+ sys::swapByteOrder(C.tool);
+ sys::swapByteOrder(C.version);
+ }
+
inline void swapStruct(data_in_code_entry &C) {
sys::swapByteOrder(C.offset);
sys::swapByteOrder(C.length);
@@ -1470,6 +1530,25 @@ namespace llvm {
CPU_SUBTYPE_MC98601 = CPU_SUBTYPE_POWERPC_601
};
+ struct x86_thread_state32_t {
+ uint32_t eax;
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t esp;
+ uint32_t ss;
+ uint32_t eflags;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+ };
+
struct x86_thread_state64_t {
uint64_t rax;
uint64_t rbx;
@@ -1599,6 +1678,25 @@ namespace llvm {
uint64_t faultvaddr;
};
+ inline void swapStruct(x86_thread_state32_t &x) {
+ sys::swapByteOrder(x.eax);
+ sys::swapByteOrder(x.ebx);
+ sys::swapByteOrder(x.ecx);
+ sys::swapByteOrder(x.edx);
+ sys::swapByteOrder(x.edi);
+ sys::swapByteOrder(x.esi);
+ sys::swapByteOrder(x.ebp);
+ sys::swapByteOrder(x.esp);
+ sys::swapByteOrder(x.ss);
+ sys::swapByteOrder(x.eflags);
+ sys::swapByteOrder(x.eip);
+ sys::swapByteOrder(x.cs);
+ sys::swapByteOrder(x.ds);
+ sys::swapByteOrder(x.es);
+ sys::swapByteOrder(x.fs);
+ sys::swapByteOrder(x.gs);
+ }
+
inline void swapStruct(x86_thread_state64_t &x) {
sys::swapByteOrder(x.rax);
sys::swapByteOrder(x.rbx);
@@ -1656,6 +1754,7 @@ namespace llvm {
x86_state_hdr_t tsh;
union {
x86_thread_state64_t ts64;
+ x86_thread_state32_t ts32;
} uts;
};
@@ -1711,6 +1810,9 @@ namespace llvm {
swapStruct(x.ues.es64);
}
+ const uint32_t x86_THREAD_STATE32_COUNT =
+ sizeof(x86_thread_state32_t) / sizeof(uint32_t);
+
const uint32_t x86_THREAD_STATE64_COUNT =
sizeof(x86_thread_state64_t) / sizeof(uint32_t);
const uint32_t x86_FLOAT_STATE64_COUNT =
diff --git a/include/llvm/Support/MathExtras.h b/include/llvm/Support/MathExtras.h
index 77970f487112a..19380b23d9d24 100644
--- a/include/llvm/Support/MathExtras.h
+++ b/include/llvm/Support/MathExtras.h
@@ -112,7 +112,7 @@ std::size_t countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed.");
- return detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB);
+ return llvm::detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB);
}
namespace detail {
@@ -181,7 +181,7 @@ std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed.");
- return detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
+ return llvm::detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
}
/// \brief Get the index of the first set bit starting from the least
diff --git a/include/llvm/Support/MemoryBuffer.h b/include/llvm/Support/MemoryBuffer.h
index f739d19907b04..e8bdc3e89fa7c 100644
--- a/include/llvm/Support/MemoryBuffer.h
+++ b/include/llvm/Support/MemoryBuffer.h
@@ -69,12 +69,12 @@ public:
/// means that the client knows that the file exists and that it has the
/// specified size.
///
- /// \param IsVolatileSize Set to true to indicate that the file size may be
- /// changing, e.g. when libclang tries to parse while the user is
- /// editing/updating the file.
+ /// \param IsVolatile Set to true to indicate that the contents of the file
+ /// can change outside the user's control, e.g. when libclang tries to parse
+ /// while the user is editing/updating the file or if the file is on an NFS.
static ErrorOr<std::unique_ptr<MemoryBuffer>>
getFile(const Twine &Filename, int64_t FileSize = -1,
- bool RequiresNullTerminator = true, bool IsVolatileSize = false);
+ bool RequiresNullTerminator = true, bool IsVolatile = false);
/// Read all of the specified file into a MemoryBuffer as a stream
/// (i.e. until EOF reached). This is useful for special files that
@@ -87,17 +87,17 @@ public:
/// Since this is in the middle of a file, the buffer is not null terminated.
static ErrorOr<std::unique_ptr<MemoryBuffer>>
getOpenFileSlice(int FD, const Twine &Filename, uint64_t MapSize,
- int64_t Offset);
+ int64_t Offset, bool IsVolatile = false);
/// Given an already-open file descriptor, read the file and return a
/// MemoryBuffer.
///
- /// \param IsVolatileSize Set to true to indicate that the file size may be
- /// changing, e.g. when libclang tries to parse while the user is
- /// editing/updating the file.
+ /// \param IsVolatile Set to true to indicate that the contents of the file
+ /// can change outside the user's control, e.g. when libclang tries to parse
+ /// while the user is editing/updating the file or if the file is on an NFS.
static ErrorOr<std::unique_ptr<MemoryBuffer>>
getOpenFile(int FD, const Twine &Filename, uint64_t FileSize,
- bool RequiresNullTerminator = true, bool IsVolatileSize = false);
+ bool RequiresNullTerminator = true, bool IsVolatile = false);
/// Open the specified memory range as a MemoryBuffer. Note that InputData
/// must be null terminated if RequiresNullTerminator is true.
@@ -136,7 +136,7 @@ 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);
+ getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset, bool IsVolatile = false);
//===--------------------------------------------------------------------===//
// Provided for performance analysis.
diff --git a/include/llvm/Support/Path.h b/include/llvm/Support/Path.h
index 2bbcef0c293f6..6ac51195519eb 100644
--- a/include/llvm/Support/Path.h
+++ b/include/llvm/Support/Path.h
@@ -24,6 +24,8 @@ namespace llvm {
namespace sys {
namespace path {
+enum class Style { windows, posix, native };
+
/// @name Lexical Component Iterator
/// @{
@@ -51,9 +53,10 @@ class const_iterator
StringRef Path; ///< The entire path.
StringRef Component; ///< The current component. Not necessarily in Path.
size_t Position; ///< The iterators current position within Path.
+ Style S; ///< The path style to use.
// An end iterator has Position = Path.size() + 1.
- friend const_iterator begin(StringRef path);
+ friend const_iterator begin(StringRef path, Style style);
friend const_iterator end(StringRef path);
public:
@@ -77,8 +80,9 @@ class reverse_iterator
StringRef Path; ///< The entire path.
StringRef Component; ///< The current component. Not necessarily in Path.
size_t Position; ///< The iterators current position within Path.
+ Style S; ///< The path style to use.
- friend reverse_iterator rbegin(StringRef path);
+ friend reverse_iterator rbegin(StringRef path, Style style);
friend reverse_iterator rend(StringRef path);
public:
@@ -95,7 +99,7 @@ public:
/// @brief Get begin iterator over \a path.
/// @param path Input path.
/// @returns Iterator initialized with the first component of \a path.
-const_iterator begin(StringRef path);
+const_iterator begin(StringRef path, Style style = Style::native);
/// @brief Get end iterator over \a path.
/// @param path Input path.
@@ -105,7 +109,7 @@ const_iterator end(StringRef path);
/// @brief Get reverse begin iterator over \a path.
/// @param path Input path.
/// @returns Iterator initialized with the first reverse component of \a path.
-reverse_iterator rbegin(StringRef path);
+reverse_iterator rbegin(StringRef path, Style style = Style::native);
/// @brief Get reverse end iterator over \a path.
/// @param path Input path.
@@ -126,7 +130,7 @@ reverse_iterator rend(StringRef path);
/// @endcode
///
/// @param path A path that is modified to not have a file component.
-void remove_filename(SmallVectorImpl<char> &path);
+void remove_filename(SmallVectorImpl<char> &path, Style style = Style::native);
/// @brief Replace the file extension of \a path with \a extension.
///
@@ -140,7 +144,8 @@ void remove_filename(SmallVectorImpl<char> &path);
/// @param extension The extension to be added. It may be empty. It may also
/// optionally start with a '.', if it does not, one will be
/// prepended.
-void replace_extension(SmallVectorImpl<char> &path, const Twine &extension);
+void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
+ Style style = Style::native);
/// @brief Replace matching path prefix with another path.
///
@@ -156,8 +161,8 @@ void replace_extension(SmallVectorImpl<char> &path, const Twine &extension);
/// @param OldPrefix The path prefix to strip from \a Path.
/// @param NewPrefix The path prefix to replace \a NewPrefix with.
void replace_path_prefix(SmallVectorImpl<char> &Path,
- const StringRef &OldPrefix,
- const StringRef &NewPrefix);
+ const StringRef &OldPrefix, const StringRef &NewPrefix,
+ Style style = Style::native);
/// @brief Append to path.
///
@@ -174,6 +179,9 @@ void append(SmallVectorImpl<char> &path, const Twine &a,
const Twine &c = "",
const Twine &d = "");
+void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
+ const Twine &b = "", const Twine &c = "", const Twine &d = "");
+
/// @brief Append to path.
///
/// @code
@@ -185,8 +193,8 @@ void append(SmallVectorImpl<char> &path, const Twine &a,
/// @param path Set to \a path + [\a begin, \a end).
/// @param begin Start of components to append.
/// @param end One past the end of components to append.
-void append(SmallVectorImpl<char> &path,
- const_iterator begin, const_iterator end);
+void append(SmallVectorImpl<char> &path, const_iterator begin,
+ const_iterator end, Style style = Style::native);
/// @}
/// @name Transforms (or some other better name)
@@ -198,14 +206,15 @@ void append(SmallVectorImpl<char> &path,
///
/// @param path A path that is transformed to native format.
/// @param result Holds the result of the transformation.
-void native(const Twine &path, SmallVectorImpl<char> &result);
+void native(const Twine &path, SmallVectorImpl<char> &result,
+ Style style = Style::native);
/// Convert path to the native form in place. This is used to give paths to
/// users and operating system calls in the platform's normal way. For example,
/// on Windows all '/' are converted to '\'.
///
/// @param path A path that is transformed to native format.
-void native(SmallVectorImpl<char> &path);
+void native(SmallVectorImpl<char> &path, Style style = Style::native);
/// @brief Replaces backslashes with slashes if Windows.
///
@@ -213,7 +222,7 @@ void native(SmallVectorImpl<char> &path);
/// @result The result of replacing backslashes with forward slashes if Windows.
/// On Unix, this function is a no-op because backslashes are valid path
/// chracters.
-std::string convert_to_slash(StringRef path);
+std::string convert_to_slash(StringRef path, Style style = Style::native);
/// @}
/// @name Lexical Observers
@@ -229,7 +238,7 @@ std::string convert_to_slash(StringRef path);
///
/// @param path Input path.
/// @result The root name of \a path if it has one, otherwise "".
-StringRef root_name(StringRef path);
+StringRef root_name(StringRef path, Style style = Style::native);
/// @brief Get root directory.
///
@@ -242,7 +251,7 @@ StringRef root_name(StringRef path);
/// @param path Input path.
/// @result The root directory of \a path if it has one, otherwise
/// "".
-StringRef root_directory(StringRef path);
+StringRef root_directory(StringRef path, Style style = Style::native);
/// @brief Get root path.
///
@@ -250,7 +259,7 @@ StringRef root_directory(StringRef path);
///
/// @param path Input path.
/// @result The root path of \a path if it has one, otherwise "".
-StringRef root_path(StringRef path);
+StringRef root_path(StringRef path, Style style = Style::native);
/// @brief Get relative path.
///
@@ -262,7 +271,7 @@ StringRef root_path(StringRef path);
///
/// @param path Input path.
/// @result The path starting after root_path if one exists, otherwise "".
-StringRef relative_path(StringRef path);
+StringRef relative_path(StringRef path, Style style = Style::native);
/// @brief Get parent path.
///
@@ -274,7 +283,7 @@ StringRef relative_path(StringRef path);
///
/// @param path Input path.
/// @result The parent path of \a path if one exists, otherwise "".
-StringRef parent_path(StringRef path);
+StringRef parent_path(StringRef path, Style style = Style::native);
/// @brief Get filename.
///
@@ -288,7 +297,7 @@ StringRef parent_path(StringRef path);
/// @param path Input path.
/// @result The filename part of \a path. This is defined as the last component
/// of \a path.
-StringRef filename(StringRef path);
+StringRef filename(StringRef path, Style style = Style::native);
/// @brief Get stem.
///
@@ -306,7 +315,7 @@ StringRef filename(StringRef path);
///
/// @param path Input path.
/// @result The stem of \a path.
-StringRef stem(StringRef path);
+StringRef stem(StringRef path, Style style = Style::native);
/// @brief Get extension.
///
@@ -322,18 +331,18 @@ StringRef stem(StringRef path);
///
/// @param path Input path.
/// @result The extension of \a path.
-StringRef extension(StringRef path);
+StringRef extension(StringRef path, Style style = Style::native);
/// @brief Check whether the given char is a path separator on the host OS.
///
/// @param value a character
/// @result true if \a value is a path separator character on the host OS
-bool is_separator(char value);
+bool is_separator(char value, Style style = Style::native);
/// @brief Return the preferred separator for this platform.
///
/// @result StringRef of the preferred separator, null-terminated.
-StringRef get_separator();
+StringRef get_separator(Style style = Style::native);
/// @brief Get the typical temporary directory for the system, e.g.,
/// "/var/tmp" or "C:/TEMP"
@@ -374,7 +383,7 @@ bool user_cache_directory(SmallVectorImpl<char> &Result, const Twine &Path1,
///
/// @param path Input path.
/// @result True if the path has a root name, false otherwise.
-bool has_root_name(const Twine &path);
+bool has_root_name(const Twine &path, Style style = Style::native);
/// @brief Has root directory?
///
@@ -382,7 +391,7 @@ bool has_root_name(const Twine &path);
///
/// @param path Input path.
/// @result True if the path has a root directory, false otherwise.
-bool has_root_directory(const Twine &path);
+bool has_root_directory(const Twine &path, Style style = Style::native);
/// @brief Has root path?
///
@@ -390,7 +399,7 @@ bool has_root_directory(const Twine &path);
///
/// @param path Input path.
/// @result True if the path has a root path, false otherwise.
-bool has_root_path(const Twine &path);
+bool has_root_path(const Twine &path, Style style = Style::native);
/// @brief Has relative path?
///
@@ -398,7 +407,7 @@ bool has_root_path(const Twine &path);
///
/// @param path Input path.
/// @result True if the path has a relative path, false otherwise.
-bool has_relative_path(const Twine &path);
+bool has_relative_path(const Twine &path, Style style = Style::native);
/// @brief Has parent path?
///
@@ -406,7 +415,7 @@ bool has_relative_path(const Twine &path);
///
/// @param path Input path.
/// @result True if the path has a parent path, false otherwise.
-bool has_parent_path(const Twine &path);
+bool has_parent_path(const Twine &path, Style style = Style::native);
/// @brief Has filename?
///
@@ -414,7 +423,7 @@ bool has_parent_path(const Twine &path);
///
/// @param path Input path.
/// @result True if the path has a filename, false otherwise.
-bool has_filename(const Twine &path);
+bool has_filename(const Twine &path, Style style = Style::native);
/// @brief Has stem?
///
@@ -422,7 +431,7 @@ bool has_filename(const Twine &path);
///
/// @param path Input path.
/// @result True if the path has a stem, false otherwise.
-bool has_stem(const Twine &path);
+bool has_stem(const Twine &path, Style style = Style::native);
/// @brief Has extension?
///
@@ -430,25 +439,25 @@ bool has_stem(const Twine &path);
///
/// @param path Input path.
/// @result True if the path has a extension, false otherwise.
-bool has_extension(const Twine &path);
+bool has_extension(const Twine &path, Style style = Style::native);
/// @brief Is path absolute?
///
/// @param path Input path.
/// @result True if the path is absolute, false if it is not.
-bool is_absolute(const Twine &path);
+bool is_absolute(const Twine &path, Style style = Style::native);
/// @brief Is path relative?
///
/// @param path Input path.
/// @result True if the path is relative, false if it is not.
-bool is_relative(const Twine &path);
+bool is_relative(const Twine &path, Style style = Style::native);
/// @brief Remove redundant leading "./" pieces and consecutive separators.
///
/// @param path Input path.
/// @result The cleaned-up \a path.
-StringRef remove_leading_dotslash(StringRef path);
+StringRef remove_leading_dotslash(StringRef path, Style style = Style::native);
/// @brief In-place remove any './' and optionally '../' components from a path.
///
@@ -456,7 +465,8 @@ StringRef remove_leading_dotslash(StringRef path);
/// @param remove_dot_dot specify if '../' (except for leading "../") should be
/// removed
/// @result True if path was changed
-bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot = false);
+bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot = false,
+ Style style = Style::native);
} // end namespace path
} // end namespace sys
diff --git a/include/llvm/Support/PointerLikeTypeTraits.h b/include/llvm/Support/PointerLikeTypeTraits.h
index 9ff894edbeb06..521a49684e45a 100644
--- a/include/llvm/Support/PointerLikeTypeTraits.h
+++ b/include/llvm/Support/PointerLikeTypeTraits.h
@@ -60,6 +60,20 @@ public:
enum { NumLowBitsAvailable = 2 };
};
+// Provide PointerLikeTypeTraits for const things.
+template <typename T> class PointerLikeTypeTraits<const T> {
+ typedef PointerLikeTypeTraits<T> NonConst;
+
+public:
+ static inline const void *getAsVoidPointer(const T P) {
+ return NonConst::getAsVoidPointer(P);
+ }
+ static inline const T getFromVoidPointer(const void *P) {
+ return NonConst::getFromVoidPointer(const_cast<void *>(P));
+ }
+ enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
+};
+
// Provide PointerLikeTypeTraits for const pointers.
template <typename T> class PointerLikeTypeTraits<const T *> {
typedef PointerLikeTypeTraits<T *> NonConst;
diff --git a/include/llvm/Support/RWMutex.h b/include/llvm/Support/RWMutex.h
index e4736b8e24eb1..85f4fc09fb87f 100644
--- a/include/llvm/Support/RWMutex.h
+++ b/include/llvm/Support/RWMutex.h
@@ -14,7 +14,7 @@
#ifndef LLVM_SUPPORT_RWMUTEX_H
#define LLVM_SUPPORT_RWMUTEX_H
-#include "llvm/Support/Compiler.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Threading.h"
#include <cassert>
@@ -32,6 +32,13 @@ namespace sys {
/// @brief Default Constructor.
explicit RWMutexImpl();
+ /// @}
+ /// @name Do Not Implement
+ /// @{
+ RWMutexImpl(const RWMutexImpl & original) = delete;
+ RWMutexImpl &operator=(const RWMutexImpl &) = delete;
+ /// @}
+
/// Releases and removes the lock
/// @brief Destructor
~RWMutexImpl();
@@ -70,16 +77,8 @@ namespace sys {
/// @{
private:
#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
- void* data_; ///< We don't know what the data will be
+ void* data_ = nullptr; ///< We don't know what the data will be
#endif
-
- /// @}
- /// @name Do Not Implement
- /// @{
- private:
- RWMutexImpl(const RWMutexImpl & original) = delete;
- void operator=(const RWMutexImpl &) = delete;
- /// @}
};
/// SmartMutex - An R/W mutex with a compile time constant parameter that
@@ -93,6 +92,8 @@ namespace sys {
public:
explicit SmartRWMutex() = default;
+ SmartRWMutex(const SmartRWMutex<mt_only> & original) = delete;
+ SmartRWMutex<mt_only> &operator=(const SmartRWMutex<mt_only> &) = delete;
bool lock_shared() {
if (!mt_only || llvm_is_multithreaded())
@@ -136,10 +137,6 @@ namespace sys {
--writers;
return true;
}
-
- private:
- SmartRWMutex(const SmartRWMutex<mt_only> & original);
- void operator=(const SmartRWMutex<mt_only> &);
};
typedef SmartRWMutex<false> RWMutex;
diff --git a/include/llvm/Support/SMLoc.h b/include/llvm/Support/SMLoc.h
index eb3a1ba7db511..5b8be55055405 100644
--- a/include/llvm/Support/SMLoc.h
+++ b/include/llvm/Support/SMLoc.h
@@ -22,10 +22,10 @@ namespace llvm {
/// Represents a location in source code.
class SMLoc {
- const char *Ptr;
+ const char *Ptr = nullptr;
public:
- SMLoc() : Ptr(nullptr) {}
+ SMLoc() = default;
bool isValid() const { return Ptr != nullptr; }
diff --git a/include/llvm/Support/SourceMgr.h b/include/llvm/Support/SourceMgr.h
index bc7478e0d7031..cb90d968c44c5 100644
--- a/include/llvm/Support/SourceMgr.h
+++ b/include/llvm/Support/SourceMgr.h
@@ -17,18 +17,24 @@
#define LLVM_SUPPORT_SOURCEMGR_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SMLoc.h"
+#include <algorithm>
+#include <cassert>
+#include <memory>
#include <string>
+#include <utility>
+#include <vector>
namespace llvm {
- class SourceMgr;
- class SMDiagnostic;
- class SMFixIt;
- class Twine;
- class raw_ostream;
+
+class raw_ostream;
+class SMDiagnostic;
+class SMFixIt;
/// This owns the files read by a parser, handles include stacks,
/// and handles diagnostic wrangling.
@@ -44,6 +50,7 @@ public:
/// register a function pointer+context as a diagnostic handler.
/// It gets called each time PrintMessage is invoked.
typedef void (*DiagHandlerTy)(const SMDiagnostic &, void *Context);
+
private:
struct SrcBuffer {
/// The memory buffer for the file.
@@ -61,18 +68,17 @@ private:
/// This is a cache for line number queries, its implementation is really
/// private to SourceMgr.cpp.
- mutable void *LineNoCache;
+ mutable void *LineNoCache = nullptr;
- DiagHandlerTy DiagHandler;
- void *DiagContext;
+ DiagHandlerTy DiagHandler = nullptr;
+ void *DiagContext = nullptr;
bool isValidBufferID(unsigned i) const { return i && i <= Buffers.size(); }
- SourceMgr(const SourceMgr&) = delete;
- void operator=(const SourceMgr&) = delete;
public:
- SourceMgr()
- : LineNoCache(nullptr), DiagHandler(nullptr), DiagContext(nullptr) {}
+ SourceMgr() = default;
+ SourceMgr(const SourceMgr &) = delete;
+ SourceMgr &operator=(const SourceMgr &) = delete;
~SourceMgr();
void setIncludeDirs(const std::vector<std::string> &Dirs) {
@@ -190,7 +196,6 @@ public:
void PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const;
};
-
/// Represents a single fixit, a replacement of one range of text with another.
class SMFixIt {
SMRange Range;
@@ -222,33 +227,31 @@ public:
}
};
-
/// Instances of this class encapsulate one diagnostic report, allowing
/// printing to a raw_ostream as a caret diagnostic.
class SMDiagnostic {
- const SourceMgr *SM;
+ const SourceMgr *SM = nullptr;
SMLoc Loc;
std::string Filename;
- int LineNo, ColumnNo;
- SourceMgr::DiagKind Kind;
+ int LineNo = 0;
+ int ColumnNo = 0;
+ SourceMgr::DiagKind Kind = SourceMgr::DK_Error;
std::string Message, LineContents;
- std::vector<std::pair<unsigned, unsigned> > Ranges;
+ std::vector<std::pair<unsigned, unsigned>> Ranges;
SmallVector<SMFixIt, 4> FixIts;
public:
// Null diagnostic.
- SMDiagnostic()
- : SM(nullptr), LineNo(0), ColumnNo(0), Kind(SourceMgr::DK_Error) {}
+ SMDiagnostic() = default;
// Diagnostic with no location (e.g. file not found, command line arg error).
SMDiagnostic(StringRef filename, SourceMgr::DiagKind Knd, StringRef Msg)
- : SM(nullptr), Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd),
- Message(Msg) {}
+ : Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd), Message(Msg) {}
// Diagnostic with a location.
SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN,
int Line, int Col, SourceMgr::DiagKind Kind,
StringRef Msg, StringRef LineStr,
- ArrayRef<std::pair<unsigned,unsigned> > Ranges,
+ ArrayRef<std::pair<unsigned,unsigned>> Ranges,
ArrayRef<SMFixIt> FixIts = None);
const SourceMgr *getSourceMgr() const { return SM; }
@@ -259,9 +262,7 @@ public:
SourceMgr::DiagKind getKind() const { return Kind; }
StringRef getMessage() const { return Message; }
StringRef getLineContents() const { return LineContents; }
- ArrayRef<std::pair<unsigned, unsigned> > getRanges() const {
- return Ranges;
- }
+ ArrayRef<std::pair<unsigned, unsigned>> getRanges() const { return Ranges; }
void addFixIt(const SMFixIt &Hint) {
FixIts.push_back(Hint);
@@ -275,6 +276,6 @@ public:
bool ShowKindLabel = true) const;
};
-} // end llvm namespace
+} // end namespace llvm
-#endif
+#endif // LLVM_SUPPORT_SOURCEMGR_H
diff --git a/include/llvm/Support/TargetParser.h b/include/llvm/Support/TargetParser.h
index 63aeca7f4e1ea..68e6b27658102 100644
--- a/include/llvm/Support/TargetParser.h
+++ b/include/llvm/Support/TargetParser.h
@@ -142,7 +142,7 @@ unsigned parseArchVersion(StringRef Arch);
} // namespace ARM
-// FIXME:This should be made into class design,to avoid dupplication.
+// FIXME:This should be made into class design,to avoid dupplication.
namespace AArch64 {
// Arch names.
diff --git a/include/llvm/Support/TargetRegistry.h b/include/llvm/Support/TargetRegistry.h
index 954cdb13abafa..bd68d24144875 100644
--- a/include/llvm/Support/TargetRegistry.h
+++ b/include/llvm/Support/TargetRegistry.h
@@ -1,4 +1,4 @@
-//===-- Support/TargetRegistry.h - Target Registration ----------*- C++ -*-===//
+//===- Support/TargetRegistry.h - Target Registration -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -20,15 +20,22 @@
#define LLVM_SUPPORT_TARGETREGISTRY_H
#include "llvm-c/Disassembler.h"
+#include "llvm/ADT/iterator_range.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
+#include <algorithm>
#include <cassert>
+#include <cstddef>
+#include <iterator>
#include <memory>
#include <string>
namespace llvm {
+
class AsmPrinter;
class MCAsmBackend;
class MCAsmInfo;
@@ -36,22 +43,20 @@ class MCAsmParser;
class MCCodeEmitter;
class MCContext;
class MCDisassembler;
-class MCInstrAnalysis;
class MCInstPrinter;
+class MCInstrAnalysis;
class MCInstrInfo;
class MCRegisterInfo;
+class MCRelocationInfo;
class MCStreamer;
class MCSubtargetInfo;
class MCSymbolizer;
-class MCRelocationInfo;
class MCTargetAsmParser;
class MCTargetOptions;
class MCTargetStreamer;
+class raw_pwrite_stream;
class TargetMachine;
class TargetOptions;
-class raw_ostream;
-class raw_pwrite_stream;
-class formatted_raw_ostream;
MCStreamer *createNullStreamer(MCContext &Ctx);
MCStreamer *createAsmStreamer(MCContext &Ctx,
@@ -68,6 +73,9 @@ MCStreamer *createMachOStreamer(MCContext &Ctx, MCAsmBackend &TAB,
raw_pwrite_stream &OS, MCCodeEmitter *CE,
bool RelaxAll, bool DWARFMustBeAtTheEnd,
bool LabelSections = false);
+MCStreamer *createWasmStreamer(MCContext &Ctx, MCAsmBackend &TAB,
+ raw_pwrite_stream &OS, MCCodeEmitter *CE,
+ bool RelaxAll);
MCRelocationInfo *createMCRelocationInfo(const Triple &TT, MCContext &Ctx);
@@ -143,6 +151,11 @@ public:
MCCodeEmitter *Emitter,
bool RelaxAll,
bool IncrementalLinkerCompatible);
+ typedef MCStreamer *(*WasmStreamerCtorTy)(const Triple &T, MCContext &Ctx,
+ MCAsmBackend &TAB,
+ raw_pwrite_stream &OS,
+ MCCodeEmitter *Emitter,
+ bool RelaxAll);
typedef MCTargetStreamer *(*NullTargetStreamerCtorTy)(MCStreamer &S);
typedef MCTargetStreamer *(*AsmTargetStreamerCtorTy)(
MCStreamer &S, formatted_raw_ostream &OS, MCInstPrinter *InstPrint,
@@ -224,36 +237,33 @@ private:
MCCodeEmitterCtorTy MCCodeEmitterCtorFn;
// Construction functions for the various object formats, if registered.
- COFFStreamerCtorTy COFFStreamerCtorFn;
- MachOStreamerCtorTy MachOStreamerCtorFn;
- ELFStreamerCtorTy ELFStreamerCtorFn;
+ COFFStreamerCtorTy COFFStreamerCtorFn = nullptr;
+ MachOStreamerCtorTy MachOStreamerCtorFn = nullptr;
+ ELFStreamerCtorTy ELFStreamerCtorFn = nullptr;
+ WasmStreamerCtorTy WasmStreamerCtorFn = nullptr;
/// Construction function for this target's null TargetStreamer, if
/// registered (default = nullptr).
- NullTargetStreamerCtorTy NullTargetStreamerCtorFn;
+ NullTargetStreamerCtorTy NullTargetStreamerCtorFn = nullptr;
/// Construction function for this target's asm TargetStreamer, if
/// registered (default = nullptr).
- AsmTargetStreamerCtorTy AsmTargetStreamerCtorFn;
+ AsmTargetStreamerCtorTy AsmTargetStreamerCtorFn = nullptr;
/// Construction function for this target's obj TargetStreamer, if
/// registered (default = nullptr).
- ObjectTargetStreamerCtorTy ObjectTargetStreamerCtorFn;
+ ObjectTargetStreamerCtorTy ObjectTargetStreamerCtorFn = nullptr;
/// MCRelocationInfoCtorFn - Construction function for this target's
/// MCRelocationInfo, if registered (default = llvm::createMCRelocationInfo)
- MCRelocationInfoCtorTy MCRelocationInfoCtorFn;
+ MCRelocationInfoCtorTy MCRelocationInfoCtorFn = nullptr;
/// MCSymbolizerCtorFn - Construction function for this target's
/// MCSymbolizer, if registered (default = llvm::createMCSymbolizer)
- MCSymbolizerCtorTy MCSymbolizerCtorFn;
+ MCSymbolizerCtorTy MCSymbolizerCtorFn = nullptr;
public:
- Target()
- : COFFStreamerCtorFn(nullptr), MachOStreamerCtorFn(nullptr),
- ELFStreamerCtorFn(nullptr), NullTargetStreamerCtorFn(nullptr),
- AsmTargetStreamerCtorFn(nullptr), ObjectTargetStreamerCtorFn(nullptr),
- MCRelocationInfoCtorFn(nullptr), MCSymbolizerCtorFn(nullptr) {}
+ Target() = default;
/// @name Target Information
/// @{
@@ -461,6 +471,12 @@ public:
else
S = createELFStreamer(Ctx, TAB, OS, Emitter, RelaxAll);
break;
+ case Triple::Wasm:
+ if (WasmStreamerCtorFn)
+ S = WasmStreamerCtorFn(T, Ctx, TAB, OS, Emitter, RelaxAll);
+ else
+ S = createWasmStreamer(Ctx, TAB, OS, Emitter, RelaxAll);
+ break;
}
if (ObjectTargetStreamerCtorFn)
ObjectTargetStreamerCtorFn(*S, STI);
@@ -548,12 +564,14 @@ struct TargetRegistry {
class iterator
: public std::iterator<std::forward_iterator_tag, Target, ptrdiff_t> {
- const Target *Current;
- explicit iterator(Target *T) : Current(T) {}
friend struct TargetRegistry;
+ const Target *Current = nullptr;
+
+ explicit iterator(Target *T) : Current(T) {}
+
public:
- iterator() : Current(nullptr) {}
+ iterator() = default;
bool operator==(const iterator &x) const { return Current == x.Current; }
bool operator!=(const iterator &x) const { return !operator==(x); }
@@ -800,6 +818,10 @@ struct TargetRegistry {
T.ELFStreamerCtorFn = Fn;
}
+ static void RegisterWasmStreamer(Target &T, Target::WasmStreamerCtorTy Fn) {
+ T.WasmStreamerCtorFn = Fn;
+ }
+
static void RegisterNullTargetStreamer(Target &T,
Target::NullTargetStreamerCtorTy Fn) {
T.NullTargetStreamerCtorFn = Fn;
@@ -1147,6 +1169,7 @@ private:
return new MCCodeEmitterImpl();
}
};
-}
-#endif
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_TARGETREGISTRY_H
diff --git a/include/llvm/Support/ThreadPool.h b/include/llvm/Support/ThreadPool.h
index 665cec2465bfc..f0e3ffa0999c2 100644
--- a/include/llvm/Support/ThreadPool.h
+++ b/include/llvm/Support/ThreadPool.h
@@ -16,23 +16,8 @@
#include "llvm/Support/thread.h"
-#ifdef _MSC_VER
-// concrt.h depends on eh.h for __uncaught_exception declaration
-// even if we disable exceptions.
-#include <eh.h>
-
-// Disable warnings from ppltasks.h transitively included by <future>.
-#pragma warning(push)
-#pragma warning(disable:4530)
-#pragma warning(disable:4062)
-#endif
-
#include <future>
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
#include <atomic>
#include <condition_variable>
#include <functional>
diff --git a/include/llvm/Support/Threading.h b/include/llvm/Support/Threading.h
index 4bef7ec8dd3f2..03963a24c107e 100644
--- a/include/llvm/Support/Threading.h
+++ b/include/llvm/Support/Threading.h
@@ -15,16 +15,22 @@
#ifndef LLVM_SUPPORT_THREADING_H
#define LLVM_SUPPORT_THREADING_H
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
#include "llvm/Support/Compiler.h"
#include <ciso646> // So we can check the C++ standard lib macros.
#include <functional>
+#if defined(_MSC_VER)
+// MSVC's call_once implementation worked since VS 2015, which is the minimum
+// supported version as of this writing.
+#define LLVM_THREADING_USE_STD_CALL_ONCE 1
+#elif defined(LLVM_ON_UNIX) && \
+ (defined(_LIBCPP_VERSION) || \
+ !(defined(__NetBSD__) || defined(__OpenBSD__) || defined(__ppc__)))
// std::call_once from libc++ is used on all Unix platforms. Other
// implementations like libstdc++ are known to have problems on NetBSD,
// OpenBSD and PowerPC.
-#if defined(LLVM_ON_UNIX) && (defined(_LIBCPP_VERSION) || \
- !(defined(__NetBSD__) || defined(__OpenBSD__) || defined(__ppc__)))
#define LLVM_THREADING_USE_STD_CALL_ONCE 1
#else
#define LLVM_THREADING_USE_STD_CALL_ONCE 0
@@ -37,41 +43,43 @@
#endif
namespace llvm {
- /// Returns true if LLVM is compiled with support for multi-threading, and
- /// false otherwise.
- bool llvm_is_multithreaded();
-
- /// llvm_execute_on_thread - Execute the given \p UserFn on a separate
- /// thread, passing it the provided \p UserData and waits for thread
- /// completion.
- ///
- /// This function does not guarantee that the code will actually be executed
- /// on a separate thread or honoring the requested stack size, but tries to do
- /// so where system support is available.
- ///
- /// \param UserFn - The callback to execute.
- /// \param UserData - An argument to pass to the callback function.
- /// \param RequestedStackSize - If non-zero, a requested size (in bytes) for
- /// the thread stack.
- void llvm_execute_on_thread(void (*UserFn)(void*), void *UserData,
- unsigned RequestedStackSize = 0);
+class Twine;
+
+/// Returns true if LLVM is compiled with support for multi-threading, and
+/// false otherwise.
+bool llvm_is_multithreaded();
+
+/// llvm_execute_on_thread - Execute the given \p UserFn on a separate
+/// thread, passing it the provided \p UserData and waits for thread
+/// completion.
+///
+/// This function does not guarantee that the code will actually be executed
+/// on a separate thread or honoring the requested stack size, but tries to do
+/// so where system support is available.
+///
+/// \param UserFn - The callback to execute.
+/// \param UserData - An argument to pass to the callback function.
+/// \param RequestedStackSize - If non-zero, a requested size (in bytes) for
+/// the thread stack.
+void llvm_execute_on_thread(void (*UserFn)(void *), void *UserData,
+ unsigned RequestedStackSize = 0);
#if LLVM_THREADING_USE_STD_CALL_ONCE
typedef std::once_flag once_flag;
- /// This macro is the only way you should define your once flag for LLVM's
- /// call_once.
-#define LLVM_DEFINE_ONCE_FLAG(flag) static once_flag flag
-
#else
enum InitStatus { Uninitialized = 0, Wait = 1, Done = 2 };
- typedef volatile sys::cas_flag once_flag;
- /// This macro is the only way you should define your once flag for LLVM's
- /// call_once.
-#define LLVM_DEFINE_ONCE_FLAG(flag) static once_flag flag = Uninitialized
+ /// \brief The llvm::once_flag structure
+ ///
+ /// This type is modeled after std::once_flag to use with llvm::call_once.
+ /// This structure must be used as an opaque object. It is a struct to force
+ /// autoinitialization and behave like std::once_flag.
+ struct once_flag {
+ volatile sys::cas_flag status = Uninitialized;
+ };
#endif
@@ -81,7 +89,7 @@ namespace llvm {
/// \code
/// void foo() {...};
/// ...
- /// LLVM_DEFINE_ONCE_FLAG(flag);
+ /// static once_flag flag;
/// call_once(flag, foo);
/// \endcode
///
@@ -95,24 +103,24 @@ namespace llvm {
#else
// For other platforms we use a generic (if brittle) version based on our
// atomics.
- sys::cas_flag old_val = sys::CompareAndSwap(&flag, Wait, Uninitialized);
+ sys::cas_flag old_val = sys::CompareAndSwap(&flag.status, Wait, Uninitialized);
if (old_val == Uninitialized) {
std::forward<Function>(F)(std::forward<Args>(ArgList)...);
sys::MemoryFence();
TsanIgnoreWritesBegin();
- TsanHappensBefore(&flag);
- flag = Done;
+ TsanHappensBefore(&flag.status);
+ flag.status = Done;
TsanIgnoreWritesEnd();
} else {
// Wait until any thread doing the call has finished.
- sys::cas_flag tmp = flag;
+ sys::cas_flag tmp = flag.status;
sys::MemoryFence();
while (tmp != Done) {
- tmp = flag;
+ tmp = flag.status;
sys::MemoryFence();
}
}
- TsanHappensAfter(&flag);
+ TsanHappensAfter(&flag.status);
#endif
}
@@ -122,6 +130,32 @@ namespace llvm {
/// thread::hardware_concurrency().
/// Returns 1 when LLVM is configured with LLVM_ENABLE_THREADS=OFF
unsigned heavyweight_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
+ /// this.
+ uint64_t get_threadid();
+
+ /// \brief Get the maximum length of a thread name on this platform.
+ /// A value of 0 means there is no limit.
+ uint32_t get_max_thread_name_length();
+
+ /// \brief Set the name of the current thread. Setting a thread's name can
+ /// be helpful for enabling useful diagnostics under a debugger or when
+ /// logging. The level of support for setting a thread's name varies
+ /// wildly across operating systems, and we only make a best effort to
+ /// perform the operation on supported platforms. No indication of success
+ /// or failure is returned.
+ void set_thread_name(const Twine &Name);
+
+ /// \brief Get the name of the current thread. The level of support for
+ /// getting a thread's name varies wildly across operating systems, and it
+ /// is not even guaranteed that if you can successfully set a thread's name
+ /// that you can later get it back. This function is intended for diagnostic
+ /// purposes, and as with setting a thread's name no indication of whether
+ /// the operation succeeded or failed is returned.
+ void get_thread_name(SmallVectorImpl<char> &Name);
}
#endif
diff --git a/include/llvm/Support/Timer.h b/include/llvm/Support/Timer.h
index 80e8f13dccfe9..198855ae03775 100644
--- a/include/llvm/Support/Timer.h
+++ b/include/llvm/Support/Timer.h
@@ -207,6 +207,9 @@ public:
/// This static method prints all timers and clears them all out.
static void printAll(raw_ostream &OS);
+ /// Prints all timers as JSON key/value pairs, and clears them all out.
+ static const char *printAllJSONValues(raw_ostream &OS, const char *delim);
+
/// Ensure global timer group lists are initialized. This function is mostly
/// used by the Statistic code to influence the construction and destruction
/// order of the global timer lists.
@@ -221,7 +224,6 @@ private:
void printJSONValue(raw_ostream &OS, const PrintRecord &R,
const char *suffix, double Value);
const char *printJSONValues(raw_ostream &OS, const char *delim);
- static const char *printAllJSONValues(raw_ostream &OS, const char *delim);
};
} // end namespace llvm
diff --git a/include/llvm/Support/TrailingObjects.h b/include/llvm/Support/TrailingObjects.h
index 4d355724149c2..cb5a52b0d861b 100644
--- a/include/llvm/Support/TrailingObjects.h
+++ b/include/llvm/Support/TrailingObjects.h
@@ -294,7 +294,14 @@ class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl<
public:
// Make this (privately inherited) member public.
+#ifndef _MSC_VER
using ParentType::OverloadToken;
+#else
+ // MSVC bug prevents the above from working, at least up through CL
+ // 19.10.24629.
+ template <typename T>
+ using OverloadToken = typename ParentType::template OverloadToken<T>;
+#endif
/// Returns a pointer to the trailing object array of the given type
/// (which must be one of those specified in the class template). The
diff --git a/include/llvm/Support/UniqueLock.h b/include/llvm/Support/UniqueLock.h
index 529284d3868bc..b4675f4b43aeb 100644
--- a/include/llvm/Support/UniqueLock.h
+++ b/include/llvm/Support/UniqueLock.h
@@ -1,4 +1,4 @@
-//===-- Support/UniqueLock.h - Acquire/Release Mutex In Scope ---*- C++ -*-===//
+//===- Support/UniqueLock.h - Acquire/Release Mutex In Scope ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,9 +15,10 @@
#ifndef LLVM_SUPPORT_UNIQUE_LOCK_H
#define LLVM_SUPPORT_UNIQUE_LOCK_H
-#include "llvm/Support/Mutex.h"
+#include <cassert>
namespace llvm {
+
/// A pared-down imitation of std::unique_lock from C++11. Contrary to the
/// name, it's really more of a wrapper for a lock. It may or may not have
/// an associated mutex, which is guaranteed to be locked upon creation
@@ -26,14 +27,14 @@ namespace llvm {
/// @brief Guard a section of code with a mutex.
template<typename MutexT>
class unique_lock {
- MutexT *M;
- bool locked;
+ MutexT *M = nullptr;
+ bool locked = false;
- unique_lock(const unique_lock &) = delete;
- void operator=(const unique_lock &) = delete;
public:
- unique_lock() : M(nullptr), locked(false) {}
+ unique_lock() = default;
explicit unique_lock(MutexT &m) : M(&m), locked(true) { M->lock(); }
+ unique_lock(const unique_lock &) = delete;
+ unique_lock &operator=(const unique_lock &) = delete;
void operator=(unique_lock &&o) {
if (owns_lock())
@@ -62,6 +63,7 @@ namespace llvm {
bool owns_lock() { return locked; }
};
-}
+
+} // end namespace llvm
#endif // LLVM_SUPPORT_UNIQUE_LOCK_H
diff --git a/include/llvm/Support/Wasm.h b/include/llvm/Support/Wasm.h
index 8ac6b9038e913..8e6c418c8189a 100644
--- a/include/llvm/Support/Wasm.h
+++ b/include/llvm/Support/Wasm.h
@@ -23,22 +23,94 @@ namespace wasm {
// Object file magic string.
const char WasmMagic[] = {'\0', 'a', 's', 'm'};
// Wasm binary format version
-const uint32_t WasmVersion = 0xd;
+const uint32_t WasmVersion = 0x1;
struct WasmObjectHeader {
StringRef Magic;
uint32_t Version;
};
-struct WasmSection {
- uint32_t Type; // Section type (See below)
- uint32_t Offset; // Offset with in the file
- StringRef Name; // Section name (User-defined sections only)
- ArrayRef<uint8_t> Content; // Section content
+struct WasmSignature {
+ std::vector<int32_t> ParamTypes;
+ int32_t ReturnType;
+};
+
+struct WasmImport {
+ StringRef Module;
+ StringRef Field;
+ uint32_t Kind;
+ union {
+ uint32_t SigIndex;
+ int32_t GlobalType;
+ };
+ bool GlobalMutable;
+};
+
+struct WasmExport {
+ StringRef Name;
+ uint32_t Kind;
+ uint32_t Index;
+};
+
+struct WasmLimits {
+ uint32_t Flags;
+ uint32_t Initial;
+ uint32_t Maximum;
+};
+
+struct WasmTable {
+ int32_t ElemType;
+ WasmLimits Limits;
+};
+
+struct WasmInitExpr {
+ uint8_t Opcode;
+ union {
+ int32_t Int32;
+ int64_t Int64;
+ int32_t Float32;
+ int64_t Float64;
+ uint32_t Global;
+ } Value;
+};
+
+struct WasmGlobal {
+ int32_t Type;
+ bool Mutable;
+ WasmInitExpr InitExpr;
+};
+
+struct WasmLocalDecl {
+ int32_t Type;
+ uint32_t Count;
+};
+
+struct WasmFunction {
+ std::vector<WasmLocalDecl> Locals;
+ ArrayRef<uint8_t> Body;
+};
+
+struct WasmDataSegment {
+ uint32_t Index;
+ WasmInitExpr Offset;
+ ArrayRef<uint8_t> Content;
+};
+
+struct WasmElemSegment {
+ uint32_t TableIndex;
+ WasmInitExpr Offset;
+ std::vector<uint32_t> Functions;
+};
+
+struct WasmRelocation {
+ uint32_t Type; // The type of the relocation.
+ int32_t Index; // Index into function to global index space.
+ uint64_t Offset; // Offset from the start of the section.
+ uint64_t Addend; // A value to add to the symbol.
};
enum : unsigned {
- WASM_SEC_USER = 0, // User-defined section
+ WASM_SEC_CUSTOM = 0, // Custom / User-defined section
WASM_SEC_TYPE = 1, // Function signature declarations
WASM_SEC_IMPORT = 2, // Import declarations
WASM_SEC_FUNCTION = 3, // Function declarations
@@ -53,14 +125,14 @@ enum : unsigned {
};
// Type immediate encodings used in various contexts.
-enum : unsigned {
- WASM_TYPE_I32 = 0x7f,
- WASM_TYPE_I64 = 0x7e,
- WASM_TYPE_F32 = 0x7d,
- WASM_TYPE_F64 = 0x7c,
- WASM_TYPE_ANYFUNC = 0x70,
- WASM_TYPE_FUNC = 0x60,
- WASM_TYPE_NORESULT = 0x40, // for blocks with no result values
+enum {
+ WASM_TYPE_I32 = -0x01,
+ WASM_TYPE_I64 = -0x02,
+ WASM_TYPE_F32 = -0x03,
+ WASM_TYPE_F64 = -0x04,
+ WASM_TYPE_ANYFUNC = -0x10,
+ WASM_TYPE_FUNC = -0x20,
+ WASM_TYPE_NORESULT = -0x40, // for blocks with no result values
};
// Kinds of externals (for imports and exports).
@@ -81,6 +153,49 @@ enum : unsigned {
WASM_OPCODE_F64_CONST = 0x44,
};
+enum : unsigned {
+ WASM_NAMES_FUNCTION = 0x1,
+ WASM_NAMES_LOCAL = 0x2,
+};
+
+enum : unsigned {
+ WASM_LIMITS_FLAG_HAS_MAX = 0x1,
+};
+
+// Subset of types that a value can have
+enum class ValType {
+ I32 = WASM_TYPE_I32,
+ I64 = WASM_TYPE_I64,
+ F32 = WASM_TYPE_F32,
+ F64 = WASM_TYPE_F64,
+};
+
+// Linking metadata kinds.
+enum : unsigned {
+ WASM_STACK_POINTER = 0x1,
+};
+
+#define WASM_RELOC(name, value) name = value,
+
+enum : unsigned {
+#include "WasmRelocs/WebAssembly.def"
+};
+
+#undef WASM_RELOC
+
+struct Global {
+ ValType Type;
+ bool Mutable;
+
+ // The initial value for this global is either the value of an imported
+ // global, in which case InitialModule and InitialName specify the global
+ // import, or a value, in which case InitialModule is empty and InitialValue
+ // holds the value.
+ StringRef InitialModule;
+ StringRef InitialName;
+ uint64_t InitialValue;
+};
+
} // end namespace wasm
} // end namespace llvm
diff --git a/include/llvm/Support/WasmRelocs/WebAssembly.def b/include/llvm/Support/WasmRelocs/WebAssembly.def
new file mode 100644
index 0000000000000..da64e025478de
--- /dev/null
+++ b/include/llvm/Support/WasmRelocs/WebAssembly.def
@@ -0,0 +1,13 @@
+
+#ifndef WASM_RELOC
+#error "WASM_RELOC must be defined"
+#endif
+
+WASM_RELOC(R_WEBASSEMBLY_FUNCTION_INDEX_LEB, 0)
+WASM_RELOC(R_WEBASSEMBLY_TABLE_INDEX_SLEB, 1)
+WASM_RELOC(R_WEBASSEMBLY_TABLE_INDEX_I32, 2)
+WASM_RELOC(R_WEBASSEMBLY_GLOBAL_ADDR_LEB, 3)
+WASM_RELOC(R_WEBASSEMBLY_GLOBAL_ADDR_SLEB, 4)
+WASM_RELOC(R_WEBASSEMBLY_GLOBAL_ADDR_I32, 5)
+WASM_RELOC(R_WEBASSEMBLY_TYPE_INDEX_LEB, 6)
+WASM_RELOC(R_WEBASSEMBLY_GLOBAL_INDEX_LEB, 7)
diff --git a/include/llvm/Support/YAMLTraits.h b/include/llvm/Support/YAMLTraits.h
index cbba9c08275a0..6d02e4aba48a7 100644
--- a/include/llvm/Support/YAMLTraits.h
+++ b/include/llvm/Support/YAMLTraits.h
@@ -689,11 +689,12 @@ private:
assert(DefaultValue.hasValue() == false &&
"Optional<T> shouldn't have a value!");
void *SaveInfo;
- bool UseDefault;
+ bool UseDefault = true;
const bool sameAsDefault = outputting() && !Val.hasValue();
if (!outputting() && !Val.hasValue())
Val = T();
- if (this->preflightKey(Key, Required, sameAsDefault, UseDefault,
+ if (Val.hasValue() &&
+ this->preflightKey(Key, Required, sameAsDefault, UseDefault,
SaveInfo)) {
yamlize(*this, Val.getValue(), Required, Ctx);
this->postflightKey(SaveInfo);
@@ -731,7 +732,7 @@ private:
}
private:
- void *Ctxt;
+ void *Ctxt;
};
namespace detail {
@@ -1251,6 +1252,13 @@ public:
Output(llvm::raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70);
~Output() override;
+ /// \brief Set whether or not to output optional values which are equal
+ /// to the default value. By default, when outputting if you attempt
+ /// to write a value that is equal to the default, the value gets ignored.
+ /// Sometimes, it is useful to be able to see these in the resulting YAML
+ /// anyway.
+ void setWriteDefaultValues(bool Write) { WriteDefaultValues = Write; }
+
bool outputting() override;
bool mapTag(StringRef, bool) override;
void beginMapping() override;
@@ -1314,6 +1322,7 @@ private:
bool NeedFlowSequenceComma;
bool EnumerationMatchFound;
bool NeedsNewLine;
+ bool WriteDefaultValues;
};
/// YAML I/O does conversion based on types. But often native data types
diff --git a/include/llvm/Support/thread.h b/include/llvm/Support/thread.h
index 9c45418df55c2..787a513d60176 100644
--- a/include/llvm/Support/thread.h
+++ b/include/llvm/Support/thread.h
@@ -21,22 +21,8 @@
#if LLVM_ENABLE_THREADS
-#ifdef _MSC_VER
-// concrt.h depends on eh.h for __uncaught_exception declaration
-// even if we disable exceptions.
-#include <eh.h>
-
-// Suppress 'C++ exception handler used, but unwind semantics are not enabled.'
-#pragma warning(push)
-#pragma warning(disable:4530)
-#endif
-
#include <thread>
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
namespace llvm {
typedef std::thread thread;
}
diff --git a/include/llvm/Support/type_traits.h b/include/llvm/Support/type_traits.h
index 7706ff527197e..ce4bbf8cb2cc5 100644
--- a/include/llvm/Support/type_traits.h
+++ b/include/llvm/Support/type_traits.h
@@ -95,6 +95,15 @@ struct add_const_past_pointer<
typedef const typename std::remove_pointer<T>::type *type;
};
+template <typename T, typename Enable = void>
+struct const_pointer_or_const_ref {
+ using type = const T &;
+};
+template <typename T>
+struct const_pointer_or_const_ref<
+ T, typename std::enable_if<std::is_pointer<T>::value>::type> {
+ using type = typename add_const_past_pointer<T>::type;
+};
}
// If the compiler supports detecting whether a class is final, define