diff options
Diffstat (limited to 'include/llvm/Support')
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 |