diff options
Diffstat (limited to 'include/llvm/Support')
53 files changed, 2110 insertions, 1650 deletions
diff --git a/include/llvm/Support/AArch64TargetParser.def b/include/llvm/Support/AArch64TargetParser.def index e152f383b3ec..15737265dfc3 100644 --- a/include/llvm/Support/AArch64TargetParser.def +++ b/include/llvm/Support/AArch64TargetParser.def @@ -50,35 +50,36 @@ AARCH64_ARCH("armv8.5-a", ARMV8_5A, "8.5-A", "v8.5a", #define AARCH64_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE) #endif // FIXME: This would be nicer were it tablegen -AARCH64_ARCH_EXT_NAME("invalid", AArch64::AEK_INVALID, nullptr, nullptr) -AARCH64_ARCH_EXT_NAME("none", AArch64::AEK_NONE, nullptr, nullptr) -AARCH64_ARCH_EXT_NAME("crc", AArch64::AEK_CRC, "+crc", "-crc") -AARCH64_ARCH_EXT_NAME("lse", AArch64::AEK_LSE, "+lse", "-lse") -AARCH64_ARCH_EXT_NAME("rdm", AArch64::AEK_RDM, "+rdm", "-rdm") -AARCH64_ARCH_EXT_NAME("crypto", AArch64::AEK_CRYPTO, "+crypto","-crypto") -AARCH64_ARCH_EXT_NAME("sm4", AArch64::AEK_SM4, "+sm4", "-sm4") -AARCH64_ARCH_EXT_NAME("sha3", AArch64::AEK_SHA3, "+sha3", "-sha3") -AARCH64_ARCH_EXT_NAME("sha2", AArch64::AEK_SHA2, "+sha2", "-sha2") -AARCH64_ARCH_EXT_NAME("aes", AArch64::AEK_AES, "+aes", "-aes") -AARCH64_ARCH_EXT_NAME("dotprod", AArch64::AEK_DOTPROD, "+dotprod","-dotprod") -AARCH64_ARCH_EXT_NAME("fp", AArch64::AEK_FP, "+fp-armv8", "-fp-armv8") -AARCH64_ARCH_EXT_NAME("simd", AArch64::AEK_SIMD, "+neon", "-neon") -AARCH64_ARCH_EXT_NAME("fp16", AArch64::AEK_FP16, "+fullfp16", "-fullfp16") -AARCH64_ARCH_EXT_NAME("fp16fml", AArch64::AEK_FP16FML, "+fp16fml", "-fp16fml") -AARCH64_ARCH_EXT_NAME("profile", AArch64::AEK_PROFILE, "+spe", "-spe") -AARCH64_ARCH_EXT_NAME("ras", AArch64::AEK_RAS, "+ras", "-ras") -AARCH64_ARCH_EXT_NAME("sve", AArch64::AEK_SVE, "+sve", "-sve") -AARCH64_ARCH_EXT_NAME("sve2", AArch64::AEK_SVE2, "+sve2", "-sve2") -AARCH64_ARCH_EXT_NAME("sve2-aes", AArch64::AEK_SVE2AES, "+sve2-aes", "-sve2-aes") -AARCH64_ARCH_EXT_NAME("sve2-sm4", AArch64::AEK_SVE2SM4, "+sve2-sm4", "-sve2-sm4") -AARCH64_ARCH_EXT_NAME("sve2-sha3", AArch64::AEK_SVE2SHA3, "+sve2-sha3", "-sve2-sha3") -AARCH64_ARCH_EXT_NAME("bitperm", AArch64::AEK_BITPERM, "+bitperm", "-bitperm") -AARCH64_ARCH_EXT_NAME("rcpc", AArch64::AEK_RCPC, "+rcpc", "-rcpc") -AARCH64_ARCH_EXT_NAME("rng", AArch64::AEK_RAND, "+rand", "-rand") -AARCH64_ARCH_EXT_NAME("memtag", AArch64::AEK_MTE, "+mte", "-mte") -AARCH64_ARCH_EXT_NAME("ssbs", AArch64::AEK_SSBS, "+ssbs", "-ssbs") -AARCH64_ARCH_EXT_NAME("sb", AArch64::AEK_SB, "+sb", "-sb") -AARCH64_ARCH_EXT_NAME("predres", AArch64::AEK_PREDRES, "+predres", "-predres") +AARCH64_ARCH_EXT_NAME("invalid", AArch64::AEK_INVALID, nullptr, nullptr) +AARCH64_ARCH_EXT_NAME("none", AArch64::AEK_NONE, nullptr, nullptr) +AARCH64_ARCH_EXT_NAME("crc", AArch64::AEK_CRC, "+crc", "-crc") +AARCH64_ARCH_EXT_NAME("lse", AArch64::AEK_LSE, "+lse", "-lse") +AARCH64_ARCH_EXT_NAME("rdm", AArch64::AEK_RDM, "+rdm", "-rdm") +AARCH64_ARCH_EXT_NAME("crypto", AArch64::AEK_CRYPTO, "+crypto","-crypto") +AARCH64_ARCH_EXT_NAME("sm4", AArch64::AEK_SM4, "+sm4", "-sm4") +AARCH64_ARCH_EXT_NAME("sha3", AArch64::AEK_SHA3, "+sha3", "-sha3") +AARCH64_ARCH_EXT_NAME("sha2", AArch64::AEK_SHA2, "+sha2", "-sha2") +AARCH64_ARCH_EXT_NAME("aes", AArch64::AEK_AES, "+aes", "-aes") +AARCH64_ARCH_EXT_NAME("dotprod", AArch64::AEK_DOTPROD, "+dotprod","-dotprod") +AARCH64_ARCH_EXT_NAME("fp", AArch64::AEK_FP, "+fp-armv8", "-fp-armv8") +AARCH64_ARCH_EXT_NAME("simd", AArch64::AEK_SIMD, "+neon", "-neon") +AARCH64_ARCH_EXT_NAME("fp16", AArch64::AEK_FP16, "+fullfp16", "-fullfp16") +AARCH64_ARCH_EXT_NAME("fp16fml", AArch64::AEK_FP16FML, "+fp16fml", "-fp16fml") +AARCH64_ARCH_EXT_NAME("profile", AArch64::AEK_PROFILE, "+spe", "-spe") +AARCH64_ARCH_EXT_NAME("ras", AArch64::AEK_RAS, "+ras", "-ras") +AARCH64_ARCH_EXT_NAME("sve", AArch64::AEK_SVE, "+sve", "-sve") +AARCH64_ARCH_EXT_NAME("sve2", AArch64::AEK_SVE2, "+sve2", "-sve2") +AARCH64_ARCH_EXT_NAME("sve2-aes", AArch64::AEK_SVE2AES, "+sve2-aes", "-sve2-aes") +AARCH64_ARCH_EXT_NAME("sve2-sm4", AArch64::AEK_SVE2SM4, "+sve2-sm4", "-sve2-sm4") +AARCH64_ARCH_EXT_NAME("sve2-sha3", AArch64::AEK_SVE2SHA3, "+sve2-sha3", "-sve2-sha3") +AARCH64_ARCH_EXT_NAME("sve2-bitperm", AArch64::AEK_SVE2BITPERM, "+sve2-bitperm", "-sve2-bitperm") +AARCH64_ARCH_EXT_NAME("rcpc", AArch64::AEK_RCPC, "+rcpc", "-rcpc") +AARCH64_ARCH_EXT_NAME("rng", AArch64::AEK_RAND, "+rand", "-rand") +AARCH64_ARCH_EXT_NAME("memtag", AArch64::AEK_MTE, "+mte", "-mte") +AARCH64_ARCH_EXT_NAME("ssbs", AArch64::AEK_SSBS, "+ssbs", "-ssbs") +AARCH64_ARCH_EXT_NAME("sb", AArch64::AEK_SB, "+sb", "-sb") +AARCH64_ARCH_EXT_NAME("predres", AArch64::AEK_PREDRES, "+predres", "-predres") +AARCH64_ARCH_EXT_NAME("tme", AArch64::AEK_TME, "+tme", "-tme") #undef AARCH64_ARCH_EXT_NAME #ifndef AARCH64_CPU_NAME @@ -92,6 +93,12 @@ AARCH64_CPU_NAME("cortex-a55", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC)) AARCH64_CPU_NAME("cortex-a57", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, (AArch64::AEK_CRC)) +AARCH64_CPU_NAME("cortex-a65", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_DOTPROD | AArch64::AEK_FP16 | AArch64::AEK_RAS | + AArch64::AEK_RCPC | AArch64::AEK_SSBS)) +AARCH64_CPU_NAME("cortex-a65ae", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_DOTPROD | AArch64::AEK_FP16 | AArch64::AEK_RAS | + AArch64::AEK_RCPC | AArch64::AEK_SSBS)) AARCH64_CPU_NAME("cortex-a72", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, (AArch64::AEK_CRC)) AARCH64_CPU_NAME("cortex-a73", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, @@ -104,6 +111,13 @@ AARCH64_CPU_NAME("cortex-a76", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, AARCH64_CPU_NAME("cortex-a76ae", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC | AArch64::AEK_SSBS)) +AARCH64_CPU_NAME("neoverse-e1", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_DOTPROD | AArch64::AEK_FP16 | AArch64::AEK_RAS | + AArch64::AEK_RCPC | AArch64::AEK_SSBS)) +AARCH64_CPU_NAME("neoverse-n1", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_DOTPROD | AArch64::AEK_FP16 | + AArch64::AEK_PROFILE | AArch64::AEK_RAS | AArch64::AEK_RCPC | + AArch64::AEK_SSBS)) AARCH64_CPU_NAME("cyclone", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, (AArch64::AEK_NONE)) AARCH64_CPU_NAME("exynos-m1", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, diff --git a/include/llvm/Support/AArch64TargetParser.h b/include/llvm/Support/AArch64TargetParser.h index 965d38535e74..94f341c83260 100644 --- a/include/llvm/Support/AArch64TargetParser.h +++ b/include/llvm/Support/AArch64TargetParser.h @@ -53,7 +53,8 @@ enum ArchExtKind : unsigned { AEK_SVE2AES = 1 << 24, AEK_SVE2SM4 = 1 << 25, AEK_SVE2SHA3 = 1 << 26, - AEK_BITPERM = 1 << 27, + AEK_SVE2BITPERM = 1 << 27, + AEK_TME = 1 << 28, }; enum class ArchKind { diff --git a/include/llvm/Support/ARMTargetParser.def b/include/llvm/Support/ARMTargetParser.def index f466b3252748..3e77e20762c1 100644 --- a/include/llvm/Support/ARMTargetParser.def +++ b/include/llvm/Support/ARMTargetParser.def @@ -274,6 +274,8 @@ ARM_CPU_NAME("cortex-a76", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) ARM_CPU_NAME("cortex-a76ae", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) +ARM_CPU_NAME("neoverse-n1", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) ARM_CPU_NAME("cyclone", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) ARM_CPU_NAME("exynos-m1", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) ARM_CPU_NAME("exynos-m2", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) diff --git a/include/llvm/Support/ARMTargetParser.h b/include/llvm/Support/ARMTargetParser.h index 4b9070dea596..02d4c975129f 100644 --- a/include/llvm/Support/ARMTargetParser.h +++ b/include/llvm/Support/ARMTargetParser.h @@ -39,19 +39,13 @@ enum ArchExtKind : unsigned { AEK_DSP = 1 << 10, AEK_FP16 = 1 << 11, AEK_RAS = 1 << 12, - AEK_SVE = 1 << 13, - AEK_DOTPROD = 1 << 14, - AEK_SHA2 = 1 << 15, - AEK_AES = 1 << 16, - AEK_FP16FML = 1 << 17, - AEK_SB = 1 << 18, - AEK_SVE2 = 1 << 19, - AEK_SVE2AES = 1 << 20, - AEK_SVE2SM4 = 1 << 21, - AEK_SVE2SHA3 = 1 << 22, - AEK_BITPERM = 1 << 23, - AEK_FP_DP = 1 << 24, - AEK_LOB = 1 << 25, + AEK_DOTPROD = 1 << 13, + AEK_SHA2 = 1 << 14, + AEK_AES = 1 << 15, + AEK_FP16FML = 1 << 16, + AEK_SB = 1 << 17, + AEK_FP_DP = 1 << 18, + AEK_LOB = 1 << 19, // Unsupported extensions. AEK_OS = 0x8000000, AEK_IWMMXT = 0x10000000, diff --git a/include/llvm/Support/AlignOf.h b/include/llvm/Support/AlignOf.h index d12401f0eb49..eb42542b777f 100644 --- a/include/llvm/Support/AlignOf.h +++ b/include/llvm/Support/AlignOf.h @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines the AlignedCharArray and AlignedCharArrayUnion classes. +// This file defines the AlignedCharArrayUnion class. // //===----------------------------------------------------------------------===// @@ -18,128 +18,38 @@ namespace llvm { -/// \struct AlignedCharArray -/// Helper for building an aligned character array type. -/// -/// This template is used to explicitly build up a collection of aligned -/// character array types. We have to build these up using a macro and explicit -/// specialization to cope with MSVC (at least till 2015) where only an -/// integer literal can be used to specify an alignment constraint. Once built -/// up here, we can then begin to indirect between these using normal C++ -/// template parameters. - -// MSVC requires special handling here. -#ifndef _MSC_VER - -template<std::size_t Alignment, std::size_t Size> -struct AlignedCharArray { - alignas(Alignment) char buffer[Size]; -}; - -#else // _MSC_VER - -/// Create a type with an aligned char buffer. -template<std::size_t Alignment, std::size_t Size> -struct AlignedCharArray; - -// We provide special variations of this template for the most common -// alignments because __declspec(align(...)) doesn't actually work when it is -// a member of a by-value function argument in MSVC, even if the alignment -// request is something reasonably like 8-byte or 16-byte. Note that we can't -// even include the declspec with the union that forces the alignment because -// MSVC warns on the existence of the declspec despite the union member forcing -// proper alignment. - -template<std::size_t Size> -struct AlignedCharArray<1, Size> { - union { - char aligned; - char buffer[Size]; - }; -}; - -template<std::size_t Size> -struct AlignedCharArray<2, Size> { - union { - short aligned; - char buffer[Size]; - }; -}; - -template<std::size_t Size> -struct AlignedCharArray<4, Size> { - union { - int aligned; - char buffer[Size]; - }; -}; +namespace detail { -template<std::size_t Size> -struct AlignedCharArray<8, Size> { - union { - double aligned; - char buffer[Size]; - }; +template <typename T, typename... Ts> class AlignerImpl { + T t; + AlignerImpl<Ts...> rest; + AlignerImpl() = delete; }; - -// The rest of these are provided with a __declspec(align(...)) and we simply -// can't pass them by-value as function arguments on MSVC. - -#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \ - template<std::size_t Size> \ - struct AlignedCharArray<x, Size> { \ - __declspec(align(x)) char buffer[Size]; \ - }; - -LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16) -LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32) -LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64) -LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128) - -#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT - -#endif // _MSC_VER - -namespace detail { -template <typename T1, - typename T2 = char, typename T3 = char, typename T4 = char, - typename T5 = char, typename T6 = char, typename T7 = char, - typename T8 = char, typename T9 = char, typename T10 = char> -class AlignerImpl { - T1 t1; T2 t2; T3 t3; T4 t4; T5 t5; T6 t6; T7 t7; T8 t8; T9 t9; T10 t10; - +template <typename T> class AlignerImpl<T> { + T t; AlignerImpl() = delete; }; -template <typename T1, - typename T2 = char, typename T3 = char, typename T4 = char, - typename T5 = char, typename T6 = char, typename T7 = char, - typename T8 = char, typename T9 = char, typename T10 = char> -union SizerImpl { - char arr1[sizeof(T1)], arr2[sizeof(T2)], arr3[sizeof(T3)], arr4[sizeof(T4)], - arr5[sizeof(T5)], arr6[sizeof(T6)], arr7[sizeof(T7)], arr8[sizeof(T8)], - arr9[sizeof(T9)], arr10[sizeof(T10)]; +template <typename T, typename... Ts> union SizerImpl { + char arr[sizeof(T)]; + SizerImpl<Ts...> rest; }; + +template <typename T> union SizerImpl<T> { char arr[sizeof(T)]; }; } // end namespace detail -/// This union template exposes a suitably aligned and sized character -/// array member which can hold elements of any of up to ten types. +/// A suitably aligned and sized character array member which can hold elements +/// of any type. /// -/// These types may be arrays, structs, or any other types. The goal is to -/// expose a char array buffer member which can be used as suitable storage for -/// a placement new of any of these types. Support for more than ten types can -/// be added at the cost of more boilerplate. -template <typename T1, - typename T2 = char, typename T3 = char, typename T4 = char, - typename T5 = char, typename T6 = char, typename T7 = char, - typename T8 = char, typename T9 = char, typename T10 = char> -struct AlignedCharArrayUnion : llvm::AlignedCharArray< - alignof(llvm::detail::AlignerImpl<T1, T2, T3, T4, T5, - T6, T7, T8, T9, T10>), - sizeof(::llvm::detail::SizerImpl<T1, T2, T3, T4, T5, - T6, T7, T8, T9, T10>)> { +/// These types may be arrays, structs, or any other types. This exposes a +/// `buffer` member which can be used as suitable storage for a placement new of +/// any of these types. +template <typename T, typename... Ts> struct AlignedCharArrayUnion { + alignas(::llvm::detail::AlignerImpl<T, Ts...>) char buffer[sizeof( + llvm::detail::SizerImpl<T, Ts...>)]; }; + } // end namespace llvm #endif // LLVM_SUPPORT_ALIGNOF_H diff --git a/include/llvm/Support/Alignment.h b/include/llvm/Support/Alignment.h new file mode 100644 index 000000000000..72fad87dd0d4 --- /dev/null +++ b/include/llvm/Support/Alignment.h @@ -0,0 +1,403 @@ +//===-- llvm/Support/Alignment.h - Useful alignment functions ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains types to represent alignments. +// They are instrumented to guarantee some invariants are preserved and prevent +// invalid manipulations. +// +// - Align represents an alignment in bytes, it is always set and always a valid +// power of two, its minimum value is 1 which means no alignment requirements. +// +// - MaybeAlign is an optional type, it may be undefined or set. When it's set +// you can get the underlying Align type by using the getValue() method. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ALIGNMENT_H_ +#define LLVM_SUPPORT_ALIGNMENT_H_ + +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MathExtras.h" +#include <cassert> +#include <limits> + +namespace llvm { + +#define ALIGN_CHECK_ISPOSITIVE(decl) \ + assert(decl > 0 && (#decl " should be defined")) +#define ALIGN_CHECK_ISSET(decl) \ + assert(decl.hasValue() && (#decl " should be defined")) + +/// This struct is a compact representation of a valid (non-zero power of two) +/// alignment. +/// It is suitable for use as static global constants. +struct Align { +private: + uint8_t ShiftValue = 0; /// The log2 of the required alignment. + /// ShiftValue is less than 64 by construction. + + friend struct MaybeAlign; + friend unsigned Log2(Align); + friend bool operator==(Align Lhs, Align Rhs); + friend bool operator!=(Align Lhs, Align Rhs); + friend bool operator<=(Align Lhs, Align Rhs); + friend bool operator>=(Align Lhs, Align Rhs); + friend bool operator<(Align Lhs, Align Rhs); + friend bool operator>(Align Lhs, Align Rhs); + friend unsigned encode(struct MaybeAlign A); + friend struct MaybeAlign decodeMaybeAlign(unsigned Value); + + /// A trivial type to allow construction of constexpr Align. + /// This is currently needed to workaround a bug in GCC 5.3 which prevents + /// definition of constexpr assign operators. + /// https://stackoverflow.com/questions/46756288/explicitly-defaulted-function-cannot-be-declared-as-constexpr-because-the-implic + /// FIXME: Remove this, make all assign operators constexpr and introduce user + /// defined literals when we don't have to support GCC 5.3 anymore. + /// https://llvm.org/docs/GettingStarted.html#getting-a-modern-host-c-toolchain + struct LogValue { + uint8_t Log; + }; + +public: + /// Default is byte-aligned. + constexpr Align() = default; + /// Do not perform checks in case of copy/move construct/assign, because the + /// checks have been performed when building `Other`. + constexpr Align(const Align &Other) = default; + constexpr Align(Align &&Other) = default; + Align &operator=(const Align &Other) = default; + Align &operator=(Align &&Other) = default; + + explicit Align(uint64_t Value) { + assert(Value > 0 && "Value must not be 0"); + assert(llvm::isPowerOf2_64(Value) && "Alignment is not a power of 2"); + ShiftValue = Log2_64(Value); + assert(ShiftValue < 64 && "Broken invariant"); + } + + /// This is a hole in the type system and should not be abused. + /// Needed to interact with C for instance. + uint64_t value() const { return uint64_t(1) << ShiftValue; } + + /// Returns a default constructed Align which corresponds to no alignment. + /// This is useful to test for unalignment as it conveys clear semantic. + /// `if (A != Align::None())` + /// would be better than + /// `if (A > Align(1))` + constexpr static const Align None() { return Align(); } + + /// Allow constructions of constexpr Align. + template <size_t kValue> constexpr static LogValue Constant() { + return LogValue{static_cast<uint8_t>(CTLog2<kValue>())}; + } + + /// Allow constructions of constexpr Align from types. + /// Compile time equivalent to Align(alignof(T)). + template <typename T> constexpr static LogValue Of() { + return Constant<std::alignment_of<T>::value>(); + } + + /// Constexpr constructor from LogValue type. + constexpr Align(LogValue CA) : ShiftValue(CA.Log) {} +}; + +/// Treats the value 0 as a 1, so Align is always at least 1. +inline Align assumeAligned(uint64_t Value) { + return Value ? Align(Value) : Align(); +} + +/// This struct is a compact representation of a valid (power of two) or +/// undefined (0) alignment. +struct MaybeAlign : public llvm::Optional<Align> { +private: + using UP = llvm::Optional<Align>; + +public: + /// Default is undefined. + MaybeAlign() = default; + /// Do not perform checks in case of copy/move construct/assign, because the + /// checks have been performed when building `Other`. + MaybeAlign(const MaybeAlign &Other) = default; + MaybeAlign &operator=(const MaybeAlign &Other) = default; + MaybeAlign(MaybeAlign &&Other) = default; + MaybeAlign &operator=(MaybeAlign &&Other) = default; + + /// Use llvm::Optional<Align> constructor. + using UP::UP; + + explicit MaybeAlign(uint64_t Value) { + assert((Value == 0 || llvm::isPowerOf2_64(Value)) && + "Alignment is neither 0 nor a power of 2"); + if (Value) + emplace(Value); + } + + /// For convenience, returns a valid alignment or 1 if undefined. + Align valueOrOne() const { return hasValue() ? getValue() : Align(); } +}; + +/// Checks that SizeInBytes is a multiple of the alignment. +inline bool isAligned(Align Lhs, uint64_t SizeInBytes) { + return SizeInBytes % Lhs.value() == 0; +} + +/// Checks that SizeInBytes is a multiple of the alignment. +/// Returns false if the alignment is undefined. +inline bool isAligned(MaybeAlign Lhs, uint64_t SizeInBytes) { + ALIGN_CHECK_ISSET(Lhs); + return SizeInBytes % (*Lhs).value() == 0; +} + +/// Checks that Addr is a multiple of the alignment. +inline bool isAddrAligned(Align Lhs, const void *Addr) { + return isAligned(Lhs, reinterpret_cast<uintptr_t>(Addr)); +} + +/// Returns a multiple of A needed to store `Size` bytes. +inline uint64_t alignTo(uint64_t Size, Align A) { + const uint64_t value = A.value(); + // The following line is equivalent to `(Size + value - 1) / value * value`. + + // The division followed by a multiplication can be thought of as a right + // shift followed by a left shift which zeros out the extra bits produced in + // the bump; `~(value - 1)` is a mask where all those bits being zeroed out + // are just zero. + + // Most compilers can generate this code but the pattern may be missed when + // multiple functions gets inlined. + return (Size + value - 1) & ~(value - 1); +} + +/// Returns a multiple of A needed to store `Size` bytes. +/// Returns `Size` if current alignment is undefined. +inline uint64_t alignTo(uint64_t Size, MaybeAlign A) { + return A ? alignTo(Size, A.getValue()) : Size; +} + +/// Aligns `Addr` to `Alignment` bytes, rounding up. +inline uintptr_t alignAddr(const void *Addr, Align Alignment) { + uintptr_t ArithAddr = reinterpret_cast<uintptr_t>(Addr); + assert(static_cast<uintptr_t>(ArithAddr + Alignment.value() - 1) >= + ArithAddr && "Overflow"); + return alignTo(ArithAddr, Alignment); +} + +/// Returns the offset to the next integer (mod 2**64) that is greater than +/// or equal to \p Value and is a multiple of \p Align. +inline uint64_t offsetToAlignment(uint64_t Value, Align Alignment) { + return alignTo(Value, Alignment) - Value; +} + +/// Returns the necessary adjustment for aligning `Addr` to `Alignment` +/// bytes, rounding up. +inline uint64_t offsetToAlignedAddr(const void *Addr, Align Alignment) { + return offsetToAlignment(reinterpret_cast<uintptr_t>(Addr), Alignment); +} + +/// Returns the log2 of the alignment. +inline unsigned Log2(Align A) { return A.ShiftValue; } + +/// Returns the log2 of the alignment. +/// \pre A must be defined. +inline unsigned Log2(MaybeAlign A) { + ALIGN_CHECK_ISSET(A); + return Log2(A.getValue()); +} + +/// Returns the alignment that satisfies both alignments. +/// Same semantic as MinAlign. +inline Align commonAlignment(Align A, Align B) { return std::min(A, B); } + +/// Returns the alignment that satisfies both alignments. +/// Same semantic as MinAlign. +inline Align commonAlignment(Align A, uint64_t Offset) { + return Align(MinAlign(A.value(), Offset)); +} + +/// Returns the alignment that satisfies both alignments. +/// Same semantic as MinAlign. +inline MaybeAlign commonAlignment(MaybeAlign A, MaybeAlign B) { + return A && B ? commonAlignment(*A, *B) : A ? A : B; +} + +/// Returns the alignment that satisfies both alignments. +/// Same semantic as MinAlign. +inline MaybeAlign commonAlignment(MaybeAlign A, uint64_t Offset) { + return MaybeAlign(MinAlign((*A).value(), Offset)); +} + +/// Returns a representation of the alignment that encodes undefined as 0. +inline unsigned encode(MaybeAlign A) { return A ? A->ShiftValue + 1 : 0; } + +/// Dual operation of the encode function above. +inline MaybeAlign decodeMaybeAlign(unsigned Value) { + if (Value == 0) + return MaybeAlign(); + Align Out; + Out.ShiftValue = Value - 1; + return Out; +} + +/// Returns a representation of the alignment, the encoded value is positive by +/// definition. +inline unsigned encode(Align A) { return encode(MaybeAlign(A)); } + +/// Comparisons between Align and scalars. Rhs must be positive. +inline bool operator==(Align Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISPOSITIVE(Rhs); + return Lhs.value() == Rhs; +} +inline bool operator!=(Align Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISPOSITIVE(Rhs); + return Lhs.value() != Rhs; +} +inline bool operator<=(Align Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISPOSITIVE(Rhs); + return Lhs.value() <= Rhs; +} +inline bool operator>=(Align Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISPOSITIVE(Rhs); + return Lhs.value() >= Rhs; +} +inline bool operator<(Align Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISPOSITIVE(Rhs); + return Lhs.value() < Rhs; +} +inline bool operator>(Align Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISPOSITIVE(Rhs); + return Lhs.value() > Rhs; +} + +/// Comparisons between MaybeAlign and scalars. +inline bool operator==(MaybeAlign Lhs, uint64_t Rhs) { + return Lhs ? (*Lhs).value() == Rhs : Rhs == 0; +} +inline bool operator!=(MaybeAlign Lhs, uint64_t Rhs) { + return Lhs ? (*Lhs).value() != Rhs : Rhs != 0; +} +inline bool operator<=(MaybeAlign Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISSET(Lhs); + ALIGN_CHECK_ISPOSITIVE(Rhs); + return (*Lhs).value() <= Rhs; +} +inline bool operator>=(MaybeAlign Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISSET(Lhs); + ALIGN_CHECK_ISPOSITIVE(Rhs); + return (*Lhs).value() >= Rhs; +} +inline bool operator<(MaybeAlign Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISSET(Lhs); + ALIGN_CHECK_ISPOSITIVE(Rhs); + return (*Lhs).value() < Rhs; +} +inline bool operator>(MaybeAlign Lhs, uint64_t Rhs) { + ALIGN_CHECK_ISSET(Lhs); + ALIGN_CHECK_ISPOSITIVE(Rhs); + return (*Lhs).value() > Rhs; +} + +/// Comparisons operators between Align. +inline bool operator==(Align Lhs, Align Rhs) { + return Lhs.ShiftValue == Rhs.ShiftValue; +} +inline bool operator!=(Align Lhs, Align Rhs) { + return Lhs.ShiftValue != Rhs.ShiftValue; +} +inline bool operator<=(Align Lhs, Align Rhs) { + return Lhs.ShiftValue <= Rhs.ShiftValue; +} +inline bool operator>=(Align Lhs, Align Rhs) { + return Lhs.ShiftValue >= Rhs.ShiftValue; +} +inline bool operator<(Align Lhs, Align Rhs) { + return Lhs.ShiftValue < Rhs.ShiftValue; +} +inline bool operator>(Align Lhs, Align Rhs) { + return Lhs.ShiftValue > Rhs.ShiftValue; +} + +/// Comparisons operators between Align and MaybeAlign. +inline bool operator==(Align Lhs, MaybeAlign Rhs) { + ALIGN_CHECK_ISSET(Rhs); + return Lhs.value() == (*Rhs).value(); +} +inline bool operator!=(Align Lhs, MaybeAlign Rhs) { + ALIGN_CHECK_ISSET(Rhs); + return Lhs.value() != (*Rhs).value(); +} +inline bool operator<=(Align Lhs, MaybeAlign Rhs) { + ALIGN_CHECK_ISSET(Rhs); + return Lhs.value() <= (*Rhs).value(); +} +inline bool operator>=(Align Lhs, MaybeAlign Rhs) { + ALIGN_CHECK_ISSET(Rhs); + return Lhs.value() >= (*Rhs).value(); +} +inline bool operator<(Align Lhs, MaybeAlign Rhs) { + ALIGN_CHECK_ISSET(Rhs); + return Lhs.value() < (*Rhs).value(); +} +inline bool operator>(Align Lhs, MaybeAlign Rhs) { + ALIGN_CHECK_ISSET(Rhs); + return Lhs.value() > (*Rhs).value(); +} + +/// Comparisons operators between MaybeAlign and Align. +inline bool operator==(MaybeAlign Lhs, Align Rhs) { + ALIGN_CHECK_ISSET(Lhs); + return Lhs && (*Lhs).value() == Rhs.value(); +} +inline bool operator!=(MaybeAlign Lhs, Align Rhs) { + ALIGN_CHECK_ISSET(Lhs); + return Lhs && (*Lhs).value() != Rhs.value(); +} +inline bool operator<=(MaybeAlign Lhs, Align Rhs) { + ALIGN_CHECK_ISSET(Lhs); + return Lhs && (*Lhs).value() <= Rhs.value(); +} +inline bool operator>=(MaybeAlign Lhs, Align Rhs) { + ALIGN_CHECK_ISSET(Lhs); + return Lhs && (*Lhs).value() >= Rhs.value(); +} +inline bool operator<(MaybeAlign Lhs, Align Rhs) { + ALIGN_CHECK_ISSET(Lhs); + return Lhs && (*Lhs).value() < Rhs.value(); +} +inline bool operator>(MaybeAlign Lhs, Align Rhs) { + ALIGN_CHECK_ISSET(Lhs); + return Lhs && (*Lhs).value() > Rhs.value(); +} + +inline Align operator/(Align Lhs, uint64_t Divisor) { + assert(llvm::isPowerOf2_64(Divisor) && + "Divisor must be positive and a power of 2"); + assert(Lhs != 1 && "Can't halve byte alignment"); + return Align(Lhs.value() / Divisor); +} + +inline MaybeAlign operator/(MaybeAlign Lhs, uint64_t Divisor) { + assert(llvm::isPowerOf2_64(Divisor) && + "Divisor must be positive and a power of 2"); + return Lhs ? Lhs.getValue() / Divisor : MaybeAlign(); +} + +inline Align max(MaybeAlign Lhs, Align Rhs) { + return Lhs && *Lhs > Rhs ? *Lhs : Rhs; +} + +inline Align max(Align Lhs, MaybeAlign Rhs) { + return Rhs && *Rhs > Lhs ? *Rhs : Lhs; +} + +#undef ALIGN_CHECK_ISPOSITIVE +#undef ALIGN_CHECK_ISSET + +} // namespace llvm + +#endif // LLVM_SUPPORT_ALIGNMENT_H_ diff --git a/include/llvm/Support/Allocator.h b/include/llvm/Support/Allocator.h index 09e967b98abc..106b90c35bf5 100644 --- a/include/llvm/Support/Allocator.h +++ b/include/llvm/Support/Allocator.h @@ -22,6 +22,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Alignment.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -211,13 +212,11 @@ public: /// Allocate space at the specified alignment. LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void * - Allocate(size_t Size, size_t Alignment) { - assert(Alignment > 0 && "0-byte alignnment is not allowed. Use 1 instead."); - + Allocate(size_t Size, Align Alignment) { // Keep track of how many bytes we've allocated. BytesAllocated += Size; - size_t Adjustment = alignmentAdjustment(CurPtr, Alignment); + size_t Adjustment = offsetToAlignedAddr(CurPtr, Alignment); assert(Adjustment + Size >= Size && "Adjustment + Size must not overflow"); size_t SizeToAllocate = Size; @@ -240,7 +239,7 @@ public: } // If Size is really big, allocate a separate slab for it. - size_t PaddedSize = SizeToAllocate + Alignment - 1; + size_t PaddedSize = SizeToAllocate + Alignment.value() - 1; if (PaddedSize > SizeThreshold) { void *NewSlab = Allocator.Allocate(PaddedSize, 0); // We own the new slab and don't want anyone reading anyting other than @@ -268,6 +267,12 @@ public: return AlignedPtr; } + inline LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void * + Allocate(size_t Size, size_t Alignment) { + assert(Alignment > 0 && "0-byte alignnment is not allowed. Use 1 instead."); + return Allocate(Size, Align(Alignment)); + } + // Pull in base class overloads. using AllocatorBase<BumpPtrAllocatorImpl>::Allocate; @@ -461,7 +466,7 @@ public: /// all memory allocated so far. void DestroyAll() { auto DestroyElements = [](char *Begin, char *End) { - assert(Begin == (char *)alignAddr(Begin, alignof(T))); + assert(Begin == (char *)alignAddr(Begin, Align::Of<T>())); for (char *Ptr = Begin; Ptr + sizeof(T) <= End; Ptr += sizeof(T)) reinterpret_cast<T *>(Ptr)->~T(); }; @@ -470,7 +475,7 @@ public: ++I) { size_t AllocatedSlabSize = BumpPtrAllocator::computeSlabSize( std::distance(Allocator.Slabs.begin(), I)); - char *Begin = (char *)alignAddr(*I, alignof(T)); + char *Begin = (char *)alignAddr(*I, Align::Of<T>()); char *End = *I == Allocator.Slabs.back() ? Allocator.CurPtr : (char *)*I + AllocatedSlabSize; @@ -480,7 +485,8 @@ public: for (auto &PtrAndSize : Allocator.CustomSizedSlabs) { void *Ptr = PtrAndSize.first; size_t Size = PtrAndSize.second; - DestroyElements((char *)alignAddr(Ptr, alignof(T)), (char *)Ptr + Size); + DestroyElements((char *)alignAddr(Ptr, Align::Of<T>()), + (char *)Ptr + Size); } Allocator.Reset(); diff --git a/include/llvm/Support/Automaton.h b/include/llvm/Support/Automaton.h new file mode 100644 index 000000000000..7c13a698e492 --- /dev/null +++ b/include/llvm/Support/Automaton.h @@ -0,0 +1,253 @@ +//===-- Automaton.h - Support for driving TableGen-produced DFAs ----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements class that drive and introspect deterministic finite- +// state automata (DFAs) as generated by TableGen's -gen-automata backend. +// +// For a description of how to define an automaton, see +// include/llvm/TableGen/Automaton.td. +// +// One important detail is that these deterministic automata are created from +// (potentially) nondeterministic definitions. Therefore a unique sequence of +// input symbols will produce one path through the DFA but multiple paths +// through the original NFA. An automaton by default only returns "accepted" or +// "not accepted", but frequently we want to analyze what NFA path was taken. +// Finding a path through the NFA states that results in a DFA state can help +// answer *what* the solution to a problem was, not just that there exists a +// solution. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_AUTOMATON_H +#define LLVM_SUPPORT_AUTOMATON_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Allocator.h" +#include <deque> +#include <map> +#include <memory> +#include <unordered_map> +#include <vector> + +namespace llvm { + +using NfaPath = SmallVector<uint64_t, 4>; + +/// Forward define the pair type used by the automata transition info tables. +/// +/// Experimental results with large tables have shown a significant (multiple +/// orders of magnitude) parsing speedup by using a custom struct here with a +/// trivial constructor rather than std::pair<uint64_t, uint64_t>. +struct NfaStatePair { + uint64_t FromDfaState, ToDfaState; + + bool operator<(const NfaStatePair &Other) const { + return std::make_tuple(FromDfaState, ToDfaState) < + std::make_tuple(Other.FromDfaState, Other.ToDfaState); + } +}; + +namespace internal { +/// The internal class that maintains all possible paths through an NFA based +/// on a path through the DFA. +class NfaTranscriber { +private: + /// Cached transition table. This is a table of NfaStatePairs that contains + /// zero-terminated sequences pointed to by DFA transitions. + ArrayRef<NfaStatePair> TransitionInfo; + + /// A simple linked-list of traversed states that can have a shared tail. The + /// traversed path is stored in reverse order with the latest state as the + /// head. + struct PathSegment { + uint64_t State; + PathSegment *Tail; + }; + + /// We allocate segment objects frequently. Allocate them upfront and dispose + /// at the end of a traversal rather than hammering the system allocator. + SpecificBumpPtrAllocator<PathSegment> Allocator; + + /// Heads of each tracked path. These are not ordered. + std::deque<PathSegment *> Heads; + + /// The returned paths. This is populated during getPaths. + SmallVector<NfaPath, 4> Paths; + + /// Create a new segment and return it. + PathSegment *makePathSegment(uint64_t State, PathSegment *Tail) { + PathSegment *P = Allocator.Allocate(); + *P = {State, Tail}; + return P; + } + + /// Pairs defines a sequence of possible NFA transitions for a single DFA + /// transition. + void transition(ArrayRef<NfaStatePair> Pairs) { + // Iterate over all existing heads. We will mutate the Heads deque during + // iteration. + unsigned NumHeads = Heads.size(); + for (unsigned I = 0; I < NumHeads; ++I) { + PathSegment *Head = Heads[I]; + // The sequence of pairs is sorted. Select the set of pairs that + // transition from the current head state. + auto PI = lower_bound(Pairs, NfaStatePair{Head->State, 0ULL}); + auto PE = upper_bound(Pairs, NfaStatePair{Head->State, INT64_MAX}); + // For every transition from the current head state, add a new path + // segment. + for (; PI != PE; ++PI) + if (PI->FromDfaState == Head->State) + Heads.push_back(makePathSegment(PI->ToDfaState, Head)); + } + // Now we've iterated over all the initial heads and added new ones, + // dispose of the original heads. + Heads.erase(Heads.begin(), std::next(Heads.begin(), NumHeads)); + } + +public: + NfaTranscriber(ArrayRef<NfaStatePair> TransitionInfo) + : TransitionInfo(TransitionInfo) { + reset(); + } + + void reset() { + Paths.clear(); + Heads.clear(); + Allocator.DestroyAll(); + // The initial NFA state is 0. + Heads.push_back(makePathSegment(0ULL, nullptr)); + } + + void transition(unsigned TransitionInfoIdx) { + unsigned EndIdx = TransitionInfoIdx; + while (TransitionInfo[EndIdx].ToDfaState != 0) + ++EndIdx; + ArrayRef<NfaStatePair> Pairs(&TransitionInfo[TransitionInfoIdx], + EndIdx - TransitionInfoIdx); + transition(Pairs); + } + + ArrayRef<NfaPath> getPaths() { + Paths.clear(); + for (auto *Head : Heads) { + NfaPath P; + while (Head->State != 0) { + P.push_back(Head->State); + Head = Head->Tail; + } + std::reverse(P.begin(), P.end()); + Paths.push_back(std::move(P)); + } + return Paths; + } +}; +} // namespace internal + +/// A deterministic finite-state automaton. The automaton is defined in +/// TableGen; this object drives an automaton defined by tblgen-emitted tables. +/// +/// An automaton accepts a sequence of input tokens ("actions"). This class is +/// templated on the type of these actions. +template <typename ActionT> class Automaton { + /// Map from {State, Action} to {NewState, TransitionInfoIdx}. + /// TransitionInfoIdx is used by the DfaTranscriber to analyze the transition. + /// FIXME: This uses a std::map because ActionT can be a pair type including + /// an enum. In particular DenseMapInfo<ActionT> must be defined to use + /// DenseMap here. + /// This is a shared_ptr to allow very quick copy-construction of Automata; this + /// state is immutable after construction so this is safe. + using MapTy = std::map<std::pair<uint64_t, ActionT>, std::pair<uint64_t, unsigned>>; + std::shared_ptr<MapTy> M; + /// An optional transcription object. This uses much more state than simply + /// traversing the DFA for acceptance, so is heap allocated. + std::shared_ptr<internal::NfaTranscriber> Transcriber; + /// The initial DFA state is 1. + uint64_t State = 1; + /// True if we should transcribe and false if not (even if Transcriber is defined). + bool Transcribe; + +public: + /// Create an automaton. + /// \param Transitions The Transitions table as created by TableGen. Note that + /// because the action type differs per automaton, the + /// table type is templated as ArrayRef<InfoT>. + /// \param TranscriptionTable The TransitionInfo table as created by TableGen. + /// + /// Providing the TranscriptionTable argument as non-empty will enable the + /// use of transcription, which analyzes the possible paths in the original + /// NFA taken by the DFA. NOTE: This is substantially more work than simply + /// driving the DFA, so unless you require the getPaths() method leave this + /// empty. + template <typename InfoT> + Automaton(ArrayRef<InfoT> Transitions, + ArrayRef<NfaStatePair> TranscriptionTable = {}) { + if (!TranscriptionTable.empty()) + Transcriber = + std::make_shared<internal::NfaTranscriber>(TranscriptionTable); + Transcribe = Transcriber != nullptr; + M = std::make_shared<MapTy>(); + for (const auto &I : Transitions) + // Greedily read and cache the transition table. + M->emplace(std::make_pair(I.FromDfaState, I.Action), + std::make_pair(I.ToDfaState, I.InfoIdx)); + } + Automaton(const Automaton &) = default; + + /// Reset the automaton to its initial state. + void reset() { + State = 1; + if (Transcriber) + Transcriber->reset(); + } + + /// Enable or disable transcription. Transcription is only available if + /// TranscriptionTable was provided to the constructor. + void enableTranscription(bool Enable = true) { + assert(Transcriber && + "Transcription is only available if TranscriptionTable was provided " + "to the Automaton constructor"); + Transcribe = Enable; + } + + /// Transition the automaton based on input symbol A. Return true if the + /// automaton transitioned to a valid state, false if the automaton + /// transitioned to an invalid state. + /// + /// If this function returns false, all methods are undefined until reset() is + /// called. + bool add(const ActionT &A) { + auto I = M->find({State, A}); + if (I == M->end()) + return false; + if (Transcriber && Transcribe) + Transcriber->transition(I->second.second); + State = I->second.first; + return true; + } + + /// Return true if the automaton can be transitioned based on input symbol A. + bool canAdd(const ActionT &A) { + auto I = M->find({State, A}); + return I != M->end(); + } + + /// Obtain a set of possible paths through the input nondeterministic + /// automaton that could be obtained from the sequence of input actions + /// presented to this deterministic automaton. + ArrayRef<NfaPath> getNfaPaths() { + assert(Transcriber && Transcribe && + "Can only obtain NFA paths if transcribing!"); + return Transcriber->getPaths(); + } +}; + +} // namespace llvm + +#endif // LLVM_SUPPORT_AUTOMATON_H diff --git a/include/llvm/Support/BinaryStreamArray.h b/include/llvm/Support/BinaryStreamArray.h index 96d09db69ae5..67ba2e4189be 100644 --- a/include/llvm/Support/BinaryStreamArray.h +++ b/include/llvm/Support/BinaryStreamArray.h @@ -286,7 +286,7 @@ public: // an exact multiple of the element size. consumeError(std::move(EC)); } - assert(llvm::alignmentAdjustment(Data.data(), alignof(T)) == 0); + assert(isAddrAligned(Align::Of<T>(), Data.data())); return *reinterpret_cast<const T *>(Data.data()); } diff --git a/include/llvm/Support/BinaryStreamReader.h b/include/llvm/Support/BinaryStreamReader.h index d8fddde66bfa..9e16ce227ff8 100644 --- a/include/llvm/Support/BinaryStreamReader.h +++ b/include/llvm/Support/BinaryStreamReader.h @@ -198,7 +198,7 @@ public: if (auto EC = readBytes(Bytes, NumElements * sizeof(T))) return EC; - assert(alignmentAdjustment(Bytes.data(), alignof(T)) == 0 && + assert(isAddrAligned(Align::Of<T>(), Bytes.data()) && "Reading at invalid alignment!"); Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements); diff --git a/include/llvm/Support/CRC.h b/include/llvm/Support/CRC.h index 6ea8e3edcea4..210890ae06d4 100644 --- a/include/llvm/Support/CRC.h +++ b/include/llvm/Support/CRC.h @@ -6,20 +6,55 @@ // //===----------------------------------------------------------------------===// // -// This file contains basic functions for calculating Cyclic Redundancy Check -// or CRC. +// This file contains implementations of CRC functions. // //===----------------------------------------------------------------------===// #ifndef LLVM_SUPPORT_CRC_H #define LLVM_SUPPORT_CRC_H -#include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" namespace llvm { -/// zlib independent CRC32 calculation. -uint32_t crc32(uint32_t CRC, StringRef S); +template <typename T> class ArrayRef; + +// Compute the CRC-32 of Data. +uint32_t crc32(ArrayRef<uint8_t> Data); + +// Compute the running CRC-32 of Data, with CRC being the previous value of the +// checksum. +uint32_t crc32(uint32_t CRC, ArrayRef<uint8_t> Data); + +// Class for computing the JamCRC. +// +// We will use the "Rocksoft^tm Model CRC Algorithm" to describe the properties +// of this CRC: +// Width : 32 +// Poly : 04C11DB7 +// Init : FFFFFFFF +// RefIn : True +// RefOut : True +// XorOut : 00000000 +// Check : 340BC6D9 (result of CRC for "123456789") +// +// In other words, this is the same as CRC-32, except that XorOut is 0 instead +// of FFFFFFFF. +// +// N.B. We permit flexibility of the "Init" value. Some consumers of this need +// it to be zero. +class JamCRC { +public: + JamCRC(uint32_t Init = 0xFFFFFFFFU) : CRC(Init) {} + + // Update the CRC calculation with Data. + void update(ArrayRef<uint8_t> Data); + + uint32_t getCRC() const { return CRC; } + +private: + uint32_t CRC; +}; + } // end namespace llvm #endif diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h index 3cc2c3c0121b..63784463e171 100644 --- a/include/llvm/Support/CommandLine.h +++ b/include/llvm/Support/CommandLine.h @@ -2000,6 +2000,9 @@ void ResetAllOptionOccurrences(); /// where no options are supported. void ResetCommandLineParser(); +/// Parses `Arg` into the option handler `Handler`. +bool ProvidePositionalOption(Option *Handler, StringRef Arg, int i); + } // end namespace cl } // end namespace llvm diff --git a/include/llvm/Support/Compiler.h b/include/llvm/Support/Compiler.h index 3f4f465f3960..cb7e57d4cd21 100644 --- a/include/llvm/Support/Compiler.h +++ b/include/llvm/Support/Compiler.h @@ -7,7 +7,8 @@ //===----------------------------------------------------------------------===// // // This file defines several macros, based on the current compiler. This allows -// use of compiler-specific features in a way that remains portable. +// use of compiler-specific features in a way that remains portable. This header +// can be included from either C or C++. // //===----------------------------------------------------------------------===// @@ -16,7 +17,9 @@ #include "llvm/Config/llvm-config.h" +#ifdef __cplusplus #include <new> +#endif #include <stddef.h> #if defined(_MSC_VER) @@ -35,14 +38,20 @@ # define __has_attribute(x) 0 #endif -#ifndef __has_cpp_attribute -# define __has_cpp_attribute(x) 0 -#endif - #ifndef __has_builtin # define __has_builtin(x) 0 #endif +// Only use __has_cpp_attribute in C++ mode. GCC defines __has_cpp_attribute in +// C mode, but the :: in __has_cpp_attribute(scoped::attribute) is invalid. +#ifndef LLVM_HAS_CPP_ATTRIBUTE +#if defined(__cplusplus) && defined(__has_cpp_attribute) +# define LLVM_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define LLVM_HAS_CPP_ATTRIBUTE(x) 0 +#endif +#endif + /// \macro LLVM_GNUC_PREREQ /// Extend the default __GNUC_PREREQ even if glibc's features.h isn't /// available. @@ -62,13 +71,21 @@ /// \macro LLVM_MSC_PREREQ /// Is the compiler MSVC of at least the specified version? /// The common \param version values to check for are: -/// * 1900: Microsoft Visual Studio 2015 / 14.0 +/// * 1910: VS2017, version 15.1 & 15.2 +/// * 1911: VS2017, version 15.3 & 15.4 +/// * 1912: VS2017, version 15.5 +/// * 1913: VS2017, version 15.6 +/// * 1914: VS2017, version 15.7 +/// * 1915: VS2017, version 15.8 +/// * 1916: VS2017, version 15.9 +/// * 1920: VS2019, version 16.0 +/// * 1921: VS2019, version 16.1 #ifdef _MSC_VER #define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version)) -// We require at least MSVC 2015. -#if !LLVM_MSC_PREREQ(1900) -#error LLVM requires at least MSVC 2015. +// We require at least MSVC 2017. +#if !LLVM_MSC_PREREQ(1910) +#error LLVM requires at least MSVC 2017. #endif #else @@ -120,14 +137,18 @@ #endif /// LLVM_NODISCARD - Warn if a type or return value is discarded. -#if __cplusplus > 201402L && __has_cpp_attribute(nodiscard) + +// Use the 'nodiscard' attribute in C++17 or newer mode. +#if __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(nodiscard) #define LLVM_NODISCARD [[nodiscard]] -#elif !__cplusplus -// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious -// error when __has_cpp_attribute is given a scoped attribute in C mode. -#define LLVM_NODISCARD -#elif __has_cpp_attribute(clang::warn_unused_result) +#elif LLVM_HAS_CPP_ATTRIBUTE(clang::warn_unused_result) #define LLVM_NODISCARD [[clang::warn_unused_result]] +// Clang in C++14 mode claims that it has the 'nodiscard' attribute, but also +// warns in the pedantic mode that 'nodiscard' is a C++17 extension (PR33518). +// Use the 'nodiscard' attribute in C++14 mode only with GCC. +// TODO: remove this workaround when PR33518 is resolved. +#elif defined(__GNUC__) && LLVM_HAS_CPP_ATTRIBUTE(nodiscard) +#define LLVM_NODISCARD [[nodiscard]] #else #define LLVM_NODISCARD #endif @@ -139,7 +160,7 @@ // The clang-tidy check bugprone-use-after-move recognizes this attribute as a // marker that a moved-from object has left the indeterminate state and can be // reused. -#if __has_cpp_attribute(clang::reinitializes) +#if LLVM_HAS_CPP_ATTRIBUTE(clang::reinitializes) #define LLVM_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]] #else #define LLVM_ATTRIBUTE_REINITIALIZES @@ -240,15 +261,13 @@ #endif /// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements. -#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough) +#if __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(fallthrough) #define LLVM_FALLTHROUGH [[fallthrough]] -#elif __has_cpp_attribute(gnu::fallthrough) +#elif LLVM_HAS_CPP_ATTRIBUTE(gnu::fallthrough) #define LLVM_FALLTHROUGH [[gnu::fallthrough]] -#elif !__cplusplus -// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious -// error when __has_cpp_attribute is given a scoped attribute in C mode. -#define LLVM_FALLTHROUGH -#elif __has_cpp_attribute(clang::fallthrough) +#elif __has_attribute(fallthrough) +#define LLVM_FALLTHROUGH __attribute__((fallthrough)) +#elif LLVM_HAS_CPP_ATTRIBUTE(clang::fallthrough) #define LLVM_FALLTHROUGH [[clang::fallthrough]] #else #define LLVM_FALLTHROUGH @@ -256,7 +275,7 @@ /// LLVM_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that /// they are constant initialized. -#if __has_cpp_attribute(clang::require_constant_initialization) +#if LLVM_HAS_CPP_ATTRIBUTE(clang::require_constant_initialization) #define LLVM_REQUIRE_CONSTANT_INITIALIZATION \ [[clang::require_constant_initialization]] #else @@ -338,14 +357,6 @@ # define LLVM_ASSUME_ALIGNED(p, a) (p) #endif -/// \macro LLVM_ALIGNAS -/// Used to specify a minimum alignment for a structure or variable. -#if __GNUC__ && !__has_feature(cxx_alignas) && !LLVM_GNUC_PREREQ(4, 8, 1) -# define LLVM_ALIGNAS(x) __attribute__((aligned(x))) -#else -# define LLVM_ALIGNAS(x) alignas(x) -#endif - /// \macro LLVM_PACKED /// Used to specify a packed structure. /// LLVM_PACKED( @@ -376,8 +387,8 @@ /// \macro LLVM_PTR_SIZE /// A constant integer equivalent to the value of sizeof(void*). -/// Generally used in combination with LLVM_ALIGNAS or when doing computation in -/// the preprocessor. +/// Generally used in combination with alignas or when doing computation in the +/// preprocessor. #ifdef __SIZEOF_POINTER__ # define LLVM_PTR_SIZE __SIZEOF_POINTER__ #elif defined(_WIN64) @@ -527,6 +538,7 @@ void AnnotateIgnoreWritesEnd(const char *file, int line); #define LLVM_ENABLE_EXCEPTIONS 1 #endif +#ifdef __cplusplus namespace llvm { /// Allocate a buffer of memory with the given size and alignment. @@ -569,4 +581,5 @@ inline void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment) { } // End namespace llvm +#endif // __cplusplus #endif diff --git a/include/llvm/Support/DataExtractor.h b/include/llvm/Support/DataExtractor.h index 6b08a2a2a445..f590a1e104fb 100644 --- a/include/llvm/Support/DataExtractor.h +++ b/include/llvm/Support/DataExtractor.h @@ -11,6 +11,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/Error.h" namespace llvm { @@ -42,6 +43,38 @@ class DataExtractor { uint8_t IsLittleEndian; uint8_t AddressSize; public: + /// A class representing a position in a DataExtractor, as well as any error + /// encountered during extraction. It enables one to extract a sequence of + /// values without error-checking and then checking for errors in bulk at the + /// end. The class holds an Error object, so failing to check the result of + /// the parse will result in a runtime error. The error flag is sticky and + /// will cause all subsequent extraction functions to fail without even + /// attempting to parse and without updating the Cursor offset. After clearing + /// the error flag, one can again use the Cursor object for parsing. + class Cursor { + uint64_t Offset; + Error Err; + + friend class DataExtractor; + + public: + /// Construct a cursor for extraction from the given offset. + explicit Cursor(uint64_t Offset) : Offset(Offset), Err(Error::success()) {} + + /// Checks whether the cursor is valid (i.e. no errors were encountered). In + /// case of errors, this does not clear the error flag -- one must call + /// takeError() instead. + explicit operator bool() { return !Err; } + + /// Return the current position of this Cursor. In the error state this is + /// the position of the Cursor before the first error was encountered. + uint64_t tell() const { return Offset; } + + /// Return error contained inside this Cursor, if any. Clears the internal + /// Cursor state. + Error takeError() { return std::move(Err); } + }; + /// Construct with a buffer that is owned by the caller. /// /// This constructor allows us to use data that is owned by the @@ -49,6 +82,11 @@ public: /// valid. DataExtractor(StringRef Data, bool IsLittleEndian, uint8_t AddressSize) : Data(Data), IsLittleEndian(IsLittleEndian), AddressSize(AddressSize) {} + DataExtractor(ArrayRef<uint8_t> Data, bool IsLittleEndian, + uint8_t AddressSize) + : Data(StringRef(reinterpret_cast<const char *>(Data.data()), + Data.size())), + IsLittleEndian(IsLittleEndian), AddressSize(AddressSize) {} /// Get the data pointed to by this extractor. StringRef getData() const { return Data; } @@ -79,17 +117,17 @@ public: /// pointed to by \a offset_ptr is out of bounds, or if the /// offset plus the length of the C string is out of bounds, /// NULL will be returned. - const char *getCStr(uint32_t *offset_ptr) const; + const char *getCStr(uint64_t *offset_ptr) const; - /// Extract a C string from \a *OffsetPtr. + /// Extract a C string from \a *offset_ptr. /// /// Returns a StringRef for the C String from the data at the offset - /// pointed to by \a OffsetPtr. A variable length NULL terminated C - /// string will be extracted and the \a OffsetPtr will be + /// pointed to by \a offset_ptr. A variable length NULL terminated C + /// string will be extracted and the \a offset_ptr will be /// updated with the offset of the byte that follows the NULL /// terminator byte. /// - /// \param[in,out] OffsetPtr + /// \param[in,out] offset_ptr /// A pointer to an offset within the data that will be advanced /// by the appropriate number of bytes if the value is extracted /// correctly. If the offset is out of bounds or there are not @@ -98,10 +136,10 @@ public: /// /// \return /// A StringRef for the C string value in the data. If the offset - /// pointed to by \a OffsetPtr is out of bounds, or if the + /// pointed to by \a offset_ptr is out of bounds, or if the /// offset plus the length of the C string is out of bounds, /// a default-initialized StringRef will be returned. - StringRef getCStrRef(uint32_t *OffsetPtr) const; + StringRef getCStrRef(uint64_t *offset_ptr) const; /// Extract an unsigned integer of size \a byte_size from \a /// *offset_ptr. @@ -124,10 +162,24 @@ public: /// @param[in] byte_size /// The size in byte of the integer to extract. /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// /// @return /// The unsigned integer value that was extracted, or zero on /// failure. - uint64_t getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const; + uint64_t getUnsigned(uint64_t *offset_ptr, uint32_t byte_size, + Error *Err = nullptr) const; + + /// Extract an unsigned integer of the given size from the location given by + /// the cursor. In case of an extraction error, or if the cursor is already in + /// an error state, zero is returned. + uint64_t getUnsigned(Cursor &C, uint32_t Size) const { + return getUnsigned(&C.Offset, Size, &C.Err); + } /// Extract an signed integer of size \a byte_size from \a *offset_ptr. /// @@ -152,7 +204,7 @@ public: /// @return /// The sign extended signed integer value that was extracted, /// or zero on failure. - int64_t getSigned(uint32_t *offset_ptr, uint32_t size) const; + int64_t getSigned(uint64_t *offset_ptr, uint32_t size) const; //------------------------------------------------------------------ /// Extract an pointer from \a *offset_ptr. @@ -171,10 +223,15 @@ public: /// /// @return /// The extracted pointer value as a 64 integer. - uint64_t getAddress(uint32_t *offset_ptr) const { + uint64_t getAddress(uint64_t *offset_ptr) const { return getUnsigned(offset_ptr, AddressSize); } + /// Extract a pointer-sized unsigned integer from the location given by the + /// cursor. In case of an extraction error, or if the cursor is already in + /// an error state, zero is returned. + uint64_t getAddress(Cursor &C) const { return getUnsigned(C, AddressSize); } + /// Extract a uint8_t value from \a *offset_ptr. /// /// Extract a single uint8_t from the binary data at the offset @@ -187,9 +244,20 @@ public: /// enough bytes to extract this value, the offset will be left /// unmodified. /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// /// @return /// The extracted uint8_t value. - uint8_t getU8(uint32_t *offset_ptr) const; + uint8_t getU8(uint64_t *offset_ptr, Error *Err = nullptr) const; + + /// Extract a single uint8_t value from the location given by the cursor. In + /// case of an extraction error, or if the cursor is already in an error + /// state, zero is returned. + uint8_t getU8(Cursor &C) const { return getU8(&C.Offset, &C.Err); } /// Extract \a count uint8_t values from \a *offset_ptr. /// @@ -214,7 +282,27 @@ public: /// @return /// \a dst if all values were properly extracted and copied, /// NULL otherise. - uint8_t *getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const; + uint8_t *getU8(uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const; + + /// Extract \a Count uint8_t values from the location given by the cursor and + /// store them into the destination buffer. In case of an extraction error, or + /// if the cursor is already in an error state, a nullptr is returned and the + /// destination buffer is left unchanged. + uint8_t *getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const; + + /// Extract \a Count uint8_t values from the location given by the cursor and + /// store them into the destination vector. The vector is resized to fit the + /// extracted data. In case of an extraction error, or if the cursor is + /// already in an error state, the destination vector is left unchanged and + /// cursor is placed into an error state. + void getU8(Cursor &C, SmallVectorImpl<uint8_t> &Dst, uint32_t Count) const { + if (isValidOffsetForDataOfSize(C.Offset, Count)) + Dst.resize(Count); + + // This relies on the fact that getU8 will not attempt to write to the + // buffer if isValidOffsetForDataOfSize(C.Offset, Count) is false. + getU8(C, Dst.data(), Count); + } //------------------------------------------------------------------ /// Extract a uint16_t value from \a *offset_ptr. @@ -229,10 +317,21 @@ public: /// enough bytes to extract this value, the offset will be left /// unmodified. /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// /// @return /// The extracted uint16_t value. //------------------------------------------------------------------ - uint16_t getU16(uint32_t *offset_ptr) const; + uint16_t getU16(uint64_t *offset_ptr, Error *Err = nullptr) const; + + /// Extract a single uint16_t value from the location given by the cursor. In + /// case of an extraction error, or if the cursor is already in an error + /// state, zero is returned. + uint16_t getU16(Cursor &C) const { return getU16(&C.Offset, &C.Err); } /// Extract \a count uint16_t values from \a *offset_ptr. /// @@ -257,7 +356,7 @@ public: /// @return /// \a dst if all values were properly extracted and copied, /// NULL otherise. - uint16_t *getU16(uint32_t *offset_ptr, uint16_t *dst, uint32_t count) const; + uint16_t *getU16(uint64_t *offset_ptr, uint16_t *dst, uint32_t count) const; /// Extract a 24-bit unsigned value from \a *offset_ptr and return it /// in a uint32_t. @@ -274,7 +373,7 @@ public: /// /// @return /// The extracted 24-bit value represented in a uint32_t. - uint32_t getU24(uint32_t *offset_ptr) const; + uint32_t getU24(uint64_t *offset_ptr) const; /// Extract a uint32_t value from \a *offset_ptr. /// @@ -288,9 +387,20 @@ public: /// enough bytes to extract this value, the offset will be left /// unmodified. /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// /// @return /// The extracted uint32_t value. - uint32_t getU32(uint32_t *offset_ptr) const; + uint32_t getU32(uint64_t *offset_ptr, Error *Err = nullptr) const; + + /// Extract a single uint32_t value from the location given by the cursor. In + /// case of an extraction error, or if the cursor is already in an error + /// state, zero is returned. + uint32_t getU32(Cursor &C) const { return getU32(&C.Offset, &C.Err); } /// Extract \a count uint32_t values from \a *offset_ptr. /// @@ -315,7 +425,7 @@ public: /// @return /// \a dst if all values were properly extracted and copied, /// NULL otherise. - uint32_t *getU32(uint32_t *offset_ptr, uint32_t *dst, uint32_t count) const; + uint32_t *getU32(uint64_t *offset_ptr, uint32_t *dst, uint32_t count) const; /// Extract a uint64_t value from \a *offset_ptr. /// @@ -329,9 +439,20 @@ public: /// enough bytes to extract this value, the offset will be left /// unmodified. /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// /// @return /// The extracted uint64_t value. - uint64_t getU64(uint32_t *offset_ptr) const; + uint64_t getU64(uint64_t *offset_ptr, Error *Err = nullptr) const; + + /// Extract a single uint64_t value from the location given by the cursor. In + /// case of an extraction error, or if the cursor is already in an error + /// state, zero is returned. + uint64_t getU64(Cursor &C) const { return getU64(&C.Offset, &C.Err); } /// Extract \a count uint64_t values from \a *offset_ptr. /// @@ -356,7 +477,7 @@ public: /// @return /// \a dst if all values were properly extracted and copied, /// NULL otherise. - uint64_t *getU64(uint32_t *offset_ptr, uint64_t *dst, uint32_t count) const; + uint64_t *getU64(uint64_t *offset_ptr, uint64_t *dst, uint32_t count) const; /// Extract a signed LEB128 value from \a *offset_ptr. /// @@ -374,7 +495,7 @@ public: /// /// @return /// The extracted signed integer value. - int64_t getSLEB128(uint32_t *offset_ptr) const; + int64_t getSLEB128(uint64_t *offset_ptr) const; /// Extract a unsigned LEB128 value from \a *offset_ptr. /// @@ -390,23 +511,44 @@ public: /// enough bytes to extract this value, the offset will be left /// unmodified. /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// /// @return /// The extracted unsigned integer value. - uint64_t getULEB128(uint32_t *offset_ptr) const; + uint64_t getULEB128(uint64_t *offset_ptr, llvm::Error *Err = nullptr) const; + + /// Extract an unsigned ULEB128 value from the location given by the cursor. + /// In case of an extraction error, or if the cursor is already in an error + /// state, zero is returned. + uint64_t getULEB128(Cursor &C) const { return getULEB128(&C.Offset, &C.Err); } + + /// Advance the Cursor position by the given number of bytes. No-op if the + /// cursor is in an error state. + void skip(Cursor &C, uint64_t Length) const; + + /// Return true iff the cursor is at the end of the buffer, regardless of the + /// error state of the cursor. The only way both eof and error states can be + /// true is if one attempts a read while the cursor is at the very end of the + /// data buffer. + bool eof(const Cursor &C) const { return Data.size() == C.Offset; } /// Test the validity of \a offset. /// /// @return /// \b true if \a offset is a valid offset into the data in this /// object, \b false otherwise. - bool isValidOffset(uint32_t offset) const { return Data.size() > offset; } + bool isValidOffset(uint64_t offset) const { return Data.size() > offset; } /// Test the availability of \a length bytes of data from \a offset. /// /// @return /// \b true if \a offset is a valid offset and there are \a /// length bytes available at that offset, \b false otherwise. - bool isValidOffsetForDataOfSize(uint32_t offset, uint32_t length) const { + bool isValidOffsetForDataOfSize(uint64_t offset, uint64_t length) const { return offset + length >= offset && isValidOffset(offset + length - 1); } @@ -417,9 +559,15 @@ public: /// \b true if \a offset is a valid offset and there are enough /// bytes for a pointer available at that offset, \b false /// otherwise. - bool isValidOffsetForAddress(uint32_t offset) const { + bool isValidOffsetForAddress(uint64_t offset) const { return isValidOffsetForDataOfSize(offset, AddressSize); } + +protected: + // Make it possible for subclasses to access these fields without making them + // public. + static uint64_t &getOffset(Cursor &C) { return C.Offset; } + static Error &getError(Cursor &C) { return C.Err; } }; } // namespace llvm diff --git a/include/llvm/Support/Endian.h b/include/llvm/Support/Endian.h index d8be94427d7e..87aecedd3a4b 100644 --- a/include/llvm/Support/Endian.h +++ b/include/llvm/Support/Endian.h @@ -203,9 +203,8 @@ inline void writeAtBitAlignment(void *memory, value_type value, namespace detail { -template<typename ValueType, - endianness Endian, - std::size_t Alignment> +template <typename ValueType, endianness Endian, std::size_t Alignment, + std::size_t ALIGN = PickAlignment<ValueType, Alignment>::value> struct packed_endian_specific_integral { using value_type = ValueType; static constexpr endianness endian = Endian; @@ -246,8 +245,9 @@ struct packed_endian_specific_integral { } private: - AlignedCharArray<PickAlignment<value_type, alignment>::value, - sizeof(value_type)> Value; + struct { + alignas(ALIGN) char buffer[sizeof(value_type)]; + } Value; public: struct ref { diff --git a/include/llvm/Support/Error.h b/include/llvm/Support/Error.h index 299fce7a1368..350877a219bf 100644 --- a/include/llvm/Support/Error.h +++ b/include/llvm/Support/Error.h @@ -328,7 +328,7 @@ inline ErrorSuccess Error::success() { return ErrorSuccess(); } /// Make a Error instance representing failure using the given error info /// type. template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) { - return Error(llvm::make_unique<ErrT>(std::forward<ArgTs>(Args)...)); + return Error(std::make_unique<ErrT>(std::forward<ArgTs>(Args)...)); } /// Base class for user error types. Users should declare their error types @@ -548,7 +548,7 @@ public: /// Take ownership of the stored error. /// After calling this the Expected<T> is in an indeterminate state that can /// only be safely destructed. No further calls (beside the destructor) should - /// be made on the Expected<T> vaule. + /// be made on the Expected<T> value. Error takeError() { #if LLVM_ENABLE_ABI_BREAKING_CHECKS Unchecked = false; @@ -704,6 +704,12 @@ inline void cantFail(Error Err, const char *Msg = nullptr) { if (Err) { if (!Msg) Msg = "Failure value returned from cantFail wrapped call"; +#ifndef NDEBUG + std::string Str; + raw_string_ostream OS(Str); + OS << Msg << "\n" << Err; + Msg = OS.str().c_str(); +#endif llvm_unreachable(Msg); } } @@ -728,6 +734,13 @@ T cantFail(Expected<T> ValOrErr, const char *Msg = nullptr) { else { if (!Msg) Msg = "Failure value returned from cantFail wrapped call"; +#ifndef NDEBUG + std::string Str; + raw_string_ostream OS(Str); + auto E = ValOrErr.takeError(); + OS << Msg << "\n" << E; + Msg = OS.str().c_str(); +#endif llvm_unreachable(Msg); } } @@ -752,6 +765,13 @@ T& cantFail(Expected<T&> ValOrErr, const char *Msg = nullptr) { else { if (!Msg) Msg = "Failure value returned from cantFail wrapped call"; +#ifndef NDEBUG + std::string Str; + raw_string_ostream OS(Str); + auto E = ValOrErr.takeError(); + OS << Msg << "\n" << E; + Msg = OS.str().c_str(); +#endif llvm_unreachable(Msg); } } @@ -982,6 +1002,20 @@ inline void consumeError(Error Err) { handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {}); } +/// Convert an Expected to an Optional without doing anything. This method +/// should be used only where an error can be considered a reasonable and +/// expected return value. +/// +/// Uses of this method are potentially indicative of problems: perhaps the +/// error should be propagated further, or the error-producer should just +/// return an Optional in the first place. +template <typename T> Optional<T> expectedToOptional(Expected<T> &&E) { + if (E) + return std::move(*E); + consumeError(E.takeError()); + return None; +} + /// Helper for converting an Error to a bool. /// /// This method returns true if Err is in an error state, or false if it is @@ -1170,6 +1204,10 @@ inline Error createStringError(std::error_code EC, char const *Fmt, Error createStringError(std::error_code EC, char const *Msg); +inline Error createStringError(std::error_code EC, const Twine &S) { + return createStringError(EC, S.str().c_str()); +} + template <typename... Ts> inline Error createStringError(std::errc EC, char const *Fmt, const Ts &... Vals) { diff --git a/include/llvm/Support/FileCheck.h b/include/llvm/Support/FileCheck.h index 0cd25a71a3b3..2547449246a8 100644 --- a/include/llvm/Support/FileCheck.h +++ b/include/llvm/Support/FileCheck.h @@ -13,12 +13,12 @@ #ifndef LLVM_SUPPORT_FILECHECK_H #define LLVM_SUPPORT_FILECHECK_H -#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Regex.h" #include "llvm/Support/SourceMgr.h" +#include <string> #include <vector> -#include <map> namespace llvm { @@ -30,6 +30,7 @@ struct FileCheckRequest { std::vector<std::string> GlobalDefines; bool AllowEmptyInput = false; bool MatchFullLines = false; + bool IgnoreCase = false; bool EnableVarScope = false; bool AllowDeprecatedDagOverlap = false; bool Verbose = false; @@ -37,217 +38,7 @@ struct FileCheckRequest { }; //===----------------------------------------------------------------------===// -// Numeric substitution handling code. -//===----------------------------------------------------------------------===// - -/// Base class representing the AST of a given expression. -class FileCheckExpressionAST { -public: - virtual ~FileCheckExpressionAST() = default; - - /// Evaluates and \returns the value of the expression represented by this - /// AST or an error if evaluation fails. - virtual Expected<uint64_t> eval() const = 0; -}; - -/// Class representing an unsigned literal in the AST of an expression. -class FileCheckExpressionLiteral : public FileCheckExpressionAST { -private: - /// Actual value of the literal. - uint64_t Value; - -public: - /// Constructs a literal with the specified value. - FileCheckExpressionLiteral(uint64_t Val) : Value(Val) {} - - /// \returns the literal's value. - Expected<uint64_t> eval() const { return Value; } -}; - -/// Class to represent an undefined variable error, which quotes that -/// variable's name when printed. -class FileCheckUndefVarError : public ErrorInfo<FileCheckUndefVarError> { -private: - StringRef VarName; - -public: - static char ID; - - FileCheckUndefVarError(StringRef VarName) : VarName(VarName) {} - - StringRef getVarName() const { return VarName; } - - std::error_code convertToErrorCode() const override { - return inconvertibleErrorCode(); - } - - /// Print name of variable associated with this error. - void log(raw_ostream &OS) const override { - OS << "\""; - OS.write_escaped(VarName) << "\""; - } -}; - -/// Class representing a numeric variable and its associated current value. -class FileCheckNumericVariable { -private: - /// Name of the numeric variable. - StringRef Name; - - /// Value of numeric variable, if defined, or None otherwise. - Optional<uint64_t> Value; - - /// Line number where this variable is defined, or None if defined before - /// input is parsed. Used to determine whether a variable is defined on the - /// same line as a given use. - Optional<size_t> DefLineNumber; - -public: - /// Constructor for a variable \p Name defined at line \p DefLineNumber or - /// defined before input is parsed if DefLineNumber is None. - FileCheckNumericVariable(StringRef Name, - Optional<size_t> DefLineNumber = None) - : Name(Name), DefLineNumber(DefLineNumber) {} - - /// \returns name of this numeric variable. - StringRef getName() const { return Name; } - - /// \returns this variable's value. - Optional<uint64_t> getValue() const { return Value; } - - /// Sets value of this numeric variable, if undefined. Triggers an assertion - /// failure if the variable is actually defined. - void setValue(uint64_t Value); - - /// Clears value of this numeric variable, regardless of whether it is - /// currently defined or not. - void clearValue(); - - /// \returns the line number where this variable is defined, if any, or None - /// if defined before input is parsed. - Optional<size_t> getDefLineNumber() { return DefLineNumber; } -}; - -/// Class representing the use of a numeric variable in the AST of an -/// expression. -class FileCheckNumericVariableUse : public FileCheckExpressionAST { -private: - /// Name of the numeric variable. - StringRef Name; - - /// Pointer to the class instance for the variable this use is about. - FileCheckNumericVariable *NumericVariable; - -public: - FileCheckNumericVariableUse(StringRef Name, - FileCheckNumericVariable *NumericVariable) - : Name(Name), NumericVariable(NumericVariable) {} - - /// \returns the value of the variable referenced by this instance. - Expected<uint64_t> eval() const; -}; - -/// Type of functions evaluating a given binary operation. -using binop_eval_t = uint64_t (*)(uint64_t, uint64_t); - -/// Class representing a single binary operation in the AST of an expression. -class FileCheckASTBinop : public FileCheckExpressionAST { -private: - /// Left operand. - std::unique_ptr<FileCheckExpressionAST> LeftOperand; - - /// Right operand. - std::unique_ptr<FileCheckExpressionAST> RightOperand; - - /// Pointer to function that can evaluate this binary operation. - binop_eval_t EvalBinop; - -public: - FileCheckASTBinop(binop_eval_t EvalBinop, - std::unique_ptr<FileCheckExpressionAST> LeftOp, - std::unique_ptr<FileCheckExpressionAST> RightOp) - : EvalBinop(EvalBinop) { - LeftOperand = std::move(LeftOp); - RightOperand = std::move(RightOp); - } - - /// Evaluates the value of the binary operation represented by this AST, - /// using EvalBinop on the result of recursively evaluating the operands. - /// \returns the expression value or an error if an undefined numeric - /// variable is used in one of the operands. - Expected<uint64_t> eval() const; -}; - -class FileCheckPatternContext; - -/// Class representing a substitution to perform in the RegExStr string. -class FileCheckSubstitution { -protected: - /// Pointer to a class instance holding, among other things, the table with - /// the values of live string variables at the start of any given CHECK line. - /// Used for substituting string variables with the text they were defined - /// as. Expressions are linked to the numeric variables they use at - /// parse time and directly access the value of the numeric variable to - /// evaluate their value. - FileCheckPatternContext *Context; - - /// The string that needs to be substituted for something else. For a - /// string variable this is its name, otherwise this is the whole expression. - StringRef FromStr; - - // Index in RegExStr of where to do the substitution. - size_t InsertIdx; - -public: - FileCheckSubstitution(FileCheckPatternContext *Context, StringRef VarName, - size_t InsertIdx) - : Context(Context), FromStr(VarName), InsertIdx(InsertIdx) {} - - virtual ~FileCheckSubstitution() = default; - - /// \returns the string to be substituted for something else. - StringRef getFromString() const { return FromStr; } - - /// \returns the index where the substitution is to be performed in RegExStr. - size_t getIndex() const { return InsertIdx; } - - /// \returns a string containing the result of the substitution represented - /// by this class instance or an error if substitution failed. - virtual Expected<std::string> getResult() const = 0; -}; - -class FileCheckStringSubstitution : public FileCheckSubstitution { -public: - FileCheckStringSubstitution(FileCheckPatternContext *Context, - StringRef VarName, size_t InsertIdx) - : FileCheckSubstitution(Context, VarName, InsertIdx) {} - - /// \returns the text that the string variable in this substitution matched - /// when defined, or an error if the variable is undefined. - Expected<std::string> getResult() const override; -}; - -class FileCheckNumericSubstitution : public FileCheckSubstitution { -private: - /// Pointer to the class representing the expression whose value is to be - /// substituted. - std::unique_ptr<FileCheckExpressionAST> ExpressionAST; - -public: - FileCheckNumericSubstitution(FileCheckPatternContext *Context, StringRef Expr, - std::unique_ptr<FileCheckExpressionAST> ExprAST, - size_t InsertIdx) - : FileCheckSubstitution(Context, Expr, InsertIdx) { - ExpressionAST = std::move(ExprAST); - } - - /// \returns a string containing the result of evaluating the expression in - /// this substitution, or an error if evaluation failed. - Expected<std::string> getResult() const override; -}; - -//===----------------------------------------------------------------------===// -// Pattern handling code. +// Summary of a FileCheck diagnostic. //===----------------------------------------------------------------------===// namespace Check { @@ -291,325 +82,6 @@ public: }; } // namespace Check -struct FileCheckDiag; - -/// Class holding the FileCheckPattern global state, shared by all patterns: -/// tables holding values of variables and whether they are defined or not at -/// any given time in the matching process. -class FileCheckPatternContext { - friend class FileCheckPattern; - -private: - /// When matching a given pattern, this holds the value of all the string - /// variables defined in previous patterns. In a pattern, only the last - /// definition for a given variable is recorded in this table. - /// Back-references are used for uses after any the other definition. - StringMap<StringRef> GlobalVariableTable; - - /// Map of all string variables defined so far. Used at parse time to detect - /// a name conflict between a numeric variable and a string variable when - /// the former is defined on a later line than the latter. - StringMap<bool> DefinedVariableTable; - - /// When matching a given pattern, this holds the pointers to the classes - /// representing the numeric variables defined in previous patterns. When - /// matching a pattern all definitions for that pattern are recorded in the - /// NumericVariableDefs table in the FileCheckPattern instance of that - /// pattern. - StringMap<FileCheckNumericVariable *> GlobalNumericVariableTable; - - /// Pointer to the class instance representing the @LINE pseudo variable for - /// easily updating its value. - FileCheckNumericVariable *LineVariable = nullptr; - - /// Vector holding pointers to all parsed numeric variables. Used to - /// automatically free them once they are guaranteed to no longer be used. - std::vector<std::unique_ptr<FileCheckNumericVariable>> NumericVariables; - - /// Vector holding pointers to all substitutions. Used to automatically free - /// them once they are guaranteed to no longer be used. - std::vector<std::unique_ptr<FileCheckSubstitution>> Substitutions; - -public: - /// \returns the value of string variable \p VarName or an error if no such - /// variable has been defined. - Expected<StringRef> getPatternVarValue(StringRef VarName); - - /// Defines string and numeric variables from definitions given on the - /// command line, passed as a vector of [#]VAR=VAL strings in - /// \p CmdlineDefines. \returns an error list containing diagnostics against - /// \p SM for all definition parsing failures, if any, or Success otherwise. - Error defineCmdlineVariables(std::vector<std::string> &CmdlineDefines, - SourceMgr &SM); - - /// Create @LINE pseudo variable. Value is set when pattern are being - /// matched. - void createLineVariable(); - - /// Undefines local variables (variables whose name does not start with a '$' - /// sign), i.e. removes them from GlobalVariableTable and from - /// GlobalNumericVariableTable and also clears the value of numeric - /// variables. - void clearLocalVars(); - -private: - /// Makes a new numeric variable and registers it for destruction when the - /// context is destroyed. - template <class... Types> - FileCheckNumericVariable *makeNumericVariable(Types... args); - - /// Makes a new string substitution and registers it for destruction when the - /// context is destroyed. - FileCheckSubstitution *makeStringSubstitution(StringRef VarName, - size_t InsertIdx); - - /// Makes a new numeric substitution and registers it for destruction when - /// the context is destroyed. - FileCheckSubstitution * - makeNumericSubstitution(StringRef ExpressionStr, - std::unique_ptr<FileCheckExpressionAST> ExpressionAST, - size_t InsertIdx); -}; - -/// Class to represent an error holding a diagnostic with location information -/// used when printing it. -class FileCheckErrorDiagnostic : public ErrorInfo<FileCheckErrorDiagnostic> { -private: - SMDiagnostic Diagnostic; - -public: - static char ID; - - FileCheckErrorDiagnostic(SMDiagnostic &&Diag) : Diagnostic(Diag) {} - - std::error_code convertToErrorCode() const override { - return inconvertibleErrorCode(); - } - - /// Print diagnostic associated with this error when printing the error. - void log(raw_ostream &OS) const override { Diagnostic.print(nullptr, OS); } - - static Error get(const SourceMgr &SM, SMLoc Loc, const Twine &ErrMsg) { - return make_error<FileCheckErrorDiagnostic>( - SM.GetMessage(Loc, SourceMgr::DK_Error, ErrMsg)); - } - - static Error get(const SourceMgr &SM, StringRef Buffer, const Twine &ErrMsg) { - return get(SM, SMLoc::getFromPointer(Buffer.data()), ErrMsg); - } -}; - -class FileCheckNotFoundError : public ErrorInfo<FileCheckNotFoundError> { -public: - static char ID; - - std::error_code convertToErrorCode() const override { - return inconvertibleErrorCode(); - } - - /// Print diagnostic associated with this error when printing the error. - void log(raw_ostream &OS) const override { - OS << "String not found in input"; - } -}; - -class FileCheckPattern { - SMLoc PatternLoc; - - /// A fixed string to match as the pattern or empty if this pattern requires - /// a regex match. - StringRef FixedStr; - - /// A regex string to match as the pattern or empty if this pattern requires - /// a fixed string to match. - std::string RegExStr; - - /// Entries in this vector represent a substitution of a string variable or - /// an expression in the RegExStr regex at match time. For example, in the - /// case of a CHECK directive with the pattern "foo[[bar]]baz[[#N+1]]", - /// RegExStr will contain "foobaz" and we'll get two entries in this vector - /// that tells us to insert the value of string variable "bar" at offset 3 - /// and the value of expression "N+1" at offset 6. - std::vector<FileCheckSubstitution *> Substitutions; - - /// Maps names of string variables defined in a pattern to the number of - /// their parenthesis group in RegExStr capturing their last definition. - /// - /// E.g. for the pattern "foo[[bar:.*]]baz([[bar]][[QUUX]][[bar:.*]])", - /// RegExStr will be "foo(.*)baz(\1<quux value>(.*))" where <quux value> is - /// the value captured for QUUX on the earlier line where it was defined, and - /// VariableDefs will map "bar" to the third parenthesis group which captures - /// the second definition of "bar". - /// - /// Note: uses std::map rather than StringMap to be able to get the key when - /// iterating over values. - std::map<StringRef, unsigned> VariableDefs; - - /// Structure representing the definition of a numeric variable in a pattern. - /// It holds the pointer to the class representing the numeric variable whose - /// value is being defined and the number of the parenthesis group in - /// RegExStr to capture that value. - struct FileCheckNumericVariableMatch { - /// Pointer to class representing the numeric variable whose value is being - /// defined. - FileCheckNumericVariable *DefinedNumericVariable; - - /// Number of the parenthesis group in RegExStr that captures the value of - /// this numeric variable definition. - unsigned CaptureParenGroup; - }; - - /// Holds the number of the parenthesis group in RegExStr and pointer to the - /// corresponding FileCheckNumericVariable class instance of all numeric - /// variable definitions. Used to set the matched value of all those - /// variables. - StringMap<FileCheckNumericVariableMatch> NumericVariableDefs; - - /// Pointer to a class instance holding the global state shared by all - /// patterns: - /// - separate tables with the values of live string and numeric variables - /// respectively at the start of any given CHECK line; - /// - table holding whether a string variable has been defined at any given - /// point during the parsing phase. - FileCheckPatternContext *Context; - - Check::FileCheckType CheckTy; - - /// Line number for this CHECK pattern or None if it is an implicit pattern. - /// Used to determine whether a variable definition is made on an earlier - /// line to the one with this CHECK. - Optional<size_t> LineNumber; - -public: - FileCheckPattern(Check::FileCheckType Ty, FileCheckPatternContext *Context, - Optional<size_t> Line = None) - : Context(Context), CheckTy(Ty), LineNumber(Line) {} - - /// \returns the location in source code. - SMLoc getLoc() const { return PatternLoc; } - - /// \returns the pointer to the global state for all patterns in this - /// FileCheck instance. - FileCheckPatternContext *getContext() const { return Context; } - - /// \returns whether \p C is a valid first character for a variable name. - static bool isValidVarNameStart(char C); - - /// Parsing information about a variable. - struct VariableProperties { - StringRef Name; - bool IsPseudo; - }; - - /// Parses the string at the start of \p Str for a variable name. \returns - /// a VariableProperties structure holding the variable name and whether it - /// is the name of a pseudo variable, or an error holding a diagnostic - /// against \p SM if parsing fail. If parsing was successful, also strips - /// \p Str from the variable name. - static Expected<VariableProperties> parseVariable(StringRef &Str, - const SourceMgr &SM); - /// Parses \p Expr for the name of a numeric variable to be defined at line - /// \p LineNumber or before input is parsed if \p LineNumber is None. - /// \returns a pointer to the class instance representing that variable, - /// creating it if needed, or an error holding a diagnostic against \p SM - /// should defining such a variable be invalid. - static Expected<FileCheckNumericVariable *> parseNumericVariableDefinition( - StringRef &Expr, FileCheckPatternContext *Context, - Optional<size_t> LineNumber, const SourceMgr &SM); - /// Parses \p Expr for a numeric substitution block. Parameter - /// \p IsLegacyLineExpr indicates whether \p Expr should be a legacy @LINE - /// expression. \returns a pointer to the class instance representing the AST - /// of the expression whose value must be substituted, or an error holding a - /// diagnostic against \p SM if parsing fails. If substitution was - /// successful, sets \p DefinedNumericVariable to point to the class - /// representing the numeric variable being defined in this numeric - /// substitution block, or None if this block does not define any variable. - Expected<std::unique_ptr<FileCheckExpressionAST>> - parseNumericSubstitutionBlock( - StringRef Expr, - Optional<FileCheckNumericVariable *> &DefinedNumericVariable, - bool IsLegacyLineExpr, const SourceMgr &SM) const; - /// Parses the pattern in \p PatternStr and initializes this FileCheckPattern - /// instance accordingly. - /// - /// \p Prefix provides which prefix is being matched, \p Req describes the - /// global options that influence the parsing such as whitespace - /// canonicalization, \p SM provides the SourceMgr used for error reports. - /// \returns true in case of an error, false otherwise. - bool parsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM, - const FileCheckRequest &Req); - /// Matches the pattern string against the input buffer \p Buffer - /// - /// \returns the position that is matched or an error indicating why matching - /// failed. If there is a match, updates \p MatchLen with the size of the - /// matched string. - /// - /// The GlobalVariableTable StringMap in the FileCheckPatternContext class - /// instance provides the current values of FileCheck string variables and - /// is updated if this match defines new values. Likewise, the - /// GlobalNumericVariableTable StringMap in the same class provides the - /// current values of FileCheck numeric variables and is updated if this - /// match defines new numeric values. - Expected<size_t> match(StringRef Buffer, size_t &MatchLen, - const SourceMgr &SM) const; - /// Prints the value of successful substitutions or the name of the undefined - /// string or numeric variables preventing a successful substitution. - void printSubstitutions(const SourceMgr &SM, StringRef Buffer, - SMRange MatchRange = None) const; - void printFuzzyMatch(const SourceMgr &SM, StringRef Buffer, - std::vector<FileCheckDiag> *Diags) const; - - bool hasVariable() const { - return !(Substitutions.empty() && VariableDefs.empty()); - } - - Check::FileCheckType getCheckTy() const { return CheckTy; } - - int getCount() const { return CheckTy.getCount(); } - -private: - bool AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM); - void AddBackrefToRegEx(unsigned BackrefNum); - /// Computes an arbitrary estimate for the quality of matching this pattern - /// at the start of \p Buffer; a distance of zero should correspond to a - /// perfect match. - unsigned computeMatchDistance(StringRef Buffer) const; - /// Finds the closing sequence of a regex variable usage or definition. - /// - /// \p Str has to point in the beginning of the definition (right after the - /// opening sequence). \p SM holds the SourceMgr used for error repporting. - /// \returns the offset of the closing sequence within Str, or npos if it - /// was not found. - size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM); - - /// Parses \p Name as a (pseudo if \p IsPseudo is true) numeric variable use. - /// \returns the pointer to the class instance representing that variable if - /// successful, or an error holding a diagnostic against \p SM otherwise. - Expected<std::unique_ptr<FileCheckNumericVariableUse>> - parseNumericVariableUse(StringRef Name, bool IsPseudo, - const SourceMgr &SM) const; - enum class AllowedOperand { LineVar, Literal, Any }; - /// Parses \p Expr for use of a numeric operand. Accepts both literal values - /// and numeric variables, depending on the value of \p AO. \returns the - /// class representing that operand in the AST of the expression or an error - /// holding a diagnostic against \p SM otherwise. - Expected<std::unique_ptr<FileCheckExpressionAST>> - parseNumericOperand(StringRef &Expr, AllowedOperand AO, - const SourceMgr &SM) const; - /// Parses \p Expr for a binary operation. The left operand of this binary - /// operation is given in \p LeftOp and \p IsLegacyLineExpr indicates whether - /// we are parsing a legacy @LINE expression. \returns the class representing - /// the binary operation in the AST of the expression, or an error holding a - /// diagnostic against \p SM otherwise. - Expected<std::unique_ptr<FileCheckExpressionAST>> - parseBinop(StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp, - bool IsLegacyLineExpr, const SourceMgr &SM) const; -}; - -//===----------------------------------------------------------------------===// -/// Summary of a FileCheck diagnostic. -//===----------------------------------------------------------------------===// - struct FileCheckDiag { /// What is the FileCheck directive for this diagnostic? Check::FileCheckType CheckTy; @@ -659,61 +131,20 @@ struct FileCheckDiag { SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange); }; -//===----------------------------------------------------------------------===// -// Check Strings. -//===----------------------------------------------------------------------===// - -/// A check that we found in the input file. -struct FileCheckString { - /// The pattern to match. - FileCheckPattern Pat; - - /// Which prefix name this check matched. - StringRef Prefix; - - /// The location in the match file that the check string was specified. - SMLoc Loc; - - /// All of the strings that are disallowed from occurring between this match - /// string and the previous one (or start of file). - std::vector<FileCheckPattern> DagNotStrings; - - FileCheckString(const FileCheckPattern &P, StringRef S, SMLoc L) - : Pat(P), Prefix(S), Loc(L) {} - - /// Matches check string and its "not strings" and/or "dag strings". - size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode, - size_t &MatchLen, FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) const; - - /// Verifies that there is a single line in the given \p Buffer. Errors are - /// reported against \p SM. - bool CheckNext(const SourceMgr &SM, StringRef Buffer) const; - /// Verifies that there is no newline in the given \p Buffer. Errors are - /// reported against \p SM. - bool CheckSame(const SourceMgr &SM, StringRef Buffer) const; - /// Verifies that none of the strings in \p NotStrings are found in the given - /// \p Buffer. Errors are reported against \p SM and diagnostics recorded in - /// \p Diags according to the verbosity level set in \p Req. - bool CheckNot(const SourceMgr &SM, StringRef Buffer, - const std::vector<const FileCheckPattern *> &NotStrings, - const FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) const; - /// Matches "dag strings" and their mixed "not strings". - size_t CheckDag(const SourceMgr &SM, StringRef Buffer, - std::vector<const FileCheckPattern *> &NotStrings, - const FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) const; -}; +class FileCheckPatternContext; +struct FileCheckString; /// FileCheck class takes the request and exposes various methods that /// use information from the request. class FileCheck { FileCheckRequest Req; - FileCheckPatternContext PatternContext; + std::unique_ptr<FileCheckPatternContext> PatternContext; + // C++17 TODO: make this a plain std::vector. + std::unique_ptr<std::vector<FileCheckString>> CheckStrings; public: - FileCheck(FileCheckRequest Req) : Req(Req) {} + explicit FileCheck(FileCheckRequest Req); + ~FileCheck(); // Combines the check prefixes into a single regex so that we can efficiently // scan for any of the set. @@ -723,13 +154,11 @@ public: Regex buildCheckPrefixRegex(); /// Reads the check file from \p Buffer and records the expected strings it - /// contains in the \p CheckStrings vector. Errors are reported against - /// \p SM. + /// contains. Errors are reported against \p SM. /// /// Only expected strings whose prefix is one of those listed in \p PrefixRE /// are recorded. \returns true in case of an error, false otherwise. - bool ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE, - std::vector<FileCheckString> &CheckStrings); + bool readCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE); bool ValidateCheckPrefixes(); @@ -739,13 +168,14 @@ public: SmallVectorImpl<char> &OutputBuffer); /// Checks the input to FileCheck provided in the \p Buffer against the - /// \p CheckStrings read from the check file and record diagnostics emitted + /// expected strings read from the check file and record diagnostics emitted /// in \p Diags. Errors are recorded against \p SM. /// /// \returns false if the input fails to satisfy the checks. - bool CheckInput(SourceMgr &SM, StringRef Buffer, - ArrayRef<FileCheckString> CheckStrings, + bool checkInput(SourceMgr &SM, StringRef Buffer, std::vector<FileCheckDiag> *Diags = nullptr); }; + } // namespace llvm + #endif diff --git a/include/llvm/Support/FileCollector.h b/include/llvm/Support/FileCollector.h new file mode 100644 index 000000000000..19429bd3e9b4 --- /dev/null +++ b/include/llvm/Support/FileCollector.h @@ -0,0 +1,79 @@ +//===-- FileCollector.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_FILE_COLLECTOR_H +#define LLVM_SUPPORT_FILE_COLLECTOR_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/VirtualFileSystem.h" + +#include <mutex> + +namespace llvm { + +/// Collects files into a directory and generates a mapping that can be used by +/// the VFS. +class FileCollector { +public: + FileCollector(std::string Root, std::string OverlayRoot); + + void addFile(const Twine &file); + + /// Write the yaml mapping (for the VFS) to the given file. + std::error_code writeMapping(StringRef mapping_file); + + /// Copy the files into the root directory. + /// + /// When StopOnError is true (the default) we abort as soon as one file + /// cannot be copied. This is relatively common, for example when a file was + /// removed after it was added to the mapping. + std::error_code copyFiles(bool StopOnError = true); + + /// Create a VFS that collects all the paths that might be looked at by the + /// file system accesses. + static IntrusiveRefCntPtr<vfs::FileSystem> + createCollectorVFS(IntrusiveRefCntPtr<vfs::FileSystem> BaseFS, + std::shared_ptr<FileCollector> Collector); + +private: + void addFileImpl(StringRef SrcPath); + + bool markAsSeen(StringRef Path) { return Seen.insert(Path).second; } + + bool getRealPath(StringRef SrcPath, SmallVectorImpl<char> &Result); + + void addFileToMapping(StringRef VirtualPath, StringRef RealPath) { + VFSWriter.addFileMapping(VirtualPath, RealPath); + } + +protected: + /// Synchronizes adding files. + std::mutex Mutex; + + /// The root directory where files are copied. + std::string Root; + + /// The root directory where the VFS overlay lives. + std::string OverlayRoot; + + /// Tracks already seen files so they can be skipped. + StringSet<> Seen; + + /// The yaml mapping writer. + vfs::YAMLVFSWriter VFSWriter; + + /// Caches RealPath calls when resolving symlinks. + StringMap<std::string> SymlinkMap; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_FILE_COLLECTOR_H diff --git a/include/llvm/Support/FileSystem.h b/include/llvm/Support/FileSystem.h index 1bec27bddad9..a29a9d787947 100644 --- a/include/llvm/Support/FileSystem.h +++ b/include/llvm/Support/FileSystem.h @@ -991,29 +991,27 @@ file_t getStdoutHandle(); /// Returns kInvalidFile when the stream is closed. file_t getStderrHandle(); -/// Reads \p Buf.size() bytes from \p FileHandle into \p Buf. The number of -/// bytes actually read is returned in \p BytesRead. On Unix, this is equivalent -/// to `*BytesRead = ::read(FD, Buf.data(), Buf.size())`, with error reporting. -/// BytesRead will contain zero when reaching EOF. +/// Reads \p Buf.size() bytes from \p FileHandle into \p Buf. Returns the number +/// of bytes actually read. On Unix, this is equivalent to `return ::read(FD, +/// Buf.data(), Buf.size())`, with error reporting. Returns 0 when reaching EOF. /// /// @param FileHandle File to read from. /// @param Buf Buffer to read into. -/// @param BytesRead Output parameter of the number of bytes read. -/// @returns The error, if any, or errc::success. -std::error_code readNativeFile(file_t FileHandle, MutableArrayRef<char> Buf, - size_t *BytesRead); +/// @returns The number of bytes read, or error. +Expected<size_t> readNativeFile(file_t FileHandle, MutableArrayRef<char> Buf); /// Reads \p Buf.size() bytes from \p FileHandle at offset \p Offset into \p /// Buf. If 'pread' is available, this will use that, otherwise it will use -/// 'lseek'. Bytes requested beyond the end of the file will be zero -/// initialized. +/// 'lseek'. Returns the number of bytes actually read. Returns 0 when reaching +/// EOF. /// /// @param FileHandle File to read from. /// @param Buf Buffer to read into. /// @param Offset Offset into the file at which the read should occur. -/// @returns The error, if any, or errc::success. -std::error_code readNativeFileSlice(file_t FileHandle, - MutableArrayRef<char> Buf, size_t Offset); +/// @returns The number of bytes read, or error. +Expected<size_t> readNativeFileSlice(file_t FileHandle, + MutableArrayRef<char> Buf, + uint64_t Offset); /// @brief Opens the file with the given name in a write-only or read-write /// mode, returning its open file descriptor. If the file does not exist, it @@ -1217,9 +1215,9 @@ class directory_entry { // that whole structure, callers end up paying for a stat(). // std::filesystem::directory_entry may be a better model. std::string Path; - file_type Type; // Most platforms can provide this. - bool FollowSymlinks; // Affects the behavior of status(). - basic_file_status Status; // If available. + file_type Type = file_type::type_unknown; // Most platforms can provide this. + bool FollowSymlinks = true; // Affects the behavior of status(). + basic_file_status Status; // If available. public: explicit directory_entry(const Twine &Path, bool FollowSymlinks = true, diff --git a/include/llvm/Support/FileUtilities.h b/include/llvm/Support/FileUtilities.h index 16b2206924c3..04efdced32a4 100644 --- a/include/llvm/Support/FileUtilities.h +++ b/include/llvm/Support/FileUtilities.h @@ -14,6 +14,9 @@ #ifndef LLVM_SUPPORT_FILEUTILITIES_H #define LLVM_SUPPORT_FILEUTILITIES_H +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -72,6 +75,41 @@ namespace llvm { /// will not be removed when the object is destroyed. void releaseFile() { DeleteIt = false; } }; + + enum class atomic_write_error { + failed_to_create_uniq_file = 0, + output_stream_error, + failed_to_rename_temp_file + }; + + class AtomicFileWriteError : public llvm::ErrorInfo<AtomicFileWriteError> { + public: + AtomicFileWriteError(atomic_write_error Error) : Error(Error) {} + + void log(raw_ostream &OS) const override; + + const atomic_write_error Error; + static char ID; + + private: + // Users are not expected to use error_code. + std::error_code convertToErrorCode() const override { + return llvm::inconvertibleErrorCode(); + } + }; + + // atomic_write_error + whatever the Writer can return + + /// Creates a unique file with name according to the given \p TempPathModel, + /// writes content of \p Buffer to the file and renames it to \p FinalPath. + /// + /// \returns \c AtomicFileWriteError in case of error. + llvm::Error writeFileAtomically(StringRef TempPathModel, StringRef FinalPath, + StringRef Buffer); + + llvm::Error + writeFileAtomically(StringRef TempPathModel, StringRef FinalPath, + std::function<llvm::Error(llvm::raw_ostream &)> Writer); } // End llvm namespace #endif diff --git a/include/llvm/Support/Format.h b/include/llvm/Support/Format.h index 77dcbaebf1a3..9dd7b401b46a 100644 --- a/include/llvm/Support/Format.h +++ b/include/llvm/Support/Format.h @@ -29,6 +29,7 @@ #include <cassert> #include <cstdio> #include <tuple> +#include <utility> namespace llvm { @@ -91,7 +92,7 @@ class format_object final : public format_object_base { template <std::size_t... Is> int snprint_tuple(char *Buffer, unsigned BufferSize, - index_sequence<Is...>) const { + std::index_sequence<Is...>) const { #ifdef _MSC_VER return _snprintf(Buffer, BufferSize, Fmt, std::get<Is>(Vals)...); #else @@ -106,7 +107,7 @@ public: } int snprint(char *Buffer, unsigned BufferSize) const override { - return snprint_tuple(Buffer, BufferSize, index_sequence_for<Ts...>()); + return snprint_tuple(Buffer, BufferSize, std::index_sequence_for<Ts...>()); } }; diff --git a/include/llvm/Support/GenericDomTree.h b/include/llvm/Support/GenericDomTree.h index 99620802505b..9169379f746d 100644 --- a/include/llvm/Support/GenericDomTree.h +++ b/include/llvm/Support/GenericDomTree.h @@ -242,7 +242,7 @@ protected: using DomTreeNodeMapType = DenseMap<NodeT *, std::unique_ptr<DomTreeNodeBase<NodeT>>>; DomTreeNodeMapType DomTreeNodes; - DomTreeNodeBase<NodeT> *RootNode; + DomTreeNodeBase<NodeT> *RootNode = nullptr; ParentPtr Parent = nullptr; mutable bool DFSInfoValid = false; @@ -571,7 +571,7 @@ protected: assert(IDomNode && "Not immediate dominator specified for block!"); DFSInfoValid = false; return (DomTreeNodes[BB] = IDomNode->addChild( - llvm::make_unique<DomTreeNodeBase<NodeT>>(BB, IDomNode))).get(); + std::make_unique<DomTreeNodeBase<NodeT>>(BB, IDomNode))).get(); } /// Add a new node to the forward dominator tree and make it a new root. @@ -585,7 +585,7 @@ protected: "Cannot change root of post-dominator tree"); DFSInfoValid = false; DomTreeNodeBase<NodeT> *NewNode = (DomTreeNodes[BB] = - llvm::make_unique<DomTreeNodeBase<NodeT>>(BB, nullptr)).get(); + std::make_unique<DomTreeNodeBase<NodeT>>(BB, nullptr)).get(); if (Roots.empty()) { addRoot(BB); } else { diff --git a/include/llvm/Support/GenericDomTreeConstruction.h b/include/llvm/Support/GenericDomTreeConstruction.h index ccceba881718..7c0278e8770e 100644 --- a/include/llvm/Support/GenericDomTreeConstruction.h +++ b/include/llvm/Support/GenericDomTreeConstruction.h @@ -186,7 +186,7 @@ struct SemiNCAInfo { // Add a new tree node for this NodeT, and link it as a child of // IDomNode return (DT.DomTreeNodes[BB] = IDomNode->addChild( - llvm::make_unique<DomTreeNodeBase<NodeT>>(BB, IDomNode))) + std::make_unique<DomTreeNodeBase<NodeT>>(BB, IDomNode))) .get(); } @@ -586,7 +586,7 @@ struct SemiNCAInfo { NodePtr Root = IsPostDom ? nullptr : DT.Roots[0]; DT.RootNode = (DT.DomTreeNodes[Root] = - llvm::make_unique<DomTreeNodeBase<NodeT>>(Root, nullptr)) + std::make_unique<DomTreeNodeBase<NodeT>>(Root, nullptr)) .get(); SNCA.attachNewSubtree(DT, DT.RootNode); } @@ -611,7 +611,7 @@ struct SemiNCAInfo { // Add a new tree node for this BasicBlock, and link it as a child of // IDomNode. DT.DomTreeNodes[W] = IDomNode->addChild( - llvm::make_unique<DomTreeNodeBase<NodeT>>(W, IDomNode)); + std::make_unique<DomTreeNodeBase<NodeT>>(W, IDomNode)); } } @@ -663,7 +663,7 @@ struct SemiNCAInfo { TreeNodePtr VirtualRoot = DT.getNode(nullptr); FromTN = (DT.DomTreeNodes[From] = VirtualRoot->addChild( - llvm::make_unique<DomTreeNodeBase<NodeT>>(From, VirtualRoot))) + std::make_unique<DomTreeNodeBase<NodeT>>(From, VirtualRoot))) .get(); DT.Roots.push_back(From); } diff --git a/include/llvm/Support/GlobPattern.h b/include/llvm/Support/GlobPattern.h index 66a4cd94c12a..0098ac65fd30 100644 --- a/include/llvm/Support/GlobPattern.h +++ b/include/llvm/Support/GlobPattern.h @@ -21,7 +21,7 @@ #include <vector> // This class represents a glob pattern. Supported metacharacters -// are "*", "?", "[<chars>]" and "[^<chars>]". +// are "*", "?", "\", "[<chars>]", "[^<chars>]", and "[!<chars>]". namespace llvm { class BitVector; template <typename T> class ArrayRef; diff --git a/include/llvm/Support/Host.h b/include/llvm/Support/Host.h index b37cc514c92e..44f543c363db 100644 --- a/include/llvm/Support/Host.h +++ b/include/llvm/Support/Host.h @@ -15,39 +15,11 @@ #include "llvm/ADT/StringMap.h" -#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) -#include <endian.h> -#elif defined(_AIX) -#include <sys/machine.h> -#elif defined(__sun) -/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */ -#include <sys/types.h> -#define BIG_ENDIAN 4321 -#define LITTLE_ENDIAN 1234 -#if defined(_BIG_ENDIAN) -#define BYTE_ORDER BIG_ENDIAN -#else -#define BYTE_ORDER LITTLE_ENDIAN -#endif -#else -#if !defined(BYTE_ORDER) && !defined(_WIN32) -#include <machine/endian.h> -#endif -#endif - #include <string> namespace llvm { namespace sys { -#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN -constexpr bool IsBigEndianHost = true; -#else -constexpr bool IsBigEndianHost = false; -#endif - - static const bool IsLittleEndianHost = !IsBigEndianHost; - /// getDefaultTargetTriple() - Return the default target triple the compiler /// has been configured to produce code for. /// diff --git a/include/llvm/Support/JamCRC.h b/include/llvm/Support/JamCRC.h deleted file mode 100644 index b6fc4e7b9b03..000000000000 --- a/include/llvm/Support/JamCRC.h +++ /dev/null @@ -1,48 +0,0 @@ -//===-- llvm/Support/JamCRC.h - Cyclic Redundancy Check ---------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file contains an implementation of JamCRC. -// -// We will use the "Rocksoft^tm Model CRC Algorithm" to describe the properties -// of this CRC: -// Width : 32 -// Poly : 04C11DB7 -// Init : FFFFFFFF -// RefIn : True -// RefOut : True -// XorOut : 00000000 -// Check : 340BC6D9 (result of CRC for "123456789") -// -// N.B. We permit flexibility of the "Init" value. Some consumers of this need -// it to be zero. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SUPPORT_JAMCRC_H -#define LLVM_SUPPORT_JAMCRC_H - -#include "llvm/Support/DataTypes.h" - -namespace llvm { -template <typename T> class ArrayRef; - -class JamCRC { -public: - JamCRC(uint32_t Init = 0xFFFFFFFFU) : CRC(Init) {} - - // Update the CRC calculation with Data. - void update(ArrayRef<char> Data); - - uint32_t getCRC() const { return CRC; } - -private: - uint32_t CRC; -}; -} // End of namespace llvm - -#endif diff --git a/include/llvm/Support/MachineValueType.h b/include/llvm/Support/MachineValueType.h index b94d2c4836cc..7f9f0b85c55e 100644 --- a/include/llvm/Support/MachineValueType.h +++ b/include/llvm/Support/MachineValueType.h @@ -17,6 +17,7 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/TypeSize.h" #include <cassert> namespace llvm { @@ -64,152 +65,162 @@ namespace llvm { v32i1 = 19, // 32 x i1 v64i1 = 20, // 64 x i1 v128i1 = 21, // 128 x i1 - v512i1 = 22, // 512 x i1 - v1024i1 = 23, // 1024 x i1 - - v1i8 = 24, // 1 x i8 - v2i8 = 25, // 2 x i8 - v4i8 = 26, // 4 x i8 - v8i8 = 27, // 8 x i8 - v16i8 = 28, // 16 x i8 - v32i8 = 29, // 32 x i8 - v64i8 = 30, // 64 x i8 - v128i8 = 31, //128 x i8 - v256i8 = 32, //256 x i8 - - v1i16 = 33, // 1 x i16 - v2i16 = 34, // 2 x i16 - v4i16 = 35, // 4 x i16 - v8i16 = 36, // 8 x i16 - v16i16 = 37, // 16 x i16 - v32i16 = 38, // 32 x i16 - v64i16 = 39, // 64 x i16 - v128i16 = 40, //128 x i16 - - v1i32 = 41, // 1 x i32 - v2i32 = 42, // 2 x i32 - v3i32 = 43, // 3 x i32 - v4i32 = 44, // 4 x i32 - v5i32 = 45, // 5 x i32 - v8i32 = 46, // 8 x i32 - v16i32 = 47, // 16 x i32 - v32i32 = 48, // 32 x i32 - v64i32 = 49, // 64 x i32 - v128i32 = 50, // 128 x i32 - v256i32 = 51, // 256 x i32 - v512i32 = 52, // 512 x i32 - v1024i32 = 53, // 1024 x i32 - v2048i32 = 54, // 2048 x i32 - - v1i64 = 55, // 1 x i64 - v2i64 = 56, // 2 x i64 - v4i64 = 57, // 4 x i64 - v8i64 = 58, // 8 x i64 - v16i64 = 59, // 16 x i64 - v32i64 = 60, // 32 x i64 - - v1i128 = 61, // 1 x i128 - - // Scalable integer types - nxv1i1 = 62, // n x 1 x i1 - nxv2i1 = 63, // n x 2 x i1 - nxv4i1 = 64, // n x 4 x i1 - nxv8i1 = 65, // n x 8 x i1 - nxv16i1 = 66, // n x 16 x i1 - nxv32i1 = 67, // n x 32 x i1 - - nxv1i8 = 68, // n x 1 x i8 - nxv2i8 = 69, // n x 2 x i8 - nxv4i8 = 70, // n x 4 x i8 - nxv8i8 = 71, // n x 8 x i8 - nxv16i8 = 72, // n x 16 x i8 - nxv32i8 = 73, // n x 32 x i8 - - nxv1i16 = 74, // n x 1 x i16 - nxv2i16 = 75, // n x 2 x i16 - nxv4i16 = 76, // n x 4 x i16 - nxv8i16 = 77, // n x 8 x i16 - nxv16i16 = 78, // n x 16 x i16 - nxv32i16 = 79, // n x 32 x i16 - - nxv1i32 = 80, // n x 1 x i32 - nxv2i32 = 81, // n x 2 x i32 - nxv4i32 = 82, // n x 4 x i32 - nxv8i32 = 83, // n x 8 x i32 - nxv16i32 = 84, // n x 16 x i32 - nxv32i32 = 85, // n x 32 x i32 - - nxv1i64 = 86, // n x 1 x i64 - nxv2i64 = 87, // n x 2 x i64 - nxv4i64 = 88, // n x 4 x i64 - nxv8i64 = 89, // n x 8 x i64 - nxv16i64 = 90, // n x 16 x i64 - nxv32i64 = 91, // n x 32 x i64 - - FIRST_INTEGER_VECTOR_VALUETYPE = v1i1, - LAST_INTEGER_VECTOR_VALUETYPE = nxv32i64, - - FIRST_INTEGER_SCALABLE_VALUETYPE = nxv1i1, - LAST_INTEGER_SCALABLE_VALUETYPE = nxv32i64, - - v2f16 = 92, // 2 x f16 - v4f16 = 93, // 4 x f16 - v8f16 = 94, // 8 x f16 - v1f32 = 95, // 1 x f32 - v2f32 = 96, // 2 x f32 - v3f32 = 97, // 3 x f32 - v4f32 = 98, // 4 x f32 - v5f32 = 99, // 5 x f32 - v8f32 = 100, // 8 x f32 - v16f32 = 101, // 16 x f32 - v32f32 = 102, // 32 x f32 - v64f32 = 103, // 64 x f32 - v128f32 = 104, // 128 x f32 - v256f32 = 105, // 256 x f32 - v512f32 = 106, // 512 x f32 - v1024f32 = 107, // 1024 x f32 - v2048f32 = 108, // 2048 x f32 - v1f64 = 109, // 1 x f64 - v2f64 = 110, // 2 x f64 - v4f64 = 111, // 4 x f64 - v8f64 = 112, // 8 x f64 - - nxv2f16 = 113, // n x 2 x f16 - nxv4f16 = 114, // n x 4 x f16 - nxv8f16 = 115, // n x 8 x f16 - nxv1f32 = 116, // n x 1 x f32 - nxv2f32 = 117, // n x 2 x f32 - nxv4f32 = 118, // n x 4 x f32 - nxv8f32 = 119, // n x 8 x f32 - nxv16f32 = 120, // n x 16 x f32 - nxv1f64 = 121, // n x 1 x f64 - nxv2f64 = 122, // n x 2 x f64 - nxv4f64 = 123, // n x 4 x f64 - nxv8f64 = 124, // n x 8 x f64 - - FIRST_FP_VECTOR_VALUETYPE = v2f16, - LAST_FP_VECTOR_VALUETYPE = nxv8f64, - - FIRST_FP_SCALABLE_VALUETYPE = nxv2f16, - LAST_FP_SCALABLE_VALUETYPE = nxv8f64, + v256i1 = 22, // 256 x i1 + v512i1 = 23, // 512 x i1 + v1024i1 = 24, // 1024 x i1 + + v1i8 = 25, // 1 x i8 + v2i8 = 26, // 2 x i8 + v4i8 = 27, // 4 x i8 + v8i8 = 28, // 8 x i8 + v16i8 = 29, // 16 x i8 + v32i8 = 30, // 32 x i8 + v64i8 = 31, // 64 x i8 + v128i8 = 32, //128 x i8 + v256i8 = 33, //256 x i8 + + v1i16 = 34, // 1 x i16 + v2i16 = 35, // 2 x i16 + v3i16 = 36, // 3 x i16 + v4i16 = 37, // 4 x i16 + v8i16 = 38, // 8 x i16 + v16i16 = 39, // 16 x i16 + v32i16 = 40, // 32 x i16 + v64i16 = 41, // 64 x i16 + v128i16 = 42, //128 x i16 + + v1i32 = 43, // 1 x i32 + v2i32 = 44, // 2 x i32 + v3i32 = 45, // 3 x i32 + v4i32 = 46, // 4 x i32 + v5i32 = 47, // 5 x i32 + v8i32 = 48, // 8 x i32 + v16i32 = 49, // 16 x i32 + v32i32 = 50, // 32 x i32 + v64i32 = 51, // 64 x i32 + v128i32 = 52, // 128 x i32 + v256i32 = 53, // 256 x i32 + v512i32 = 54, // 512 x i32 + v1024i32 = 55, // 1024 x i32 + v2048i32 = 56, // 2048 x i32 + + v1i64 = 57, // 1 x i64 + v2i64 = 58, // 2 x i64 + v4i64 = 59, // 4 x i64 + v8i64 = 60, // 8 x i64 + v16i64 = 61, // 16 x i64 + v32i64 = 62, // 32 x i64 + + v1i128 = 63, // 1 x i128 + + FIRST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE = v1i1, + LAST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE = v1i128, + + v2f16 = 64, // 2 x f16 + v3f16 = 65, // 3 x f16 + v4f16 = 66, // 4 x f16 + v8f16 = 67, // 8 x f16 + v16f16 = 68, // 16 x f16 + v32f16 = 69, // 32 x f16 + v1f32 = 70, // 1 x f32 + v2f32 = 71, // 2 x f32 + v3f32 = 72, // 3 x f32 + v4f32 = 73, // 4 x f32 + v5f32 = 74, // 5 x f32 + v8f32 = 75, // 8 x f32 + v16f32 = 76, // 16 x f32 + v32f32 = 77, // 32 x f32 + v64f32 = 78, // 64 x f32 + v128f32 = 79, // 128 x f32 + v256f32 = 80, // 256 x f32 + v512f32 = 81, // 512 x f32 + v1024f32 = 82, // 1024 x f32 + v2048f32 = 83, // 2048 x f32 + v1f64 = 84, // 1 x f64 + v2f64 = 85, // 2 x f64 + v4f64 = 86, // 4 x f64 + v8f64 = 87, // 8 x f64 + + FIRST_FP_FIXEDLEN_VECTOR_VALUETYPE = v2f16, + LAST_FP_FIXEDLEN_VECTOR_VALUETYPE = v8f64, + + FIRST_FIXEDLEN_VECTOR_VALUETYPE = v1i1, + LAST_FIXEDLEN_VECTOR_VALUETYPE = v8f64, + + nxv1i1 = 88, // n x 1 x i1 + nxv2i1 = 89, // n x 2 x i1 + nxv4i1 = 90, // n x 4 x i1 + nxv8i1 = 91, // n x 8 x i1 + nxv16i1 = 92, // n x 16 x i1 + nxv32i1 = 93, // n x 32 x i1 + + nxv1i8 = 94, // n x 1 x i8 + nxv2i8 = 95, // n x 2 x i8 + nxv4i8 = 96, // n x 4 x i8 + nxv8i8 = 97, // n x 8 x i8 + nxv16i8 = 98, // n x 16 x i8 + nxv32i8 = 99, // n x 32 x i8 + + nxv1i16 = 100, // n x 1 x i16 + nxv2i16 = 101, // n x 2 x i16 + nxv4i16 = 102, // n x 4 x i16 + nxv8i16 = 103, // n x 8 x i16 + nxv16i16 = 104, // n x 16 x i16 + nxv32i16 = 105, // n x 32 x i16 + + nxv1i32 = 106, // n x 1 x i32 + nxv2i32 = 107, // n x 2 x i32 + nxv4i32 = 108, // n x 4 x i32 + nxv8i32 = 109, // n x 8 x i32 + nxv16i32 = 110, // n x 16 x i32 + nxv32i32 = 111, // n x 32 x i32 + + nxv1i64 = 112, // n x 1 x i64 + nxv2i64 = 113, // n x 2 x i64 + nxv4i64 = 114, // n x 4 x i64 + nxv8i64 = 115, // n x 8 x i64 + nxv16i64 = 116, // n x 16 x i64 + nxv32i64 = 117, // n x 32 x i64 + + FIRST_INTEGER_SCALABLE_VECTOR_VALUETYPE = nxv1i1, + LAST_INTEGER_SCALABLE_VECTOR_VALUETYPE = nxv32i64, + + nxv2f16 = 118, // n x 2 x f16 + nxv4f16 = 119, // n x 4 x f16 + nxv8f16 = 120, // n x 8 x f16 + nxv1f32 = 121, // n x 1 x f32 + nxv2f32 = 122, // n x 2 x f32 + nxv4f32 = 123, // n x 4 x f32 + nxv8f32 = 124, // n x 8 x f32 + nxv16f32 = 125, // n x 16 x f32 + nxv1f64 = 126, // n x 1 x f64 + nxv2f64 = 127, // n x 2 x f64 + nxv4f64 = 128, // n x 4 x f64 + nxv8f64 = 129, // n x 8 x f64 + + FIRST_FP_SCALABLE_VECTOR_VALUETYPE = nxv2f16, + LAST_FP_SCALABLE_VECTOR_VALUETYPE = nxv8f64, + + FIRST_SCALABLE_VECTOR_VALUETYPE = nxv1i1, + LAST_SCALABLE_VECTOR_VALUETYPE = nxv8f64, FIRST_VECTOR_VALUETYPE = v1i1, LAST_VECTOR_VALUETYPE = nxv8f64, - x86mmx = 125, // This is an X86 MMX value + x86mmx = 130, // This is an X86 MMX value - Glue = 126, // This glues nodes together during pre-RA sched + Glue = 131, // This glues nodes together during pre-RA sched - isVoid = 127, // This has no value + isVoid = 132, // This has no value - Untyped = 128, // This value takes a register, but has + Untyped = 133, // This value takes a register, but has // unspecified type. The register class // will be determined by the opcode. - exnref = 129, // WebAssembly's exnref type + exnref = 134, // WebAssembly's exnref type FIRST_VALUETYPE = 1, // This is always the beginning of the list. - LAST_VALUETYPE = 130, // This always remains at the end of the list. + LAST_VALUETYPE = 135, // This always remains at the end of the list. // This is the current maximum for LAST_VALUETYPE. // MVT::MAX_ALLOWED_VALUETYPE is used for asserts and to size bit vectors @@ -253,41 +264,6 @@ namespace llvm { SimpleValueType SimpleTy = INVALID_SIMPLE_VALUE_TYPE; - // A class to represent the number of elements in a vector - // - // For fixed-length vectors, the total number of elements is equal to 'Min' - // For scalable vectors, the total number of elements is a multiple of 'Min' - class ElementCount { - public: - unsigned Min; - bool Scalable; - - ElementCount(unsigned Min, bool Scalable) - : Min(Min), Scalable(Scalable) {} - - ElementCount operator*(unsigned RHS) { - return { Min * RHS, Scalable }; - } - - ElementCount& operator*=(unsigned RHS) { - Min *= RHS; - return *this; - } - - ElementCount operator/(unsigned RHS) { - return { Min / RHS, Scalable }; - } - - ElementCount& operator/=(unsigned RHS) { - Min /= RHS; - return *this; - } - - bool operator==(const ElementCount& RHS) { - return Min == RHS.Min && Scalable == RHS.Scalable; - } - }; - constexpr MVT() = default; constexpr MVT(SimpleValueType SVT) : SimpleTy(SVT) {} @@ -308,16 +284,20 @@ namespace llvm { bool isFloatingPoint() const { return ((SimpleTy >= MVT::FIRST_FP_VALUETYPE && SimpleTy <= MVT::LAST_FP_VALUETYPE) || - (SimpleTy >= MVT::FIRST_FP_VECTOR_VALUETYPE && - SimpleTy <= MVT::LAST_FP_VECTOR_VALUETYPE)); + (SimpleTy >= MVT::FIRST_FP_FIXEDLEN_VECTOR_VALUETYPE && + SimpleTy <= MVT::LAST_FP_FIXEDLEN_VECTOR_VALUETYPE) || + (SimpleTy >= MVT::FIRST_FP_SCALABLE_VECTOR_VALUETYPE && + SimpleTy <= MVT::LAST_FP_SCALABLE_VECTOR_VALUETYPE)); } /// Return true if this is an integer or a vector integer type. bool isInteger() const { return ((SimpleTy >= MVT::FIRST_INTEGER_VALUETYPE && SimpleTy <= MVT::LAST_INTEGER_VALUETYPE) || - (SimpleTy >= MVT::FIRST_INTEGER_VECTOR_VALUETYPE && - SimpleTy <= MVT::LAST_INTEGER_VECTOR_VALUETYPE)); + (SimpleTy >= MVT::FIRST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE && + SimpleTy <= MVT::LAST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE) || + (SimpleTy >= MVT::FIRST_INTEGER_SCALABLE_VECTOR_VALUETYPE && + SimpleTy <= MVT::LAST_INTEGER_SCALABLE_VECTOR_VALUETYPE)); } /// Return true if this is an integer, not including vectors. @@ -335,10 +315,13 @@ namespace llvm { /// Return true if this is a vector value type where the /// runtime length is machine dependent bool isScalableVector() const { - return ((SimpleTy >= MVT::FIRST_INTEGER_SCALABLE_VALUETYPE && - SimpleTy <= MVT::LAST_INTEGER_SCALABLE_VALUETYPE) || - (SimpleTy >= MVT::FIRST_FP_SCALABLE_VALUETYPE && - SimpleTy <= MVT::LAST_FP_SCALABLE_VALUETYPE)); + return (SimpleTy >= MVT::FIRST_SCALABLE_VECTOR_VALUETYPE && + SimpleTy <= MVT::LAST_SCALABLE_VECTOR_VALUETYPE); + } + + bool isFixedLengthVector() const { + return (SimpleTy >= MVT::FIRST_FIXEDLEN_VECTOR_VALUETYPE && + SimpleTy <= MVT::LAST_FIXEDLEN_VECTOR_VALUETYPE); } /// Return true if this is a 16-bit vector type. @@ -373,17 +356,18 @@ namespace llvm { /// Return true if this is a 256-bit vector type. bool is256BitVector() const { - return (SimpleTy == MVT::v8f32 || SimpleTy == MVT::v4f64 || - SimpleTy == MVT::v32i8 || SimpleTy == MVT::v16i16 || - SimpleTy == MVT::v8i32 || SimpleTy == MVT::v4i64); + return (SimpleTy == MVT::v16f16 || SimpleTy == MVT::v8f32 || + SimpleTy == MVT::v4f64 || SimpleTy == MVT::v32i8 || + SimpleTy == MVT::v16i16 || SimpleTy == MVT::v8i32 || + SimpleTy == MVT::v4i64 || SimpleTy == MVT::v256i1); } /// Return true if this is a 512-bit vector type. bool is512BitVector() const { - return (SimpleTy == MVT::v16f32 || SimpleTy == MVT::v8f64 || - SimpleTy == MVT::v512i1 || SimpleTy == MVT::v64i8 || - SimpleTy == MVT::v32i16 || SimpleTy == MVT::v16i32 || - SimpleTy == MVT::v8i64); + return (SimpleTy == MVT::v32f16 || SimpleTy == MVT::v16f32 || + SimpleTy == MVT::v8f64 || SimpleTy == MVT::v512i1 || + SimpleTy == MVT::v64i8 || SimpleTy == MVT::v32i16 || + SimpleTy == MVT::v16i32 || SimpleTy == MVT::v8i64); } /// Return true if this is a 1024-bit vector type. @@ -406,6 +390,15 @@ namespace llvm { SimpleTy==MVT::vAny || SimpleTy==MVT::iPTRAny); } + /// Return a VT for a vector type with the same element type but + /// half the number of elements. + MVT getHalfNumVectorElementsVT() const { + MVT EltVT = getVectorElementType(); + auto EltCnt = getVectorElementCount(); + assert(!(EltCnt.Min & 1) && "Splitting vector, but not in half!"); + return getVectorVT(EltVT, EltCnt / 2); + } + /// Returns true if the given vector is a power of 2. bool isPow2VectorType() const { unsigned NElts = getVectorNumElements(); @@ -440,6 +433,7 @@ namespace llvm { case v32i1: case v64i1: case v128i1: + case v256i1: case v512i1: case v1024i1: case nxv1i1: @@ -465,6 +459,7 @@ namespace llvm { case nxv32i8: return i8; case v1i16: case v2i16: + case v3i16: case v4i16: case v8i16: case v16i16: @@ -511,8 +506,11 @@ namespace llvm { case nxv32i64: return i64; case v1i128: return i128; case v2f16: + case v3f16: case v4f16: case v8f16: + case v16f16: + case v32f16: case nxv2f16: case nxv4f16: case nxv8f16: return f16; @@ -558,6 +556,7 @@ namespace llvm { case v512i1: case v512i32: case v512f32: return 512; + case v256i1: case v256i8: case v256i32: case v256f32: return 256; @@ -576,6 +575,7 @@ namespace llvm { case v32i16: case v32i32: case v32i64: + case v32f16: case v32f32: case nxv32i1: case nxv32i8: @@ -587,6 +587,7 @@ namespace llvm { case v16i16: case v16i32: case v16i64: + case v16f16: case v16f32: case nxv16i1: case nxv16i8: @@ -628,7 +629,9 @@ namespace llvm { case nxv4f16: case nxv4f32: case nxv4f64: return 4; + case v3i16: case v3i32: + case v3f16: case v3f32: return 3; case v2i1: case v2i8: @@ -664,7 +667,7 @@ namespace llvm { } } - MVT::ElementCount getVectorElementCount() const { + ElementCount getVectorElementCount() const { return { getVectorNumElements(), isScalableVector() }; } @@ -721,6 +724,8 @@ namespace llvm { case nxv1i32: case nxv2f16: case nxv1f32: return 32; + case v3i16: + case v3f16: return 48; case x86mmx: case f64 : case i64 : @@ -763,10 +768,12 @@ namespace llvm { case nxv2f64: return 128; case v5i32: case v5f32: return 160; + case v256i1: case v32i8: case v16i16: case v8i32: case v4i64: + case v16f16: case v8f32: case v4f64: case nxv32i8: @@ -780,6 +787,7 @@ namespace llvm { case v32i16: case v16i32: case v8i64: + case v32f16: case v16f32: case v8f64: case nxv32i16: @@ -900,6 +908,7 @@ namespace llvm { if (NumElements == 32) return MVT::v32i1; if (NumElements == 64) return MVT::v64i1; if (NumElements == 128) return MVT::v128i1; + if (NumElements == 256) return MVT::v256i1; if (NumElements == 512) return MVT::v512i1; if (NumElements == 1024) return MVT::v1024i1; break; @@ -917,6 +926,7 @@ namespace llvm { case MVT::i16: if (NumElements == 1) return MVT::v1i16; if (NumElements == 2) return MVT::v2i16; + if (NumElements == 3) return MVT::v3i16; if (NumElements == 4) return MVT::v4i16; if (NumElements == 8) return MVT::v8i16; if (NumElements == 16) return MVT::v16i16; @@ -953,8 +963,11 @@ namespace llvm { break; case MVT::f16: if (NumElements == 2) return MVT::v2f16; + if (NumElements == 3) return MVT::v3f16; if (NumElements == 4) return MVT::v4f16; if (NumElements == 8) return MVT::v8f16; + if (NumElements == 16) return MVT::v16f16; + if (NumElements == 32) return MVT::v32f16; break; case MVT::f32: if (NumElements == 1) return MVT::v1f32; @@ -1054,7 +1067,7 @@ namespace llvm { return getVectorVT(VT, NumElements); } - static MVT getVectorVT(MVT VT, MVT::ElementCount EC) { + static MVT getVectorVT(MVT VT, ElementCount EC) { if (EC.Scalable) return getScalableVectorVT(VT, EC.Min); return getVectorVT(VT, EC.Min); @@ -1108,26 +1121,40 @@ namespace llvm { (MVT::SimpleValueType)(MVT::LAST_VECTOR_VALUETYPE + 1)); } - static mvt_range integer_vector_valuetypes() { + static mvt_range fixedlen_vector_valuetypes() { return mvt_range( - MVT::FIRST_INTEGER_VECTOR_VALUETYPE, - (MVT::SimpleValueType)(MVT::LAST_INTEGER_VECTOR_VALUETYPE + 1)); + MVT::FIRST_FIXEDLEN_VECTOR_VALUETYPE, + (MVT::SimpleValueType)(MVT::LAST_FIXEDLEN_VECTOR_VALUETYPE + 1)); } - static mvt_range fp_vector_valuetypes() { + static mvt_range scalable_vector_valuetypes() { return mvt_range( - MVT::FIRST_FP_VECTOR_VALUETYPE, - (MVT::SimpleValueType)(MVT::LAST_FP_VECTOR_VALUETYPE + 1)); + MVT::FIRST_SCALABLE_VECTOR_VALUETYPE, + (MVT::SimpleValueType)(MVT::LAST_SCALABLE_VECTOR_VALUETYPE + 1)); + } + + static mvt_range integer_fixedlen_vector_valuetypes() { + return mvt_range( + MVT::FIRST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE, + (MVT::SimpleValueType)(MVT::LAST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE + 1)); + } + + static mvt_range fp_fixedlen_vector_valuetypes() { + return mvt_range( + MVT::FIRST_FP_FIXEDLEN_VECTOR_VALUETYPE, + (MVT::SimpleValueType)(MVT::LAST_FP_FIXEDLEN_VECTOR_VALUETYPE + 1)); } static mvt_range integer_scalable_vector_valuetypes() { - return mvt_range(MVT::FIRST_INTEGER_SCALABLE_VALUETYPE, - (MVT::SimpleValueType)(MVT::LAST_INTEGER_SCALABLE_VALUETYPE + 1)); + return mvt_range( + MVT::FIRST_INTEGER_SCALABLE_VECTOR_VALUETYPE, + (MVT::SimpleValueType)(MVT::LAST_INTEGER_SCALABLE_VECTOR_VALUETYPE + 1)); } static mvt_range fp_scalable_vector_valuetypes() { - return mvt_range(MVT::FIRST_FP_SCALABLE_VALUETYPE, - (MVT::SimpleValueType)(MVT::LAST_FP_SCALABLE_VALUETYPE + 1)); + return mvt_range( + MVT::FIRST_FP_SCALABLE_VECTOR_VALUETYPE, + (MVT::SimpleValueType)(MVT::LAST_FP_SCALABLE_VECTOR_VALUETYPE + 1)); } /// @} }; diff --git a/include/llvm/Support/MathExtras.h b/include/llvm/Support/MathExtras.h index 249139e824b5..004a6f5f6eb8 100644 --- a/include/llvm/Support/MathExtras.h +++ b/include/llvm/Support/MathExtras.h @@ -39,6 +39,7 @@ unsigned char _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask); #endif namespace llvm { + /// The behavior an operation has on an input of 0. enum ZeroBehavior { /// The returned value is undefined. @@ -49,6 +50,42 @@ enum ZeroBehavior { ZB_Width }; +/// Mathematical constants. +namespace numbers { +// TODO: Track C++20 std::numbers. +// TODO: Favor using the hexadecimal FP constants (requires C++17). +constexpr double e = 2.7182818284590452354, // (0x1.5bf0a8b145749P+1) https://oeis.org/A001113 + egamma = .57721566490153286061, // (0x1.2788cfc6fb619P-1) https://oeis.org/A001620 + ln2 = .69314718055994530942, // (0x1.62e42fefa39efP-1) https://oeis.org/A002162 + ln10 = 2.3025850929940456840, // (0x1.24bb1bbb55516P+1) https://oeis.org/A002392 + log2e = 1.4426950408889634074, // (0x1.71547652b82feP+0) + log10e = .43429448190325182765, // (0x1.bcb7b1526e50eP-2) + pi = 3.1415926535897932385, // (0x1.921fb54442d18P+1) https://oeis.org/A000796 + inv_pi = .31830988618379067154, // (0x1.45f306bc9c883P-2) https://oeis.org/A049541 + sqrtpi = 1.7724538509055160273, // (0x1.c5bf891b4ef6bP+0) https://oeis.org/A002161 + inv_sqrtpi = .56418958354775628695, // (0x1.20dd750429b6dP-1) https://oeis.org/A087197 + sqrt2 = 1.4142135623730950488, // (0x1.6a09e667f3bcdP+0) https://oeis.org/A00219 + inv_sqrt2 = .70710678118654752440, // (0x1.6a09e667f3bcdP-1) + sqrt3 = 1.7320508075688772935, // (0x1.bb67ae8584caaP+0) https://oeis.org/A002194 + inv_sqrt3 = .57735026918962576451, // (0x1.279a74590331cP-1) + phi = 1.6180339887498948482; // (0x1.9e3779b97f4a8P+0) https://oeis.org/A001622 +constexpr float ef = 2.71828183F, // (0x1.5bf0a8P+1) https://oeis.org/A001113 + egammaf = .577215665F, // (0x1.2788d0P-1) https://oeis.org/A001620 + ln2f = .693147181F, // (0x1.62e430P-1) https://oeis.org/A002162 + ln10f = 2.30258509F, // (0x1.26bb1cP+1) https://oeis.org/A002392 + log2ef = 1.44269504F, // (0x1.715476P+0) + log10ef = .434294482F, // (0x1.bcb7b2P-2) + pif = 3.14159265F, // (0x1.921fb6P+1) https://oeis.org/A000796 + inv_pif = .318309886F, // (0x1.45f306P-2) https://oeis.org/A049541 + sqrtpif = 1.77245385F, // (0x1.c5bf8aP+0) https://oeis.org/A002161 + inv_sqrtpif = .564189584F, // (0x1.20dd76P-1) https://oeis.org/A087197 + sqrt2f = 1.41421356F, // (0x1.6a09e6P+0) https://oeis.org/A002193 + inv_sqrt2f = .707106781F, // (0x1.6a09e6P-1) + sqrt3f = 1.73205081F, // (0x1.bb67aeP+0) https://oeis.org/A002194 + inv_sqrt3f = .577350269F, // (0x1.279a74P-1) + phif = 1.61803399F; // (0x1.9e377aP+0) https://oeis.org/A001622 +} // namespace numbers + namespace detail { template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter { static unsigned count(T Val, ZeroBehavior) { @@ -73,13 +110,13 @@ template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter { } }; -#if __GNUC__ >= 4 || defined(_MSC_VER) +#if defined(__GNUC__) || defined(_MSC_VER) template <typename T> struct TrailingZerosCounter<T, 4> { static unsigned count(T Val, ZeroBehavior ZB) { if (ZB != ZB_Undefined && Val == 0) return 32; -#if __has_builtin(__builtin_ctz) || LLVM_GNUC_PREREQ(4, 0, 0) +#if __has_builtin(__builtin_ctz) || defined(__GNUC__) return __builtin_ctz(Val); #elif defined(_MSC_VER) unsigned long Index; @@ -95,7 +132,7 @@ template <typename T> struct TrailingZerosCounter<T, 8> { if (ZB != ZB_Undefined && Val == 0) return 64; -#if __has_builtin(__builtin_ctzll) || LLVM_GNUC_PREREQ(4, 0, 0) +#if __has_builtin(__builtin_ctzll) || defined(__GNUC__) return __builtin_ctzll(Val); #elif defined(_MSC_VER) unsigned long Index; @@ -142,13 +179,13 @@ template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter { } }; -#if __GNUC__ >= 4 || defined(_MSC_VER) +#if defined(__GNUC__) || defined(_MSC_VER) template <typename T> struct LeadingZerosCounter<T, 4> { static unsigned count(T Val, ZeroBehavior ZB) { if (ZB != ZB_Undefined && Val == 0) return 32; -#if __has_builtin(__builtin_clz) || LLVM_GNUC_PREREQ(4, 0, 0) +#if __has_builtin(__builtin_clz) || defined(__GNUC__) return __builtin_clz(Val); #elif defined(_MSC_VER) unsigned long Index; @@ -164,7 +201,7 @@ template <typename T> struct LeadingZerosCounter<T, 8> { if (ZB != ZB_Undefined && Val == 0) return 64; -#if __has_builtin(__builtin_clzll) || LLVM_GNUC_PREREQ(4, 0, 0) +#if __has_builtin(__builtin_clzll) || defined(__GNUC__) return __builtin_clzll(Val); #elif defined(_MSC_VER) unsigned long Index; @@ -486,7 +523,7 @@ template <typename T, std::size_t SizeOfT> struct PopulationCounter { static unsigned count(T Value) { // Generic version, forward to 32 bits. static_assert(SizeOfT <= 4, "Not implemented!"); -#if __GNUC__ >= 4 +#if defined(__GNUC__) return __builtin_popcount(Value); #else uint32_t v = Value; @@ -499,7 +536,7 @@ template <typename T, std::size_t SizeOfT> struct PopulationCounter { template <typename T> struct PopulationCounter<T, 8> { static unsigned count(T Value) { -#if __GNUC__ >= 4 +#if defined(__GNUC__) return __builtin_popcountll(Value); #else uint64_t v = Value; @@ -523,6 +560,16 @@ inline unsigned countPopulation(T Value) { return detail::PopulationCounter<T, sizeof(T)>::count(Value); } +/// Compile time Log2. +/// Valid only for positive powers of two. +template <size_t kValue> constexpr inline size_t CTLog2() { + static_assert(kValue > 0 && llvm::isPowerOf2_64(kValue), + "Value is not a valid power of 2"); + return 1 + CTLog2<kValue / 2>(); +} + +template <> constexpr inline size_t CTLog2<1>() { return 0; } + /// Return the log base 2 of the specified value. inline double Log2(double Value) { #if defined(__ANDROID_API__) && __ANDROID_API__ < 18 @@ -620,25 +667,6 @@ constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) { return (A | B) & (1 + ~(A | B)); } -/// Aligns \c Addr to \c Alignment bytes, rounding up. -/// -/// Alignment should be a power of two. This method rounds up, so -/// alignAddr(7, 4) == 8 and alignAddr(8, 4) == 8. -inline uintptr_t alignAddr(const void *Addr, size_t Alignment) { - assert(Alignment && isPowerOf2_64((uint64_t)Alignment) && - "Alignment is not a power of two!"); - - assert((uintptr_t)Addr + Alignment - 1 >= (uintptr_t)Addr); - - return (((uintptr_t)Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1)); -} - -/// Returns the necessary adjustment for aligning \c Ptr to \c Alignment -/// bytes, rounding up. -inline size_t alignmentAdjustment(const void *Ptr, size_t Alignment) { - return alignAddr(Ptr, Alignment) - (uintptr_t)Ptr; -} - /// Returns the next power of two (in 64-bits) that is strictly greater than A. /// Returns zero on overflow. inline uint64_t NextPowerOf2(uint64_t A) { @@ -704,19 +732,6 @@ inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) { return alignTo(Numerator, Denominator) / Denominator; } -/// \c alignTo for contexts where a constant expression is required. -/// \sa alignTo -/// -/// \todo FIXME: remove when \c constexpr becomes really \c constexpr -template <uint64_t Align> -struct AlignTo { - static_assert(Align != 0u, "Align must be non-zero"); - template <uint64_t Value> - struct from_value { - static const uint64_t value = (Value + Align - 1) / Align * Align; - }; -}; - /// Returns the largest uint64_t less than or equal to \p Value and is /// \p Skew mod \p Align. \p Align must be non-zero inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) { @@ -725,13 +740,6 @@ inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) { return (Value - Skew) / Align * Align + Skew; } -/// Returns the offset to the next integer (mod 2**64) that is greater than -/// or equal to \p Value and is a multiple of \p Align. \p Align must be -/// non-zero. -inline uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align) { - return alignTo(Value, Align) - Value; -} - /// Sign-extend the number in the bottom B bits of X to a 32-bit integer. /// Requires 0 < B <= 32. template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) { @@ -853,6 +861,91 @@ SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) { /// Use this rather than HUGE_VALF; the latter causes warnings on MSVC. extern const float huge_valf; + + +/// Add two signed integers, computing the two's complement truncated result, +/// returning true if overflow occured. +template <typename T> +typename std::enable_if<std::is_signed<T>::value, T>::type +AddOverflow(T X, T Y, T &Result) { +#if __has_builtin(__builtin_add_overflow) + return __builtin_add_overflow(X, Y, &Result); +#else + // Perform the unsigned addition. + using U = typename std::make_unsigned<T>::type; + const U UX = static_cast<U>(X); + const U UY = static_cast<U>(Y); + const U UResult = UX + UY; + + // Convert to signed. + Result = static_cast<T>(UResult); + + // Adding two positive numbers should result in a positive number. + if (X > 0 && Y > 0) + return Result <= 0; + // Adding two negatives should result in a negative number. + if (X < 0 && Y < 0) + return Result >= 0; + return false; +#endif +} + +/// Subtract two signed integers, computing the two's complement truncated +/// result, returning true if an overflow ocurred. +template <typename T> +typename std::enable_if<std::is_signed<T>::value, T>::type +SubOverflow(T X, T Y, T &Result) { +#if __has_builtin(__builtin_sub_overflow) + return __builtin_sub_overflow(X, Y, &Result); +#else + // Perform the unsigned addition. + using U = typename std::make_unsigned<T>::type; + const U UX = static_cast<U>(X); + const U UY = static_cast<U>(Y); + const U UResult = UX - UY; + + // Convert to signed. + Result = static_cast<T>(UResult); + + // Subtracting a positive number from a negative results in a negative number. + if (X <= 0 && Y > 0) + return Result >= 0; + // Subtracting a negative number from a positive results in a positive number. + if (X >= 0 && Y < 0) + return Result <= 0; + return false; +#endif +} + + +/// Multiply two signed integers, computing the two's complement truncated +/// result, returning true if an overflow ocurred. +template <typename T> +typename std::enable_if<std::is_signed<T>::value, T>::type +MulOverflow(T X, T Y, T &Result) { + // Perform the unsigned multiplication on absolute values. + using U = typename std::make_unsigned<T>::type; + const U UX = X < 0 ? (0 - static_cast<U>(X)) : static_cast<U>(X); + const U UY = Y < 0 ? (0 - static_cast<U>(Y)) : static_cast<U>(Y); + const U UResult = UX * UY; + + // Convert to signed. + const bool IsNegative = (X < 0) ^ (Y < 0); + Result = IsNegative ? (0 - UResult) : UResult; + + // If any of the args was 0, result is 0 and no overflow occurs. + if (UX == 0 || UY == 0) + return false; + + // UX and UY are in [1, 2^n], where n is the number of digits. + // Check how the max allowed absolute value (2^n for negative, 2^(n-1) for + // positive) divided by an argument compares to the other. + if (IsNegative) + return UX > (static_cast<U>(std::numeric_limits<T>::max()) + U(1)) / UY; + else + return UX > (static_cast<U>(std::numeric_limits<T>::max())) / UY; +} + } // End llvm namespace #endif diff --git a/include/llvm/Support/Mutex.h b/include/llvm/Support/Mutex.h index c3abfc7a7806..1d8a0d3c87cb 100644 --- a/include/llvm/Support/Mutex.h +++ b/include/llvm/Support/Mutex.h @@ -13,97 +13,31 @@ #ifndef LLVM_SUPPORT_MUTEX_H #define LLVM_SUPPORT_MUTEX_H -#include "llvm/Config/llvm-config.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Threading.h" #include <cassert> +#include <mutex> namespace llvm { namespace sys { - /// Platform agnostic Mutex class. - class MutexImpl - { - /// @name Constructors - /// @{ - public: - - /// Initializes the lock but doesn't acquire it. if \p recursive is set - /// to false, the lock will not be recursive which makes it cheaper but - /// also more likely to deadlock (same thread can't acquire more than - /// once). - /// Default Constructor. - explicit MutexImpl(bool recursive = true); - - /// Releases and removes the lock - /// Destructor - ~MutexImpl(); - - /// @} - /// @name Methods - /// @{ - public: - - /// Attempts to unconditionally acquire the lock. If the lock is held by - /// another thread, this method will wait until it can acquire the lock. - /// @returns false if any kind of error occurs, true otherwise. - /// Unconditionally acquire the lock. - bool acquire(); - - /// Attempts to release the lock. If the lock is held by the current - /// thread, the lock is released allowing other threads to acquire the - /// lock. - /// @returns false if any kind of error occurs, true otherwise. - /// Unconditionally release the lock. - bool release(); - - /// Attempts to acquire the lock without blocking. If the lock is not - /// available, this function returns false quickly (without blocking). If - /// the lock is available, it is acquired. - /// @returns false if any kind of error occurs or the lock is not - /// available, true otherwise. - /// Try to acquire the lock. - bool tryacquire(); - - //@} - /// @name Platform Dependent Data - /// @{ - private: -#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0 - void* data_; ///< We don't know what the data will be -#endif - - /// @} - /// @name Do Not Implement - /// @{ - private: - MutexImpl(const MutexImpl &) = delete; - void operator=(const MutexImpl &) = delete; - /// @} - }; - - /// SmartMutex - A mutex with a compile time constant parameter that /// indicates whether this mutex should become a no-op when we're not /// running in multithreaded mode. template<bool mt_only> class SmartMutex { - MutexImpl impl; - unsigned acquired; - bool recursive; - public: - explicit SmartMutex(bool rec = true) : - impl(rec), acquired(0), recursive(rec) { } + std::recursive_mutex impl; + unsigned acquired = 0; + public: bool lock() { if (!mt_only || llvm_is_multithreaded()) { - return impl.acquire(); + impl.lock(); + return true; } else { // Single-threaded debugging code. This would be racy in // multithreaded mode, but provides not sanity checks in single // threaded mode. - assert((recursive || acquired == 0) && "Lock already acquired!!"); ++acquired; return true; } @@ -111,13 +45,13 @@ namespace llvm bool unlock() { if (!mt_only || llvm_is_multithreaded()) { - return impl.release(); + impl.unlock(); + return true; } else { // Single-threaded debugging code. This would be racy in // multithreaded mode, but provides not sanity checks in single // threaded mode. - assert(((recursive && acquired) || (acquired == 1)) && - "Lock not acquired before release!"); + assert(acquired && "Lock not acquired before release!"); --acquired; return true; } @@ -125,31 +59,16 @@ namespace llvm bool try_lock() { if (!mt_only || llvm_is_multithreaded()) - return impl.tryacquire(); + return impl.try_lock(); else return true; } - - private: - SmartMutex(const SmartMutex<mt_only> & original); - void operator=(const SmartMutex<mt_only> &); }; /// Mutex - A standard, always enforced mutex. typedef SmartMutex<false> Mutex; - template<bool mt_only> - class SmartScopedLock { - SmartMutex<mt_only>& mtx; - - public: - SmartScopedLock(SmartMutex<mt_only>& m) : mtx(m) { - mtx.lock(); - } - - ~SmartScopedLock() { - mtx.unlock(); - } - }; + template <bool mt_only> + using SmartScopedLock = std::lock_guard<SmartMutex<mt_only>>; typedef SmartScopedLock<false> ScopedLock; } diff --git a/include/llvm/Support/MutexGuard.h b/include/llvm/Support/MutexGuard.h deleted file mode 100644 index d86ced145816..000000000000 --- a/include/llvm/Support/MutexGuard.h +++ /dev/null @@ -1,40 +0,0 @@ -//===-- Support/MutexGuard.h - Acquire/Release Mutex In Scope ---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines a guard for a block of code that ensures a Mutex is locked -// upon construction and released upon destruction. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SUPPORT_MUTEXGUARD_H -#define LLVM_SUPPORT_MUTEXGUARD_H - -#include "llvm/Support/Mutex.h" - -namespace llvm { - /// Instances of this class acquire a given Mutex Lock when constructed and - /// hold that lock until destruction. The intention is to instantiate one of - /// these on the stack at the top of some scope to be assured that C++ - /// destruction of the object will always release the Mutex and thus avoid - /// a host of nasty multi-threading problems in the face of exceptions, etc. - /// Guard a section of code with a Mutex. - class MutexGuard { - sys::Mutex &M; - MutexGuard(const MutexGuard &) = delete; - void operator=(const MutexGuard &) = delete; - public: - MutexGuard(sys::Mutex &m) : M(m) { M.lock(); } - ~MutexGuard() { M.unlock(); } - /// holds - Returns true if this locker instance holds the specified lock. - /// This is mostly used in assertions to validate that the correct mutex - /// is held. - bool holds(const sys::Mutex& lock) const { return &M == &lock; } - }; -} - -#endif // LLVM_SUPPORT_MUTEXGUARD_H diff --git a/include/llvm/Support/OnDiskHashTable.h b/include/llvm/Support/OnDiskHashTable.h index d84da92aab9b..11dc0de0f354 100644 --- a/include/llvm/Support/OnDiskHashTable.h +++ b/include/llvm/Support/OnDiskHashTable.h @@ -13,6 +13,7 @@ #ifndef LLVM_SUPPORT_ONDISKHASHTABLE_H #define LLVM_SUPPORT_ONDISKHASHTABLE_H +#include "llvm/Support/Alignment.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/EndianStream.h" @@ -207,7 +208,7 @@ public: // Pad with zeros so that we can start the hashtable at an aligned address. offset_type TableOff = Out.tell(); - uint64_t N = llvm::OffsetToAlignment(TableOff, alignof(offset_type)); + uint64_t N = offsetToAlignment(TableOff, Align(alignof(offset_type))); TableOff += N; while (N--) LE.write<uint8_t>(0); diff --git a/include/llvm/Support/Parallel.h b/include/llvm/Support/Parallel.h index eab9b492c4a5..3c0ed2c11127 100644 --- a/include/llvm/Support/Parallel.h +++ b/include/llvm/Support/Parallel.h @@ -18,14 +18,6 @@ #include <functional> #include <mutex> -#if defined(_MSC_VER) && LLVM_ENABLE_THREADS -#pragma warning(push) -#pragma warning(disable : 4530) -#include <concrt.h> -#include <ppl.h> -#pragma warning(pop) -#endif - namespace llvm { namespace parallel { @@ -84,23 +76,6 @@ public: void sync() const { L.sync(); } }; -#if defined(_MSC_VER) -template <class RandomAccessIterator, class Comparator> -void parallel_sort(RandomAccessIterator Start, RandomAccessIterator End, - const Comparator &Comp) { - concurrency::parallel_sort(Start, End, Comp); -} -template <class IterTy, class FuncTy> -void parallel_for_each(IterTy Begin, IterTy End, FuncTy Fn) { - concurrency::parallel_for_each(Begin, End, Fn); -} - -template <class IndexTy, class FuncTy> -void parallel_for_each_n(IndexTy Begin, IndexTy End, FuncTy Fn) { - concurrency::parallel_for(Begin, End, Fn); -} - -#else const ptrdiff_t MinParallelSize = 1024; /// Inclusive median. @@ -188,8 +163,6 @@ void parallel_for_each_n(IndexTy Begin, IndexTy End, FuncTy Fn) { #endif -#endif - template <typename Iter> using DefComparator = std::less<typename std::iterator_traits<Iter>::value_type>; diff --git a/include/llvm/Support/RWMutex.h b/include/llvm/Support/RWMutex.h index 9cd57cbd65a1..150bc7dbbce1 100644 --- a/include/llvm/Support/RWMutex.h +++ b/include/llvm/Support/RWMutex.h @@ -16,161 +16,184 @@ #include "llvm/Config/llvm-config.h" #include "llvm/Support/Threading.h" #include <cassert> +#include <mutex> +#include <shared_mutex> + +// std::shared_timed_mutex is only availble on macOS 10.12 and later. +#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101200 +#define LLVM_USE_RW_MUTEX_IMPL +#endif +#endif namespace llvm { namespace sys { - /// Platform agnostic RWMutex class. - class RWMutexImpl - { - /// @name Constructors - /// @{ - public: - - /// Initializes the lock but doesn't acquire it. - /// Default Constructor. - explicit RWMutexImpl(); - - /// @} - /// @name Do Not Implement - /// @{ - RWMutexImpl(const RWMutexImpl & original) = delete; - RWMutexImpl &operator=(const RWMutexImpl &) = delete; - /// @} - - /// Releases and removes the lock - /// Destructor - ~RWMutexImpl(); - - /// @} - /// @name Methods - /// @{ - public: - - /// Attempts to unconditionally acquire the lock in reader mode. If the - /// lock is held by a writer, this method will wait until it can acquire - /// the lock. - /// @returns false if any kind of error occurs, true otherwise. - /// Unconditionally acquire the lock in reader mode. - bool reader_acquire(); - - /// Attempts to release the lock in reader mode. - /// @returns false if any kind of error occurs, true otherwise. - /// Unconditionally release the lock in reader mode. - bool reader_release(); - - /// Attempts to unconditionally acquire the lock in reader mode. If the - /// lock is held by any readers, this method will wait until it can - /// acquire the lock. - /// @returns false if any kind of error occurs, true otherwise. - /// Unconditionally acquire the lock in writer mode. - bool writer_acquire(); - - /// Attempts to release the lock in writer mode. - /// @returns false if any kind of error occurs, true otherwise. - /// Unconditionally release the lock in write mode. - bool writer_release(); - - //@} - /// @name Platform Dependent Data - /// @{ - private: +#if defined(LLVM_USE_RW_MUTEX_IMPL) +/// Platform agnostic RWMutex class. +class RWMutexImpl { + /// @name Constructors + /// @{ +public: + /// Initializes the lock but doesn't acquire it. + /// Default Constructor. + explicit RWMutexImpl(); + + /// @} + /// @name Do Not Implement + /// @{ + RWMutexImpl(const RWMutexImpl &original) = delete; + RWMutexImpl &operator=(const RWMutexImpl &) = delete; + /// @} + + /// Releases and removes the lock + /// Destructor + ~RWMutexImpl(); + + /// @} + /// @name Methods + /// @{ +public: + /// Attempts to unconditionally acquire the lock in reader mode. If the + /// lock is held by a writer, this method will wait until it can acquire + /// the lock. + /// @returns false if any kind of error occurs, true otherwise. + /// Unconditionally acquire the lock in reader mode. + bool lock_shared(); + + /// Attempts to release the lock in reader mode. + /// @returns false if any kind of error occurs, true otherwise. + /// Unconditionally release the lock in reader mode. + bool unlock_shared(); + + /// Attempts to unconditionally acquire the lock in reader mode. If the + /// lock is held by any readers, this method will wait until it can + /// acquire the lock. + /// @returns false if any kind of error occurs, true otherwise. + /// Unconditionally acquire the lock in writer mode. + bool lock(); + + /// Attempts to release the lock in writer mode. + /// @returns false if any kind of error occurs, true otherwise. + /// Unconditionally release the lock in write mode. + bool unlock(); + + //@} + /// @name Platform Dependent Data + /// @{ +private: #if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0 - void* data_ = nullptr; ///< We don't know what the data will be + void *data_ = nullptr; ///< We don't know what the data will be +#endif +}; +#endif + +/// SmartMutex - An R/W mutex with a compile time constant parameter that +/// indicates whether this mutex should become a no-op when we're not +/// running in multithreaded mode. +template <bool mt_only> class SmartRWMutex { + // shared_mutex (C++17) is more efficient than shared_timed_mutex (C++14) + // on Windows and always available on MSVC. +#if defined(_MSC_VER) || __cplusplus > 201402L + std::shared_mutex impl; +#else +#if !defined(LLVM_USE_RW_MUTEX_IMPL) + std::shared_timed_mutex impl; +#else + RWMutexImpl impl; +#endif +#endif + unsigned readers = 0; + unsigned writers = 0; + +public: + bool lock_shared() { + if (!mt_only || llvm_is_multithreaded()) { + impl.lock_shared(); + return true; + } + + // Single-threaded debugging code. This would be racy in multithreaded + // mode, but provides not sanity checks in single threaded mode. + ++readers; + return true; + } + + bool unlock_shared() { + if (!mt_only || llvm_is_multithreaded()) { + impl.unlock_shared(); + return true; + } + + // Single-threaded debugging code. This would be racy in multithreaded + // mode, but provides not sanity checks in single threaded mode. + assert(readers > 0 && "Reader lock not acquired before release!"); + --readers; + return true; + } + + bool lock() { + if (!mt_only || llvm_is_multithreaded()) { + impl.lock(); + return true; + } + + // Single-threaded debugging code. This would be racy in multithreaded + // mode, but provides not sanity checks in single threaded mode. + assert(writers == 0 && "Writer lock already acquired!"); + ++writers; + return true; + } + + bool unlock() { + if (!mt_only || llvm_is_multithreaded()) { + impl.unlock(); + return true; + } + + // Single-threaded debugging code. This would be racy in multithreaded + // mode, but provides not sanity checks in single threaded mode. + assert(writers == 1 && "Writer lock not acquired before release!"); + --writers; + return true; + } +}; + +typedef SmartRWMutex<false> RWMutex; + +/// ScopedReader - RAII acquisition of a reader lock +#if !defined(LLVM_USE_RW_MUTEX_IMPL) +template <bool mt_only> +using SmartScopedReader = const std::shared_lock<SmartRWMutex<mt_only>>; +#else +template <bool mt_only> struct SmartScopedReader { + SmartRWMutex<mt_only> &mutex; + + explicit SmartScopedReader(SmartRWMutex<mt_only> &m) : mutex(m) { + mutex.lock_shared(); + } + + ~SmartScopedReader() { mutex.unlock_shared(); } +}; +#endif +typedef SmartScopedReader<false> ScopedReader; + +/// ScopedWriter - RAII acquisition of a writer lock +#if !defined(LLVM_USE_RW_MUTEX_IMPL) +template <bool mt_only> +using SmartScopedWriter = std::lock_guard<SmartRWMutex<mt_only>>; +#else +template <bool mt_only> struct SmartScopedWriter { + SmartRWMutex<mt_only> &mutex; + + explicit SmartScopedWriter(SmartRWMutex<mt_only> &m) : mutex(m) { + mutex.lock(); + } + + ~SmartScopedWriter() { mutex.unlock(); } +}; #endif - }; - - /// SmartMutex - An R/W mutex with a compile time constant parameter that - /// indicates whether this mutex should become a no-op when we're not - /// running in multithreaded mode. - template<bool mt_only> - class SmartRWMutex { - RWMutexImpl impl; - unsigned readers = 0; - unsigned writers = 0; - - 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()) - return impl.reader_acquire(); - - // Single-threaded debugging code. This would be racy in multithreaded - // mode, but provides not sanity checks in single threaded mode. - ++readers; - return true; - } - - bool unlock_shared() { - if (!mt_only || llvm_is_multithreaded()) - return impl.reader_release(); - - // Single-threaded debugging code. This would be racy in multithreaded - // mode, but provides not sanity checks in single threaded mode. - assert(readers > 0 && "Reader lock not acquired before release!"); - --readers; - return true; - } - - bool lock() { - if (!mt_only || llvm_is_multithreaded()) - return impl.writer_acquire(); - - // Single-threaded debugging code. This would be racy in multithreaded - // mode, but provides not sanity checks in single threaded mode. - assert(writers == 0 && "Writer lock already acquired!"); - ++writers; - return true; - } - - bool unlock() { - if (!mt_only || llvm_is_multithreaded()) - return impl.writer_release(); - - // Single-threaded debugging code. This would be racy in multithreaded - // mode, but provides not sanity checks in single threaded mode. - assert(writers == 1 && "Writer lock not acquired before release!"); - --writers; - return true; - } - }; - - typedef SmartRWMutex<false> RWMutex; - - /// ScopedReader - RAII acquisition of a reader lock - template<bool mt_only> - struct SmartScopedReader { - SmartRWMutex<mt_only>& mutex; - - explicit SmartScopedReader(SmartRWMutex<mt_only>& m) : mutex(m) { - mutex.lock_shared(); - } - - ~SmartScopedReader() { - mutex.unlock_shared(); - } - }; - - typedef SmartScopedReader<false> ScopedReader; - - /// ScopedWriter - RAII acquisition of a writer lock - template<bool mt_only> - struct SmartScopedWriter { - SmartRWMutex<mt_only>& mutex; - - explicit SmartScopedWriter(SmartRWMutex<mt_only>& m) : mutex(m) { - mutex.lock(); - } - - ~SmartScopedWriter() { - mutex.unlock(); - } - }; - - typedef SmartScopedWriter<false> ScopedWriter; +typedef SmartScopedWriter<false> ScopedWriter; } // end namespace sys } // end namespace llvm diff --git a/include/llvm/Support/Regex.h b/include/llvm/Support/Regex.h index 2d19b10fd890..b2620ab4cfc9 100644 --- a/include/llvm/Support/Regex.h +++ b/include/llvm/Support/Regex.h @@ -44,6 +44,9 @@ namespace llvm { Regex(); /// Compiles the given regular expression \p Regex. + /// + /// \param Regex - referenced string is no longer needed after this + /// constructor does finish. Only its compiled form is kept stored. Regex(StringRef Regex, unsigned Flags = NoFlags); Regex(const Regex &) = delete; Regex &operator=(Regex regex) { @@ -54,9 +57,10 @@ namespace llvm { Regex(Regex &®ex); ~Regex(); - /// isValid - returns the error encountered during regex compilation, or - /// matching, if any. + /// isValid - returns the error encountered during regex compilation, if + /// any. bool isValid(std::string &Error) const; + bool isValid() const { return !error; } /// getNumMatches - In a valid regex, return the number of parenthesized /// matches it contains. The number filled in by match will include this @@ -69,8 +73,12 @@ namespace llvm { /// with references to the matched group expressions (inside \p String), /// the first group is always the entire pattern. /// + /// \param Error - If non-null, any errors in the matching will be recorded + /// as a non-empty string. If there is no error, it will be an empty string. + /// /// This returns true on a successful match. - bool match(StringRef String, SmallVectorImpl<StringRef> *Matches = nullptr); + bool match(StringRef String, SmallVectorImpl<StringRef> *Matches = nullptr, + std::string *Error = nullptr) const; /// sub - Return the result of replacing the first match of the regex in /// \p String with the \p Repl string. Backreferences like "\0" in the @@ -81,9 +89,9 @@ namespace llvm { /// /// \param Error If non-null, any errors in the substitution (invalid /// backreferences, trailing backslashes) will be recorded as a non-empty - /// string. + /// string. If there is no error, it will be an empty string. std::string sub(StringRef Repl, StringRef String, - std::string *Error = nullptr); + std::string *Error = nullptr) const; /// If this function returns true, ^Str$ is an extended regular /// expression that matches Str and only Str. diff --git a/include/llvm/Support/Registry.h b/include/llvm/Support/Registry.h index 4d8aa5f1470d..5bb6a254a47f 100644 --- a/include/llvm/Support/Registry.h +++ b/include/llvm/Support/Registry.h @@ -115,7 +115,7 @@ namespace llvm { entry Entry; node Node; - static std::unique_ptr<T> CtorFn() { return make_unique<V>(); } + static std::unique_ptr<T> CtorFn() { return std::make_unique<V>(); } public: Add(StringRef Name, StringRef Desc) diff --git a/include/llvm/Support/SHA1.h b/include/llvm/Support/SHA1.h index 87fe94bbd5cd..2cfbd2179364 100644 --- a/include/llvm/Support/SHA1.h +++ b/include/llvm/Support/SHA1.h @@ -16,13 +16,13 @@ #define LLVM_SUPPORT_SHA1_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" #include <array> #include <cstdint> namespace llvm { template <typename T> class ArrayRef; -class StringRef; /// A class that wrap the SHA1 algorithm. class SHA1 { diff --git a/include/llvm/Support/ScalableSize.h b/include/llvm/Support/ScalableSize.h deleted file mode 100644 index 96bf043773a0..000000000000 --- a/include/llvm/Support/ScalableSize.h +++ /dev/null @@ -1,43 +0,0 @@ -//===- ScalableSize.h - Scalable vector size info ---------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file provides a struct that can be used to query the size of IR types -// which may be scalable vectors. It provides convenience operators so that -// it can be used in much the same way as a single scalar value. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SUPPORT_SCALABLESIZE_H -#define LLVM_SUPPORT_SCALABLESIZE_H - -namespace llvm { - -class ElementCount { -public: - unsigned Min; // Minimum number of vector elements. - bool Scalable; // If true, NumElements is a multiple of 'Min' determined - // at runtime rather than compile time. - - ElementCount(unsigned Min, bool Scalable) - : Min(Min), Scalable(Scalable) {} - - ElementCount operator*(unsigned RHS) { - return { Min * RHS, Scalable }; - } - ElementCount operator/(unsigned RHS) { - return { Min / RHS, Scalable }; - } - - bool operator==(const ElementCount& RHS) const { - return Min == RHS.Min && Scalable == RHS.Scalable; - } -}; - -} // end namespace llvm - -#endif // LLVM_SUPPORT_SCALABLESIZE_H diff --git a/include/llvm/Support/Signals.h b/include/llvm/Support/Signals.h index a6b215a24311..a4f1fad22dd5 100644 --- a/include/llvm/Support/Signals.h +++ b/include/llvm/Support/Signals.h @@ -84,6 +84,17 @@ namespace sys { /// function. Note also that the handler may be executed on a different /// thread on some platforms. void SetInfoSignalFunction(void (*Handler)()); + + /// Registers a function to be called when a "pipe" signal is delivered to + /// the process. + /// + /// The "pipe" signal typically indicates a failed write to a pipe (SIGPIPE). + /// The default installed handler calls `exit(EX_IOERR)`, causing the process + /// to immediately exit with an IO error exit code. + /// + /// This function is only applicable on POSIX systems. + void SetPipeSignalFunction(void (*Handler)()); + } // End sys namespace } // End llvm namespace diff --git a/include/llvm/Support/SwapByteOrder.h b/include/llvm/Support/SwapByteOrder.h index 06a447a27c2a..6cec87006c02 100644 --- a/include/llvm/Support/SwapByteOrder.h +++ b/include/llvm/Support/SwapByteOrder.h @@ -22,9 +22,37 @@ #include <stdlib.h> #endif +#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) +#include <endian.h> +#elif defined(_AIX) +#include <sys/machine.h> +#elif defined(__sun) +/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */ +#include <sys/types.h> +#define BIG_ENDIAN 4321 +#define LITTLE_ENDIAN 1234 +#if defined(_BIG_ENDIAN) +#define BYTE_ORDER BIG_ENDIAN +#else +#define BYTE_ORDER LITTLE_ENDIAN +#endif +#else +#if !defined(BYTE_ORDER) && !defined(_WIN32) +#include <machine/endian.h> +#endif +#endif + namespace llvm { namespace sys { +#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN +constexpr bool IsBigEndianHost = true; +#else +constexpr bool IsBigEndianHost = false; +#endif + +static const bool IsLittleEndianHost = !IsBigEndianHost; + /// SwapByteOrder_16 - This function returns a byte-swapped representation of /// the 16-bit argument. inline uint16_t SwapByteOrder_16(uint16_t value) { @@ -39,10 +67,9 @@ inline uint16_t SwapByteOrder_16(uint16_t value) { #endif } -/// SwapByteOrder_32 - This function returns a byte-swapped representation of -/// the 32-bit argument. +/// This function returns a byte-swapped representation of the 32-bit argument. inline uint32_t SwapByteOrder_32(uint32_t value) { -#if defined(__llvm__) || (LLVM_GNUC_PREREQ(4, 3, 0) && !defined(__ICC)) +#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC)) return __builtin_bswap32(value); #elif defined(_MSC_VER) && !defined(_DEBUG) return _byteswap_ulong(value); @@ -55,10 +82,9 @@ inline uint32_t SwapByteOrder_32(uint32_t value) { #endif } -/// SwapByteOrder_64 - This function returns a byte-swapped representation of -/// the 64-bit argument. +/// This function returns a byte-swapped representation of the 64-bit argument. inline uint64_t SwapByteOrder_64(uint64_t value) { -#if defined(__llvm__) || (LLVM_GNUC_PREREQ(4, 3, 0) && !defined(__ICC)) +#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC)) return __builtin_bswap64(value); #elif defined(_MSC_VER) && !defined(_DEBUG) return _byteswap_uint64(value); diff --git a/include/llvm/Support/TargetOpcodes.def b/include/llvm/Support/TargetOpcodes.def index 598c1064efd0..11731ac35415 100644 --- a/include/llvm/Support/TargetOpcodes.def +++ b/include/llvm/Support/TargetOpcodes.def @@ -294,9 +294,21 @@ HANDLE_TARGET_OPCODE(G_SEXTLOAD) /// Generic zeroext load HANDLE_TARGET_OPCODE(G_ZEXTLOAD) +/// Generic indexed load (including anyext load) +HANDLE_TARGET_OPCODE(G_INDEXED_LOAD) + +/// Generic indexed signext load +HANDLE_TARGET_OPCODE(G_INDEXED_SEXTLOAD) + +/// Generic indexed zeroext load +HANDLE_TARGET_OPCODE(G_INDEXED_ZEXTLOAD) + /// Generic store. HANDLE_TARGET_OPCODE(G_STORE) +/// Generic indexed store. +HANDLE_TARGET_OPCODE(G_INDEXED_STORE) + /// Generic atomic cmpxchg with internal success check. HANDLE_TARGET_OPCODE(G_ATOMIC_CMPXCHG_WITH_SUCCESS) @@ -315,6 +327,8 @@ HANDLE_TARGET_OPCODE(G_ATOMICRMW_MAX) HANDLE_TARGET_OPCODE(G_ATOMICRMW_MIN) HANDLE_TARGET_OPCODE(G_ATOMICRMW_UMAX) HANDLE_TARGET_OPCODE(G_ATOMICRMW_UMIN) +HANDLE_TARGET_OPCODE(G_ATOMICRMW_FADD) +HANDLE_TARGET_OPCODE(G_ATOMICRMW_FSUB) // Generic atomic fence HANDLE_TARGET_OPCODE(G_FENCE) @@ -354,6 +368,7 @@ HANDLE_TARGET_OPCODE(G_VAARG) // Generic sign extend HANDLE_TARGET_OPCODE(G_SEXT) +HANDLE_TARGET_OPCODE(G_SEXT_INREG) // Generic zero extend HANDLE_TARGET_OPCODE(G_ZEXT) @@ -436,6 +451,9 @@ HANDLE_TARGET_OPCODE(G_FMUL) /// Generic FMA multiplication. Behaves like llvm fma intrinsic HANDLE_TARGET_OPCODE(G_FMA) +/// Generic FP multiply and add. Behaves as separate fmul and fadd. +HANDLE_TARGET_OPCODE(G_FMAD) + /// Generic FP division. HANDLE_TARGET_OPCODE(G_FDIV) @@ -557,6 +575,9 @@ HANDLE_TARGET_OPCODE(G_CTPOP) /// Generic byte swap. HANDLE_TARGET_OPCODE(G_BSWAP) +/// Generic bit reverse. +HANDLE_TARGET_OPCODE(G_BITREVERSE) + /// Floating point ceil. HANDLE_TARGET_OPCODE(G_FCEIL) @@ -587,12 +608,15 @@ HANDLE_TARGET_OPCODE(G_BLOCK_ADDR) /// Generic jump table address HANDLE_TARGET_OPCODE(G_JUMP_TABLE) +/// Generic dynamic stack allocation. +HANDLE_TARGET_OPCODE(G_DYN_STACKALLOC) + // TODO: Add more generic opcodes as we move along. /// Marker for the end of the generic opcode. /// This is used to check if an opcode is in the range of the /// generic opcodes. -HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_END, G_JUMP_TABLE) +HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_END, G_DYN_STACKALLOC) /// BUILTIN_OP_END - This must be the last enum value in this list. /// The target-specific post-isel opcode values start here. diff --git a/include/llvm/Support/TargetRegistry.h b/include/llvm/Support/TargetRegistry.h index bf75650760d0..f4bc26b858c8 100644 --- a/include/llvm/Support/TargetRegistry.h +++ b/include/llvm/Support/TargetRegistry.h @@ -510,8 +510,8 @@ public: std::move(Emitter), RelaxAll); break; case Triple::XCOFF: - S = createXCOFFStreamer(Ctx, std::move(TAB), std::move(OW), - std::move(Emitter), RelaxAll); + S = createXCOFFStreamer(Ctx, std::move(TAB), std::move(OW), + std::move(Emitter), RelaxAll); break; } if (ObjectTargetStreamerCtorFn) diff --git a/include/llvm/Support/TimeProfiler.h b/include/llvm/Support/TimeProfiler.h index 72b6f7180bde..8cc430d0bc72 100644 --- a/include/llvm/Support/TimeProfiler.h +++ b/include/llvm/Support/TimeProfiler.h @@ -19,7 +19,7 @@ extern TimeTraceProfiler *TimeTraceProfilerInstance; /// Initialize the time trace profiler. /// This sets up the global \p TimeTraceProfilerInstance /// variable to be the profiler instance. -void timeTraceProfilerInitialize(); +void timeTraceProfilerInitialize(unsigned TimeTraceGranularity); /// Cleanup the time trace profiler, if it was initialized. void timeTraceProfilerCleanup(); diff --git a/include/llvm/Support/TrailingObjects.h b/include/llvm/Support/TrailingObjects.h index 8cf4f7aed7f8..49be89613c43 100644 --- a/include/llvm/Support/TrailingObjects.h +++ b/include/llvm/Support/TrailingObjects.h @@ -47,6 +47,7 @@ #define LLVM_SUPPORT_TRAILINGOBJECTS_H #include "llvm/Support/AlignOf.h" +#include "llvm/Support/Alignment.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/type_traits.h" @@ -87,11 +88,6 @@ protected: template <typename T> struct OverloadToken {}; }; -/// This helper template works-around MSVC 2013's lack of useful -/// alignas() support. The argument to alignas(), in MSVC, is -/// required to be a literal integer. But, you *can* use template -/// specialization to select between a bunch of different alignas() -/// expressions... template <int Align> class TrailingObjectsAligner : public TrailingObjectsBase {}; template <> @@ -172,7 +168,7 @@ protected: if (requiresRealignment()) return reinterpret_cast<const NextTy *>( - llvm::alignAddr(Ptr, alignof(NextTy))); + alignAddr(Ptr, Align::Of<NextTy>())); else return reinterpret_cast<const NextTy *>(Ptr); } @@ -186,7 +182,7 @@ protected: Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); if (requiresRealignment()) - return reinterpret_cast<NextTy *>(llvm::alignAddr(Ptr, alignof(NextTy))); + return reinterpret_cast<NextTy *>(alignAddr(Ptr, Align::Of<NextTy>())); else return reinterpret_cast<NextTy *>(Ptr); } @@ -254,9 +250,7 @@ class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl< // because BaseTy isn't complete at class instantiation time, but // will be by the time this function is instantiated. static void verifyTrailingObjectsAssertions() { -#ifdef LLVM_IS_FINAL - static_assert(LLVM_IS_FINAL(BaseTy), "BaseTy must be final."); -#endif + static_assert(std::is_final<BaseTy>(), "BaseTy must be final."); } // These two methods are the base of the recursion for this method. @@ -369,7 +363,9 @@ public: template <typename... Tys> struct FixedSizeStorage { template <size_t... Counts> struct with_counts { enum { Size = totalSizeToAlloc<Tys...>(Counts...) }; - typedef llvm::AlignedCharArray<alignof(BaseTy), Size> type; + struct type { + alignas(BaseTy) char buffer[Size]; + }; }; }; diff --git a/include/llvm/Support/TypeSize.h b/include/llvm/Support/TypeSize.h new file mode 100644 index 000000000000..711679cdcacb --- /dev/null +++ b/include/llvm/Support/TypeSize.h @@ -0,0 +1,201 @@ +//===- TypeSize.h - Wrapper around type sizes -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides a struct that can be used to query the size of IR types +// which may be scalable vectors. It provides convenience operators so that +// it can be used in much the same way as a single scalar value. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_TYPESIZE_H +#define LLVM_SUPPORT_TYPESIZE_H + +#include <cassert> +#include <tuple> + +namespace llvm { + +class ElementCount { +public: + unsigned Min; // Minimum number of vector elements. + bool Scalable; // If true, NumElements is a multiple of 'Min' determined + // at runtime rather than compile time. + + ElementCount(unsigned Min, bool Scalable) + : Min(Min), Scalable(Scalable) {} + + ElementCount operator*(unsigned RHS) { + return { Min * RHS, Scalable }; + } + ElementCount operator/(unsigned RHS) { + return { Min / RHS, Scalable }; + } + + bool operator==(const ElementCount& RHS) const { + return Min == RHS.Min && Scalable == RHS.Scalable; + } + bool operator!=(const ElementCount& RHS) const { + return !(*this == RHS); + } +}; + +// This class is used to represent the size of types. If the type is of fixed +// size, it will represent the exact size. If the type is a scalable vector, +// it will represent the known minimum size. +class TypeSize { + uint64_t MinSize; // The known minimum size. + bool IsScalable; // If true, then the runtime size is an integer multiple + // of MinSize. + +public: + constexpr TypeSize(uint64_t MinSize, bool Scalable) + : MinSize(MinSize), IsScalable(Scalable) {} + + static constexpr TypeSize Fixed(uint64_t Size) { + return TypeSize(Size, /*IsScalable=*/false); + } + + static constexpr TypeSize Scalable(uint64_t MinSize) { + return TypeSize(MinSize, /*IsScalable=*/true); + } + + // Scalable vector types with the same minimum size as a fixed size type are + // not guaranteed to be the same size at runtime, so they are never + // considered to be equal. + friend bool operator==(const TypeSize &LHS, const TypeSize &RHS) { + return std::tie(LHS.MinSize, LHS.IsScalable) == + std::tie(RHS.MinSize, RHS.IsScalable); + } + + friend bool operator!=(const TypeSize &LHS, const TypeSize &RHS) { + return !(LHS == RHS); + } + + // For many cases, size ordering between scalable and fixed size types cannot + // be determined at compile time, so such comparisons aren't allowed. + // + // e.g. <vscale x 2 x i16> could be bigger than <4 x i32> with a runtime + // vscale >= 5, equal sized with a vscale of 4, and smaller with + // a vscale <= 3. + // + // If the scalable flags match, just perform the requested comparison + // between the minimum sizes. + friend bool operator<(const TypeSize &LHS, const TypeSize &RHS) { + assert(LHS.IsScalable == RHS.IsScalable && + "Ordering comparison of scalable and fixed types"); + + return LHS.MinSize < RHS.MinSize; + } + + friend bool operator>(const TypeSize &LHS, const TypeSize &RHS) { + return RHS < LHS; + } + + friend bool operator<=(const TypeSize &LHS, const TypeSize &RHS) { + return !(RHS < LHS); + } + + friend bool operator>=(const TypeSize &LHS, const TypeSize& RHS) { + return !(LHS < RHS); + } + + // Convenience operators to obtain relative sizes independently of + // the scalable flag. + TypeSize operator*(unsigned RHS) const { + return { MinSize * RHS, IsScalable }; + } + + friend TypeSize operator*(const unsigned LHS, const TypeSize &RHS) { + return { LHS * RHS.MinSize, RHS.IsScalable }; + } + + TypeSize operator/(unsigned RHS) const { + return { MinSize / RHS, IsScalable }; + } + + // Return the minimum size with the assumption that the size is exact. + // Use in places where a scalable size doesn't make sense (e.g. non-vector + // types, or vectors in backends which don't support scalable vectors). + uint64_t getFixedSize() const { + assert(!IsScalable && "Request for a fixed size on a scalable object"); + return MinSize; + } + + // Return the known minimum size. Use in places where the scalable property + // doesn't matter (e.g. determining alignment) or in conjunction with the + // isScalable method below. + uint64_t getKnownMinSize() const { + return MinSize; + } + + // Return whether or not the size is scalable. + bool isScalable() const { + return IsScalable; + } + + // Casts to a uint64_t if this is a fixed-width size. + // + // NOTE: This interface is obsolete and will be removed in a future version + // of LLVM in favour of calling getFixedSize() directly. + operator uint64_t() const { + return getFixedSize(); + } + + // Additional convenience operators needed to avoid ambiguous parses. + // TODO: Make uint64_t the default operator? + TypeSize operator*(uint64_t RHS) const { + return { MinSize * RHS, IsScalable }; + } + + TypeSize operator*(int RHS) const { + return { MinSize * RHS, IsScalable }; + } + + TypeSize operator*(int64_t RHS) const { + return { MinSize * RHS, IsScalable }; + } + + friend TypeSize operator*(const uint64_t LHS, const TypeSize &RHS) { + return { LHS * RHS.MinSize, RHS.IsScalable }; + } + + friend TypeSize operator*(const int LHS, const TypeSize &RHS) { + return { LHS * RHS.MinSize, RHS.IsScalable }; + } + + friend TypeSize operator*(const int64_t LHS, const TypeSize &RHS) { + return { LHS * RHS.MinSize, RHS.IsScalable }; + } + + TypeSize operator/(uint64_t RHS) const { + return { MinSize / RHS, IsScalable }; + } + + TypeSize operator/(int RHS) const { + return { MinSize / RHS, IsScalable }; + } + + TypeSize operator/(int64_t RHS) const { + return { MinSize / RHS, IsScalable }; + } +}; + +/// Returns a TypeSize with a known minimum size that is the next integer +/// (mod 2**64) that is greater than or equal to \p Value and is a multiple +/// of \p Align. \p Align must be non-zero. +/// +/// Similar to the alignTo functions in MathExtras.h +inline TypeSize alignTo(TypeSize Size, uint64_t Align) { + assert(Align != 0u && "Align must be non-zero"); + return {(Size.getKnownMinSize() + Align - 1) / Align * Align, + Size.isScalable()}; +} + +} // end namespace llvm + +#endif // LLVM_SUPPORT_TypeSize_H diff --git a/include/llvm/Support/UnicodeCharRanges.h b/include/llvm/Support/UnicodeCharRanges.h index 4b59f8a92b76..73d3603b74df 100644 --- a/include/llvm/Support/UnicodeCharRanges.h +++ b/include/llvm/Support/UnicodeCharRanges.h @@ -9,11 +9,8 @@ #define LLVM_SUPPORT_UNICODECHARRANGES_H #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/Mutex.h" -#include "llvm/Support/MutexGuard.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> diff --git a/include/llvm/Support/UniqueLock.h b/include/llvm/Support/UniqueLock.h deleted file mode 100644 index 0a887ad5965d..000000000000 --- a/include/llvm/Support/UniqueLock.h +++ /dev/null @@ -1,68 +0,0 @@ -//===- Support/UniqueLock.h - Acquire/Release Mutex In Scope ----*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines a guard for a block of code that ensures a Mutex is locked -// upon construction and released upon destruction. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SUPPORT_UNIQUE_LOCK_H -#define LLVM_SUPPORT_UNIQUE_LOCK_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 - /// and unlocked after destruction. unique_lock can also unlock the mutex - /// and re-lock it freely during its lifetime. - /// Guard a section of code with a mutex. - template<typename MutexT> - class unique_lock { - MutexT *M = nullptr; - bool locked = false; - - public: - 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()) - M->unlock(); - M = o.M; - locked = o.locked; - o.M = nullptr; - o.locked = false; - } - - ~unique_lock() { if (owns_lock()) M->unlock(); } - - void lock() { - assert(!locked && "mutex already locked!"); - assert(M && "no associated mutex!"); - M->lock(); - locked = true; - } - - void unlock() { - assert(locked && "unlocking a mutex that isn't locked!"); - assert(M && "no associated mutex!"); - M->unlock(); - locked = false; - } - - bool owns_lock() { return locked; } - }; - -} // end namespace llvm - -#endif // LLVM_SUPPORT_UNIQUE_LOCK_H diff --git a/include/llvm/Support/VirtualFileSystem.h b/include/llvm/Support/VirtualFileSystem.h index 31c9e851daed..c844d9d194f0 100644 --- a/include/llvm/Support/VirtualFileSystem.h +++ b/include/llvm/Support/VirtualFileSystem.h @@ -647,9 +647,19 @@ private: friend class VFSFromYamlDirIterImpl; friend class RedirectingFileSystemParser; + bool shouldUseExternalFS() const { + return ExternalFSValidWD && IsFallthrough; + } + /// The root(s) of the virtual file system. std::vector<std::unique_ptr<Entry>> Roots; + /// The current working directory of the file system. + std::string WorkingDirectory; + + /// Whether the current working directory is valid for the external FS. + bool ExternalFSValidWD = false; + /// The file system to use for external references. IntrusiveRefCntPtr<FileSystem> ExternalFS; @@ -689,8 +699,7 @@ private: true; #endif - RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS) - : ExternalFS(std::move(ExternalFS)) {} + RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS); /// Looks up the path <tt>[Start, End)</tt> in \p From, possibly /// recursing into the contents of \p From if it is a directory. @@ -730,9 +739,10 @@ public: StringRef getExternalContentsPrefixDir() const; + void dump(raw_ostream &OS) const; + void dumpEntry(raw_ostream &OS, Entry *E, int NumSpaces = 0) const; #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void dump() const; - LLVM_DUMP_METHOD void dumpEntry(Entry *E, int NumSpaces = 0) const; #endif }; diff --git a/include/llvm/Support/Win64EH.h b/include/llvm/Support/Win64EH.h index bdd23b41594e..8220131e5be9 100644 --- a/include/llvm/Support/Win64EH.h +++ b/include/llvm/Support/Win64EH.h @@ -30,7 +30,9 @@ enum UnwindOpcodes { UOP_SetFPReg, UOP_SaveNonVol, UOP_SaveNonVolBig, - UOP_SaveXMM128 = 8, + UOP_Epilog, + UOP_SpareCode, + UOP_SaveXMM128, UOP_SaveXMM128Big, UOP_PushMachFrame, // The following set of unwind opcodes is for ARM64. They are documented at diff --git a/include/llvm/Support/X86TargetParser.def b/include/llvm/Support/X86TargetParser.def index 1749be3b3ae2..4ebf2d79cb8d 100644 --- a/include/llvm/Support/X86TargetParser.def +++ b/include/llvm/Support/X86TargetParser.def @@ -112,6 +112,7 @@ X86_CPU_SUBTYPE ("k6-2", AMDPENTIUM_K62) X86_CPU_SUBTYPE ("k6-3", AMDPENTIUM_K63) X86_CPU_SUBTYPE ("geode", AMDPENTIUM_GEODE) X86_CPU_SUBTYPE ("cooperlake", INTEL_COREI7_COOPERLAKE) +X86_CPU_SUBTYPE ("tigerlake", INTEL_COREI7_TIGERLAKE) #undef X86_CPU_SUBTYPE_COMPAT #undef X86_CPU_SUBTYPE @@ -160,12 +161,13 @@ X86_FEATURE_COMPAT(32, FEATURE_GFNI, "gfni") X86_FEATURE_COMPAT(33, FEATURE_VPCLMULQDQ, "vpclmulqdq") X86_FEATURE_COMPAT(34, FEATURE_AVX512VNNI, "avx512vnni") X86_FEATURE_COMPAT(35, FEATURE_AVX512BITALG, "avx512bitalg") +X86_FEATURE_COMPAT(36, FEATURE_AVX512BF16, "avx512bf16") // Features below here are not in libgcc/compiler-rt. X86_FEATURE (64, FEATURE_MOVBE) X86_FEATURE (65, FEATURE_ADX) X86_FEATURE (66, FEATURE_EM64T) X86_FEATURE (67, FEATURE_CLFLUSHOPT) X86_FEATURE (68, FEATURE_SHA) -X86_FEATURE (69, FEATURE_AVX512BF16) +X86_FEATURE (69, FEATURE_AVX512VP2INTERSECT) #undef X86_FEATURE_COMPAT #undef X86_FEATURE diff --git a/include/llvm/Support/YAMLTraits.h b/include/llvm/Support/YAMLTraits.h index 5181dc56d81d..a3bfa7dc4678 100644 --- a/include/llvm/Support/YAMLTraits.h +++ b/include/llvm/Support/YAMLTraits.h @@ -649,7 +649,8 @@ inline bool isBool(StringRef S) { inline QuotingType needsQuotes(StringRef S) { if (S.empty()) return QuotingType::Single; - if (isspace(S.front()) || isspace(S.back())) + if (isspace(static_cast<unsigned char>(S.front())) || + isspace(static_cast<unsigned char>(S.back()))) return QuotingType::Single; if (isNull(S)) return QuotingType::Single; @@ -748,7 +749,7 @@ public: IO(void *Ctxt = nullptr); virtual ~IO(); - virtual bool outputting() = 0; + virtual bool outputting() const = 0; virtual unsigned beginSequence() = 0; virtual bool preflightElement(unsigned, void *&) = 0; @@ -842,7 +843,7 @@ public: Val = Val | ConstVal; } - void *getContext(); + void *getContext() const; void setContext(void *); template <typename T> void mapRequired(const char *Key, T &Val) { @@ -1402,7 +1403,7 @@ public: std::error_code error(); private: - bool outputting() override; + bool outputting() const override; bool mapTag(StringRef, bool) override; void beginMapping() override; void endMapping() override; @@ -1549,7 +1550,7 @@ public: /// anyway. void setWriteDefaultValues(bool Write) { WriteDefaultValues = Write; } - bool outputting() override; + bool outputting() const override; bool mapTag(StringRef, bool) override; void beginMapping() override; void endMapping() override; diff --git a/include/llvm/Support/circular_raw_ostream.h b/include/llvm/Support/circular_raw_ostream.h index 4ecdb17376f1..a72acd4fe002 100644 --- a/include/llvm/Support/circular_raw_ostream.h +++ b/include/llvm/Support/circular_raw_ostream.h @@ -122,6 +122,10 @@ namespace llvm { delete[] BufferArray; } + bool is_displayed() const override { + return TheStream->is_displayed(); + } + /// setStream - Tell the circular_raw_ostream to output a /// different stream. "Owns" tells circular_raw_ostream whether /// it should take responsibility for managing the underlying diff --git a/include/llvm/Support/raw_ostream.h b/include/llvm/Support/raw_ostream.h index 48bb623b0638..0debc5da7a68 100644 --- a/include/llvm/Support/raw_ostream.h +++ b/include/llvm/Support/raw_ostream.h @@ -72,7 +72,7 @@ private: public: // color order matches ANSI escape sequence, don't change - enum Colors { + enum class Colors { BLACK = 0, RED, GREEN, @@ -81,9 +81,21 @@ public: MAGENTA, CYAN, WHITE, - SAVEDCOLOR + SAVEDCOLOR, + RESET, }; + static const Colors BLACK = Colors::BLACK; + static const Colors RED = Colors::RED; + static const Colors GREEN = Colors::GREEN; + static const Colors YELLOW = Colors::YELLOW; + static const Colors BLUE = Colors::BLUE; + static const Colors MAGENTA = Colors::MAGENTA; + static const Colors CYAN = Colors::CYAN; + static const Colors WHITE = Colors::WHITE; + static const Colors SAVEDCOLOR = Colors::SAVEDCOLOR; + static const Colors RESET = Colors::RESET; + explicit raw_ostream(bool unbuffered = false) : BufferMode(unbuffered ? Unbuffered : InternalBuffer) { // Start out ready to flush. @@ -214,6 +226,9 @@ public: /// Output \p N in hexadecimal, without any prefix or padding. raw_ostream &write_hex(unsigned long long N); + // Change the foreground color of text. + raw_ostream &operator<<(Colors C); + /// Output a formatted UUID with dash separators. using uuid_t = uint8_t[16]; raw_ostream &write_uuid(const uuid_t UUID); @@ -277,6 +292,10 @@ public: /// This function determines if this stream is displayed and supports colors. virtual bool has_colors() const { return is_displayed(); } + // Enable or disable colors. Once disable_colors() is called, + // changeColor() has no effect until enable_colors() is called. + virtual void enable_colors(bool /*enable*/) {} + //===--------------------------------------------------------------------===// // Subclass Interface //===--------------------------------------------------------------------===// @@ -365,8 +384,8 @@ public: class raw_fd_ostream : public raw_pwrite_stream { int FD; bool ShouldClose; - bool SupportsSeeking; + bool ColorEnabled = true; #ifdef _WIN32 /// True if this fd refers to a Windows console device. Mintty and other @@ -442,6 +461,8 @@ public: bool has_colors() const override; + void enable_colors(bool enable) override { ColorEnabled = enable; } + std::error_code error() const { return EC; } /// Return the value of the flag in this raw_fd_ostream indicating whether an diff --git a/include/llvm/Support/type_traits.h b/include/llvm/Support/type_traits.h index c8c6a76a90f1..b7d48e8e1ade 100644 --- a/include/llvm/Support/type_traits.h +++ b/include/llvm/Support/type_traits.h @@ -17,11 +17,6 @@ #include <type_traits> #include <utility> -#ifndef __has_feature -#define LLVM_DEFINED_HAS_FEATURE -#define __has_feature(x) 0 -#endif - namespace llvm { @@ -194,17 +189,4 @@ class is_trivially_copyable<T*> : public std::true_type { } // end namespace llvm -// If the compiler supports detecting whether a class is final, define -// an LLVM_IS_FINAL macro. If it cannot be defined properly, this -// macro will be left undefined. -#if __cplusplus >= 201402L || defined(_MSC_VER) -#define LLVM_IS_FINAL(Ty) std::is_final<Ty>() -#elif __has_feature(is_final) || LLVM_GNUC_PREREQ(4, 7, 0) -#define LLVM_IS_FINAL(Ty) __is_final(Ty) -#endif - -#ifdef LLVM_DEFINED_HAS_FEATURE -#undef __has_feature -#endif - #endif // LLVM_SUPPORT_TYPE_TRAITS_H |