diff options
Diffstat (limited to 'contrib/llvm/lib/Support')
54 files changed, 3508 insertions, 1203 deletions
diff --git a/contrib/llvm/lib/Support/APFloat.cpp b/contrib/llvm/lib/Support/APFloat.cpp index 19b8221..f9370b8 100644 --- a/contrib/llvm/lib/Support/APFloat.cpp +++ b/contrib/llvm/lib/Support/APFloat.cpp @@ -14,6 +14,7 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringExtras.h" @@ -501,7 +502,9 @@ powerOf5(integerPart *dst, unsigned int power) /* Now result is in p1 with partsCount parts and p2 is scratch space. */ - tmp = p1, p1 = p2, p2 = tmp; + tmp = p1; + p1 = p2; + p2 = tmp; } pow5 += pc; @@ -3940,22 +3943,68 @@ APFloat::makeZero(bool Negative) { category = fcZero; sign = Negative; exponent = semantics->minExponent-1; - APInt::tcSet(significandParts(), 0, partCount()); + APInt::tcSet(significandParts(), 0, partCount()); +} + +void APFloat::makeQuiet() { + assert(isNaN()); + APInt::tcSetBit(significandParts(), semantics->precision - 2); } -APFloat llvm::scalbn(APFloat X, int Exp) { - if (X.isInfinity() || X.isZero() || X.isNaN()) - return X; +int llvm::ilogb(const APFloat &Arg) { + if (Arg.isNaN()) + return APFloat::IEK_NaN; + if (Arg.isZero()) + return APFloat::IEK_Zero; + if (Arg.isInfinity()) + return APFloat::IEK_Inf; + if (!Arg.isDenormal()) + return Arg.exponent; + + APFloat Normalized(Arg); + int SignificandBits = Arg.getSemantics().precision - 1; + Normalized.exponent += SignificandBits; + Normalized.normalize(APFloat::rmNearestTiesToEven, lfExactlyZero); + return Normalized.exponent - SignificandBits; +} + +APFloat llvm::scalbn(APFloat X, int Exp, APFloat::roundingMode RoundingMode) { auto MaxExp = X.getSemantics().maxExponent; auto MinExp = X.getSemantics().minExponent; - if (Exp > (MaxExp - X.exponent)) - // Overflow saturates to infinity. - return APFloat::getInf(X.getSemantics(), X.isNegative()); - if (Exp < (MinExp - X.exponent)) - // Underflow saturates to zero. - return APFloat::getZero(X.getSemantics(), X.isNegative()); - - X.exponent += Exp; + + // If Exp is wildly out-of-scale, simply adding it to X.exponent will + // overflow; clamp it to a safe range before adding, but ensure that the range + // is large enough that the clamp does not change the result. The range we + // need to support is the difference between the largest possible exponent and + // the normalized exponent of half the smallest denormal. + + int SignificandBits = X.getSemantics().precision - 1; + int MaxIncrement = MaxExp - (MinExp - SignificandBits) + 1; + + // Clamp to one past the range ends to let normalize handle overlflow. + X.exponent += std::min(std::max(Exp, -MaxIncrement - 1), MaxIncrement); + X.normalize(RoundingMode, lfExactlyZero); + if (X.isNaN()) + X.makeQuiet(); return X; } + +APFloat llvm::frexp(const APFloat &Val, int &Exp, APFloat::roundingMode RM) { + Exp = ilogb(Val); + + // Quiet signalling nans. + if (Exp == APFloat::IEK_NaN) { + APFloat Quiet(Val); + Quiet.makeQuiet(); + return Quiet; + } + + if (Exp == APFloat::IEK_Inf) + return Val; + + // 1 is added because frexp is defined to return a normalized fraction in + // +/-[0.5, 1.0), rather than the usual +/-[1.0, 2.0). + Exp = Exp == APFloat::IEK_Zero ? 0 : Exp + 1; + return scalbn(Val, -Exp, RM); +} diff --git a/contrib/llvm/lib/Support/APInt.cpp b/contrib/llvm/lib/Support/APInt.cpp index 23f89bb..66eee99 100644 --- a/contrib/llvm/lib/Support/APInt.cpp +++ b/contrib/llvm/lib/Support/APInt.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallString.h" @@ -74,7 +75,7 @@ inline static unsigned getDigit(char cdigit, uint8_t radix) { } -void APInt::initSlowCase(unsigned numBits, uint64_t val, bool isSigned) { +void APInt::initSlowCase(uint64_t val, bool isSigned) { pVal = getClearedMemory(getNumWords()); pVal[0] = val; if (isSigned && int64_t(val) < 0) @@ -479,6 +480,15 @@ APInt APInt::operator+(const APInt& RHS) const { return Result; } +APInt APInt::operator+(uint64_t RHS) const { + if (isSingleWord()) + return APInt(BitWidth, VAL + RHS); + APInt Result(*this); + add_1(Result.pVal, Result.pVal, getNumWords(), RHS); + Result.clearUnusedBits(); + return Result; +} + APInt APInt::operator-(const APInt& RHS) const { assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); if (isSingleWord()) @@ -489,24 +499,17 @@ APInt APInt::operator-(const APInt& RHS) const { return Result; } -bool APInt::EqualSlowCase(const APInt& RHS) const { - // Get some facts about the number of bits used in the two operands. - unsigned n1 = getActiveBits(); - unsigned n2 = RHS.getActiveBits(); - - // If the number of bits isn't the same, they aren't equal - if (n1 != n2) - return false; - - // If the number of bits fits in a word, we only need to compare the low word. - if (n1 <= APINT_BITS_PER_WORD) - return pVal[0] == RHS.pVal[0]; +APInt APInt::operator-(uint64_t RHS) const { + if (isSingleWord()) + return APInt(BitWidth, VAL - RHS); + APInt Result(*this); + sub_1(Result.pVal, getNumWords(), RHS); + Result.clearUnusedBits(); + return Result; +} - // Otherwise, compare everything - for (int i = whichWord(n1 - 1); i >= 0; --i) - if (pVal[i] != RHS.pVal[i]) - return false; - return true; +bool APInt::EqualSlowCase(const APInt& RHS) const { + return std::equal(pVal, pVal + getNumWords(), RHS.pVal); } bool APInt::EqualSlowCase(uint64_t Val) const { @@ -552,37 +555,21 @@ bool APInt::ult(const APInt& RHS) const { bool APInt::slt(const APInt& RHS) const { assert(BitWidth == RHS.BitWidth && "Bit widths must be same for comparison"); if (isSingleWord()) { - int64_t lhsSext = (int64_t(VAL) << (64-BitWidth)) >> (64-BitWidth); - int64_t rhsSext = (int64_t(RHS.VAL) << (64-BitWidth)) >> (64-BitWidth); + int64_t lhsSext = SignExtend64(VAL, BitWidth); + int64_t rhsSext = SignExtend64(RHS.VAL, BitWidth); return lhsSext < rhsSext; } - APInt lhs(*this); - APInt rhs(RHS); bool lhsNeg = isNegative(); - bool rhsNeg = rhs.isNegative(); - if (lhsNeg) { - // Sign bit is set so perform two's complement to make it positive - lhs.flipAllBits(); - ++lhs; - } - if (rhsNeg) { - // Sign bit is set so perform two's complement to make it positive - rhs.flipAllBits(); - ++rhs; - } - - // Now we have unsigned values to compare so do the comparison if necessary - // based on the negativeness of the values. - if (lhsNeg) - if (rhsNeg) - return lhs.ugt(rhs); - else - return true; - else if (rhsNeg) - return false; - else - return lhs.ult(rhs); + bool rhsNeg = RHS.isNegative(); + + // If the sign bits don't match, then (LHS < RHS) if LHS is negative + if (lhsNeg != rhsNeg) + return lhsNeg; + + // Otherwise we can just use an unsigned comparision, because even negative + // numbers compare correctly this way if both have the same signed-ness. + return ult(RHS); } void APInt::setBit(unsigned bitPosition) { @@ -692,30 +679,19 @@ APInt APInt::getLoBits(unsigned numBits) const { } unsigned APInt::countLeadingZerosSlowCase() const { - // Treat the most significand word differently because it might have - // meaningless bits set beyond the precision. - unsigned BitsInMSW = BitWidth % APINT_BITS_PER_WORD; - integerPart MSWMask; - if (BitsInMSW) MSWMask = (integerPart(1) << BitsInMSW) - 1; - else { - MSWMask = ~integerPart(0); - BitsInMSW = APINT_BITS_PER_WORD; - } - - unsigned i = getNumWords(); - integerPart MSW = pVal[i-1] & MSWMask; - if (MSW) - return llvm::countLeadingZeros(MSW) - (APINT_BITS_PER_WORD - BitsInMSW); - - unsigned Count = BitsInMSW; - for (--i; i > 0u; --i) { - if (pVal[i-1] == 0) + unsigned Count = 0; + for (int i = getNumWords()-1; i >= 0; --i) { + integerPart V = pVal[i]; + if (V == 0) Count += APINT_BITS_PER_WORD; else { - Count += llvm::countLeadingZeros(pVal[i-1]); + Count += llvm::countLeadingZeros(V); break; } } + // Adjust for unused bits in the most significant word (they are zero). + unsigned Mod = BitWidth % APINT_BITS_PER_WORD; + Count -= Mod > 0 ? APINT_BITS_PER_WORD - Mod : 0; return Count; } @@ -814,6 +790,36 @@ APInt APInt::byteSwap() const { return Result; } +APInt APInt::reverseBits() const { + switch (BitWidth) { + case 64: + return APInt(BitWidth, llvm::reverseBits<uint64_t>(VAL)); + case 32: + return APInt(BitWidth, llvm::reverseBits<uint32_t>(VAL)); + case 16: + return APInt(BitWidth, llvm::reverseBits<uint16_t>(VAL)); + case 8: + return APInt(BitWidth, llvm::reverseBits<uint8_t>(VAL)); + default: + break; + } + + APInt Val(*this); + APInt Reversed(*this); + int S = BitWidth - 1; + + const APInt One(BitWidth, 1); + + for ((Val = Val.lshr(1)); Val != 0; (Val = Val.lshr(1))) { + Reversed <<= 1; + Reversed |= (Val & One); + --S; + } + + Reversed <<= S; + return Reversed; +} + APInt llvm::APIntOps::GreatestCommonDivisor(const APInt& API1, const APInt& API2) { APInt A = API1, B = API2; @@ -874,7 +880,7 @@ double APInt::roundToDouble(bool isSigned) const { // It is wrong to optimize getWord(0) to VAL; there might be more than one word. if (isSingleWord() || getActiveBits() <= APINT_BITS_PER_WORD) { if (isSigned) { - int64_t sext = (int64_t(getWord(0)) << (64-BitWidth)) >> (64-BitWidth); + int64_t sext = SignExtend64(getWord(0), BitWidth); return double(sext); } else return double(getWord(0)); @@ -1658,10 +1664,8 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, DEBUG(dbgs() << '\n'); } -void APInt::divide(const APInt LHS, unsigned lhsWords, - const APInt &RHS, unsigned rhsWords, - APInt *Quotient, APInt *Remainder) -{ +void APInt::divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS, + unsigned rhsWords, APInt *Quotient, APInt *Remainder) { assert(lhsWords >= rhsWords && "Fractional result"); // First, compose the values into an array of 32-bit words instead of @@ -2268,7 +2272,7 @@ std::string APInt::toString(unsigned Radix = 10, bool Signed = true) const { } -void APInt::dump() const { +LLVM_DUMP_METHOD void APInt::dump() const { SmallString<40> S, U; this->toStringUnsigned(U); this->toStringSigned(S); @@ -2725,8 +2729,10 @@ APInt::tcDivide(integerPart *lhs, const integerPart *rhs, break; shiftCount--; tcShiftRight(srhs, parts, 1); - if ((mask >>= 1) == 0) - mask = (integerPart) 1 << (integerPartWidth - 1), n--; + if ((mask >>= 1) == 0) { + mask = (integerPart) 1 << (integerPartWidth - 1); + n--; + } } return false; diff --git a/contrib/llvm/lib/Support/APSInt.cpp b/contrib/llvm/lib/Support/APSInt.cpp index 975457c..46c0f70 100644 --- a/contrib/llvm/lib/Support/APSInt.cpp +++ b/contrib/llvm/lib/Support/APSInt.cpp @@ -14,6 +14,7 @@ #include "llvm/ADT/APSInt.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/StringRef.h" using namespace llvm; diff --git a/contrib/llvm/lib/Support/ARMBuildAttrs.cpp b/contrib/llvm/lib/Support/ARMBuildAttrs.cpp index 960a0f1..6d34f76 100644 --- a/contrib/llvm/lib/Support/ARMBuildAttrs.cpp +++ b/contrib/llvm/lib/Support/ARMBuildAttrs.cpp @@ -54,6 +54,7 @@ const struct { { ARMBuildAttrs::ABI_FP_16bit_format, "Tag_ABI_FP_16bit_format" }, { ARMBuildAttrs::MPextension_use, "Tag_MPextension_use" }, { ARMBuildAttrs::DIV_use, "Tag_DIV_use" }, + { ARMBuildAttrs::DSP_extension, "Tag_DSP_extension" }, { ARMBuildAttrs::nodefaults, "Tag_nodefaults" }, { ARMBuildAttrs::also_compatible_with, "Tag_also_compatible_with" }, { ARMBuildAttrs::T2EE_use, "Tag_T2EE_use" }, diff --git a/contrib/llvm/lib/Support/Atomic.cpp b/contrib/llvm/lib/Support/Atomic.cpp index ac4ff3e..80550e2 100644 --- a/contrib/llvm/lib/Support/Atomic.cpp +++ b/contrib/llvm/lib/Support/Atomic.cpp @@ -56,62 +56,3 @@ sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr, # error No compare-and-swap implementation for your platform! #endif } - -sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) { -#if LLVM_HAS_ATOMICS == 0 - ++(*ptr); - return *ptr; -#elif defined(GNU_ATOMICS) - return __sync_add_and_fetch(ptr, 1); -#elif defined(_MSC_VER) - return InterlockedIncrement(ptr); -#else -# error No atomic increment implementation for your platform! -#endif -} - -sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) { -#if LLVM_HAS_ATOMICS == 0 - --(*ptr); - return *ptr; -#elif defined(GNU_ATOMICS) - return __sync_sub_and_fetch(ptr, 1); -#elif defined(_MSC_VER) - return InterlockedDecrement(ptr); -#else -# error No atomic decrement implementation for your platform! -#endif -} - -sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) { -#if LLVM_HAS_ATOMICS == 0 - *ptr += val; - return *ptr; -#elif defined(GNU_ATOMICS) - return __sync_add_and_fetch(ptr, val); -#elif defined(_MSC_VER) - return InterlockedExchangeAdd(ptr, val) + val; -#else -# error No atomic add implementation for your platform! -#endif -} - -sys::cas_flag sys::AtomicMul(volatile sys::cas_flag* ptr, sys::cas_flag val) { - sys::cas_flag original, result; - do { - original = *ptr; - result = original * val; - } while (sys::CompareAndSwap(ptr, result, original) != original); - - return result; -} - -sys::cas_flag sys::AtomicDiv(volatile sys::cas_flag* ptr, sys::cas_flag val) { - sys::cas_flag original, result; - do { - original = *ptr; - result = original / val; - } while (sys::CompareAndSwap(ptr, result, original) != original); - - return result; -} diff --git a/contrib/llvm/lib/Support/BranchProbability.cpp b/contrib/llvm/lib/Support/BranchProbability.cpp index 771d02c..1c41659 100644 --- a/contrib/llvm/lib/Support/BranchProbability.cpp +++ b/contrib/llvm/lib/Support/BranchProbability.cpp @@ -32,7 +32,7 @@ raw_ostream &BranchProbability::print(raw_ostream &OS) const { Percent); } -void BranchProbability::dump() const { print(dbgs()) << '\n'; } +LLVM_DUMP_METHOD void BranchProbability::dump() const { print(dbgs()) << '\n'; } BranchProbability::BranchProbability(uint32_t Numerator, uint32_t Denominator) { assert(Denominator > 0 && "Denominator cannot be 0!"); diff --git a/contrib/llvm/lib/Support/CachePruning.cpp b/contrib/llvm/lib/Support/CachePruning.cpp new file mode 100644 index 0000000..bd42bef --- /dev/null +++ b/contrib/llvm/lib/Support/CachePruning.cpp @@ -0,0 +1,159 @@ +//===-CachePruning.cpp - LLVM Cache Directory Pruning ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the pruning of a directory based on least recently used. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/CachePruning.h" + +#include "llvm/Support/Debug.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUG_TYPE "cache-pruning" + +#include <set> + +using namespace llvm; + +/// Write a new timestamp file with the given path. This is used for the pruning +/// interval option. +static void writeTimestampFile(StringRef TimestampFile) { + std::error_code EC; + raw_fd_ostream Out(TimestampFile.str(), EC, sys::fs::F_None); +} + +/// Prune the cache of files that haven't been accessed in a long time. +bool CachePruning::prune() { + if (Path.empty()) + return false; + + bool isPathDir; + if (sys::fs::is_directory(Path, isPathDir)) + return false; + + if (!isPathDir) + return false; + + if (Expiration == 0 && PercentageOfAvailableSpace == 0) { + DEBUG(dbgs() << "No pruning settings set, exit early\n"); + // Nothing will be pruned, early exit + return false; + } + + // Try to stat() the timestamp file. + SmallString<128> TimestampFile(Path); + sys::path::append(TimestampFile, "llvmcache.timestamp"); + sys::fs::file_status FileStatus; + sys::TimeValue CurrentTime = sys::TimeValue::now(); + if (auto EC = sys::fs::status(TimestampFile, FileStatus)) { + if (EC == errc::no_such_file_or_directory) { + // If the timestamp file wasn't there, create one now. + writeTimestampFile(TimestampFile); + } else { + // Unknown error? + return false; + } + } else { + if (Interval) { + // Check whether the time stamp is older than our pruning interval. + // If not, do nothing. + sys::TimeValue TimeStampModTime = FileStatus.getLastModificationTime(); + auto TimeInterval = sys::TimeValue(sys::TimeValue::SecondsType(Interval)); + auto TimeStampAge = CurrentTime - TimeStampModTime; + if (TimeStampAge <= TimeInterval) { + DEBUG(dbgs() << "Timestamp file too recent (" << TimeStampAge.seconds() + << "s old), do not prune.\n"); + return false; + } + } + // Write a new timestamp file so that nobody else attempts to prune. + // There is a benign race condition here, if two processes happen to + // notice at the same time that the timestamp is out-of-date. + writeTimestampFile(TimestampFile); + } + + bool ShouldComputeSize = (PercentageOfAvailableSpace > 0); + + // Keep track of space + std::set<std::pair<uint64_t, std::string>> FileSizes; + uint64_t TotalSize = 0; + // Helper to add a path to the set of files to consider for size-based + // pruning, sorted by size. + auto AddToFileListForSizePruning = + [&](StringRef Path) { + if (!ShouldComputeSize) + return; + TotalSize += FileStatus.getSize(); + FileSizes.insert( + std::make_pair(FileStatus.getSize(), std::string(Path))); + }; + + // Walk the entire directory cache, looking for unused files. + std::error_code EC; + SmallString<128> CachePathNative; + sys::path::native(Path, CachePathNative); + auto TimeExpiration = sys::TimeValue(sys::TimeValue::SecondsType(Expiration)); + // Walk all of the files within this directory. + for (sys::fs::directory_iterator File(CachePathNative, EC), FileEnd; + File != FileEnd && !EC; File.increment(EC)) { + // Do not touch the timestamp. + if (File->path() == TimestampFile) + continue; + + // Look at this file. If we can't stat it, there's nothing interesting + // there. + if (sys::fs::status(File->path(), FileStatus)) { + DEBUG(dbgs() << "Ignore " << File->path() << " (can't stat)\n"); + continue; + } + + // If the file hasn't been used recently enough, delete it + sys::TimeValue FileAccessTime = FileStatus.getLastAccessedTime(); + auto FileAge = CurrentTime - FileAccessTime; + if (FileAge > TimeExpiration) { + DEBUG(dbgs() << "Remove " << File->path() << " (" << FileAge.seconds() + << "s old)\n"); + sys::fs::remove(File->path()); + continue; + } + + // Leave it here for now, but add it to the list of size-based pruning. + AddToFileListForSizePruning(File->path()); + } + + // Prune for size now if needed + if (ShouldComputeSize) { + auto ErrOrSpaceInfo = sys::fs::disk_space(Path); + if (!ErrOrSpaceInfo) { + report_fatal_error("Can't get available size"); + } + sys::fs::space_info SpaceInfo = ErrOrSpaceInfo.get(); + auto AvailableSpace = TotalSize + SpaceInfo.free; + auto FileAndSize = FileSizes.rbegin(); + DEBUG(dbgs() << "Occupancy: " << ((100 * TotalSize) / AvailableSpace) + << "% target is: " << PercentageOfAvailableSpace << "\n"); + // Remove the oldest accessed files first, till we get below the threshold + while (((100 * TotalSize) / AvailableSpace) > PercentageOfAvailableSpace && + FileAndSize != FileSizes.rend()) { + // Remove the file. + sys::fs::remove(FileAndSize->second); + // Update size + TotalSize -= FileAndSize->first; + DEBUG(dbgs() << " - Remove " << FileAndSize->second << " (size " + << FileAndSize->first << "), new occupancy is " << TotalSize + << "%\n"); + ++FileAndSize; + } + } + return true; +} diff --git a/contrib/llvm/lib/Support/CommandLine.cpp b/contrib/llvm/lib/Support/CommandLine.cpp index fdcdb03..a5d2ba2 100644 --- a/contrib/llvm/lib/Support/CommandLine.cpp +++ b/contrib/llvm/lib/Support/CommandLine.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm-c/Support.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" @@ -94,35 +95,56 @@ public: // This collects additional help to be printed. std::vector<const char *> MoreHelp; - SmallVector<Option *, 4> PositionalOpts; - SmallVector<Option *, 4> SinkOpts; - StringMap<Option *> OptionsMap; - - Option *ConsumeAfterOpt; // The ConsumeAfter option if it exists. - // This collects the different option categories that have been registered. SmallPtrSet<OptionCategory *, 16> RegisteredOptionCategories; - CommandLineParser() : ProgramOverview(nullptr), ConsumeAfterOpt(nullptr) {} + // This collects the different subcommands that have been registered. + SmallPtrSet<SubCommand *, 4> RegisteredSubCommands; - void ParseCommandLineOptions(int argc, const char *const *argv, - const char *Overview); + CommandLineParser() : ProgramOverview(nullptr), ActiveSubCommand(nullptr) { + registerSubCommand(&*TopLevelSubCommand); + registerSubCommand(&*AllSubCommands); + } - void addLiteralOption(Option &Opt, const char *Name) { - if (!Opt.hasArgStr()) { - if (!OptionsMap.insert(std::make_pair(Name, &Opt)).second) { - errs() << ProgramName << ": CommandLine Error: Option '" << Name - << "' registered more than once!\n"; - report_fatal_error("inconsistency in registered CommandLine options"); + void ResetAllOptionOccurrences(); + + bool ParseCommandLineOptions(int argc, const char *const *argv, + const char *Overview, bool IgnoreErrors); + + void addLiteralOption(Option &Opt, SubCommand *SC, const char *Name) { + if (Opt.hasArgStr()) + return; + if (!SC->OptionsMap.insert(std::make_pair(Name, &Opt)).second) { + errs() << ProgramName << ": CommandLine Error: Option '" << Name + << "' registered more than once!\n"; + report_fatal_error("inconsistency in registered CommandLine options"); + } + + // If we're adding this to all sub-commands, add it to the ones that have + // already been registered. + if (SC == &*AllSubCommands) { + for (const auto &Sub : RegisteredSubCommands) { + if (SC == Sub) + continue; + addLiteralOption(Opt, Sub, Name); } } } - void addOption(Option *O) { + void addLiteralOption(Option &Opt, const char *Name) { + if (Opt.Subs.empty()) + addLiteralOption(Opt, &*TopLevelSubCommand, Name); + else { + for (auto SC : Opt.Subs) + addLiteralOption(Opt, SC, Name); + } + } + + void addOption(Option *O, SubCommand *SC) { bool HadErrors = false; if (O->hasArgStr()) { // Add argument to the argument map! - if (!OptionsMap.insert(std::make_pair(O->ArgStr, O)).second) { + if (!SC->OptionsMap.insert(std::make_pair(O->ArgStr, O)).second) { errs() << ProgramName << ": CommandLine Error: Option '" << O->ArgStr << "' registered more than once!\n"; HadErrors = true; @@ -131,15 +153,15 @@ public: // Remember information about positional options. if (O->getFormattingFlag() == cl::Positional) - PositionalOpts.push_back(O); + SC->PositionalOpts.push_back(O); else if (O->getMiscFlags() & cl::Sink) // Remember sink options - SinkOpts.push_back(O); + SC->SinkOpts.push_back(O); else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) { - if (ConsumeAfterOpt) { + if (SC->ConsumeAfterOpt) { O->error("Cannot specify more than one option with cl::ConsumeAfter!"); HadErrors = true; } - ConsumeAfterOpt = O; + SC->ConsumeAfterOpt = O; } // Fail hard if there were errors. These are strictly unrecoverable and @@ -148,64 +170,165 @@ public: // linked LLVM distribution. if (HadErrors) report_fatal_error("inconsistency in registered CommandLine options"); + + // If we're adding this to all sub-commands, add it to the ones that have + // already been registered. + if (SC == &*AllSubCommands) { + for (const auto &Sub : RegisteredSubCommands) { + if (SC == Sub) + continue; + addOption(O, Sub); + } + } } - void removeOption(Option *O) { + void addOption(Option *O) { + if (O->Subs.empty()) { + addOption(O, &*TopLevelSubCommand); + } else { + for (auto SC : O->Subs) + addOption(O, SC); + } + } + + void removeOption(Option *O, SubCommand *SC) { SmallVector<StringRef, 16> OptionNames; O->getExtraOptionNames(OptionNames); if (O->hasArgStr()) OptionNames.push_back(O->ArgStr); + + SubCommand &Sub = *SC; for (auto Name : OptionNames) - OptionsMap.erase(Name); + Sub.OptionsMap.erase(Name); if (O->getFormattingFlag() == cl::Positional) - for (auto Opt = PositionalOpts.begin(); Opt != PositionalOpts.end(); - ++Opt) { + for (auto Opt = Sub.PositionalOpts.begin(); + Opt != Sub.PositionalOpts.end(); ++Opt) { if (*Opt == O) { - PositionalOpts.erase(Opt); + Sub.PositionalOpts.erase(Opt); break; } } else if (O->getMiscFlags() & cl::Sink) - for (auto Opt = SinkOpts.begin(); Opt != SinkOpts.end(); ++Opt) { + for (auto Opt = Sub.SinkOpts.begin(); Opt != Sub.SinkOpts.end(); ++Opt) { if (*Opt == O) { - SinkOpts.erase(Opt); + Sub.SinkOpts.erase(Opt); break; } } - else if (O == ConsumeAfterOpt) - ConsumeAfterOpt = nullptr; + else if (O == Sub.ConsumeAfterOpt) + Sub.ConsumeAfterOpt = nullptr; } - bool hasOptions() { - return (!OptionsMap.empty() || !PositionalOpts.empty() || - nullptr != ConsumeAfterOpt); + void removeOption(Option *O) { + if (O->Subs.empty()) + removeOption(O, &*TopLevelSubCommand); + else { + if (O->isInAllSubCommands()) { + for (auto SC : RegisteredSubCommands) + removeOption(O, SC); + } else { + for (auto SC : O->Subs) + removeOption(O, SC); + } + } } - void updateArgStr(Option *O, StringRef NewName) { - if (!OptionsMap.insert(std::make_pair(NewName, O)).second) { + bool hasOptions(const SubCommand &Sub) const { + return (!Sub.OptionsMap.empty() || !Sub.PositionalOpts.empty() || + nullptr != Sub.ConsumeAfterOpt); + } + + bool hasOptions() const { + for (const auto &S : RegisteredSubCommands) { + if (hasOptions(*S)) + return true; + } + return false; + } + + SubCommand *getActiveSubCommand() { return ActiveSubCommand; } + + void updateArgStr(Option *O, StringRef NewName, SubCommand *SC) { + SubCommand &Sub = *SC; + if (!Sub.OptionsMap.insert(std::make_pair(NewName, O)).second) { errs() << ProgramName << ": CommandLine Error: Option '" << O->ArgStr << "' registered more than once!\n"; report_fatal_error("inconsistency in registered CommandLine options"); } - OptionsMap.erase(O->ArgStr); + Sub.OptionsMap.erase(O->ArgStr); + } + + void updateArgStr(Option *O, StringRef NewName) { + if (O->Subs.empty()) + updateArgStr(O, NewName, &*TopLevelSubCommand); + else { + for (auto SC : O->Subs) + updateArgStr(O, NewName, SC); + } } void printOptionValues(); void registerCategory(OptionCategory *cat) { - assert(std::count_if(RegisteredOptionCategories.begin(), - RegisteredOptionCategories.end(), - [cat](const OptionCategory *Category) { - return cat->getName() == Category->getName(); - }) == 0 && + assert(count_if(RegisteredOptionCategories, + [cat](const OptionCategory *Category) { + return cat->getName() == Category->getName(); + }) == 0 && "Duplicate option categories"); RegisteredOptionCategories.insert(cat); } + void registerSubCommand(SubCommand *sub) { + assert(count_if(RegisteredSubCommands, + [sub](const SubCommand *Sub) { + return (sub->getName() != nullptr) && + (Sub->getName() == sub->getName()); + }) == 0 && + "Duplicate subcommands"); + RegisteredSubCommands.insert(sub); + + // For all options that have been registered for all subcommands, add the + // option to this subcommand now. + if (sub != &*AllSubCommands) { + for (auto &E : AllSubCommands->OptionsMap) { + Option *O = E.second; + if ((O->isPositional() || O->isSink() || O->isConsumeAfter()) || + O->hasArgStr()) + addOption(O, sub); + else + addLiteralOption(*O, sub, E.first().str().c_str()); + } + } + } + + void unregisterSubCommand(SubCommand *sub) { + RegisteredSubCommands.erase(sub); + } + + void reset() { + ActiveSubCommand = nullptr; + ProgramName.clear(); + ProgramOverview = nullptr; + + MoreHelp.clear(); + RegisteredOptionCategories.clear(); + + ResetAllOptionOccurrences(); + RegisteredSubCommands.clear(); + + TopLevelSubCommand->reset(); + AllSubCommands->reset(); + registerSubCommand(&*TopLevelSubCommand); + registerSubCommand(&*AllSubCommands); + } + private: - Option *LookupOption(StringRef &Arg, StringRef &Value); + SubCommand *ActiveSubCommand; + + Option *LookupOption(SubCommand &Sub, StringRef &Arg, StringRef &Value); + SubCommand *LookupSubCommand(const char *Name); }; } // namespace @@ -240,6 +363,32 @@ void OptionCategory::registerCategory() { GlobalParser->registerCategory(this); } +// A special subcommand representing no subcommand +ManagedStatic<SubCommand> llvm::cl::TopLevelSubCommand; + +// A special subcommand that can be used to put an option into all subcommands. +ManagedStatic<SubCommand> llvm::cl::AllSubCommands; + +void SubCommand::registerSubCommand() { + GlobalParser->registerSubCommand(this); +} + +void SubCommand::unregisterSubCommand() { + GlobalParser->unregisterSubCommand(this); +} + +void SubCommand::reset() { + PositionalOpts.clear(); + SinkOpts.clear(); + OptionsMap.clear(); + + ConsumeAfterOpt = nullptr; +} + +SubCommand::operator bool() const { + return (GlobalParser->getActiveSubCommand() == this); +} + //===----------------------------------------------------------------------===// // Basic, shared command line option processing machinery. // @@ -247,25 +396,29 @@ void OptionCategory::registerCategory() { /// LookupOption - Lookup the option specified by the specified option on the /// command line. If there is a value specified (after an equal sign) return /// that as well. This assumes that leading dashes have already been stripped. -Option *CommandLineParser::LookupOption(StringRef &Arg, StringRef &Value) { +Option *CommandLineParser::LookupOption(SubCommand &Sub, StringRef &Arg, + StringRef &Value) { // Reject all dashes. if (Arg.empty()) return nullptr; + assert(&Sub != &*AllSubCommands); size_t EqualPos = Arg.find('='); // If we have an equals sign, remember the value. if (EqualPos == StringRef::npos) { // Look up the option. - StringMap<Option *>::const_iterator I = OptionsMap.find(Arg); - return I != OptionsMap.end() ? I->second : nullptr; + auto I = Sub.OptionsMap.find(Arg); + if (I == Sub.OptionsMap.end()) + return nullptr; + + return I != Sub.OptionsMap.end() ? I->second : nullptr; } // If the argument before the = is a valid option name, we match. If not, // return Arg unmolested. - StringMap<Option *>::const_iterator I = - OptionsMap.find(Arg.substr(0, EqualPos)); - if (I == OptionsMap.end()) + auto I = Sub.OptionsMap.find(Arg.substr(0, EqualPos)); + if (I == Sub.OptionsMap.end()) return nullptr; Value = Arg.substr(EqualPos + 1); @@ -273,6 +426,21 @@ Option *CommandLineParser::LookupOption(StringRef &Arg, StringRef &Value) { return I->second; } +SubCommand *CommandLineParser::LookupSubCommand(const char *Name) { + if (Name == nullptr) + return &*TopLevelSubCommand; + for (auto S : RegisteredSubCommands) { + if (S == &*AllSubCommands) + continue; + if (S->getName() == nullptr) + continue; + + if (StringRef(S->getName()) == StringRef(Name)) + return S; + } + return &*TopLevelSubCommand; +} + /// LookupNearestOption - Lookup the closest match to the option specified by /// the specified option on the command line. If there is a value specified /// (after an equal sign) return that as well. This assumes that leading dashes @@ -515,8 +683,6 @@ static bool isWhitespace(char C) { return strchr(" \t\n\r\f\v", C); } static bool isQuote(char C) { return C == '\"' || C == '\''; } -static bool isGNUSpecial(char C) { return strchr("\\\"\' ", C); } - void cl::TokenizeGNUCommandLine(StringRef Src, StringSaver &Saver, SmallVectorImpl<const char *> &NewArgv, bool MarkEOLs) { @@ -534,9 +700,8 @@ void cl::TokenizeGNUCommandLine(StringRef Src, StringSaver &Saver, break; } - // Backslashes can escape backslashes, spaces, and other quotes. Otherwise - // they are literal. This makes it much easier to read Windows file paths. - if (I + 1 < E && Src[I] == '\\' && isGNUSpecial(Src[I + 1])) { + // Backslash escapes the next character. + if (I + 1 < E && Src[I] == '\\') { ++I; // Skip the escape. Token.push_back(Src[I]); continue; @@ -546,8 +711,8 @@ void cl::TokenizeGNUCommandLine(StringRef Src, StringSaver &Saver, if (isQuote(Src[I])) { char Quote = Src[I++]; while (I != E && Src[I] != Quote) { - // Backslashes are literal, unless they escape a special character. - if (Src[I] == '\\' && I + 1 != E && isGNUSpecial(Src[I + 1])) + // Backslash escapes the next character. + if (Src[I] == '\\' && I + 1 != E) ++I; Token.push_back(Src[I]); ++I; @@ -787,9 +952,28 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, assert(envVar && "Environment variable name missing"); // Get the environment variable they want us to parse options out of. +#ifdef _WIN32 + std::wstring wenvVar; + if (!llvm::ConvertUTF8toWide(envVar, wenvVar)) { + assert(false && + "Unicode conversion of environment variable name failed"); + return; + } + const wchar_t *wenvValue = _wgetenv(wenvVar.c_str()); + if (!wenvValue) + return; + std::string envValueBuffer; + if (!llvm::convertWideToUTF8(wenvValue, envValueBuffer)) { + assert(false && + "Unicode conversion of environment variable value failed"); + return; + } + const char *envValue = envValueBuffer.c_str(); +#else const char *envValue = getenv(envVar); if (!envValue) return; +#endif // Get program's "name", which we wouldn't know without the caller // telling us. @@ -805,14 +989,25 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, ParseCommandLineOptions(newArgc, &newArgv[0], Overview); } -void cl::ParseCommandLineOptions(int argc, const char *const *argv, - const char *Overview) { - GlobalParser->ParseCommandLineOptions(argc, argv, Overview); +bool cl::ParseCommandLineOptions(int argc, const char *const *argv, + const char *Overview, bool IgnoreErrors) { + return GlobalParser->ParseCommandLineOptions(argc, argv, Overview, + IgnoreErrors); } -void CommandLineParser::ParseCommandLineOptions(int argc, +void CommandLineParser::ResetAllOptionOccurrences() { + // So that we can parse different command lines multiple times in succession + // we reset all option values to look like they have never been seen before. + for (auto SC : RegisteredSubCommands) { + for (auto &O : SC->OptionsMap) + O.second->reset(); + } +} + +bool CommandLineParser::ParseCommandLineOptions(int argc, const char *const *argv, - const char *Overview) { + const char *Overview, + bool IgnoreErrors) { assert(hasOptions() && "No options specified!"); // Expand response files. @@ -835,6 +1030,23 @@ void CommandLineParser::ParseCommandLineOptions(int argc, // Determine whether or not there are an unlimited number of positionals bool HasUnlimitedPositionals = false; + int FirstArg = 1; + SubCommand *ChosenSubCommand = &*TopLevelSubCommand; + if (argc >= 2 && argv[FirstArg][0] != '-') { + // If the first argument specifies a valid subcommand, start processing + // options from the second argument. + ChosenSubCommand = LookupSubCommand(argv[FirstArg]); + if (ChosenSubCommand != &*TopLevelSubCommand) + FirstArg = 2; + } + GlobalParser->ActiveSubCommand = ChosenSubCommand; + + assert(ChosenSubCommand); + auto &ConsumeAfterOpt = ChosenSubCommand->ConsumeAfterOpt; + auto &PositionalOpts = ChosenSubCommand->PositionalOpts; + auto &SinkOpts = ChosenSubCommand->SinkOpts; + auto &OptionsMap = ChosenSubCommand->OptionsMap; + if (ConsumeAfterOpt) { assert(PositionalOpts.size() > 0 && "Cannot specify cl::ConsumeAfter without a positional argument!"); @@ -850,23 +1062,28 @@ void CommandLineParser::ParseCommandLineOptions(int argc, else if (ConsumeAfterOpt) { // ConsumeAfter cannot be combined with "optional" positional options // unless there is only one positional argument... - if (PositionalOpts.size() > 1) - ErrorParsing |= Opt->error( - "error - this positional option will never be matched, " - "because it does not Require a value, and a " - "cl::ConsumeAfter option is active!"); + if (PositionalOpts.size() > 1) { + if (!IgnoreErrors) + Opt->error("error - this positional option will never be matched, " + "because it does not Require a value, and a " + "cl::ConsumeAfter option is active!"); + ErrorParsing = true; + } } else if (UnboundedFound && !Opt->hasArgStr()) { // This option does not "require" a value... Make sure this option is // not specified after an option that eats all extra arguments, or this // one will never get any! // - ErrorParsing |= Opt->error("error - option can never match, because " - "another positional argument will match an " - "unbounded number of values, and this option" - " does not require a value!"); - errs() << ProgramName << ": CommandLine Error: Option '" << Opt->ArgStr - << "' is all messed up!\n"; - errs() << PositionalOpts.size(); + if (!IgnoreErrors) { + Opt->error("error - option can never match, because " + "another positional argument will match an " + "unbounded number of values, and this option" + " does not require a value!"); + errs() << ProgramName << ": CommandLine Error: Option '" + << Opt->ArgStr << "' is all messed up!\n"; + errs() << PositionalOpts.size(); + } + ErrorParsing = true; } UnboundedFound |= EatsUnboundedNumberOfValues(Opt); } @@ -885,7 +1102,7 @@ void CommandLineParser::ParseCommandLineOptions(int argc, // Loop over all of the arguments... processing them. bool DashDashFound = false; // Have we read '--'? - for (int i = 1; i < argc; ++i) { + for (int i = FirstArg; i < argc; ++i) { Option *Handler = nullptr; Option *NearestHandler = nullptr; std::string NearestHandlerString; @@ -932,7 +1149,7 @@ void CommandLineParser::ParseCommandLineOptions(int argc, while (!ArgName.empty() && ArgName[0] == '-') ArgName = ArgName.substr(1); - Handler = LookupOption(ArgName, Value); + Handler = LookupOption(*ChosenSubCommand, ArgName, Value); if (!Handler || Handler->getFormattingFlag() != cl::Positional) { ProvidePositionalOption(ActivePositionalArg, argv[i], i); continue; // We are done! @@ -944,7 +1161,7 @@ void CommandLineParser::ParseCommandLineOptions(int argc, while (!ArgName.empty() && ArgName[0] == '-') ArgName = ArgName.substr(1); - Handler = LookupOption(ArgName, Value); + Handler = LookupOption(*ChosenSubCommand, ArgName, Value); // Check to see if this "option" is really a prefixed or grouped argument. if (!Handler) @@ -960,13 +1177,15 @@ void CommandLineParser::ParseCommandLineOptions(int argc, if (!Handler) { if (SinkOpts.empty()) { - errs() << ProgramName << ": Unknown command line argument '" << argv[i] - << "'. Try: '" << argv[0] << " -help'\n"; - - if (NearestHandler) { - // If we know a near match, report it as well. - errs() << ProgramName << ": Did you mean '-" << NearestHandlerString - << "'?\n"; + if (!IgnoreErrors) { + errs() << ProgramName << ": Unknown command line argument '" + << argv[i] << "'. Try: '" << argv[0] << " -help'\n"; + + if (NearestHandler) { + // If we know a near match, report it as well. + errs() << ProgramName << ": Did you mean '-" << NearestHandlerString + << "'?\n"; + } } ErrorParsing = true; @@ -989,17 +1208,21 @@ void CommandLineParser::ParseCommandLineOptions(int argc, // Check and handle positional arguments now... if (NumPositionalRequired > PositionalVals.size()) { - errs() << ProgramName - << ": Not enough positional command line arguments specified!\n" - << "Must specify at least " << NumPositionalRequired - << " positional arguments: See: " << argv[0] << " -help\n"; + if (!IgnoreErrors) { + errs() << ProgramName + << ": Not enough positional command line arguments specified!\n" + << "Must specify at least " << NumPositionalRequired + << " positional arguments: See: " << argv[0] << " -help\n"; + } ErrorParsing = true; } else if (!HasUnlimitedPositionals && PositionalVals.size() > PositionalOpts.size()) { - errs() << ProgramName << ": Too many positional arguments specified!\n" - << "Can specify at most " << PositionalOpts.size() - << " positional arguments: See: " << argv[0] << " -help\n"; + if (!IgnoreErrors) { + errs() << ProgramName << ": Too many positional arguments specified!\n" + << "Can specify at most " << PositionalOpts.size() + << " positional arguments: See: " << argv[0] << " -help\n"; + } ErrorParsing = true; } else if (!ConsumeAfterOpt) { @@ -1094,8 +1317,12 @@ void CommandLineParser::ParseCommandLineOptions(int argc, MoreHelp.clear(); // If we had an error processing our arguments, don't let the program execute - if (ErrorParsing) - exit(1); + if (ErrorParsing) { + if (!IgnoreErrors) + exit(1); + return false; + } + return true; } //===----------------------------------------------------------------------===// @@ -1416,7 +1643,7 @@ PRINT_OPT_DIFF(float) PRINT_OPT_DIFF(char) void parser<std::string>::printOptionDiff(const Option &O, StringRef V, - OptionValue<std::string> D, + const OptionValue<std::string> &D, size_t GlobalWidth) const { printOptionName(O, GlobalWidth); outs() << "= " << V; @@ -1445,11 +1672,16 @@ static int OptNameCompare(const std::pair<const char *, Option *> *LHS, return strcmp(LHS->first, RHS->first); } +static int SubNameCompare(const std::pair<const char *, SubCommand *> *LHS, + const std::pair<const char *, SubCommand *> *RHS) { + return strcmp(LHS->first, RHS->first); +} + // Copy Options into a vector so we can sort them as we like. static void sortOpts(StringMap<Option *> &OptMap, SmallVectorImpl<std::pair<const char *, Option *>> &Opts, bool ShowHidden) { - SmallPtrSet<Option *, 128> OptionSet; // Duplicate option detection. + SmallPtrSet<Option *, 32> OptionSet; // Duplicate option detection. for (StringMap<Option *>::iterator I = OptMap.begin(), E = OptMap.end(); I != E; ++I) { @@ -1473,6 +1705,17 @@ static void sortOpts(StringMap<Option *> &OptMap, array_pod_sort(Opts.begin(), Opts.end(), OptNameCompare); } +static void +sortSubCommands(const SmallPtrSetImpl<SubCommand *> &SubMap, + SmallVectorImpl<std::pair<const char *, SubCommand *>> &Subs) { + for (const auto &S : SubMap) { + if (S->getName() == nullptr) + continue; + Subs.push_back(std::make_pair(S->getName(), S)); + } + array_pod_sort(Subs.begin(), Subs.end(), SubNameCompare); +} + namespace { class HelpPrinter { @@ -1480,12 +1723,25 @@ protected: const bool ShowHidden; typedef SmallVector<std::pair<const char *, Option *>, 128> StrOptionPairVector; + typedef SmallVector<std::pair<const char *, SubCommand *>, 128> + StrSubCommandPairVector; // Print the options. Opts is assumed to be alphabetically sorted. virtual void printOptions(StrOptionPairVector &Opts, size_t MaxArgLen) { for (size_t i = 0, e = Opts.size(); i != e; ++i) Opts[i].second->printOptionInfo(MaxArgLen); } + void printSubCommands(StrSubCommandPairVector &Subs, size_t MaxSubLen) { + for (const auto &S : Subs) { + outs() << " " << S.first; + if (S.second->getDescription()) { + outs().indent(MaxSubLen - strlen(S.first)); + outs() << " - " << S.second->getDescription(); + } + outs() << "\n"; + } + } + public: explicit HelpPrinter(bool showHidden) : ShowHidden(showHidden) {} virtual ~HelpPrinter() {} @@ -1495,23 +1751,56 @@ public: if (!Value) return; + SubCommand *Sub = GlobalParser->getActiveSubCommand(); + auto &OptionsMap = Sub->OptionsMap; + auto &PositionalOpts = Sub->PositionalOpts; + auto &ConsumeAfterOpt = Sub->ConsumeAfterOpt; + StrOptionPairVector Opts; - sortOpts(GlobalParser->OptionsMap, Opts, ShowHidden); + sortOpts(OptionsMap, Opts, ShowHidden); + + StrSubCommandPairVector Subs; + sortSubCommands(GlobalParser->RegisteredSubCommands, Subs); if (GlobalParser->ProgramOverview) outs() << "OVERVIEW: " << GlobalParser->ProgramOverview << "\n"; - outs() << "USAGE: " << GlobalParser->ProgramName << " [options]"; + if (Sub == &*TopLevelSubCommand) + outs() << "USAGE: " << GlobalParser->ProgramName + << " [subcommand] [options]"; + else { + if (Sub->getDescription() != nullptr) { + outs() << "SUBCOMMAND '" << Sub->getName() + << "': " << Sub->getDescription() << "\n\n"; + } + outs() << "USAGE: " << GlobalParser->ProgramName << " " << Sub->getName() + << " [options]"; + } - for (auto Opt : GlobalParser->PositionalOpts) { + for (auto Opt : PositionalOpts) { if (Opt->hasArgStr()) outs() << " --" << Opt->ArgStr; outs() << " " << Opt->HelpStr; } // Print the consume after option info if it exists... - if (GlobalParser->ConsumeAfterOpt) - outs() << " " << GlobalParser->ConsumeAfterOpt->HelpStr; + if (ConsumeAfterOpt) + outs() << " " << ConsumeAfterOpt->HelpStr; + + if (Sub == &*TopLevelSubCommand && Subs.size() > 2) { + // Compute the maximum subcommand length... + size_t MaxSubLen = 0; + for (size_t i = 0, e = Subs.size(); i != e; ++i) + MaxSubLen = std::max(MaxSubLen, strlen(Subs[i].first)); + + outs() << "\n\n"; + outs() << "SUBCOMMANDS:\n\n"; + printSubCommands(Subs, MaxSubLen); + outs() << "\n"; + outs() << " Type \"" << GlobalParser->ProgramName + << " <subcommand> -help\" to get more help on a specific " + "subcommand"; + } outs() << "\n\n"; @@ -1589,7 +1878,8 @@ protected: E = SortedCategories.end(); Category != E; ++Category) { // Hide empty categories for -help, but show for -help-hidden. - bool IsEmptyCategory = CategorizedOptions[*Category].size() == 0; + const auto &CategoryOptions = CategorizedOptions[*Category]; + bool IsEmptyCategory = CategoryOptions.empty(); if (!ShowHidden && IsEmptyCategory) continue; @@ -1610,11 +1900,8 @@ protected: continue; } // Loop over the options in the category and print. - for (std::vector<Option *>::const_iterator - Opt = CategorizedOptions[*Category].begin(), - E = CategorizedOptions[*Category].end(); - Opt != E; ++Opt) - (*Opt)->printOptionInfo(MaxArgLen); + for (const Option *Opt : CategoryOptions) + Opt->printOptionInfo(MaxArgLen); } } }; @@ -1662,12 +1949,13 @@ static cl::opt<HelpPrinter, true, parser<bool>> HLOp( "help-list", cl::desc("Display list of available options (-help-list-hidden for more)"), cl::location(UncategorizedNormalPrinter), cl::Hidden, cl::ValueDisallowed, - cl::cat(GenericCategory)); + cl::cat(GenericCategory), cl::sub(*AllSubCommands)); static cl::opt<HelpPrinter, true, parser<bool>> HLHOp("help-list-hidden", cl::desc("Display list of all available options"), cl::location(UncategorizedHiddenPrinter), cl::Hidden, - cl::ValueDisallowed, cl::cat(GenericCategory)); + cl::ValueDisallowed, cl::cat(GenericCategory), + cl::sub(*AllSubCommands)); // Define uncategorized/categorized help printers. These printers change their // behaviour at runtime depending on whether one or more Option categories have @@ -1675,22 +1963,23 @@ static cl::opt<HelpPrinter, true, parser<bool>> static cl::opt<HelpPrinterWrapper, true, parser<bool>> HOp("help", cl::desc("Display available options (-help-hidden for more)"), cl::location(WrappedNormalPrinter), cl::ValueDisallowed, - cl::cat(GenericCategory)); + cl::cat(GenericCategory), cl::sub(*AllSubCommands)); static cl::opt<HelpPrinterWrapper, true, parser<bool>> HHOp("help-hidden", cl::desc("Display all available options"), cl::location(WrappedHiddenPrinter), cl::Hidden, cl::ValueDisallowed, - cl::cat(GenericCategory)); + cl::cat(GenericCategory), cl::sub(*AllSubCommands)); static cl::opt<bool> PrintOptions( "print-options", cl::desc("Print non-default options after command line parsing"), - cl::Hidden, cl::init(false), cl::cat(GenericCategory)); + cl::Hidden, cl::init(false), cl::cat(GenericCategory), + cl::sub(*AllSubCommands)); static cl::opt<bool> PrintAllOptions( "print-all-options", cl::desc("Print all option values after command line parsing"), cl::Hidden, - cl::init(false), cl::cat(GenericCategory)); + cl::init(false), cl::cat(GenericCategory), cl::sub(*AllSubCommands)); void HelpPrinterWrapper::operator=(bool Value) { if (!Value) @@ -1717,7 +2006,7 @@ void CommandLineParser::printOptionValues() { return; SmallVector<std::pair<const char *, Option *>, 128> Opts; - sortOpts(OptionsMap, Opts, /*ShowHidden*/ true); + sortOpts(ActiveSubCommand->OptionsMap, Opts, /*ShowHidden*/ true); // Compute the maximum argument length... size_t MaxArgLen = 0; @@ -1737,8 +2026,12 @@ class VersionPrinter { public: void print() { raw_ostream &OS = outs(); - OS << "LLVM (http://llvm.org/):\n" - << " " << PACKAGE_NAME << " version " << PACKAGE_VERSION; +#ifdef PACKAGE_VENDOR + OS << PACKAGE_VENDOR << " "; +#else + OS << "LLVM (http://llvm.org/):\n "; +#endif + OS << PACKAGE_NAME << " version " << PACKAGE_VERSION; #ifdef LLVM_VERSION_INFO OS << " " << LLVM_VERSION_INFO; #endif @@ -1755,9 +2048,6 @@ public: if (CPU == "generic") CPU = "(unknown)"; OS << ".\n" -#if (ENABLE_TIMESTAMPS == 1) - << " Built " << __DATE__ << " (" << __TIME__ << ").\n" -#endif << " Default target: " << sys::getDefaultTargetTriple() << '\n' << " Host CPU: " << CPU << '\n'; } @@ -1825,22 +2115,26 @@ void cl::AddExtraVersionPrinter(void (*func)()) { ExtraVersionPrinters->push_back(func); } -StringMap<Option *> &cl::getRegisteredOptions() { - return GlobalParser->OptionsMap; +StringMap<Option *> &cl::getRegisteredOptions(SubCommand &Sub) { + auto &Subs = GlobalParser->RegisteredSubCommands; + (void)Subs; + assert(std::find(Subs.begin(), Subs.end(), &Sub) != Subs.end()); + return Sub.OptionsMap; } -void cl::HideUnrelatedOptions(cl::OptionCategory &Category) { - for (auto &I : GlobalParser->OptionsMap) { +void cl::HideUnrelatedOptions(cl::OptionCategory &Category, SubCommand &Sub) { + for (auto &I : Sub.OptionsMap) { if (I.second->Category != &Category && I.second->Category != &GenericCategory) I.second->setHiddenFlag(cl::ReallyHidden); } } -void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories) { +void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories, + SubCommand &Sub) { auto CategoriesBegin = Categories.begin(); auto CategoriesEnd = Categories.end(); - for (auto &I : GlobalParser->OptionsMap) { + for (auto &I : Sub.OptionsMap) { if (std::find(CategoriesBegin, CategoriesEnd, I.second->Category) == CategoriesEnd && I.second->Category != &GenericCategory) @@ -1848,7 +2142,12 @@ void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories) { } } +void cl::ResetCommandLineParser() { GlobalParser->reset(); } +void cl::ResetAllOptionOccurrences() { + GlobalParser->ResetAllOptionOccurrences(); +} + void LLVMParseCommandLineOptions(int argc, const char *const *argv, const char *Overview) { - llvm::cl::ParseCommandLineOptions(argc, argv, Overview); + llvm::cl::ParseCommandLineOptions(argc, argv, Overview, true); } diff --git a/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp b/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp index 1bbef23..217cedb 100644 --- a/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp +++ b/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp @@ -8,6 +8,9 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/ConvertUTF.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SwapByteOrder.h" #include <string> #include <vector> @@ -36,7 +39,7 @@ bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source, ConversionFlags flags = strictConversion; result = ConvertUTF8toUTF16( &sourceStart, sourceStart + Source.size(), - &targetStart, targetStart + 2*Source.size(), flags); + &targetStart, targetStart + Source.size(), flags); if (result == conversionOK) ResultPtr = reinterpret_cast<char*>(targetStart); else @@ -49,7 +52,7 @@ bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source, ConversionFlags flags = strictConversion; result = ConvertUTF8toUTF32( &sourceStart, sourceStart + Source.size(), - &targetStart, targetStart + 4*Source.size(), flags); + &targetStart, targetStart + Source.size(), flags); if (result == conversionOK) ResultPtr = reinterpret_cast<char*>(targetStart); else @@ -130,6 +133,13 @@ bool convertUTF16ToUTF8String(ArrayRef<char> SrcBytes, std::string &Out) { return true; } +bool convertUTF16ToUTF8String(ArrayRef<UTF16> Src, std::string &Out) +{ + return convertUTF16ToUTF8String( + llvm::ArrayRef<char>(reinterpret_cast<const char *>(Src.data()), + Src.size() * sizeof(UTF16)), Out); +} + bool convertUTF8ToUTF16String(StringRef SrcUTF8, SmallVectorImpl<UTF16> &DstUTF16) { assert(DstUTF16.empty()); @@ -168,5 +178,74 @@ bool convertUTF8ToUTF16String(StringRef SrcUTF8, return true; } +static_assert(sizeof(wchar_t) == 1 || sizeof(wchar_t) == 2 || + sizeof(wchar_t) == 4, + "Expected wchar_t to be 1, 2, or 4 bytes"); + +template <typename TResult> +static inline bool ConvertUTF8toWideInternal(llvm::StringRef Source, + TResult &Result) { + // Even in the case of UTF-16, the number of bytes in a UTF-8 string is + // at least as large as the number of elements in the resulting wide + // string, because surrogate pairs take at least 4 bytes in UTF-8. + Result.resize(Source.size() + 1); + char *ResultPtr = reinterpret_cast<char *>(&Result[0]); + const UTF8 *ErrorPtr; + if (!ConvertUTF8toWide(sizeof(wchar_t), Source, ResultPtr, ErrorPtr)) { + Result.clear(); + return false; + } + Result.resize(reinterpret_cast<wchar_t *>(ResultPtr) - &Result[0]); + return true; +} + +bool ConvertUTF8toWide(llvm::StringRef Source, std::wstring &Result) { + return ConvertUTF8toWideInternal(Source, Result); +} + +bool ConvertUTF8toWide(const char *Source, std::wstring &Result) { + if (!Source) { + Result.clear(); + return true; + } + return ConvertUTF8toWide(llvm::StringRef(Source), Result); +} + +bool convertWideToUTF8(const std::wstring &Source, std::string &Result) { + if (sizeof(wchar_t) == 1) { + const UTF8 *Start = reinterpret_cast<const UTF8 *>(Source.data()); + const UTF8 *End = + reinterpret_cast<const UTF8 *>(Source.data() + Source.size()); + if (!isLegalUTF8String(&Start, End)) + return false; + Result.resize(Source.size()); + memcpy(&Result[0], Source.data(), Source.size()); + return true; + } else if (sizeof(wchar_t) == 2) { + return convertUTF16ToUTF8String( + llvm::ArrayRef<UTF16>(reinterpret_cast<const UTF16 *>(Source.data()), + Source.size()), + Result); + } else if (sizeof(wchar_t) == 4) { + const UTF32 *Start = reinterpret_cast<const UTF32 *>(Source.data()); + const UTF32 *End = + reinterpret_cast<const UTF32 *>(Source.data() + Source.size()); + Result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * Source.size()); + UTF8 *ResultPtr = reinterpret_cast<UTF8 *>(&Result[0]); + UTF8 *ResultEnd = reinterpret_cast<UTF8 *>(&Result[0] + Result.size()); + if (ConvertUTF32toUTF8(&Start, End, &ResultPtr, ResultEnd, + strictConversion) == conversionOK) { + Result.resize(reinterpret_cast<char *>(ResultPtr) - &Result[0]); + return true; + } else { + Result.clear(); + return false; + } + } else { + llvm_unreachable( + "Control should never reach this point; see static_assert further up"); + } +} + } // end namespace llvm diff --git a/contrib/llvm/lib/Support/CrashRecoveryContext.cpp b/contrib/llvm/lib/Support/CrashRecoveryContext.cpp index 3f4ef9d..98865f5 100644 --- a/contrib/llvm/lib/Support/CrashRecoveryContext.cpp +++ b/contrib/llvm/lib/Support/CrashRecoveryContext.cpp @@ -31,7 +31,6 @@ struct CrashRecoveryContextImpl { const CrashRecoveryContextImpl *Next; CrashRecoveryContext *CRC; - std::string Backtrace; ::jmp_buf JumpBuffer; volatile unsigned Failed : 1; unsigned SwitchedThread : 1; @@ -335,13 +334,6 @@ void CrashRecoveryContext::HandleCrash() { CRCI->HandleCrash(); } -const std::string &CrashRecoveryContext::getBacktrace() const { - CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *) Impl; - assert(CRC && "Crash recovery context never initialized!"); - assert(CRC->Failed && "No crash was detected!"); - return CRC->Backtrace; -} - // FIXME: Portability. static void setThreadBackgroundPriority() { #ifdef __APPLE__ diff --git a/contrib/llvm/lib/Support/Dwarf.cpp b/contrib/llvm/lib/Support/Dwarf.cpp index 7d72256..7aea05d 100644 --- a/contrib/llvm/lib/Support/Dwarf.cpp +++ b/contrib/llvm/lib/Support/Dwarf.cpp @@ -384,23 +384,22 @@ const char *llvm::dwarf::CaseString(unsigned Case) { return nullptr; } -const char *llvm::dwarf::ConventionString(unsigned Convention) { - switch (Convention) { - case DW_CC_normal: return "DW_CC_normal"; - case DW_CC_program: return "DW_CC_program"; - case DW_CC_nocall: return "DW_CC_nocall"; - case DW_CC_lo_user: return "DW_CC_lo_user"; - case DW_CC_hi_user: return "DW_CC_hi_user"; - case DW_CC_GNU_borland_fastcall_i386: return "DW_CC_GNU_borland_fastcall_i386"; - case DW_CC_BORLAND_safecall: return "DW_CC_BORLAND_safecall"; - case DW_CC_BORLAND_stdcall: return "DW_CC_BORLAND_stdcall"; - case DW_CC_BORLAND_pascal: return "DW_CC_BORLAND_pascal"; - case DW_CC_BORLAND_msfastcall: return "DW_CC_BORLAND_msfastcall"; - case DW_CC_BORLAND_msreturn: return "DW_CC_BORLAND_msreturn"; - case DW_CC_BORLAND_thiscall: return "DW_CC_BORLAND_thiscall"; - case DW_CC_BORLAND_fastcall: return "DW_CC_BORLAND_fastcall"; +const char *llvm::dwarf::ConventionString(unsigned CC) { + switch (CC) { + default: + return nullptr; +#define HANDLE_DW_CC(ID, NAME) \ + case DW_CC_##NAME: \ + return "DW_CC_" #NAME; +#include "llvm/Support/Dwarf.def" } - return nullptr; +} + +unsigned llvm::dwarf::getCallingConvention(StringRef CCString) { + return StringSwitch<unsigned>(CCString) +#define HANDLE_DW_CC(ID, NAME) .Case("DW_CC_" #NAME, DW_CC_##NAME) +#include "llvm/Support/Dwarf.def" + .Default(0); } const char *llvm::dwarf::InlineCodeString(unsigned Code) { @@ -546,6 +545,12 @@ const char *llvm::dwarf::ApplePropertyString(unsigned Prop) { return "DW_APPLE_PROPERTY_strong"; case DW_APPLE_PROPERTY_unsafe_unretained: return "DW_APPLE_PROPERTY_unsafe_unretained"; + case DW_APPLE_PROPERTY_nullability: + return "DW_APPLE_PROPERTY_nullability"; + case DW_APPLE_PROPERTY_null_resettable: + return "DW_APPLE_PROPERTY_null_resettable"; + case DW_APPLE_PROPERTY_class: + return "DW_APPLE_PROPERTY_class"; } return nullptr; } diff --git a/contrib/llvm/lib/Support/Error.cpp b/contrib/llvm/lib/Support/Error.cpp new file mode 100644 index 0000000..6b22691 --- /dev/null +++ b/contrib/llvm/lib/Support/Error.cpp @@ -0,0 +1,113 @@ +//===----- lib/Support/Error.cpp - Error and associated utilities ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Error.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" + + +using namespace llvm; + +namespace { + + enum class ErrorErrorCode : int { + MultipleErrors = 1, + InconvertibleError + }; + + // FIXME: This class is only here to support the transition to llvm::Error. It + // will be removed once this transition is complete. Clients should prefer to + // deal with the Error value directly, rather than converting to error_code. + class ErrorErrorCategory : public std::error_category { + public: + const char *name() const LLVM_NOEXCEPT override { return "Error"; } + + std::string message(int condition) const override { + switch (static_cast<ErrorErrorCode>(condition)) { + case ErrorErrorCode::MultipleErrors: + return "Multiple errors"; + case ErrorErrorCode::InconvertibleError: + return "Inconvertible error value. An error has occurred that could " + "not be converted to a known std::error_code. Please file a " + "bug."; + } + llvm_unreachable("Unhandled error code"); + } + }; + +} + +static ManagedStatic<ErrorErrorCategory> ErrorErrorCat; + +namespace llvm { + +void ErrorInfoBase::anchor() {} +char ErrorInfoBase::ID = 0; +char ErrorList::ID = 0; +char ECError::ID = 0; +char StringError::ID = 0; + +void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner) { + if (!E) + return; + OS << ErrorBanner; + handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) { + EI.log(OS); + OS << "\n"; + }); +} + + +std::error_code ErrorList::convertToErrorCode() const { + return std::error_code(static_cast<int>(ErrorErrorCode::MultipleErrors), + *ErrorErrorCat); +} + +std::error_code inconvertibleErrorCode() { + return std::error_code(static_cast<int>(ErrorErrorCode::InconvertibleError), + *ErrorErrorCat); +} + +Error errorCodeToError(std::error_code EC) { + if (!EC) + return Error::success(); + return Error(llvm::make_unique<ECError>(ECError(EC))); +} + +std::error_code errorToErrorCode(Error Err) { + std::error_code EC; + handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) { + EC = EI.convertToErrorCode(); + }); + if (EC == inconvertibleErrorCode()) + report_fatal_error(EC.message()); + return EC; +} + +StringError::StringError(const Twine &S, std::error_code EC) + : Msg(S.str()), EC(EC) {} + +void StringError::log(raw_ostream &OS) const { OS << Msg; } + +std::error_code StringError::convertToErrorCode() const { + return EC; +} + +void report_fatal_error(Error Err, bool GenCrashDiag) { + assert(Err && "report_fatal_error called with success value"); + std::string ErrMsg; + { + raw_string_ostream ErrStream(ErrMsg); + logAllUnhandledErrors(std::move(Err), ErrStream, ""); + } + report_fatal_error(ErrMsg); +} + +} diff --git a/contrib/llvm/lib/Support/ErrorHandling.cpp b/contrib/llvm/lib/Support/ErrorHandling.cpp index 2808bd3..a7d3a18 100644 --- a/contrib/llvm/lib/Support/ErrorHandling.cpp +++ b/contrib/llvm/lib/Support/ErrorHandling.cpp @@ -19,6 +19,7 @@ #include "llvm/Config/config.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/MutexGuard.h" diff --git a/contrib/llvm/lib/Support/FileUtilities.cpp b/contrib/llvm/lib/Support/FileUtilities.cpp index 5316f04..c6a58cc 100644 --- a/contrib/llvm/lib/Support/FileUtilities.cpp +++ b/contrib/llvm/lib/Support/FileUtilities.cpp @@ -217,8 +217,10 @@ int llvm::DiffFilesWithTolerance(StringRef NameA, bool CompareFailed = false; while (1) { // Scan for the end of file or next difference. - while (F1P < File1End && F2P < File2End && *F1P == *F2P) - ++F1P, ++F2P; + while (F1P < File1End && F2P < File2End && *F1P == *F2P) { + ++F1P; + ++F2P; + } if (F1P >= File1End || F2P >= File2End) break; diff --git a/contrib/llvm/lib/Support/FoldingSet.cpp b/contrib/llvm/lib/Support/FoldingSet.cpp index bb0ec2d..52baf86 100644 --- a/contrib/llvm/lib/Support/FoldingSet.cpp +++ b/contrib/llvm/lib/Support/FoldingSet.cpp @@ -266,12 +266,12 @@ void FoldingSetImpl::clear() { NumNodes = 0; } -/// GrowHashTable - Double the size of the hash table and rehash everything. -/// -void FoldingSetImpl::GrowHashTable() { +void FoldingSetImpl::GrowBucketCount(unsigned NewBucketCount) { + assert((NewBucketCount > NumBuckets) && "Can't shrink a folding set with GrowBucketCount"); + assert(isPowerOf2_32(NewBucketCount) && "Bad bucket count!"); void **OldBuckets = Buckets; unsigned OldNumBuckets = NumBuckets; - NumBuckets <<= 1; + NumBuckets = NewBucketCount; // Clear out new buckets. Buckets = AllocateBuckets(NumBuckets); @@ -298,6 +298,21 @@ void FoldingSetImpl::GrowHashTable() { free(OldBuckets); } +/// GrowHashTable - Double the size of the hash table and rehash everything. +/// +void FoldingSetImpl::GrowHashTable() { + GrowBucketCount(NumBuckets * 2); +} + +void FoldingSetImpl::reserve(unsigned EltCount) { + // This will give us somewhere between EltCount / 2 and + // EltCount buckets. This puts us in the load factor + // range of 1.0 - 2.0. + if(EltCount < capacity()) + return; + GrowBucketCount(PowerOf2Floor(EltCount)); +} + /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, /// return it. If not, return the insertion token that will make insertion /// faster. @@ -330,7 +345,7 @@ FoldingSetImpl::Node void FoldingSetImpl::InsertNode(Node *N, void *InsertPos) { assert(!N->getNextInBucket()); // Do we need to grow the hashtable? - if (NumNodes+1 > NumBuckets*2) { + if (NumNodes+1 > capacity()) { GrowHashTable(); FoldingSetNodeID TempID; InsertPos = GetBucketFor(ComputeNodeHash(N, TempID), Buckets, NumBuckets); diff --git a/contrib/llvm/lib/Support/Host.cpp b/contrib/llvm/lib/Support/Host.cpp index c0f9e07..12ac19d 100644 --- a/contrib/llvm/lib/Support/Host.cpp +++ b/contrib/llvm/lib/Support/Host.cpp @@ -33,9 +33,9 @@ #include <intrin.h> #endif #if defined(__APPLE__) && (defined(__ppc__) || defined(__powerpc__)) +#include <mach/host_info.h> #include <mach/mach.h> #include <mach/mach_host.h> -#include <mach/host_info.h> #include <mach/machine.h> #endif @@ -69,40 +69,131 @@ static ssize_t LLVM_ATTRIBUTE_UNUSED readCpuInfo(void *Buf, size_t Size) { } #endif -#if defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86)\ - || defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) - -/// GetX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in the -/// specified arguments. If we can't run cpuid on the host, return true. -static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, +#if defined(i386) || defined(__i386__) || defined(__x86__) || \ + defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) || \ + defined(_M_X64) + +enum VendorSignatures { + SIG_INTEL = 0x756e6547 /* Genu */, + SIG_AMD = 0x68747541 /* Auth */ +}; + +enum ProcessorVendors { + VENDOR_INTEL = 1, + VENDOR_AMD, + VENDOR_OTHER, + VENDOR_MAX +}; + +enum ProcessorTypes { + INTEL_ATOM = 1, + INTEL_CORE2, + INTEL_COREI7, + AMDFAM10H, + AMDFAM15H, + INTEL_i386, + INTEL_i486, + INTEL_PENTIUM, + INTEL_PENTIUM_PRO, + INTEL_PENTIUM_II, + INTEL_PENTIUM_III, + INTEL_PENTIUM_IV, + INTEL_PENTIUM_M, + INTEL_CORE_DUO, + INTEL_XEONPHI, + INTEL_X86_64, + INTEL_NOCONA, + INTEL_PRESCOTT, + AMD_i486, + AMDPENTIUM, + AMDATHLON, + AMDFAM14H, + AMDFAM16H, + CPU_TYPE_MAX +}; + +enum ProcessorSubtypes { + INTEL_COREI7_NEHALEM = 1, + INTEL_COREI7_WESTMERE, + INTEL_COREI7_SANDYBRIDGE, + AMDFAM10H_BARCELONA, + AMDFAM10H_SHANGHAI, + AMDFAM10H_ISTANBUL, + AMDFAM15H_BDVER1, + AMDFAM15H_BDVER2, + INTEL_PENTIUM_MMX, + INTEL_CORE2_65, + INTEL_CORE2_45, + INTEL_COREI7_IVYBRIDGE, + INTEL_COREI7_HASWELL, + INTEL_COREI7_BROADWELL, + INTEL_COREI7_SKYLAKE, + INTEL_COREI7_SKYLAKE_AVX512, + INTEL_ATOM_BONNELL, + INTEL_ATOM_SILVERMONT, + INTEL_KNIGHTS_LANDING, + AMDPENTIUM_K6, + AMDPENTIUM_K62, + AMDPENTIUM_K63, + AMDPENTIUM_GEODE, + AMDATHLON_TBIRD, + AMDATHLON_MP, + AMDATHLON_XP, + AMDATHLON_K8SSE3, + AMDATHLON_OPTERON, + AMDATHLON_FX, + AMDATHLON_64, + AMD_BTVER1, + AMD_BTVER2, + AMDFAM15H_BDVER3, + AMDFAM15H_BDVER4, + CPU_SUBTYPE_MAX +}; + +enum ProcessorFeatures { + FEATURE_CMOV = 0, + FEATURE_MMX, + FEATURE_POPCNT, + FEATURE_SSE, + FEATURE_SSE2, + FEATURE_SSE3, + FEATURE_SSSE3, + FEATURE_SSE4_1, + FEATURE_SSE4_2, + FEATURE_AVX, + FEATURE_AVX2, + FEATURE_AVX512, + FEATURE_AVX512SAVE, + FEATURE_MOVBE, + FEATURE_ADX, + FEATURE_EM64T +}; + +/// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in +/// the specified arguments. If we can't run cpuid on the host, return true. +static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { #if defined(__GNUC__) || defined(__clang__) - #if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) - // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. - asm ("movq\t%%rbx, %%rsi\n\t" - "cpuid\n\t" - "xchgq\t%%rbx, %%rsi\n\t" - : "=a" (*rEAX), - "=S" (*rEBX), - "=c" (*rECX), - "=d" (*rEDX) - : "a" (value)); - return false; - #elif defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86) - asm ("movl\t%%ebx, %%esi\n\t" - "cpuid\n\t" - "xchgl\t%%ebx, %%esi\n\t" - : "=a" (*rEAX), - "=S" (*rEBX), - "=c" (*rECX), - "=d" (*rEDX) - : "a" (value)); - return false; +#if defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64) + // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. + asm("movq\t%%rbx, %%rsi\n\t" + "cpuid\n\t" + "xchgq\t%%rbx, %%rsi\n\t" + : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) + : "a"(value)); + return false; +#elif defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86) + asm("movl\t%%ebx, %%esi\n\t" + "cpuid\n\t" + "xchgl\t%%ebx, %%esi\n\t" + : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) + : "a"(value)); + return false; // pedantic #else returns to appease -Wunreachable-code (so we don't generate // postprocessed code that looks like "return true; return false;") - #else - return true; - #endif +#else + return true; +#endif #elif defined(_MSC_VER) // The MSVC intrinsic is portable across x86 and x64. int registers[4]; @@ -117,50 +208,42 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, #endif } -/// GetX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return the -/// 4 values in the specified arguments. If we can't run cpuid on the host, +/// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return +/// the 4 values in the specified arguments. If we can't run cpuid on the host, /// return true. -static bool GetX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, +static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, unsigned *rEAX, unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { -#if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) - #if defined(__GNUC__) - // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. - asm ("movq\t%%rbx, %%rsi\n\t" - "cpuid\n\t" - "xchgq\t%%rbx, %%rsi\n\t" - : "=a" (*rEAX), - "=S" (*rEBX), - "=c" (*rECX), - "=d" (*rEDX) - : "a" (value), - "c" (subleaf)); - return false; - #elif defined(_MSC_VER) - int registers[4]; - __cpuidex(registers, value, subleaf); - *rEAX = registers[0]; - *rEBX = registers[1]; - *rECX = registers[2]; - *rEDX = registers[3]; - return false; - #else - return true; - #endif +#if defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64) +#if defined(__GNUC__) + // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. + asm("movq\t%%rbx, %%rsi\n\t" + "cpuid\n\t" + "xchgq\t%%rbx, %%rsi\n\t" + : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) + : "a"(value), "c"(subleaf)); + return false; +#elif defined(_MSC_VER) + int registers[4]; + __cpuidex(registers, value, subleaf); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; + return false; +#else + return true; +#endif #elif defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86) - #if defined(__GNUC__) - asm ("movl\t%%ebx, %%esi\n\t" - "cpuid\n\t" - "xchgl\t%%ebx, %%esi\n\t" - : "=a" (*rEAX), - "=S" (*rEBX), - "=c" (*rECX), - "=d" (*rEDX) - : "a" (value), - "c" (subleaf)); - return false; - #elif defined(_MSC_VER) - __asm { +#if defined(__GNUC__) + asm("movl\t%%ebx, %%esi\n\t" + "cpuid\n\t" + "xchgl\t%%ebx, %%esi\n\t" + : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) + : "a"(value), "c"(subleaf)); + return false; +#elif defined(_MSC_VER) + __asm { mov eax,value mov ecx,subleaf cpuid @@ -172,22 +255,22 @@ static bool GetX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, mov dword ptr [esi],ecx mov esi,rEDX mov dword ptr [esi],edx - } - return false; - #else - return true; - #endif + } + return false; +#else + return true; +#endif #else return true; #endif } -static bool GetX86XCR0(unsigned *rEAX, unsigned *rEDX) { +static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) { #if defined(__GNUC__) // Check xgetbv; this uses a .byte sequence instead of the instruction // directly because older assemblers do not include support for xgetbv and // there is no easy way to conditionally compile based on the assembler used. - __asm__ (".byte 0x0f, 0x01, 0xd0" : "=a" (*rEAX), "=d" (*rEDX) : "c" (0)); + __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(*rEAX), "=d"(*rEDX) : "c"(0)); return false; #elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); @@ -199,342 +282,669 @@ static bool GetX86XCR0(unsigned *rEAX, unsigned *rEDX) { #endif } -static void DetectX86FamilyModel(unsigned EAX, unsigned &Family, - unsigned &Model) { - Family = (EAX >> 8) & 0xf; // Bits 8 - 11 - Model = (EAX >> 4) & 0xf; // Bits 4 - 7 - if (Family == 6 || Family == 0xf) { - if (Family == 0xf) +static void detectX86FamilyModel(unsigned EAX, unsigned *Family, + unsigned *Model) { + *Family = (EAX >> 8) & 0xf; // Bits 8 - 11 + *Model = (EAX >> 4) & 0xf; // Bits 4 - 7 + if (*Family == 6 || *Family == 0xf) { + if (*Family == 0xf) // Examine extended family ID if family ID is F. - Family += (EAX >> 20) & 0xff; // Bits 20 - 27 + *Family += (EAX >> 20) & 0xff; // Bits 20 - 27 // Examine extended model ID if family ID is 6 or F. - Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 + *Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 } } -StringRef sys::getHostCPUName() { - unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; - if (GetX86CpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX)) - return "generic"; - unsigned Family = 0; - unsigned Model = 0; - DetectX86FamilyModel(EAX, Family, Model); - - union { - unsigned u[3]; - char c[12]; - } text; - - unsigned MaxLeaf; - GetX86CpuIDAndInfo(0, &MaxLeaf, text.u+0, text.u+2, text.u+1); - - bool HasMMX = (EDX >> 23) & 1; - bool HasSSE = (EDX >> 25) & 1; - bool HasSSE2 = (EDX >> 26) & 1; - bool HasSSE3 = (ECX >> 0) & 1; - bool HasSSSE3 = (ECX >> 9) & 1; - bool HasSSE41 = (ECX >> 19) & 1; - bool HasSSE42 = (ECX >> 20) & 1; - bool HasMOVBE = (ECX >> 22) & 1; - // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV - // indicates that the AVX registers will be saved and restored on context - // switch, then we have full AVX support. - const unsigned AVXBits = (1 << 27) | (1 << 28); - bool HasAVX = ((ECX & AVXBits) == AVXBits) && !GetX86XCR0(&EAX, &EDX) && - ((EAX & 0x6) == 0x6); - bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); - bool HasLeaf7 = MaxLeaf >= 0x7 && - !GetX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); - bool HasADX = HasLeaf7 && ((EBX >> 19) & 1); - bool HasAVX2 = HasAVX && HasLeaf7 && (EBX & 0x20); - bool HasAVX512 = HasLeaf7 && HasAVX512Save && ((EBX >> 16) & 1); - - GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); - bool Em64T = (EDX >> 29) & 0x1; - bool HasTBM = (ECX >> 21) & 0x1; - - if (memcmp(text.c, "GenuineIntel", 12) == 0) { - switch (Family) { - case 3: - return "i386"; - case 4: - switch (Model) { - case 0: // Intel486 DX processors - case 1: // Intel486 DX processors - case 2: // Intel486 SX processors - case 3: // Intel487 processors, IntelDX2 OverDrive processors, - // IntelDX2 processors - case 4: // Intel486 SL processor - case 5: // IntelSX2 processors - case 7: // Write-Back Enhanced IntelDX2 processors - case 8: // IntelDX4 OverDrive processors, IntelDX4 processors - default: return "i486"; - } - case 5: - switch (Model) { - case 1: // Pentium OverDrive processor for Pentium processor (60, 66), - // Pentium processors (60, 66) - case 2: // Pentium OverDrive processor for Pentium processor (75, 90, - // 100, 120, 133), Pentium processors (75, 90, 100, 120, 133, - // 150, 166, 200) - case 3: // Pentium OverDrive processors for Intel486 processor-based - // systems - return "pentium"; - - case 4: // Pentium OverDrive processor with MMX technology for Pentium - // processor (75, 90, 100, 120, 133), Pentium processor with - // MMX technology (166, 200) - return "pentium-mmx"; - - default: return "pentium"; - } - case 6: - switch (Model) { - case 1: // Pentium Pro processor - return "pentiumpro"; - - case 3: // Intel Pentium II OverDrive processor, Pentium II processor, +static void +getIntelProcessorTypeAndSubtype(unsigned int Family, unsigned int Model, + unsigned int Brand_id, unsigned int Features, + unsigned *Type, unsigned *Subtype) { + if (Brand_id != 0) + return; + switch (Family) { + case 3: + *Type = INTEL_i386; + break; + case 4: + switch (Model) { + case 0: // Intel486 DX processors + case 1: // Intel486 DX processors + case 2: // Intel486 SX processors + case 3: // Intel487 processors, IntelDX2 OverDrive processors, + // IntelDX2 processors + case 4: // Intel486 SL processor + case 5: // IntelSX2 processors + case 7: // Write-Back Enhanced IntelDX2 processors + case 8: // IntelDX4 OverDrive processors, IntelDX4 processors + default: + *Type = INTEL_i486; + break; + } + break; + case 5: + switch (Model) { + case 1: // Pentium OverDrive processor for Pentium processor (60, 66), + // Pentium processors (60, 66) + case 2: // Pentium OverDrive processor for Pentium processor (75, 90, + // 100, 120, 133), Pentium processors (75, 90, 100, 120, 133, + // 150, 166, 200) + case 3: // Pentium OverDrive processors for Intel486 processor-based + // systems + *Type = INTEL_PENTIUM; + break; + case 4: // Pentium OverDrive processor with MMX technology for Pentium + // processor (75, 90, 100, 120, 133), Pentium processor with + // MMX technology (166, 200) + *Type = INTEL_PENTIUM; + *Subtype = INTEL_PENTIUM_MMX; + break; + default: + *Type = INTEL_PENTIUM; + break; + } + break; + case 6: + switch (Model) { + case 0x01: // Pentium Pro processor + *Type = INTEL_PENTIUM_PRO; + break; + case 0x03: // Intel Pentium II OverDrive processor, Pentium II processor, // model 03 - case 5: // Pentium II processor, model 05, Pentium II Xeon processor, + case 0x05: // Pentium II processor, model 05, Pentium II Xeon processor, // model 05, and Intel Celeron processor, model 05 - case 6: // Celeron processor, model 06 - return "pentium2"; - - case 7: // Pentium III processor, model 07, and Pentium III Xeon + case 0x06: // Celeron processor, model 06 + *Type = INTEL_PENTIUM_II; + break; + case 0x07: // Pentium III processor, model 07, and Pentium III Xeon // processor, model 07 - case 8: // Pentium III processor, model 08, Pentium III Xeon processor, + case 0x08: // Pentium III processor, model 08, Pentium III Xeon processor, // model 08, and Celeron processor, model 08 - case 10: // Pentium III Xeon processor, model 0Ah - case 11: // Pentium III processor, model 0Bh - return "pentium3"; - - case 9: // Intel Pentium M processor, Intel Celeron M processor model 09. - case 13: // Intel Pentium M processor, Intel Celeron M processor, model + case 0x0a: // Pentium III Xeon processor, model 0Ah + case 0x0b: // Pentium III processor, model 0Bh + *Type = INTEL_PENTIUM_III; + break; + case 0x09: // Intel Pentium M processor, Intel Celeron M processor model 09. + case 0x0d: // Intel Pentium M processor, Intel Celeron M processor, model // 0Dh. All processors are manufactured using the 90 nm process. - case 21: // Intel EP80579 Integrated Processor and Intel EP80579 + case 0x15: // Intel EP80579 Integrated Processor and Intel EP80579 // Integrated Processor with Intel QuickAssist Technology - return "pentium-m"; - - case 14: // Intel Core Duo processor, Intel Core Solo processor, model + *Type = INTEL_PENTIUM_M; + break; + case 0x0e: // Intel Core Duo processor, Intel Core Solo processor, model // 0Eh. All processors are manufactured using the 65 nm process. - return "yonah"; - - case 15: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile + *Type = INTEL_CORE_DUO; + break; // yonah + case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile // processor, Intel Core 2 Quad processor, Intel Core 2 Quad // mobile processor, Intel Core 2 Extreme processor, Intel // Pentium Dual-Core processor, Intel Xeon processor, model // 0Fh. All processors are manufactured using the 65 nm process. - case 22: // Intel Celeron processor model 16h. All processors are + case 0x16: // Intel Celeron processor model 16h. All processors are // manufactured using the 65 nm process - return "core2"; - - case 23: // Intel Core 2 Extreme processor, Intel Xeon processor, model + *Type = INTEL_CORE2; // "core2" + *Subtype = INTEL_CORE2_65; + break; + case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model // 17h. All processors are manufactured using the 45 nm process. // // 45nm: Penryn , Wolfdale, Yorkfield (XE) - case 29: // Intel Xeon processor MP. All processors are manufactured using + case 0x1d: // Intel Xeon processor MP. All processors are manufactured using // the 45 nm process. - return "penryn"; - - case 26: // Intel Core i7 processor and Intel Xeon processor. All + *Type = INTEL_CORE2; // "penryn" + *Subtype = INTEL_CORE2_45; + break; + case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All // processors are manufactured using the 45 nm process. - case 30: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. + case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. // As found in a Summer 2010 model iMac. - case 46: // Nehalem EX - return "nehalem"; - case 37: // Intel Core i7, laptop version. - case 44: // Intel Core i7 processor and Intel Xeon processor. All + case 0x1f: + case 0x2e: // Nehalem EX + *Type = INTEL_COREI7; // "nehalem" + *Subtype = INTEL_COREI7_NEHALEM; + break; + case 0x25: // Intel Core i7, laptop version. + case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All // processors are manufactured using the 32 nm process. - case 47: // Westmere EX - return "westmere"; - - // SandyBridge: - case 42: // Intel Core i7 processor. All processors are manufactured + case 0x2f: // Westmere EX + *Type = INTEL_COREI7; // "westmere" + *Subtype = INTEL_COREI7_WESTMERE; + break; + case 0x2a: // Intel Core i7 processor. All processors are manufactured // using the 32 nm process. - case 45: - return "sandybridge"; + case 0x2d: + *Type = INTEL_COREI7; //"sandybridge" + *Subtype = INTEL_COREI7_SANDYBRIDGE; + break; + case 0x3a: + case 0x3e: // Ivy Bridge EP + *Type = INTEL_COREI7; // "ivybridge" + *Subtype = INTEL_COREI7_IVYBRIDGE; + break; - // Ivy Bridge: - case 58: - case 62: // Ivy Bridge EP - return "ivybridge"; + // Haswell: + case 0x3c: + case 0x3f: + case 0x45: + case 0x46: + *Type = INTEL_COREI7; // "haswell" + *Subtype = INTEL_COREI7_HASWELL; + break; - // Haswell: - case 60: - case 63: - case 69: - case 70: - return "haswell"; + // Broadwell: + case 0x3d: + case 0x47: + case 0x4f: + case 0x56: + *Type = INTEL_COREI7; // "broadwell" + *Subtype = INTEL_COREI7_BROADWELL; + break; - // Broadwell: - case 61: - case 71: - return "broadwell"; + // Skylake: + case 0x4e: + *Type = INTEL_COREI7; // "skylake-avx512" + *Subtype = INTEL_COREI7_SKYLAKE_AVX512; + break; + case 0x5e: + *Type = INTEL_COREI7; // "skylake" + *Subtype = INTEL_COREI7_SKYLAKE; + break; - // Skylake: - case 78: - case 94: - return "skylake"; + case 0x1c: // Most 45 nm Intel Atom processors + case 0x26: // 45 nm Atom Lincroft + case 0x27: // 32 nm Atom Medfield + case 0x35: // 32 nm Atom Midview + case 0x36: // 32 nm Atom Midview + *Type = INTEL_ATOM; + *Subtype = INTEL_ATOM_BONNELL; + break; // "bonnell" + + // Atom Silvermont codes from the Intel software optimization guide. + case 0x37: + case 0x4a: + case 0x4d: + case 0x5a: + case 0x5d: + case 0x4c: // really airmont + *Type = INTEL_ATOM; + *Subtype = INTEL_ATOM_SILVERMONT; + break; // "silvermont" + + case 0x57: + *Type = INTEL_XEONPHI; // knl + *Subtype = INTEL_KNIGHTS_LANDING; + break; - case 28: // Most 45 nm Intel Atom processors - case 38: // 45 nm Atom Lincroft - case 39: // 32 nm Atom Medfield - case 53: // 32 nm Atom Midview - case 54: // 32 nm Atom Midview - return "bonnell"; + default: // Unknown family 6 CPU, try to guess. + if (Features & (1 << FEATURE_AVX512)) { + *Type = INTEL_XEONPHI; // knl + *Subtype = INTEL_KNIGHTS_LANDING; + break; + } + if (Features & (1 << FEATURE_ADX)) { + *Type = INTEL_COREI7; + *Subtype = INTEL_COREI7_BROADWELL; + break; + } + if (Features & (1 << FEATURE_AVX2)) { + *Type = INTEL_COREI7; + *Subtype = INTEL_COREI7_HASWELL; + break; + } + if (Features & (1 << FEATURE_AVX)) { + *Type = INTEL_COREI7; + *Subtype = INTEL_COREI7_SANDYBRIDGE; + break; + } + if (Features & (1 << FEATURE_SSE4_2)) { + if (Features & (1 << FEATURE_MOVBE)) { + *Type = INTEL_ATOM; + *Subtype = INTEL_ATOM_SILVERMONT; + } else { + *Type = INTEL_COREI7; + *Subtype = INTEL_COREI7_NEHALEM; + } + break; + } + if (Features & (1 << FEATURE_SSE4_1)) { + *Type = INTEL_CORE2; // "penryn" + *Subtype = INTEL_CORE2_45; + break; + } + if (Features & (1 << FEATURE_SSSE3)) { + if (Features & (1 << FEATURE_MOVBE)) { + *Type = INTEL_ATOM; + *Subtype = INTEL_ATOM_BONNELL; // "bonnell" + } else { + *Type = INTEL_CORE2; // "core2" + *Subtype = INTEL_CORE2_65; + } + break; + } + if (Features & (1 << FEATURE_EM64T)) { + *Type = INTEL_X86_64; + break; // x86-64 + } + if (Features & (1 << FEATURE_SSE2)) { + *Type = INTEL_PENTIUM_M; + break; + } + if (Features & (1 << FEATURE_SSE)) { + *Type = INTEL_PENTIUM_III; + break; + } + if (Features & (1 << FEATURE_MMX)) { + *Type = INTEL_PENTIUM_II; + break; + } + *Type = INTEL_PENTIUM_PRO; + break; + } + break; + case 15: { + switch (Model) { + case 0: // Pentium 4 processor, Intel Xeon processor. All processors are + // model 00h and manufactured using the 0.18 micron process. + case 1: // Pentium 4 processor, Intel Xeon processor, Intel Xeon + // processor MP, and Intel Celeron processor. All processors are + // model 01h and manufactured using the 0.18 micron process. + case 2: // Pentium 4 processor, Mobile Intel Pentium 4 processor - M, + // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron + // processor, and Mobile Intel Celeron processor. All processors + // are model 02h and manufactured using the 0.13 micron process. + *Type = + ((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV); + break; - // Atom Silvermont codes from the Intel software optimization guide. - case 55: - case 74: - case 77: - case 90: - case 93: - return "silvermont"; + case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D + // processor. All processors are model 03h and manufactured using + // the 90 nm process. + case 4: // Pentium 4 processor, Pentium 4 processor Extreme Edition, + // Pentium D processor, Intel Xeon processor, Intel Xeon + // processor MP, Intel Celeron D processor. All processors are + // model 04h and manufactured using the 90 nm process. + case 6: // Pentium 4 processor, Pentium D processor, Pentium processor + // Extreme Edition, Intel Xeon processor, Intel Xeon processor + // MP, Intel Celeron D processor. All processors are model 06h + // and manufactured using the 65 nm process. + *Type = + ((Features & (1 << FEATURE_EM64T)) ? INTEL_NOCONA : INTEL_PRESCOTT); + break; - default: // Unknown family 6 CPU, try to guess. - if (HasAVX512) - return "knl"; - if (HasADX) - return "broadwell"; - if (HasAVX2) - return "haswell"; - if (HasAVX) - return "sandybridge"; - if (HasSSE42) - return HasMOVBE ? "silvermont" : "nehalem"; - if (HasSSE41) - return "penryn"; - if (HasSSSE3) - return HasMOVBE ? "bonnell" : "core2"; - if (Em64T) - return "x86-64"; - if (HasSSE2) - return "pentium-m"; - if (HasSSE) - return "pentium3"; - if (HasMMX) - return "pentium2"; - return "pentiumpro"; - } - case 15: { - switch (Model) { - case 0: // Pentium 4 processor, Intel Xeon processor. All processors are - // model 00h and manufactured using the 0.18 micron process. - case 1: // Pentium 4 processor, Intel Xeon processor, Intel Xeon - // processor MP, and Intel Celeron processor. All processors are - // model 01h and manufactured using the 0.18 micron process. - case 2: // Pentium 4 processor, Mobile Intel Pentium 4 processor - M, - // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron - // processor, and Mobile Intel Celeron processor. All processors - // are model 02h and manufactured using the 0.13 micron process. - return (Em64T) ? "x86-64" : "pentium4"; - - case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D - // processor. All processors are model 03h and manufactured using - // the 90 nm process. - case 4: // Pentium 4 processor, Pentium 4 processor Extreme Edition, - // Pentium D processor, Intel Xeon processor, Intel Xeon - // processor MP, Intel Celeron D processor. All processors are - // model 04h and manufactured using the 90 nm process. - case 6: // Pentium 4 processor, Pentium D processor, Pentium processor - // Extreme Edition, Intel Xeon processor, Intel Xeon processor - // MP, Intel Celeron D processor. All processors are model 06h - // and manufactured using the 65 nm process. - return (Em64T) ? "nocona" : "prescott"; + default: + *Type = + ((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV); + break; + } + break; + } + default: + break; /*"generic"*/ + } +} - default: - return (Em64T) ? "x86-64" : "pentium4"; - } +static void getAMDProcessorTypeAndSubtype(unsigned int Family, + unsigned int Model, + unsigned int Features, + unsigned *Type, + unsigned *Subtype) { + // FIXME: this poorly matches the generated SubtargetFeatureKV table. There + // appears to be no way to generate the wide variety of AMD-specific targets + // from the information returned from CPUID. + switch (Family) { + case 4: + *Type = AMD_i486; + break; + case 5: + *Type = AMDPENTIUM; + switch (Model) { + case 6: + case 7: + *Subtype = AMDPENTIUM_K6; + break; // "k6" + case 8: + *Subtype = AMDPENTIUM_K62; + break; // "k6-2" + case 9: + case 13: + *Subtype = AMDPENTIUM_K63; + break; // "k6-3" + case 10: + *Subtype = AMDPENTIUM_GEODE; + break; // "geode" + } + break; + case 6: + *Type = AMDATHLON; + switch (Model) { + case 4: + *Subtype = AMDATHLON_TBIRD; + break; // "athlon-tbird" + case 6: + case 7: + case 8: + *Subtype = AMDATHLON_MP; + break; // "athlon-mp" + case 10: + *Subtype = AMDATHLON_XP; + break; // "athlon-xp" } + break; + case 15: + *Type = AMDATHLON; + if (Features & (1 << FEATURE_SSE3)) { + *Subtype = AMDATHLON_K8SSE3; + break; // "k8-sse3" + } + switch (Model) { + case 1: + *Subtype = AMDATHLON_OPTERON; + break; // "opteron" + case 5: + *Subtype = AMDATHLON_FX; + break; // "athlon-fx"; also opteron + default: + *Subtype = AMDATHLON_64; + break; // "athlon64" + } + break; + case 16: + *Type = AMDFAM10H; // "amdfam10" + switch (Model) { + case 2: + *Subtype = AMDFAM10H_BARCELONA; + break; + case 4: + *Subtype = AMDFAM10H_SHANGHAI; + break; + case 8: + *Subtype = AMDFAM10H_ISTANBUL; + break; + } + break; + case 20: + *Type = AMDFAM14H; + *Subtype = AMD_BTVER1; + break; // "btver1"; + case 21: + *Type = AMDFAM15H; + if (!(Features & + (1 << FEATURE_AVX))) { // If no AVX support, provide a sane fallback. + *Subtype = AMD_BTVER1; + break; // "btver1" + } + if (Model >= 0x50 && Model <= 0x6f) { + *Subtype = AMDFAM15H_BDVER4; + break; // "bdver4"; 50h-6Fh: Excavator + } + if (Model >= 0x30 && Model <= 0x3f) { + *Subtype = AMDFAM15H_BDVER3; + break; // "bdver3"; 30h-3Fh: Steamroller + } + if (Model >= 0x10 && Model <= 0x1f) { + *Subtype = AMDFAM15H_BDVER2; + break; // "bdver2"; 10h-1Fh: Piledriver + } + if (Model <= 0x0f) { + *Subtype = AMDFAM15H_BDVER1; + break; // "bdver1"; 00h-0Fh: Bulldozer + } + break; + case 22: + *Type = AMDFAM16H; + if (!(Features & + (1 << FEATURE_AVX))) { // If no AVX support provide a sane fallback. + *Subtype = AMD_BTVER1; + break; // "btver1"; + } + *Subtype = AMD_BTVER2; + break; // "btver2" + default: + break; // "generic" + } +} + +static unsigned getAvailableFeatures(unsigned int ECX, unsigned int EDX, + unsigned MaxLeaf) { + unsigned Features = 0; + unsigned int EAX, EBX; + Features |= (((EDX >> 23) & 1) << FEATURE_MMX); + Features |= (((EDX >> 25) & 1) << FEATURE_SSE); + Features |= (((EDX >> 26) & 1) << FEATURE_SSE2); + Features |= (((ECX >> 0) & 1) << FEATURE_SSE3); + Features |= (((ECX >> 9) & 1) << FEATURE_SSSE3); + Features |= (((ECX >> 19) & 1) << FEATURE_SSE4_1); + Features |= (((ECX >> 20) & 1) << FEATURE_SSE4_2); + Features |= (((ECX >> 22) & 1) << FEATURE_MOVBE); + + // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV + // indicates that the AVX registers will be saved and restored on context + // switch, then we have full AVX support. + const unsigned AVXBits = (1 << 27) | (1 << 28); + bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && + ((EAX & 0x6) == 0x6); + bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); + bool HasLeaf7 = + MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); + bool HasADX = HasLeaf7 && ((EBX >> 19) & 1); + bool HasAVX2 = HasAVX && HasLeaf7 && (EBX & 0x20); + bool HasAVX512 = HasLeaf7 && HasAVX512Save && ((EBX >> 16) & 1); + Features |= (HasAVX << FEATURE_AVX); + Features |= (HasAVX2 << FEATURE_AVX2); + Features |= (HasAVX512 << FEATURE_AVX512); + Features |= (HasAVX512Save << FEATURE_AVX512SAVE); + Features |= (HasADX << FEATURE_ADX); + + getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + Features |= (((EDX >> 29) & 0x1) << FEATURE_EM64T); + return Features; +} +StringRef sys::getHostCPUName() { + unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; + unsigned MaxLeaf, Vendor; + + if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX)) + return "generic"; + if (getX86CpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX)) + return "generic"; + + unsigned Brand_id = EBX & 0xff; + unsigned Family = 0, Model = 0; + unsigned Features = 0; + detectX86FamilyModel(EAX, &Family, &Model); + Features = getAvailableFeatures(ECX, EDX, MaxLeaf); + + unsigned Type; + unsigned Subtype; + + if (Vendor == SIG_INTEL) { + getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features, &Type, + &Subtype); + switch (Type) { + case INTEL_i386: + return "i386"; + case INTEL_i486: + return "i486"; + case INTEL_PENTIUM: + if (Subtype == INTEL_PENTIUM_MMX) + return "pentium-mmx"; + return "pentium"; + case INTEL_PENTIUM_PRO: + return "pentiumpro"; + case INTEL_PENTIUM_II: + return "pentium2"; + case INTEL_PENTIUM_III: + return "pentium3"; + case INTEL_PENTIUM_IV: + return "pentium4"; + case INTEL_PENTIUM_M: + return "pentium-m"; + case INTEL_CORE_DUO: + return "yonah"; + case INTEL_CORE2: + switch (Subtype) { + case INTEL_CORE2_65: + return "core2"; + case INTEL_CORE2_45: + return "penryn"; + default: + return "core2"; + } + case INTEL_COREI7: + switch (Subtype) { + case INTEL_COREI7_NEHALEM: + return "nehalem"; + case INTEL_COREI7_WESTMERE: + return "westmere"; + case INTEL_COREI7_SANDYBRIDGE: + return "sandybridge"; + case INTEL_COREI7_IVYBRIDGE: + return "ivybridge"; + case INTEL_COREI7_HASWELL: + return "haswell"; + case INTEL_COREI7_BROADWELL: + return "broadwell"; + case INTEL_COREI7_SKYLAKE: + return "skylake"; + case INTEL_COREI7_SKYLAKE_AVX512: + return "skylake-avx512"; + default: + return "corei7"; + } + case INTEL_ATOM: + switch (Subtype) { + case INTEL_ATOM_BONNELL: + return "bonnell"; + case INTEL_ATOM_SILVERMONT: + return "silvermont"; + default: + return "atom"; + } + case INTEL_XEONPHI: + return "knl"; /*update for more variants added*/ + case INTEL_X86_64: + return "x86-64"; + case INTEL_NOCONA: + return "nocona"; + case INTEL_PRESCOTT: + return "prescott"; default: return "generic"; } - } else if (memcmp(text.c, "AuthenticAMD", 12) == 0) { - // FIXME: this poorly matches the generated SubtargetFeatureKV table. There - // appears to be no way to generate the wide variety of AMD-specific targets - // from the information returned from CPUID. - switch (Family) { - case 4: - return "i486"; - case 5: - switch (Model) { - case 6: - case 7: return "k6"; - case 8: return "k6-2"; - case 9: - case 13: return "k6-3"; - case 10: return "geode"; - default: return "pentium"; - } - case 6: - switch (Model) { - case 4: return "athlon-tbird"; - case 6: - case 7: - case 8: return "athlon-mp"; - case 10: return "athlon-xp"; - default: return "athlon"; - } - case 15: - if (HasSSE3) - return "k8-sse3"; - switch (Model) { - case 1: return "opteron"; - case 5: return "athlon-fx"; // also opteron - default: return "athlon64"; - } - case 16: - return "amdfam10"; - case 20: + } else if (Vendor == SIG_AMD) { + getAMDProcessorTypeAndSubtype(Family, Model, Features, &Type, &Subtype); + switch (Type) { + case AMD_i486: + return "i486"; + case AMDPENTIUM: + switch (Subtype) { + case AMDPENTIUM_K6: + return "k6"; + case AMDPENTIUM_K62: + return "k6-2"; + case AMDPENTIUM_K63: + return "k6-3"; + case AMDPENTIUM_GEODE: + return "geode"; + default: + return "pentium"; + } + case AMDATHLON: + switch (Subtype) { + case AMDATHLON_TBIRD: + return "athlon-tbird"; + case AMDATHLON_MP: + return "athlon-mp"; + case AMDATHLON_XP: + return "athlon-xp"; + case AMDATHLON_K8SSE3: + return "k8-sse3"; + case AMDATHLON_OPTERON: + return "opteron"; + case AMDATHLON_FX: + return "athlon-fx"; + case AMDATHLON_64: + return "athlon64"; + default: + return "athlon"; + } + case AMDFAM10H: + if(Subtype == AMDFAM10H_BARCELONA) + return "barcelona"; + return "amdfam10"; + case AMDFAM14H: + return "btver1"; + case AMDFAM15H: + switch (Subtype) { + case AMDFAM15H_BDVER1: + return "bdver1"; + case AMDFAM15H_BDVER2: + return "bdver2"; + case AMDFAM15H_BDVER3: + return "bdver3"; + case AMDFAM15H_BDVER4: + return "bdver4"; + case AMD_BTVER1: return "btver1"; - case 21: - if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback. - return "btver1"; - if (Model >= 0x50) - return "bdver4"; // 50h-6Fh: Excavator - if (Model >= 0x30) - return "bdver3"; // 30h-3Fh: Steamroller - if (Model >= 0x10 || HasTBM) - return "bdver2"; // 10h-1Fh: Piledriver - return "bdver1"; // 00h-0Fh: Bulldozer - case 22: - if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback. - return "btver1"; + default: + return "amdfam15"; + } + case AMDFAM16H: + switch (Subtype) { + case AMD_BTVER1: + return "btver1"; + case AMD_BTVER2: return "btver2"; + default: + return "amdfam16"; + } default: return "generic"; } } return "generic"; } + #elif defined(__APPLE__) && (defined(__ppc__) || defined(__powerpc__)) StringRef sys::getHostCPUName() { host_basic_info_data_t hostInfo; mach_msg_type_number_t infoCount; infoCount = HOST_BASIC_INFO_COUNT; - host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, + host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount); - - if (hostInfo.cpu_type != CPU_TYPE_POWERPC) return "generic"; - - switch(hostInfo.cpu_subtype) { - case CPU_SUBTYPE_POWERPC_601: return "601"; - case CPU_SUBTYPE_POWERPC_602: return "602"; - case CPU_SUBTYPE_POWERPC_603: return "603"; - case CPU_SUBTYPE_POWERPC_603e: return "603e"; - case CPU_SUBTYPE_POWERPC_603ev: return "603ev"; - case CPU_SUBTYPE_POWERPC_604: return "604"; - case CPU_SUBTYPE_POWERPC_604e: return "604e"; - case CPU_SUBTYPE_POWERPC_620: return "620"; - case CPU_SUBTYPE_POWERPC_750: return "750"; - case CPU_SUBTYPE_POWERPC_7400: return "7400"; - case CPU_SUBTYPE_POWERPC_7450: return "7450"; - case CPU_SUBTYPE_POWERPC_970: return "970"; - default: ; + + if (hostInfo.cpu_type != CPU_TYPE_POWERPC) + return "generic"; + + switch (hostInfo.cpu_subtype) { + case CPU_SUBTYPE_POWERPC_601: + return "601"; + case CPU_SUBTYPE_POWERPC_602: + return "602"; + case CPU_SUBTYPE_POWERPC_603: + return "603"; + case CPU_SUBTYPE_POWERPC_603e: + return "603e"; + case CPU_SUBTYPE_POWERPC_603ev: + return "603ev"; + case CPU_SUBTYPE_POWERPC_604: + return "604"; + case CPU_SUBTYPE_POWERPC_604e: + return "604e"; + case CPU_SUBTYPE_POWERPC_620: + return "620"; + case CPU_SUBTYPE_POWERPC_750: + return "750"; + case CPU_SUBTYPE_POWERPC_7400: + return "7400"; + case CPU_SUBTYPE_POWERPC_7450: + return "7450"; + case CPU_SUBTYPE_POWERPC_970: + return "970"; + default:; } - + return "generic"; } #elif defined(__linux__) && (defined(__ppc__) || defined(__powerpc__)) @@ -573,12 +983,12 @@ StringRef sys::getHostCPUName() { ++CIP; while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t')) ++CIP; - + if (CIP < CPUInfoEnd && *CIP == ':') { ++CIP; while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t')) ++CIP; - + if (CIP < CPUInfoEnd) { CPUStart = CIP; while (CIP < CPUInfoEnd && (*CIP != ' ' && *CIP != '\t' && @@ -600,24 +1010,25 @@ StringRef sys::getHostCPUName() { return generic; return StringSwitch<const char *>(StringRef(CPUStart, CPULen)) - .Case("604e", "604e") - .Case("604", "604") - .Case("7400", "7400") - .Case("7410", "7400") - .Case("7447", "7400") - .Case("7455", "7450") - .Case("G4", "g4") - .Case("POWER4", "970") - .Case("PPC970FX", "970") - .Case("PPC970MP", "970") - .Case("G5", "g5") - .Case("POWER5", "g5") - .Case("A2", "a2") - .Case("POWER6", "pwr6") - .Case("POWER7", "pwr7") - .Case("POWER8", "pwr8") - .Case("POWER8E", "pwr8") - .Default(generic); + .Case("604e", "604e") + .Case("604", "604") + .Case("7400", "7400") + .Case("7410", "7400") + .Case("7447", "7400") + .Case("7455", "7450") + .Case("G4", "g4") + .Case("POWER4", "970") + .Case("PPC970FX", "970") + .Case("PPC970MP", "970") + .Case("G5", "g5") + .Case("POWER5", "g5") + .Case("A2", "a2") + .Case("POWER6", "pwr6") + .Case("POWER7", "pwr7") + .Case("POWER8", "pwr8") + .Case("POWER8E", "pwr8") + .Case("POWER9", "pwr9") + .Default(generic); } #elif defined(__linux__) && defined(__arm__) StringRef sys::getHostCPUName() { @@ -650,18 +1061,18 @@ StringRef sys::getHostCPUName() { // values correspond to the "Part number" in the CP15/c0 register. The // contents are specified in the various processor manuals. return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) - .Case("0x926", "arm926ej-s") - .Case("0xb02", "mpcore") - .Case("0xb36", "arm1136j-s") - .Case("0xb56", "arm1156t2-s") - .Case("0xb76", "arm1176jz-s") - .Case("0xc08", "cortex-a8") - .Case("0xc09", "cortex-a9") - .Case("0xc0f", "cortex-a15") - .Case("0xc20", "cortex-m0") - .Case("0xc23", "cortex-m3") - .Case("0xc24", "cortex-m4") - .Default("generic"); + .Case("0x926", "arm926ej-s") + .Case("0xb02", "mpcore") + .Case("0xb36", "arm1136j-s") + .Case("0xb56", "arm1156t2-s") + .Case("0xb76", "arm1176jz-s") + .Case("0xc08", "cortex-a8") + .Case("0xc09", "cortex-a9") + .Case("0xc0f", "cortex-a15") + .Case("0xc20", "cortex-m0") + .Case("0xc23", "cortex-m3") + .Case("0xc24", "cortex-m4") + .Default("generic"); if (Implementer == "0x51") // Qualcomm Technologies, Inc. // Look for the CPU part line. @@ -671,8 +1082,8 @@ StringRef sys::getHostCPUName() { // values correspond to the "Part number" in the CP15/c0 register. The // contents are specified in the various processor manuals. return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) - .Case("0x06f", "krait") // APQ8064 - .Default("generic"); + .Case("0x06f", "krait") // APQ8064 + .Default("generic"); return "generic"; } @@ -730,107 +1141,117 @@ StringRef sys::getHostCPUName() { break; } } - + return "generic"; } #else -StringRef sys::getHostCPUName() { - return "generic"; -} +StringRef sys::getHostCPUName() { return "generic"; } #endif -#if defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86)\ - || defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) +#if defined(i386) || defined(__i386__) || defined(__x86__) || \ + defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) || \ + defined(_M_X64) bool sys::getHostCPUFeatures(StringMap<bool> &Features) { unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; unsigned MaxLevel; union { unsigned u[3]; - char c[12]; + char c[12]; } text; - if (GetX86CpuIDAndInfo(0, &MaxLevel, text.u+0, text.u+2, text.u+1) || + if (getX86CpuIDAndInfo(0, &MaxLevel, text.u + 0, text.u + 2, text.u + 1) || MaxLevel < 1) return false; - GetX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX); + getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX); - Features["cmov"] = (EDX >> 15) & 1; - Features["mmx"] = (EDX >> 23) & 1; - Features["sse"] = (EDX >> 25) & 1; - Features["sse2"] = (EDX >> 26) & 1; - Features["sse3"] = (ECX >> 0) & 1; - Features["ssse3"] = (ECX >> 9) & 1; + Features["cmov"] = (EDX >> 15) & 1; + Features["mmx"] = (EDX >> 23) & 1; + Features["sse"] = (EDX >> 25) & 1; + Features["sse2"] = (EDX >> 26) & 1; + Features["sse3"] = (ECX >> 0) & 1; + Features["ssse3"] = (ECX >> 9) & 1; Features["sse4.1"] = (ECX >> 19) & 1; Features["sse4.2"] = (ECX >> 20) & 1; - Features["pclmul"] = (ECX >> 1) & 1; - Features["cx16"] = (ECX >> 13) & 1; - Features["movbe"] = (ECX >> 22) & 1; + Features["pclmul"] = (ECX >> 1) & 1; + Features["cx16"] = (ECX >> 13) & 1; + Features["movbe"] = (ECX >> 22) & 1; Features["popcnt"] = (ECX >> 23) & 1; - Features["aes"] = (ECX >> 25) & 1; - Features["rdrnd"] = (ECX >> 30) & 1; + Features["aes"] = (ECX >> 25) & 1; + Features["rdrnd"] = (ECX >> 30) & 1; // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV // indicates that the AVX registers will be saved and restored on context // switch, then we have full AVX support. bool HasAVXSave = ((ECX >> 27) & 1) && ((ECX >> 28) & 1) && - !GetX86XCR0(&EAX, &EDX) && ((EAX & 0x6) == 0x6); - Features["avx"] = HasAVXSave; - Features["fma"] = HasAVXSave && (ECX >> 12) & 1; - Features["f16c"] = HasAVXSave && (ECX >> 29) & 1; + !getX86XCR0(&EAX, &EDX) && ((EAX & 0x6) == 0x6); + Features["avx"] = HasAVXSave; + Features["fma"] = HasAVXSave && (ECX >> 12) & 1; + Features["f16c"] = HasAVXSave && (ECX >> 29) & 1; // Only enable XSAVE if OS has enabled support for saving YMM state. - Features["xsave"] = HasAVXSave && (ECX >> 26) & 1; + Features["xsave"] = HasAVXSave && (ECX >> 26) & 1; // AVX512 requires additional context to be saved by the OS. bool HasAVX512Save = HasAVXSave && ((EAX & 0xe0) == 0xe0); unsigned MaxExtLevel; - GetX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); + getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 && - !GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); - Features["lzcnt"] = HasExtLeaf1 && ((ECX >> 5) & 1); - Features["sse4a"] = HasExtLeaf1 && ((ECX >> 6) & 1); - Features["prfchw"] = HasExtLeaf1 && ((ECX >> 8) & 1); - Features["xop"] = HasExtLeaf1 && ((ECX >> 11) & 1) && HasAVXSave; - Features["fma4"] = HasExtLeaf1 && ((ECX >> 16) & 1) && HasAVXSave; - Features["tbm"] = HasExtLeaf1 && ((ECX >> 21) & 1); - - bool HasLeaf7 = MaxLevel >= 7 && - !GetX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); + !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + Features["lzcnt"] = HasExtLeaf1 && ((ECX >> 5) & 1); + Features["sse4a"] = HasExtLeaf1 && ((ECX >> 6) & 1); + Features["prfchw"] = HasExtLeaf1 && ((ECX >> 8) & 1); + Features["xop"] = HasExtLeaf1 && ((ECX >> 11) & 1) && HasAVXSave; + Features["fma4"] = HasExtLeaf1 && ((ECX >> 16) & 1) && HasAVXSave; + Features["tbm"] = HasExtLeaf1 && ((ECX >> 21) & 1); + Features["mwaitx"] = HasExtLeaf1 && ((ECX >> 29) & 1); + + bool HasLeaf7 = + MaxLevel >= 7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); // AVX2 is only supported if we have the OS save support from AVX. - Features["avx2"] = HasAVXSave && HasLeaf7 && ((EBX >> 5) & 1); - - Features["fsgsbase"] = HasLeaf7 && ((EBX >> 0) & 1); - Features["bmi"] = HasLeaf7 && ((EBX >> 3) & 1); - Features["hle"] = HasLeaf7 && ((EBX >> 4) & 1); - Features["bmi2"] = HasLeaf7 && ((EBX >> 8) & 1); - Features["rtm"] = HasLeaf7 && ((EBX >> 11) & 1); - Features["rdseed"] = HasLeaf7 && ((EBX >> 18) & 1); - Features["adx"] = HasLeaf7 && ((EBX >> 19) & 1); - Features["sha"] = HasLeaf7 && ((EBX >> 29) & 1); - // Enable protection keys - Features["pku"] = HasLeaf7 && ((ECX >> 4) & 1); + Features["avx2"] = HasAVXSave && HasLeaf7 && ((EBX >> 5) & 1); + + Features["fsgsbase"] = HasLeaf7 && ((EBX >> 0) & 1); + Features["sgx"] = HasLeaf7 && ((EBX >> 2) & 1); + Features["bmi"] = HasLeaf7 && ((EBX >> 3) & 1); + Features["hle"] = HasLeaf7 && ((EBX >> 4) & 1); + Features["bmi2"] = HasLeaf7 && ((EBX >> 8) & 1); + Features["invpcid"] = HasLeaf7 && ((EBX >> 10) & 1); + Features["rtm"] = HasLeaf7 && ((EBX >> 11) & 1); + Features["rdseed"] = HasLeaf7 && ((EBX >> 18) & 1); + Features["adx"] = HasLeaf7 && ((EBX >> 19) & 1); + Features["smap"] = HasLeaf7 && ((EBX >> 20) & 1); + Features["pcommit"] = HasLeaf7 && ((EBX >> 22) & 1); + Features["clflushopt"] = HasLeaf7 && ((EBX >> 23) & 1); + Features["clwb"] = HasLeaf7 && ((EBX >> 24) & 1); + Features["sha"] = HasLeaf7 && ((EBX >> 29) & 1); // AVX512 is only supported if the OS supports the context save for it. - Features["avx512f"] = HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save; + Features["avx512f"] = HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save; Features["avx512dq"] = HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save; + Features["avx512ifma"] = HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save; Features["avx512pf"] = HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save; Features["avx512er"] = HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save; Features["avx512cd"] = HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save; Features["avx512bw"] = HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save; Features["avx512vl"] = HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save; + Features["prefetchwt1"] = HasLeaf7 && (ECX & 1); + Features["avx512vbmi"] = HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save; + // Enable protection keys + Features["pku"] = HasLeaf7 && ((ECX >> 4) & 1); + bool HasLeafD = MaxLevel >= 0xd && - !GetX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX); + !getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX); // Only enable XSAVE if OS has enabled support for saving YMM state. Features["xsaveopt"] = HasAVXSave && HasLeafD && ((EAX >> 0) & 1); - Features["xsavec"] = HasAVXSave && HasLeafD && ((EAX >> 1) & 1); - Features["xsaves"] = HasAVXSave && HasLeafD && ((EAX >> 3) & 1); + Features["xsavec"] = HasAVXSave && HasLeafD && ((EAX >> 1) & 1); + Features["xsaves"] = HasAVXSave && HasLeafD && ((EAX >> 3) & 1); return true; } @@ -859,31 +1280,26 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { #if defined(__aarch64__) // Keep track of which crypto features we have seen - enum { - CAP_AES = 0x1, - CAP_PMULL = 0x2, - CAP_SHA1 = 0x4, - CAP_SHA2 = 0x8 - }; + enum { CAP_AES = 0x1, CAP_PMULL = 0x2, CAP_SHA1 = 0x4, CAP_SHA2 = 0x8 }; uint32_t crypto = 0; #endif for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) { StringRef LLVMFeatureStr = StringSwitch<StringRef>(CPUFeatures[I]) #if defined(__aarch64__) - .Case("asimd", "neon") - .Case("fp", "fp-armv8") - .Case("crc32", "crc") + .Case("asimd", "neon") + .Case("fp", "fp-armv8") + .Case("crc32", "crc") #else - .Case("half", "fp16") - .Case("neon", "neon") - .Case("vfpv3", "vfp3") - .Case("vfpv3d16", "d16") - .Case("vfpv4", "vfp4") - .Case("idiva", "hwdiv-arm") - .Case("idivt", "hwdiv") + .Case("half", "fp16") + .Case("neon", "neon") + .Case("vfpv3", "vfp3") + .Case("vfpv3d16", "d16") + .Case("vfpv4", "vfp4") + .Case("idiva", "hwdiv-arm") + .Case("idivt", "hwdiv") #endif - .Default(""); + .Default(""); #if defined(__aarch64__) // We need to check crypto separately since we need all of the crypto @@ -911,9 +1327,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { return true; } #else -bool sys::getHostCPUFeatures(StringMap<bool> &Features){ - return false; -} +bool sys::getHostCPUFeatures(StringMap<bool> &Features) { return false; } #endif std::string sys::getProcessTriple() { diff --git a/contrib/llvm/lib/Support/IntEqClasses.cpp b/contrib/llvm/lib/Support/IntEqClasses.cpp index ff21357..cb6e3a1 100644 --- a/contrib/llvm/lib/Support/IntEqClasses.cpp +++ b/contrib/llvm/lib/Support/IntEqClasses.cpp @@ -37,10 +37,15 @@ unsigned IntEqClasses::join(unsigned a, unsigned b) { // incrementally. The larger leader will eventually be updated, joining the // classes. while (eca != ecb) - if (eca < ecb) - EC[b] = eca, b = ecb, ecb = EC[b]; - else - EC[a] = ecb, a = eca, eca = EC[a]; + if (eca < ecb) { + EC[b] = eca; + b = ecb; + ecb = EC[b]; + } else { + EC[a] = ecb; + a = eca; + eca = EC[a]; + } return eca; } diff --git a/contrib/llvm/lib/Support/JamCRC.cpp b/contrib/llvm/lib/Support/JamCRC.cpp index bc21c91..17c55f5 100644 --- a/contrib/llvm/lib/Support/JamCRC.cpp +++ b/contrib/llvm/lib/Support/JamCRC.cpp @@ -18,6 +18,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/JamCRC.h" +#include "llvm/ADT/ArrayRef.h" using namespace llvm; diff --git a/contrib/llvm/lib/Support/Locale.cpp b/contrib/llvm/lib/Support/Locale.cpp index 53bc0e3..e24a28b 100644 --- a/contrib/llvm/lib/Support/Locale.cpp +++ b/contrib/llvm/lib/Support/Locale.cpp @@ -1,5 +1,6 @@ -#include "llvm/Config/llvm-config.h" #include "llvm/Support/Locale.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Unicode.h" namespace llvm { diff --git a/contrib/llvm/lib/Support/LockFileManager.cpp b/contrib/llvm/lib/Support/LockFileManager.cpp index fb81d60..611f94a 100644 --- a/contrib/llvm/lib/Support/LockFileManager.cpp +++ b/contrib/llvm/lib/Support/LockFileManager.cpp @@ -144,7 +144,9 @@ LockFileManager::LockFileManager(StringRef FileName) { this->FileName = FileName; if (std::error_code EC = sys::fs::make_absolute(this->FileName)) { - Error = EC; + std::string S("failed to obtain absolute path for "); + S.append(this->FileName.str()); + setError(EC, S); return; } LockFileName = this->FileName; @@ -161,7 +163,9 @@ LockFileManager::LockFileManager(StringRef FileName) int UniqueLockFileID; if (std::error_code EC = sys::fs::createUniqueFile( UniqueLockFileName, UniqueLockFileID, UniqueLockFileName)) { - Error = EC; + std::string S("failed to create unique file "); + S.append(UniqueLockFileName.str()); + setError(EC, S); return; } @@ -169,7 +173,7 @@ LockFileManager::LockFileManager(StringRef FileName) { SmallString<256> HostID; if (auto EC = getHostID(HostID)) { - Error = EC; + setError(EC, "failed to get host id"); return; } @@ -185,7 +189,10 @@ LockFileManager::LockFileManager(StringRef FileName) if (Out.has_error()) { // We failed to write out PID, so make up an excuse, remove the // unique lock file, and fail. - Error = make_error_code(errc::no_space_on_device); + auto EC = make_error_code(errc::no_space_on_device); + std::string S("failed to write to "); + S.append(UniqueLockFileName.str()); + setError(EC, S); sys::fs::remove(UniqueLockFileName); return; } @@ -205,7 +212,10 @@ LockFileManager::LockFileManager(StringRef FileName) } if (EC != errc::file_exists) { - Error = EC; + std::string S("failed to create link "); + raw_string_ostream OSS(S); + OSS << LockFileName.str() << " to " << UniqueLockFileName.str(); + setError(EC, OSS.str()); return; } @@ -226,7 +236,9 @@ LockFileManager::LockFileManager(StringRef FileName) // There is a lock file that nobody owns; try to clean it up and get // ownership. if ((EC = sys::fs::remove(LockFileName))) { - Error = EC; + std::string S("failed to remove lockfile "); + S.append(UniqueLockFileName.str()); + setError(EC, S); return; } } @@ -242,6 +254,19 @@ LockFileManager::LockFileState LockFileManager::getState() const { return LFS_Owned; } +std::string LockFileManager::getErrorMessage() const { + if (Error) { + std::string Str(ErrorDiagMsg); + std::string ErrCodeMsg = Error->message(); + raw_string_ostream OSS(Str); + if (!ErrCodeMsg.empty()) + OSS << ": " << Error->message(); + OSS.flush(); + return Str; + } + return ""; +} + LockFileManager::~LockFileManager() { if (getState() != LFS_Owned) return; diff --git a/contrib/llvm/lib/Support/ManagedStatic.cpp b/contrib/llvm/lib/Support/ManagedStatic.cpp index 9868207..7dd3131 100644 --- a/contrib/llvm/lib/Support/ManagedStatic.cpp +++ b/contrib/llvm/lib/Support/ManagedStatic.cpp @@ -13,20 +13,25 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Config/config.h" -#include "llvm/Support/Atomic.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/MutexGuard.h" +#include "llvm/Support/Threading.h" #include <cassert> using namespace llvm; static const ManagedStaticBase *StaticList = nullptr; +static sys::Mutex *ManagedStaticMutex = nullptr; +LLVM_DEFINE_ONCE_FLAG(mutex_init_flag); -static sys::Mutex& getManagedStaticMutex() { +static void initializeMutex() { + ManagedStaticMutex = new sys::Mutex(); +} + +static sys::Mutex* getManagedStaticMutex() { // We need to use a function local static here, since this can get called // during a static constructor and we need to guarantee that it's initialized // correctly. - static sys::Mutex ManagedStaticMutex; + llvm::call_once(mutex_init_flag, initializeMutex); return ManagedStaticMutex; } @@ -34,20 +39,12 @@ void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(), void (*Deleter)(void*)) const { assert(Creator); if (llvm_is_multithreaded()) { - MutexGuard Lock(getManagedStaticMutex()); - - if (!Ptr) { - void* tmp = Creator(); + MutexGuard Lock(*getManagedStaticMutex()); - TsanHappensBefore(this); - sys::MemoryFence(); + if (!Ptr.load(std::memory_order_relaxed)) { + void *Tmp = Creator(); - // This write is racy against the first read in the ManagedStatic - // accessors. The race is benign because it does a second read after a - // memory fence, at which point it isn't possible to get a partial value. - TsanIgnoreWritesBegin(); - Ptr = tmp; - TsanIgnoreWritesEnd(); + Ptr.store(Tmp, std::memory_order_release); DeleterFn = Deleter; // Add to list of managed statics. @@ -84,7 +81,7 @@ void ManagedStaticBase::destroy() const { /// llvm_shutdown - Deallocate and destroy all ManagedStatic variables. void llvm::llvm_shutdown() { - MutexGuard Lock(getManagedStaticMutex()); + MutexGuard Lock(*getManagedStaticMutex()); while (StaticList) StaticList->destroy(); diff --git a/contrib/llvm/lib/Support/MemoryBuffer.cpp b/contrib/llvm/lib/Support/MemoryBuffer.cpp index faee10b..b935cbf 100644 --- a/contrib/llvm/lib/Support/MemoryBuffer.cpp +++ b/contrib/llvm/lib/Support/MemoryBuffer.cpp @@ -86,6 +86,10 @@ public: init(InputData.begin(), InputData.end(), RequiresNullTerminator); } + /// Disable sized deallocation for MemoryBufferMem, because it has + /// tail-allocated data. + void operator delete(void *p) { ::operator delete(p); } + const char *getBufferIdentifier() const override { // The name is stored after the class itself. return reinterpret_cast<const char*>(this + 1); @@ -135,7 +139,7 @@ MemoryBuffer::getNewUninitMemBuffer(size_t Size, const Twine &BufferName) { SmallString<256> NameBuf; StringRef NameRef = BufferName.toStringRef(NameBuf); size_t AlignedStringLen = - RoundUpToAlignment(sizeof(MemoryBufferMem) + NameRef.size() + 1, 16); + alignTo(sizeof(MemoryBufferMem) + NameRef.size() + 1, 16); size_t RealLen = AlignedStringLen + Size + 1; char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow)); if (!Mem) @@ -213,6 +217,10 @@ public: } } + /// Disable sized deallocation for MemoryBufferMMapFile, because it has + /// tail-allocated data. + void operator delete(void *p) { ::operator delete(p); } + const char *getBufferIdentifier() const override { // The name is stored after the class itself. return reinterpret_cast<const char *>(this + 1); diff --git a/contrib/llvm/lib/Support/Path.cpp b/contrib/llvm/lib/Support/Path.cpp index 4952f59..f6355d1 100644 --- a/contrib/llvm/lib/Support/Path.cpp +++ b/contrib/llvm/lib/Support/Path.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/COFF.h" +#include "llvm/Support/MachO.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" @@ -352,6 +353,10 @@ bool reverse_iterator::operator==(const reverse_iterator &RHS) const { Position == RHS.Position; } +ptrdiff_t reverse_iterator::operator-(const reverse_iterator &RHS) const { + return Position - RHS.Position; +} + StringRef root_path(StringRef path) { const_iterator b = begin(path), pos = b, @@ -517,6 +522,29 @@ void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) { path.append(ext.begin(), ext.end()); } +void replace_path_prefix(SmallVectorImpl<char> &Path, + const StringRef &OldPrefix, + const StringRef &NewPrefix) { + if (OldPrefix.empty() && NewPrefix.empty()) + return; + + StringRef OrigPath(Path.begin(), Path.size()); + if (!OrigPath.startswith(OldPrefix)) + return; + + // If prefixes have the same size we can simply copy the new one over. + if (OldPrefix.size() == NewPrefix.size()) { + std::copy(NewPrefix.begin(), NewPrefix.end(), Path.begin()); + return; + } + + StringRef RelPath = OrigPath.substr(OldPrefix.size()); + SmallString<256> NewPath; + path::append(NewPath, NewPrefix); + path::append(NewPath, RelPath); + Path.swap(NewPath); +} + void native(const Twine &path, SmallVectorImpl<char> &result) { assert((!path.isSingleStringRef() || path.getSingleStringRef().data() != result.data()) && @@ -1021,7 +1049,7 @@ file_magic identify_magic(StringRef Magic) { case 0xCA: if (Magic[1] == char(0xFE) && Magic[2] == char(0xBA) && - Magic[3] == char(0xBE)) { + (Magic[3] == char(0xBE) || Magic[3] == char(0xBF))) { // This is complicated by an overlap with Java class files. // See the Mach-O section in /usr/share/file/magic for details. if (Magic.size() >= 8 && Magic[7] < 43) @@ -1040,12 +1068,24 @@ file_magic identify_magic(StringRef Magic) { Magic[2] == char(0xFA) && (Magic[3] == char(0xCE) || Magic[3] == char(0xCF))) { /* Native endian */ - if (Magic.size() >= 16) type = Magic[14] << 8 | Magic[15]; + size_t MinSize; + if (Magic[3] == char(0xCE)) + MinSize = sizeof(MachO::mach_header); + else + MinSize = sizeof(MachO::mach_header_64); + if (Magic.size() >= MinSize) + type = Magic[12] << 24 | Magic[13] << 12 | Magic[14] << 8 | Magic[15]; } else if ((Magic[0] == char(0xCE) || Magic[0] == char(0xCF)) && Magic[1] == char(0xFA) && Magic[2] == char(0xED) && Magic[3] == char(0xFE)) { /* Reverse endian */ - if (Magic.size() >= 14) type = Magic[13] << 8 | Magic[12]; + size_t MinSize; + if (Magic[0] == char(0xCE)) + MinSize = sizeof(MachO::mach_header); + else + MinSize = sizeof(MachO::mach_header_64); + if (Magic.size() >= MinSize) + type = Magic[15] << 24 | Magic[14] << 12 |Magic[13] << 8 | Magic[12]; } switch (type) { default: break; diff --git a/contrib/llvm/lib/Support/PrettyStackTrace.cpp b/contrib/llvm/lib/Support/PrettyStackTrace.cpp index 05b3e31..ebad67b 100644 --- a/contrib/llvm/lib/Support/PrettyStackTrace.cpp +++ b/contrib/llvm/lib/Support/PrettyStackTrace.cpp @@ -21,6 +21,8 @@ #include "llvm/Support/Watchdog.h" #include "llvm/Support/raw_ostream.h" +#include <tuple> + #ifdef HAVE_CRASHREPORTERCLIENT_H #include <CrashReporterClient.h> #endif @@ -36,20 +38,32 @@ using namespace llvm; // objects, but we *really* cannot tolerate destructors running and do not want // to pay any overhead of synchronizing. As a consequence, we use a raw // thread-local variable. -static LLVM_THREAD_LOCAL const PrettyStackTraceEntry *PrettyStackTraceHead = - nullptr; - -static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){ - unsigned NextID = 0; - if (Entry->getNextEntry()) - NextID = PrintStack(Entry->getNextEntry(), OS); - OS << NextID << ".\t"; - { +static LLVM_THREAD_LOCAL PrettyStackTraceEntry *PrettyStackTraceHead = nullptr; + +namespace llvm { +PrettyStackTraceEntry *ReverseStackTrace(PrettyStackTraceEntry *Head) { + PrettyStackTraceEntry *Prev = nullptr; + while (Head) + std::tie(Prev, Head, Head->NextEntry) = + std::make_tuple(Head, Head->NextEntry, Prev); + return Prev; +} +} + +static void PrintStack(raw_ostream &OS) { + // Print out the stack in reverse order. To avoid recursion (which is likely + // to fail if we crashed due to stack overflow), we do an up-front pass to + // reverse the stack, then print it, then reverse it again. + unsigned ID = 0; + PrettyStackTraceEntry *ReversedStack = + llvm::ReverseStackTrace(PrettyStackTraceHead); + for (const PrettyStackTraceEntry *Entry = ReversedStack; Entry; + Entry = Entry->getNextEntry()) { + OS << ID++ << ".\t"; sys::Watchdog W(5); Entry->print(OS); } - - return NextID+1; + llvm::ReverseStackTrace(ReversedStack); } /// PrintCurStackTrace - Print the current stack trace to the specified stream. @@ -60,7 +74,7 @@ static void PrintCurStackTrace(raw_ostream &OS) { // If there are pretty stack frames registered, walk and emit them. OS << "Stack dump:\n"; - PrintStack(PrettyStackTraceHead, OS); + PrintStack(OS); OS.flush(); } @@ -123,7 +137,7 @@ PrettyStackTraceEntry::~PrettyStackTraceEntry() { #if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) assert(PrettyStackTraceHead == this && "Pretty stack trace entry destruction is out of order"); - PrettyStackTraceHead = getNextEntry(); + PrettyStackTraceHead = NextEntry; #endif } @@ -154,7 +168,7 @@ void llvm::EnablePrettyStackTrace() { #endif } -const void* llvm::SavePrettyStackState() { +const void *llvm::SavePrettyStackState() { #if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) return PrettyStackTraceHead; #else @@ -162,9 +176,10 @@ const void* llvm::SavePrettyStackState() { #endif } -void llvm::RestorePrettyStackState(const void* Top) { +void llvm::RestorePrettyStackState(const void *Top) { #if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) - PrettyStackTraceHead = (const PrettyStackTraceEntry*)Top; + PrettyStackTraceHead = + static_cast<PrettyStackTraceEntry *>(const_cast<void *>(Top)); #endif } diff --git a/contrib/llvm/lib/Support/Process.cpp b/contrib/llvm/lib/Support/Process.cpp index 6dcbb47..290c30f 100644 --- a/contrib/llvm/lib/Support/Process.cpp +++ b/contrib/llvm/lib/Support/Process.cpp @@ -73,6 +73,13 @@ static const char colorcodes[2][2][8][10] = { { ALLCOLORS("4",""), ALLCOLORS("4","1;") } }; +// This is set to true when Process::PreventCoreFiles() is called. +static bool coreFilesPrevented = false; + +bool Process::AreCoreFilesPrevented() { + return coreFilesPrevented; +} + // Include the platform-specific parts of this class. #ifdef LLVM_ON_UNIX #include "Unix/Process.inc" diff --git a/contrib/llvm/lib/Support/SHA1.cpp b/contrib/llvm/lib/Support/SHA1.cpp new file mode 100644 index 0000000..a461d1e --- /dev/null +++ b/contrib/llvm/lib/Support/SHA1.cpp @@ -0,0 +1,170 @@ +//======- SHA1.h - Private copy of the SHA1 implementation ---*- C++ -* ======// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This code is taken from public domain +// (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c) +// and modified by wrapping it in a C++ interface for LLVM, +// and removing unnecessary code. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Host.h" +#include "llvm/Support/SHA1.h" +#include "llvm/ADT/ArrayRef.h" +using namespace llvm; + +#include <stdint.h> +#include <string.h> + +#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN +#define SHA_BIG_ENDIAN +#endif + +/* code */ +#define SHA1_K0 0x5a827999 +#define SHA1_K20 0x6ed9eba1 +#define SHA1_K40 0x8f1bbcdc +#define SHA1_K60 0xca62c1d6 + +#define SEED_0 0x67452301 +#define SEED_1 0xefcdab89 +#define SEED_2 0x98badcfe +#define SEED_3 0x10325476 +#define SEED_4 0xc3d2e1f0 + +void SHA1::init() { + InternalState.State[0] = SEED_0; + InternalState.State[1] = SEED_1; + InternalState.State[2] = SEED_2; + InternalState.State[3] = SEED_3; + InternalState.State[4] = SEED_4; + InternalState.ByteCount = 0; + InternalState.BufferOffset = 0; +} + +static uint32_t rol32(uint32_t number, uint8_t bits) { + return ((number << bits) | (number >> (32 - bits))); +} + +void SHA1::hashBlock() { + uint8_t i; + uint32_t a, b, c, d, e, t; + + a = InternalState.State[0]; + b = InternalState.State[1]; + c = InternalState.State[2]; + d = InternalState.State[3]; + e = InternalState.State[4]; + for (i = 0; i < 80; i++) { + if (i >= 16) { + t = InternalState.Buffer[(i + 13) & 15] ^ + InternalState.Buffer[(i + 8) & 15] ^ + InternalState.Buffer[(i + 2) & 15] ^ InternalState.Buffer[i & 15]; + InternalState.Buffer[i & 15] = rol32(t, 1); + } + if (i < 20) { + t = (d ^ (b & (c ^ d))) + SHA1_K0; + } else if (i < 40) { + t = (b ^ c ^ d) + SHA1_K20; + } else if (i < 60) { + t = ((b & c) | (d & (b | c))) + SHA1_K40; + } else { + t = (b ^ c ^ d) + SHA1_K60; + } + t += rol32(a, 5) + e + InternalState.Buffer[i & 15]; + e = d; + d = c; + c = rol32(b, 30); + b = a; + a = t; + } + InternalState.State[0] += a; + InternalState.State[1] += b; + InternalState.State[2] += c; + InternalState.State[3] += d; + InternalState.State[4] += e; +} + +void SHA1::addUncounted(uint8_t data) { + uint8_t *const b = (uint8_t *)InternalState.Buffer; +#ifdef SHA_BIG_ENDIAN + b[InternalState.BufferOffset] = data; +#else + b[InternalState.BufferOffset ^ 3] = data; +#endif + InternalState.BufferOffset++; + if (InternalState.BufferOffset == BLOCK_LENGTH) { + hashBlock(); + InternalState.BufferOffset = 0; + } +} + +void SHA1::writebyte(uint8_t data) { + ++InternalState.ByteCount; + addUncounted(data); +} + +void SHA1::update(ArrayRef<uint8_t> Data) { + for (auto &C : Data) + writebyte(C); +} + +void SHA1::pad() { + // Implement SHA-1 padding (fips180-2 5.1.1) + + // Pad with 0x80 followed by 0x00 until the end of the block + addUncounted(0x80); + while (InternalState.BufferOffset != 56) + addUncounted(0x00); + + // Append length in the last 8 bytes + addUncounted(0); // We're only using 32 bit lengths + addUncounted(0); // But SHA-1 supports 64 bit lengths + addUncounted(0); // So zero pad the top bits + addUncounted(InternalState.ByteCount >> 29); // Shifting to multiply by 8 + addUncounted(InternalState.ByteCount >> + 21); // as SHA-1 supports bitstreams as well as + addUncounted(InternalState.ByteCount >> 13); // byte. + addUncounted(InternalState.ByteCount >> 5); + addUncounted(InternalState.ByteCount << 3); +} + +StringRef SHA1::final() { + // Pad to complete the last block + pad(); + +#ifdef SHA_BIG_ENDIAN + // Just copy the current state + for (int i = 0; i < 5; i++) { + HashResult[i] = InternalState.State[i]; + } +#else + // Swap byte order back + for (int i = 0; i < 5; i++) { + HashResult[i] = (((InternalState.State[i]) << 24) & 0xff000000) | + (((InternalState.State[i]) << 8) & 0x00ff0000) | + (((InternalState.State[i]) >> 8) & 0x0000ff00) | + (((InternalState.State[i]) >> 24) & 0x000000ff); + } +#endif + + // Return pointer to hash (20 characters) + return StringRef((char *)HashResult, HASH_LENGTH); +} + +StringRef SHA1::result() { + auto StateToRestore = InternalState; + + auto Hash = final(); + + // Restore the state + InternalState = StateToRestore; + + // Return pointer to hash (20 characters) + return Hash; +} diff --git a/contrib/llvm/lib/Support/ScaledNumber.cpp b/contrib/llvm/lib/Support/ScaledNumber.cpp index 987c2d8..b9432d4 100644 --- a/contrib/llvm/lib/Support/ScaledNumber.cpp +++ b/contrib/llvm/lib/Support/ScaledNumber.cpp @@ -13,6 +13,7 @@ #include "llvm/Support/ScaledNumber.h" #include "llvm/ADT/APFloat.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" diff --git a/contrib/llvm/lib/Support/ScopedPrinter.cpp b/contrib/llvm/lib/Support/ScopedPrinter.cpp new file mode 100644 index 0000000..0225f01 --- /dev/null +++ b/contrib/llvm/lib/Support/ScopedPrinter.cpp @@ -0,0 +1,72 @@ +#include "llvm/Support/ScopedPrinter.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Format.h" +#include <cctype> + +using namespace llvm::support; + +namespace llvm { + +raw_ostream &operator<<(raw_ostream &OS, const HexNumber &Value) { + OS << "0x" << to_hexString(Value.Value); + return OS; +} + +const std::string to_hexString(uint64_t Value, bool UpperCase) { + std::string number; + llvm::raw_string_ostream stream(number); + stream << format_hex_no_prefix(Value, 1, UpperCase); + return stream.str(); +} + +void ScopedPrinter::printBinaryImpl(StringRef Label, StringRef Str, + ArrayRef<uint8_t> Data, bool Block) { + if (Data.size() > 16) + Block = true; + + if (Block) { + startLine() << Label; + if (Str.size() > 0) + OS << ": " << Str; + OS << " (\n"; + for (size_t addr = 0, end = Data.size(); addr < end; addr += 16) { + startLine() << format(" %04" PRIX64 ": ", uint64_t(addr)); + // Dump line of hex. + for (size_t i = 0; i < 16; ++i) { + if (i != 0 && i % 4 == 0) + OS << ' '; + if (addr + i < end) + OS << hexdigit((Data[addr + i] >> 4) & 0xF, false) + << hexdigit(Data[addr + i] & 0xF, false); + else + OS << " "; + } + // Print ascii. + OS << " |"; + for (std::size_t i = 0; i < 16 && addr + i < end; ++i) { + if (std::isprint(Data[addr + i] & 0xFF)) + OS << Data[addr + i]; + else + OS << "."; + } + OS << "|\n"; + } + + startLine() << ")\n"; + } else { + startLine() << Label << ":"; + if (Str.size() > 0) + OS << " " << Str; + OS << " ("; + for (size_t i = 0; i < Data.size(); ++i) { + if (i > 0) + OS << " "; + + OS << format("%02X", static_cast<int>(Data[i])); + } + OS << ")\n"; + } +} + +} // namespace llvm diff --git a/contrib/llvm/lib/Support/Signals.cpp b/contrib/llvm/lib/Support/Signals.cpp index 3dc6b7c..e5e38f5 100644 --- a/contrib/llvm/lib/Support/Signals.cpp +++ b/contrib/llvm/lib/Support/Signals.cpp @@ -62,28 +62,40 @@ static FormattedNumber format_ptr(void *PC) { return format_hex((uint64_t)PC, PtrWidth); } -static bool printSymbolizedStackTrace(void **StackTrace, int Depth, +static bool printSymbolizedStackTrace(StringRef Argv0, + void **StackTrace, int Depth, llvm::raw_ostream &OS) LLVM_ATTRIBUTE_USED; /// Helper that launches llvm-symbolizer and symbolizes a backtrace. -static bool printSymbolizedStackTrace(void **StackTrace, int Depth, +static bool printSymbolizedStackTrace(StringRef Argv0, + void **StackTrace, int Depth, llvm::raw_ostream &OS) { + // Don't recursively invoke the llvm-symbolizer binary. + if (Argv0.find("llvm-symbolizer") != std::string::npos) + return false; + // FIXME: Subtract necessary number from StackTrace entries to turn return addresses // into actual instruction addresses. - // Use llvm-symbolizer tool to symbolize the stack traces. - ErrorOr<std::string> LLVMSymbolizerPathOrErr = - sys::findProgramByName("llvm-symbolizer"); + // Use llvm-symbolizer tool to symbolize the stack traces. First look for it + // alongside our binary, then in $PATH. + ErrorOr<std::string> LLVMSymbolizerPathOrErr = std::error_code(); + if (!Argv0.empty()) { + StringRef Parent = llvm::sys::path::parent_path(Argv0); + if (!Parent.empty()) + LLVMSymbolizerPathOrErr = sys::findProgramByName("llvm-symbolizer", Parent); + } + if (!LLVMSymbolizerPathOrErr) + LLVMSymbolizerPathOrErr = sys::findProgramByName("llvm-symbolizer"); if (!LLVMSymbolizerPathOrErr) return false; const std::string &LLVMSymbolizerPath = *LLVMSymbolizerPathOrErr; - // We don't know argv0 or the address of main() at this point, but try - // to guess it anyway (it's possible on some platforms). - std::string MainExecutableName = sys::fs::getMainExecutable(nullptr, nullptr); - if (MainExecutableName.empty() || - MainExecutableName.find("llvm-symbolizer") != std::string::npos) - return false; + // If we don't know argv0 or the address of main() at this point, try + // to guess it anyway (it's possible on some platforms). + std::string MainExecutableName = + Argv0.empty() ? sys::fs::getMainExecutable(nullptr, nullptr) + : (std::string)Argv0; BumpPtrAllocator Allocator; StringSaver StrPool(Allocator); std::vector<const char *> Modules(Depth, nullptr); diff --git a/contrib/llvm/lib/Support/SmallPtrSet.cpp b/contrib/llvm/lib/Support/SmallPtrSet.cpp index 358c8e8..539b4eb 100644 --- a/contrib/llvm/lib/Support/SmallPtrSet.cpp +++ b/contrib/llvm/lib/Support/SmallPtrSet.cpp @@ -25,8 +25,9 @@ void SmallPtrSetImplBase::shrink_and_clear() { free(CurArray); // Reduce the number of buckets. - CurArraySize = NumElements > 16 ? 1 << (Log2_32_Ceil(NumElements) + 1) : 32; - NumElements = NumTombstones = 0; + unsigned Size = size(); + CurArraySize = Size > 16 ? 1 << (Log2_32_Ceil(Size) + 1) : 32; + NumNonEmpty = NumTombstones = 0; // Install the new array. Clear all the buckets to empty. CurArray = (const void**)malloc(sizeof(void*) * CurArraySize); @@ -35,32 +36,16 @@ void SmallPtrSetImplBase::shrink_and_clear() { } std::pair<const void *const *, bool> -SmallPtrSetImplBase::insert_imp(const void *Ptr) { - if (isSmall()) { - // Check to see if it is already in the set. - for (const void **APtr = SmallArray, **E = SmallArray+NumElements; - APtr != E; ++APtr) - if (*APtr == Ptr) - return std::make_pair(APtr, false); - - // Nope, there isn't. If we stay small, just 'pushback' now. - if (NumElements < CurArraySize) { - SmallArray[NumElements++] = Ptr; - return std::make_pair(SmallArray + (NumElements - 1), true); - } - // Otherwise, hit the big set case, which will call grow. - } - - if (LLVM_UNLIKELY(NumElements * 4 >= CurArraySize * 3)) { +SmallPtrSetImplBase::insert_imp_big(const void *Ptr) { + if (LLVM_UNLIKELY(size() * 4 >= CurArraySize * 3)) { // If more than 3/4 of the array is full, grow. - Grow(CurArraySize < 64 ? 128 : CurArraySize*2); - } else if (LLVM_UNLIKELY(CurArraySize - (NumElements + NumTombstones) < - CurArraySize / 8)) { + Grow(CurArraySize < 64 ? 128 : CurArraySize * 2); + } else if (LLVM_UNLIKELY(CurArraySize - NumNonEmpty < CurArraySize / 8)) { // If fewer of 1/8 of the array is empty (meaning that many are filled with // tombstones), rehash. Grow(CurArraySize); } - + // Okay, we know we have space. Find a hash bucket. const void **Bucket = const_cast<const void**>(FindBucketFor(Ptr)); if (*Bucket == Ptr) @@ -69,34 +54,33 @@ SmallPtrSetImplBase::insert_imp(const void *Ptr) { // Otherwise, insert it! if (*Bucket == getTombstoneMarker()) --NumTombstones; + else + ++NumNonEmpty; // Track density. *Bucket = Ptr; - ++NumElements; // Track density. return std::make_pair(Bucket, true); } bool SmallPtrSetImplBase::erase_imp(const void * Ptr) { if (isSmall()) { // Check to see if it is in the set. - for (const void **APtr = SmallArray, **E = SmallArray+NumElements; - APtr != E; ++APtr) + for (const void **APtr = CurArray, **E = CurArray + NumNonEmpty; APtr != E; + ++APtr) if (*APtr == Ptr) { // If it is in the set, replace this element. - *APtr = E[-1]; - E[-1] = getEmptyMarker(); - --NumElements; + *APtr = getTombstoneMarker(); + ++NumTombstones; return true; } - + return false; } - + // Okay, we know we have space. Find a hash bucket. void **Bucket = const_cast<void**>(FindBucketFor(Ptr)); if (*Bucket != Ptr) return false; // Not in the set? // Set this as a tombstone. *Bucket = getTombstoneMarker(); - --NumElements; ++NumTombstones; return true; } @@ -122,7 +106,7 @@ const void * const *SmallPtrSetImplBase::FindBucketFor(const void *Ptr) const { // prefer to return it than something that would require more probing. if (Array[Bucket] == getTombstoneMarker() && !Tombstone) Tombstone = Array+Bucket; // Remember the first tombstone found. - + // It's a hash collision or a tombstone. Reprobe. Bucket = (Bucket + ProbeAmt++) & (ArraySize-1); } @@ -131,43 +115,32 @@ const void * const *SmallPtrSetImplBase::FindBucketFor(const void *Ptr) const { /// Grow - Allocate a larger backing store for the buckets and move it over. /// void SmallPtrSetImplBase::Grow(unsigned NewSize) { - // Allocate at twice as many buckets, but at least 128. - unsigned OldSize = CurArraySize; - const void **OldBuckets = CurArray; + const void **OldEnd = EndPointer(); bool WasSmall = isSmall(); - + // Install the new array. Clear all the buckets to empty. CurArray = (const void**)malloc(sizeof(void*) * NewSize); assert(CurArray && "Failed to allocate memory?"); CurArraySize = NewSize; memset(CurArray, -1, NewSize*sizeof(void*)); - - // Copy over all the elements. - if (WasSmall) { - // Small sets store their elements in order. - for (const void **BucketPtr = OldBuckets, **E = OldBuckets+NumElements; - BucketPtr != E; ++BucketPtr) { - const void *Elt = *BucketPtr; + + // Copy over all valid entries. + for (const void **BucketPtr = OldBuckets; BucketPtr != OldEnd; ++BucketPtr) { + // Copy over the element if it is valid. + const void *Elt = *BucketPtr; + if (Elt != getTombstoneMarker() && Elt != getEmptyMarker()) *const_cast<void**>(FindBucketFor(Elt)) = const_cast<void*>(Elt); - } - } else { - // Copy over all valid entries. - for (const void **BucketPtr = OldBuckets, **E = OldBuckets+OldSize; - BucketPtr != E; ++BucketPtr) { - // Copy over the element if it is valid. - const void *Elt = *BucketPtr; - if (Elt != getTombstoneMarker() && Elt != getEmptyMarker()) - *const_cast<void**>(FindBucketFor(Elt)) = const_cast<void*>(Elt); - } - - free(OldBuckets); - NumTombstones = 0; } + + if (!WasSmall) + free(OldBuckets); + NumNonEmpty -= NumTombstones; + NumTombstones = 0; } SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage, - const SmallPtrSetImplBase& that) { + const SmallPtrSetImplBase &that) { SmallArray = SmallStorage; // If we're becoming small, prepare to insert into our stack space @@ -178,46 +151,18 @@ SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage, CurArray = (const void**)malloc(sizeof(void*) * that.CurArraySize); assert(CurArray && "Failed to allocate memory?"); } - - // Copy over the new array size - CurArraySize = that.CurArraySize; - // Copy over the contents from the other set - memcpy(CurArray, that.CurArray, sizeof(void*)*CurArraySize); - - NumElements = that.NumElements; - NumTombstones = that.NumTombstones; + // Copy over the that array. + CopyHelper(that); } SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize, SmallPtrSetImplBase &&that) { SmallArray = SmallStorage; - - // Copy over the basic members. - CurArraySize = that.CurArraySize; - NumElements = that.NumElements; - NumTombstones = that.NumTombstones; - - // When small, just copy into our small buffer. - if (that.isSmall()) { - CurArray = SmallArray; - memcpy(CurArray, that.CurArray, sizeof(void *) * CurArraySize); - } else { - // Otherwise, we steal the large memory allocation and no copy is needed. - CurArray = that.CurArray; - that.CurArray = that.SmallArray; - } - - // Make the "that" object small and empty. - that.CurArraySize = SmallSize; - assert(that.CurArray == that.SmallArray); - that.NumElements = 0; - that.NumTombstones = 0; + MoveHelper(SmallSize, std::move(that)); } -/// CopyFrom - implement operator= from a smallptrset that has the same pointer -/// type, but may have a different small size. void SmallPtrSetImplBase::CopyFrom(const SmallPtrSetImplBase &RHS) { assert(&RHS != this && "Self-copy should be handled by the caller."); @@ -243,28 +188,36 @@ void SmallPtrSetImplBase::CopyFrom(const SmallPtrSetImplBase &RHS) { } assert(CurArray && "Failed to allocate memory?"); } - + + CopyHelper(RHS); +} + +void SmallPtrSetImplBase::CopyHelper(const SmallPtrSetImplBase &RHS) { // Copy over the new array size CurArraySize = RHS.CurArraySize; // Copy over the contents from the other set - memcpy(CurArray, RHS.CurArray, sizeof(void*)*CurArraySize); - - NumElements = RHS.NumElements; + std::copy(RHS.CurArray, RHS.EndPointer(), CurArray); + + NumNonEmpty = RHS.NumNonEmpty; NumTombstones = RHS.NumTombstones; } void SmallPtrSetImplBase::MoveFrom(unsigned SmallSize, SmallPtrSetImplBase &&RHS) { - assert(&RHS != this && "Self-move should be handled by the caller."); - if (!isSmall()) free(CurArray); + MoveHelper(SmallSize, std::move(RHS)); +} + +void SmallPtrSetImplBase::MoveHelper(unsigned SmallSize, + SmallPtrSetImplBase &&RHS) { + assert(&RHS != this && "Self-move should be handled by the caller."); if (RHS.isSmall()) { // Copy a small RHS rather than moving. CurArray = SmallArray; - memcpy(CurArray, RHS.CurArray, sizeof(void*)*RHS.CurArraySize); + std::copy(RHS.CurArray, RHS.CurArray + RHS.NumNonEmpty, CurArray); } else { CurArray = RHS.CurArray; RHS.CurArray = RHS.SmallArray; @@ -272,13 +225,13 @@ void SmallPtrSetImplBase::MoveFrom(unsigned SmallSize, // Copy the rest of the trivial members. CurArraySize = RHS.CurArraySize; - NumElements = RHS.NumElements; + NumNonEmpty = RHS.NumNonEmpty; NumTombstones = RHS.NumTombstones; // Make the RHS small and empty. RHS.CurArraySize = SmallSize; assert(RHS.CurArray == RHS.SmallArray); - RHS.NumElements = 0; + RHS.NumNonEmpty = 0; RHS.NumTombstones = 0; } @@ -289,7 +242,7 @@ void SmallPtrSetImplBase::swap(SmallPtrSetImplBase &RHS) { if (!this->isSmall() && !RHS.isSmall()) { std::swap(this->CurArray, RHS.CurArray); std::swap(this->CurArraySize, RHS.CurArraySize); - std::swap(this->NumElements, RHS.NumElements); + std::swap(this->NumNonEmpty, RHS.NumNonEmpty); std::swap(this->NumTombstones, RHS.NumTombstones); return; } @@ -299,40 +252,44 @@ void SmallPtrSetImplBase::swap(SmallPtrSetImplBase &RHS) { // If only RHS is small, copy the small elements into LHS and move the pointer // from LHS to RHS. if (!this->isSmall() && RHS.isSmall()) { - std::copy(RHS.SmallArray, RHS.SmallArray+RHS.CurArraySize, - this->SmallArray); - std::swap(this->NumElements, RHS.NumElements); - std::swap(this->CurArraySize, RHS.CurArraySize); + assert(RHS.CurArray == RHS.SmallArray); + std::copy(RHS.CurArray, RHS.CurArray + RHS.NumNonEmpty, this->SmallArray); + std::swap(RHS.CurArraySize, this->CurArraySize); + std::swap(this->NumNonEmpty, RHS.NumNonEmpty); + std::swap(this->NumTombstones, RHS.NumTombstones); RHS.CurArray = this->CurArray; - RHS.NumTombstones = this->NumTombstones; this->CurArray = this->SmallArray; - this->NumTombstones = 0; return; } // If only LHS is small, copy the small elements into RHS and move the pointer // from RHS to LHS. if (this->isSmall() && !RHS.isSmall()) { - std::copy(this->SmallArray, this->SmallArray+this->CurArraySize, + assert(this->CurArray == this->SmallArray); + std::copy(this->CurArray, this->CurArray + this->NumNonEmpty, RHS.SmallArray); - std::swap(RHS.NumElements, this->NumElements); std::swap(RHS.CurArraySize, this->CurArraySize); + std::swap(RHS.NumNonEmpty, this->NumNonEmpty); + std::swap(RHS.NumTombstones, this->NumTombstones); this->CurArray = RHS.CurArray; - this->NumTombstones = RHS.NumTombstones; RHS.CurArray = RHS.SmallArray; - RHS.NumTombstones = 0; return; } // Both a small, just swap the small elements. assert(this->isSmall() && RHS.isSmall()); - assert(this->CurArraySize == RHS.CurArraySize); - std::swap_ranges(this->SmallArray, this->SmallArray+this->CurArraySize, + unsigned MinNonEmpty = std::min(this->NumNonEmpty, RHS.NumNonEmpty); + std::swap_ranges(this->SmallArray, this->SmallArray + MinNonEmpty, RHS.SmallArray); - std::swap(this->NumElements, RHS.NumElements); -} - -SmallPtrSetImplBase::~SmallPtrSetImplBase() { - if (!isSmall()) - free(CurArray); + if (this->NumNonEmpty > MinNonEmpty) { + std::copy(this->SmallArray + MinNonEmpty, + this->SmallArray + this->NumNonEmpty, + RHS.SmallArray + MinNonEmpty); + } else { + std::copy(RHS.SmallArray + MinNonEmpty, RHS.SmallArray + RHS.NumNonEmpty, + this->SmallArray + MinNonEmpty); + } + assert(this->CurArraySize == RHS.CurArraySize); + std::swap(this->NumNonEmpty, RHS.NumNonEmpty); + std::swap(this->NumTombstones, RHS.NumTombstones); } diff --git a/contrib/llvm/lib/Support/SpecialCaseList.cpp b/contrib/llvm/lib/Support/SpecialCaseList.cpp index ea417c4..0ffe444 100644 --- a/contrib/llvm/lib/Support/SpecialCaseList.cpp +++ b/contrib/llvm/lib/Support/SpecialCaseList.cpp @@ -50,7 +50,7 @@ std::unique_ptr<SpecialCaseList> SpecialCaseList::create(const std::vector<std::string> &Paths, std::string &Error) { std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList()); - for (auto Path : Paths) { + for (const auto &Path : Paths) { ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = MemoryBuffer::getFile(Path); if (std::error_code EC = FileOrErr.getError()) { diff --git a/contrib/llvm/lib/Support/Statistic.cpp b/contrib/llvm/lib/Support/Statistic.cpp index e49d1cb..cdd3679 100644 --- a/contrib/llvm/lib/Support/Statistic.cpp +++ b/contrib/llvm/lib/Support/Statistic.cpp @@ -43,6 +43,9 @@ Enabled( cl::desc("Enable statistics output from program (available with Asserts)")); +static cl::opt<bool> StatsAsJSON("stats-json", + cl::desc("Display statistics as json data")); + namespace { /// StatisticInfo - This class is used in a ManagedStatic so that it is created /// on demand (when the first statistic is bumped) and destroyed only when @@ -51,6 +54,10 @@ class StatisticInfo { std::vector<const Statistic*> Stats; friend void llvm::PrintStatistics(); friend void llvm::PrintStatistics(raw_ostream &OS); + friend void llvm::PrintStatisticsJSON(raw_ostream &OS); + + /// Sort statistics by debugtype,name,description. + void sort(); public: ~StatisticInfo(); @@ -95,27 +102,32 @@ bool llvm::AreStatisticsEnabled() { return Enabled; } +void StatisticInfo::sort() { + std::stable_sort(Stats.begin(), Stats.end(), + [](const Statistic *LHS, const Statistic *RHS) { + if (int Cmp = std::strcmp(LHS->getDebugType(), RHS->getDebugType())) + return Cmp < 0; + + if (int Cmp = std::strcmp(LHS->getName(), RHS->getName())) + return Cmp < 0; + + return std::strcmp(LHS->getDesc(), RHS->getDesc()) < 0; + }); +} + void llvm::PrintStatistics(raw_ostream &OS) { StatisticInfo &Stats = *StatInfo; // Figure out how long the biggest Value and Name fields are. - unsigned MaxNameLen = 0, MaxValLen = 0; + unsigned MaxDebugTypeLen = 0, MaxValLen = 0; for (size_t i = 0, e = Stats.Stats.size(); i != e; ++i) { MaxValLen = std::max(MaxValLen, (unsigned)utostr(Stats.Stats[i]->getValue()).size()); - MaxNameLen = std::max(MaxNameLen, - (unsigned)std::strlen(Stats.Stats[i]->getName())); + MaxDebugTypeLen = std::max(MaxDebugTypeLen, + (unsigned)std::strlen(Stats.Stats[i]->getDebugType())); } - // Sort the fields by name. - std::stable_sort(Stats.Stats.begin(), Stats.Stats.end(), - [](const Statistic *LHS, const Statistic *RHS) { - if (int Cmp = std::strcmp(LHS->getName(), RHS->getName())) - return Cmp < 0; - - // Secondary key is the description. - return std::strcmp(LHS->getDesc(), RHS->getDesc()) < 0; - }); + Stats.sort(); // Print out the statistics header... OS << "===" << std::string(73, '-') << "===\n" @@ -126,12 +138,43 @@ void llvm::PrintStatistics(raw_ostream &OS) { for (size_t i = 0, e = Stats.Stats.size(); i != e; ++i) OS << format("%*u %-*s - %s\n", MaxValLen, Stats.Stats[i]->getValue(), - MaxNameLen, Stats.Stats[i]->getName(), + MaxDebugTypeLen, Stats.Stats[i]->getDebugType(), Stats.Stats[i]->getDesc()); OS << '\n'; // Flush the output stream. OS.flush(); +} + +static void write_json_string_escaped(raw_ostream &OS, const char *string) { + // Out current usage should not need any escaping. Keep it simple and just + // check that the input is pure ASCII without special characers. +#ifndef NDEBUG + for (const unsigned char *c = (const unsigned char*)string; *c != '\0'; ++c) { + assert(*c != '\\' && *c != '\"' && *c >= 0x20 && *c < 0x80); + } +#endif + OS << string; +} + +void llvm::PrintStatisticsJSON(raw_ostream &OS) { + StatisticInfo &Stats = *StatInfo; + + Stats.sort(); + // Print all of the statistics. + OS << "{\n"; + const char *delim = ""; + for (const Statistic *Stat : Stats.Stats) { + OS << delim; + OS << "\t\""; + write_json_string_escaped(OS, Stat->getDebugType()); + OS << '.'; + write_json_string_escaped(OS, Stat->getName()); + OS << "\": " << Stat->getValue(); + delim = ",\n"; + } + OS << "\n}\n"; + OS.flush(); } void llvm::PrintStatistics() { @@ -143,7 +186,10 @@ void llvm::PrintStatistics() { // Get the stream to write to. std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile(); - PrintStatistics(*OutStream); + if (StatsAsJSON) + PrintStatisticsJSON(*OutStream); + else + PrintStatistics(*OutStream); #else // Check if the -stats option is set instead of checking diff --git a/contrib/llvm/lib/Support/StreamingMemoryObject.cpp b/contrib/llvm/lib/Support/StreamingMemoryObject.cpp index 5a44e62..fb56617 100644 --- a/contrib/llvm/lib/Support/StreamingMemoryObject.cpp +++ b/contrib/llvm/lib/Support/StreamingMemoryObject.cpp @@ -104,6 +104,12 @@ uint64_t StreamingMemoryObject::readBytes(uint8_t *Buf, uint64_t Size, return Size; } +const uint8_t *StreamingMemoryObject::getPointer(uint64_t Address, + uint64_t Size) const { + fetchToPos(Address + Size - 1); + return &Bytes[Address + BytesSkipped]; +} + bool StreamingMemoryObject::dropLeadingBytes(size_t s) { if (BytesRead < s) return true; BytesSkipped = s; diff --git a/contrib/llvm/lib/Support/StringMap.cpp b/contrib/llvm/lib/Support/StringMap.cpp index 7be9466..7da9ccb 100644 --- a/contrib/llvm/lib/Support/StringMap.cpp +++ b/contrib/llvm/lib/Support/StringMap.cpp @@ -17,12 +17,26 @@ #include <cassert> using namespace llvm; +/// Returns the number of buckets to allocate to ensure that the DenseMap can +/// accommodate \p NumEntries without need to grow(). +static unsigned getMinBucketToReserveForEntries(unsigned NumEntries) { + // Ensure that "NumEntries * 4 < NumBuckets * 3" + if (NumEntries == 0) + return 0; + // +1 is required because of the strict equality. + // For example if NumEntries is 48, we need to return 401. + return NextPowerOf2(NumEntries * 4 / 3 + 1); +} + StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) { ItemSize = itemSize; // If a size is specified, initialize the table with that many buckets. if (InitSize) { - init(InitSize); + // The table will grow when the number of entries reach 3/4 of the number of + // buckets. To guarantee that "InitSize" number of entries can be inserted + // in the table without growing, we allocate just what is needed here. + init(getMinBucketToReserveForEntries(InitSize)); return; } diff --git a/contrib/llvm/lib/Support/StringRef.cpp b/contrib/llvm/lib/Support/StringRef.cpp index 7ecff29..8a9da5e 100644 --- a/contrib/llvm/lib/Support/StringRef.cpp +++ b/contrib/llvm/lib/Support/StringRef.cpp @@ -351,12 +351,12 @@ size_t StringRef::count(StringRef Str) const { } static unsigned GetAutoSenseRadix(StringRef &Str) { - if (Str.startswith("0x")) { + if (Str.startswith("0x") || Str.startswith("0X")) { Str = Str.substr(2); return 16; } - if (Str.startswith("0b")) { + if (Str.startswith("0b") || Str.startswith("0B")) { Str = Str.substr(2); return 2; } diff --git a/contrib/llvm/lib/Support/TargetParser.cpp b/contrib/llvm/lib/Support/TargetParser.cpp index 337532e..c3f8613 100644 --- a/contrib/llvm/lib/Support/TargetParser.cpp +++ b/contrib/llvm/lib/Support/TargetParser.cpp @@ -21,6 +21,7 @@ using namespace llvm; using namespace ARM; +using namespace AArch64; namespace { @@ -75,6 +76,11 @@ static const struct { {NAME, sizeof(NAME) - 1, CPU_ATTR, sizeof(CPU_ATTR) - 1, SUB_ARCH, \ sizeof(SUB_ARCH) - 1, ARCH_FPU, ARCH_BASE_EXT, ID, ARCH_ATTR}, #include "llvm/Support/ARMTargetParser.def" +},AArch64ARCHNames[] = { +#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) \ + {NAME, sizeof(NAME) - 1, CPU_ATTR, sizeof(CPU_ATTR) - 1, SUB_ARCH, \ + sizeof(SUB_ARCH) - 1, ARCH_FPU, ARCH_BASE_EXT, ID, ARCH_ATTR}, +#include "llvm/Support/AArch64TargetParser.def" }; // List of Arch Extension names. @@ -91,6 +97,10 @@ static const struct { #define ARM_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE) \ { NAME, sizeof(NAME) - 1, ID, FEATURE, NEGFEATURE }, #include "llvm/Support/ARMTargetParser.def" +},AArch64ARCHExtNames[] = { +#define AARCH64_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE) \ + { NAME, sizeof(NAME) - 1, ID, FEATURE, NEGFEATURE }, +#include "llvm/Support/AArch64TargetParser.def" }; // List of HWDiv names (use getHWDivSynonym) and which architectural @@ -124,6 +134,10 @@ static const struct { #define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ { NAME, sizeof(NAME) - 1, ID, IS_DEFAULT, DEFAULT_EXT }, #include "llvm/Support/ARMTargetParser.def" +},AArch64CPUNames[] = { +#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ + { NAME, sizeof(NAME) - 1, ID, IS_DEFAULT, DEFAULT_EXT }, +#include "llvm/Support/AArch64TargetParser.def" }; } // namespace @@ -305,13 +319,13 @@ StringRef llvm::ARM::getArchName(unsigned ArchKind) { } StringRef llvm::ARM::getCPUAttr(unsigned ArchKind) { - if (ArchKind >= ARM::AK_LAST) + if (ArchKind == ARM::AK_INVALID || ArchKind >= ARM::AK_LAST) return StringRef(); return ARCHNames[ArchKind].getCPUAttr(); } StringRef llvm::ARM::getSubArch(unsigned ArchKind) { - if (ArchKind >= ARM::AK_LAST) + if (ArchKind == ARM::AK_INVALID || ArchKind >= ARM::AK_LAST) return StringRef(); return ARCHNames[ArchKind].getSubArch(); } @@ -369,6 +383,156 @@ StringRef llvm::ARM::getDefaultCPU(StringRef Arch) { return "generic"; } +StringRef llvm::AArch64::getFPUName(unsigned FPUKind) { + return ARM::getFPUName(FPUKind); +} + +unsigned llvm::AArch64::getFPUVersion(unsigned FPUKind) { + return ARM::getFPUVersion(FPUKind); +} + +unsigned llvm::AArch64::getFPUNeonSupportLevel(unsigned FPUKind) { + return ARM::getFPUNeonSupportLevel( FPUKind); +} + +unsigned llvm::AArch64::getFPURestriction(unsigned FPUKind) { + return ARM::getFPURestriction(FPUKind); +} + +unsigned llvm::AArch64::getDefaultFPU(StringRef CPU, unsigned ArchKind) { + if (CPU == "generic") + return AArch64ARCHNames[ArchKind].DefaultFPU; + + return StringSwitch<unsigned>(CPU) +#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ + .Case(NAME, DEFAULT_FPU) +#include "llvm/Support/AArch64TargetParser.def" + .Default(ARM::FK_INVALID); +} + +unsigned llvm::AArch64::getDefaultExtensions(StringRef CPU, unsigned ArchKind) { + if (CPU == "generic") + return AArch64ARCHNames[ArchKind].ArchBaseExtensions; + + return StringSwitch<unsigned>(CPU) +#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ + .Case(NAME, AArch64ARCHNames[ID].ArchBaseExtensions | DEFAULT_EXT) +#include "llvm/Support/AArch64TargetParser.def" + .Default(AArch64::AEK_INVALID); +} + +bool llvm::AArch64::getExtensionFeatures(unsigned Extensions, + std::vector<const char *> &Features) { + + if (Extensions == AArch64::AEK_INVALID) + return false; + + if (Extensions & AArch64::AEK_FP) + Features.push_back("+fp-armv8"); + if (Extensions & AArch64::AEK_SIMD) + Features.push_back("+neon"); + if (Extensions & AArch64::AEK_CRC) + Features.push_back("+crc"); + if (Extensions & AArch64::AEK_CRYPTO) + Features.push_back("+crypto"); + if (Extensions & AArch64::AEK_FP16) + Features.push_back("+fullfp16"); + if (Extensions & AArch64::AEK_PROFILE) + Features.push_back("+spe"); + if (Extensions & AArch64::AEK_RAS) + Features.push_back("+ras"); + + return true; +} + +bool llvm::AArch64::getFPUFeatures(unsigned FPUKind, + std::vector<const char *> &Features) { + return ARM::getFPUFeatures(FPUKind, Features); +} + +bool llvm::AArch64::getArchFeatures(unsigned ArchKind, + std::vector<const char *> &Features) { + if (ArchKind == ARM::AK_INVALID || ArchKind >= ARM::AK_LAST) + return false; + + if (ArchKind == ARM::AK_ARMV8_1A) + Features.push_back("+v8.1a"); + if (ArchKind == ARM::AK_ARMV8_2A) + Features.push_back("+v8.2a"); + + return true; +} + +StringRef llvm::AArch64::getArchName(unsigned ArchKind) { + for (const auto &AI : AArch64ARCHNames) + if (AI.ID == ArchKind) + return AI.getName(); + return StringRef(); +} + +StringRef llvm::AArch64::getCPUAttr(unsigned ArchKind) { + for (const auto &AI : AArch64ARCHNames) + if (AI.ID == ArchKind) + return AI.getCPUAttr(); + return StringRef(); +} + +StringRef llvm::AArch64::getSubArch(unsigned ArchKind) { + for (const auto &AI : AArch64ARCHNames) + if (AI.ID == ArchKind) + return AI.getSubArch(); + return StringRef(); +} + +unsigned llvm::AArch64::getArchAttr(unsigned ArchKind) { + for (const auto &AI : AArch64ARCHNames) + if (AI.ID == ArchKind) + return AI.ArchAttr; + return ARMBuildAttrs::CPUArch::v8_A; +} + +StringRef llvm::AArch64::getArchExtName(unsigned AArchExtKind) { + for (const auto &AE : AArch64ARCHExtNames) + if (AArchExtKind == AE.ID) + return AE.getName(); + return StringRef(); +} + +const char *llvm::AArch64::getArchExtFeature(StringRef ArchExt) { + if (ArchExt.startswith("no")) { + StringRef ArchExtBase(ArchExt.substr(2)); + for (const auto &AE : AArch64ARCHExtNames) { + if (AE.NegFeature && ArchExtBase == AE.getName()) + return AE.NegFeature; + } + } + + for (const auto &AE : AArch64ARCHExtNames) + if (AE.Feature && ArchExt == AE.getName()) + return AE.Feature; + return nullptr; +} + +StringRef llvm::AArch64::getDefaultCPU(StringRef Arch) { + unsigned AK = parseArch(Arch); + if (AK == ARM::AK_INVALID) + return StringRef(); + + // Look for multiple AKs to find the default for pair AK+Name. + for (const auto &CPU : AArch64CPUNames) + if (CPU.ArchID == AK && CPU.Default) + return CPU.getName(); + + // If we can't find a default then target the architecture instead + return "generic"; +} + +unsigned llvm::AArch64::checkArchVersion(StringRef Arch) { + if (Arch[0] == 'v' && std::isdigit(Arch[1])) + return (Arch[1] - 48); + return 0; +} + // ======================================================= // // Parsers // ======================================================= // @@ -411,6 +575,8 @@ static StringRef getArchSynonym(StringRef Arch) { .Cases("v8", "v8a", "aarch64", "arm64", "v8-a") .Case("v8.1a", "v8.1-a") .Case("v8.2a", "v8.2-a") + .Case("v8m.base", "v8-m.base") + .Case("v8m.main", "v8-m.main") .Default(Arch); } @@ -548,6 +714,8 @@ unsigned llvm::ARM::parseArchProfile(StringRef Arch) { case ARM::AK_ARMV6M: case ARM::AK_ARMV7M: case ARM::AK_ARMV7EM: + case ARM::AK_ARMV8MMainline: + case ARM::AK_ARMV8MBaseline: return ARM::PK_M; case ARM::AK_ARMV7R: return ARM::PK_R; @@ -597,7 +765,67 @@ unsigned llvm::ARM::parseArchVersion(StringRef Arch) { case ARM::AK_ARMV8A: case ARM::AK_ARMV8_1A: case ARM::AK_ARMV8_2A: + case ARM::AK_ARMV8MBaseline: + case ARM::AK_ARMV8MMainline: return 8; } return 0; } + +StringRef llvm::AArch64::getCanonicalArchName(StringRef Arch) { + return ARM::getCanonicalArchName(Arch); +} + +unsigned llvm::AArch64::parseFPU(StringRef FPU) { + return ARM::parseFPU(FPU); +} + +// Allows partial match, ex. "v8a" matches "armv8a". +unsigned llvm::AArch64::parseArch(StringRef Arch) { + Arch = getCanonicalArchName(Arch); + if (checkArchVersion(Arch) < 8) + return ARM::AK_INVALID; + + StringRef Syn = getArchSynonym(Arch); + for (const auto A : AArch64ARCHNames) { + if (A.getName().endswith(Syn)) + return A.ID; + } + return ARM::AK_INVALID; +} + +unsigned llvm::AArch64::parseArchExt(StringRef ArchExt) { + for (const auto A : AArch64ARCHExtNames) { + if (ArchExt == A.getName()) + return A.ID; + } + return AArch64::AEK_INVALID; +} + +unsigned llvm::AArch64::parseCPUArch(StringRef CPU) { + for (const auto C : AArch64CPUNames) { + if (CPU == C.getName()) + return C.ArchID; + } + return ARM::AK_INVALID; +} + +// ARM, Thumb, AArch64 +unsigned llvm::AArch64::parseArchISA(StringRef Arch) { + return ARM::parseArchISA(Arch); +} + +// Little/Big endian +unsigned llvm::AArch64::parseArchEndian(StringRef Arch) { + return ARM::parseArchEndian(Arch); +} + +// Profile A/R/M +unsigned llvm::AArch64::parseArchProfile(StringRef Arch) { + return ARM::parseArchProfile(Arch); +} + +// Version number (ex. v8 = 8). +unsigned llvm::AArch64::parseArchVersion(StringRef Arch) { + return ARM::parseArchVersion(Arch); +} diff --git a/contrib/llvm/lib/Support/TargetRegistry.cpp b/contrib/llvm/lib/Support/TargetRegistry.cpp index eefef8a..02a6d33 100644 --- a/contrib/llvm/lib/Support/TargetRegistry.cpp +++ b/contrib/llvm/lib/Support/TargetRegistry.cpp @@ -73,8 +73,7 @@ const Target *TargetRegistry::lookupTarget(const std::string &TT, auto I = std::find_if(targets().begin(), targets().end(), ArchMatch); if (I == targets().end()) { - Error = "No available targets are compatible with this triple, " - "see -version for the available targets."; + Error = "No available targets are compatible with this triple."; return nullptr; } diff --git a/contrib/llvm/lib/Support/ThreadPool.cpp b/contrib/llvm/lib/Support/ThreadPool.cpp index d4dcb2e..db03a4d 100644 --- a/contrib/llvm/lib/Support/ThreadPool.cpp +++ b/contrib/llvm/lib/Support/ThreadPool.cpp @@ -75,8 +75,11 @@ ThreadPool::ThreadPool(unsigned ThreadCount) void ThreadPool::wait() { // Wait for all threads to complete and the queue to be empty std::unique_lock<std::mutex> LockGuard(CompletionLock); + // The order of the checks for ActiveThreads and Tasks.empty() matters because + // any active threads might be modifying the Tasks queue, and this would be a + // race. CompletionCondition.wait(LockGuard, - [&] { return Tasks.empty() && !ActiveThreads; }); + [&] { return !ActiveThreads && Tasks.empty(); }); } std::shared_future<ThreadPool::VoidTy> ThreadPool::asyncImpl(TaskTy Task) { diff --git a/contrib/llvm/lib/Support/Threading.cpp b/contrib/llvm/lib/Support/Threading.cpp index ca7f3f6..e8f5622 100644 --- a/contrib/llvm/lib/Support/Threading.cpp +++ b/contrib/llvm/lib/Support/Threading.cpp @@ -16,6 +16,7 @@ #include "llvm/Config/config.h" #include "llvm/Support/Atomic.h" #include "llvm/Support/Mutex.h" +#include "llvm/Support/thread.h" #include <cassert> using namespace llvm; @@ -71,6 +72,11 @@ void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, #include "Windows/WindowsSupport.h" #include <process.h> +// Windows will at times define MemoryFence. +#ifdef MemoryFence +#undef MemoryFence +#endif + struct ThreadInfo { void (*func)(void*); void *param; diff --git a/contrib/llvm/lib/Support/Timer.cpp b/contrib/llvm/lib/Support/Timer.cpp index 414f559..49bd39e 100644 --- a/contrib/llvm/lib/Support/Timer.cpp +++ b/contrib/llvm/lib/Support/Timer.cpp @@ -79,7 +79,7 @@ static TimerGroup *getDefaultTimerGroup() { TimerGroup *tmp = DefaultTimerGroup; sys::MemoryFence(); if (tmp) return tmp; - + sys::SmartScopedLock<true> Lock(*TimerLock); tmp = DefaultTimerGroup; if (!tmp) { @@ -120,7 +120,7 @@ static inline size_t getMemUsage() { TimeRecord TimeRecord::getCurrentTime(bool Start) { TimeRecord Result; sys::TimeValue now(0,0), user(0,0), sys(0,0); - + if (Start) { Result.MemUsed = getMemUsage(); sys::Process::GetTimeUsage(now, user, sys); @@ -168,9 +168,9 @@ void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const { if (Total.getProcessTime()) printVal(getProcessTime(), Total.getProcessTime(), OS); printVal(getWallTime(), Total.getWallTime(), OS); - + OS << " "; - + if (Total.getMemUsed()) OS << format("%9" PRId64 " ", (int64_t)getMemUsed()); } @@ -192,15 +192,15 @@ public: I = Map.begin(), E = Map.end(); I != E; ++I) delete I->second.first; } - + Timer &get(StringRef Name, StringRef GroupName) { sys::SmartScopedLock<true> L(*TimerLock); - + std::pair<TimerGroup*, Name2TimerMap> &GroupEntry = Map[GroupName]; - + if (!GroupEntry.first) GroupEntry.first = new TimerGroup(GroupName); - + Timer &T = GroupEntry.second[Name]; if (!T.isInitialized()) T.init(Name, *GroupEntry.first); @@ -215,7 +215,7 @@ static ManagedStatic<Name2PairMap> NamedGroupedTimers; static Timer &getNamedRegionTimer(StringRef Name) { sys::SmartScopedLock<true> L(*TimerLock); - + Timer &T = (*NamedTimers)[Name]; if (!T.isInitialized()) T.init(Name); @@ -240,7 +240,7 @@ static TimerGroup *TimerGroupList = nullptr; TimerGroup::TimerGroup(StringRef name) : Name(name.begin(), name.end()), FirstTimer(nullptr) { - + // Add the group to TimerGroupList. sys::SmartScopedLock<true> L(*TimerLock); if (TimerGroupList) @@ -255,7 +255,7 @@ TimerGroup::~TimerGroup() { // print the timing data. while (FirstTimer) removeTimer(*FirstTimer); - + // Remove the group from the TimerGroupList. sys::SmartScopedLock<true> L(*TimerLock); *Prev = Next; @@ -266,18 +266,18 @@ TimerGroup::~TimerGroup() { void TimerGroup::removeTimer(Timer &T) { sys::SmartScopedLock<true> L(*TimerLock); - + // If the timer was started, move its data to TimersToPrint. if (T.hasTriggered()) TimersToPrint.emplace_back(T.Time, T.Name); T.TG = nullptr; - + // Unlink the timer from our list. *T.Prev = T.Next; if (T.Next) T.Next->Prev = T.Prev; - + // Print the report when all timers in this group are destroyed if some of // them were started. if (FirstTimer || TimersToPrint.empty()) @@ -289,7 +289,7 @@ void TimerGroup::removeTimer(Timer &T) { void TimerGroup::addTimer(Timer &T) { sys::SmartScopedLock<true> L(*TimerLock); - + // Add the timer to our list. if (FirstTimer) FirstTimer->Prev = &T.Next; @@ -301,11 +301,11 @@ void TimerGroup::addTimer(Timer &T) { void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { // Sort the timers in descending order by amount of time taken. std::sort(TimersToPrint.begin(), TimersToPrint.end()); - + TimeRecord Total; for (auto &RecordNamePair : TimersToPrint) Total += RecordNamePair.first; - + // Print out timing header. OS << "===" << std::string(73, '-') << "===\n"; // Figure out how many spaces to indent TimerGroup name. @@ -313,7 +313,7 @@ void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { if (Padding > 80) Padding = 0; // Don't allow "negative" numbers OS.indent(Padding) << Name << '\n'; OS << "===" << std::string(73, '-') << "===\n"; - + // If this is not an collection of ungrouped times, print the total time. // Ungrouped timers don't really make sense to add up. We still print the // TOTAL line to make the percentages make sense. @@ -321,7 +321,7 @@ void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { OS << format(" Total Execution Time: %5.4f seconds (%5.4f wall clock)\n", Total.getProcessTime(), Total.getWallTime()); OS << '\n'; - + if (Total.getUserTime()) OS << " ---User Time---"; if (Total.getSystemTime()) @@ -332,18 +332,18 @@ void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { if (Total.getMemUsed()) OS << " ---Mem---"; OS << " --- Name ---\n"; - + // Loop through all of the timing data, printing it out. for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i) { const std::pair<TimeRecord, std::string> &Entry = TimersToPrint[e-i-1]; Entry.first.print(Total, OS); OS << Entry.second << '\n'; } - + Total.print(Total, OS); OS << "Total\n\n"; OS.flush(); - + TimersToPrint.clear(); } diff --git a/contrib/llvm/lib/Support/Triple.cpp b/contrib/llvm/lib/Support/Triple.cpp index 11afcf7..2bac2a3 100644 --- a/contrib/llvm/lib/Support/Triple.cpp +++ b/contrib/llvm/lib/Support/Triple.cpp @@ -19,50 +19,53 @@ using namespace llvm; const char *Triple::getArchTypeName(ArchType Kind) { switch (Kind) { - case UnknownArch: return "unknown"; - - case aarch64: return "aarch64"; - case aarch64_be: return "aarch64_be"; - case arm: return "arm"; - case armeb: return "armeb"; - case avr: return "avr"; - case bpfel: return "bpfel"; - case bpfeb: return "bpfeb"; - case hexagon: return "hexagon"; - case mips: return "mips"; - case mipsel: return "mipsel"; - case mips64: return "mips64"; - case mips64el: return "mips64el"; - case msp430: return "msp430"; - case ppc64: return "powerpc64"; - case ppc64le: return "powerpc64le"; - case ppc: return "powerpc"; - case r600: return "r600"; - case amdgcn: return "amdgcn"; - case sparc: return "sparc"; - case sparcv9: return "sparcv9"; - case sparcel: return "sparcel"; - case systemz: return "s390x"; - case tce: return "tce"; - case thumb: return "thumb"; - case thumbeb: return "thumbeb"; - case x86: return "i386"; - case x86_64: return "x86_64"; - case xcore: return "xcore"; - case nvptx: return "nvptx"; - case nvptx64: return "nvptx64"; - case le32: return "le32"; - case le64: return "le64"; - case amdil: return "amdil"; - case amdil64: return "amdil64"; - case hsail: return "hsail"; - case hsail64: return "hsail64"; - case spir: return "spir"; - case spir64: return "spir64"; - case kalimba: return "kalimba"; - case shave: return "shave"; - case wasm32: return "wasm32"; - case wasm64: return "wasm64"; + case UnknownArch: return "unknown"; + + case aarch64: return "aarch64"; + case aarch64_be: return "aarch64_be"; + case arm: return "arm"; + case armeb: return "armeb"; + case avr: return "avr"; + case bpfel: return "bpfel"; + case bpfeb: return "bpfeb"; + case hexagon: return "hexagon"; + case mips: return "mips"; + case mipsel: return "mipsel"; + case mips64: return "mips64"; + case mips64el: return "mips64el"; + case msp430: return "msp430"; + case ppc64: return "powerpc64"; + case ppc64le: return "powerpc64le"; + case ppc: return "powerpc"; + case r600: return "r600"; + case amdgcn: return "amdgcn"; + case sparc: return "sparc"; + case sparcv9: return "sparcv9"; + case sparcel: return "sparcel"; + case systemz: return "s390x"; + case tce: return "tce"; + case thumb: return "thumb"; + case thumbeb: return "thumbeb"; + case x86: return "i386"; + case x86_64: return "x86_64"; + case xcore: return "xcore"; + case nvptx: return "nvptx"; + case nvptx64: return "nvptx64"; + case le32: return "le32"; + case le64: return "le64"; + case amdil: return "amdil"; + case amdil64: return "amdil64"; + case hsail: return "hsail"; + case hsail64: return "hsail64"; + case spir: return "spir"; + case spir64: return "spir64"; + case kalimba: return "kalimba"; + case lanai: return "lanai"; + case shave: return "shave"; + case wasm32: return "wasm32"; + case wasm64: return "wasm64"; + case renderscript32: return "renderscript32"; + case renderscript64: return "renderscript64"; } llvm_unreachable("Invalid ArchType!"); @@ -94,8 +97,8 @@ const char *Triple::getArchTypePrefix(ArchType Kind) { case hexagon: return "hexagon"; - case amdgcn: - case r600: return "amdgpu"; + case amdgcn: return "amdgcn"; + case r600: return "r600"; case bpfel: case bpfeb: return "bpf"; @@ -111,8 +114,9 @@ const char *Triple::getArchTypePrefix(ArchType Kind) { case xcore: return "xcore"; - case nvptx: return "nvptx"; - case nvptx64: return "nvptx"; + // NVPTX intrinsics are namespaced under nvvm. + case nvptx: return "nvvm"; + case nvptx64: return "nvvm"; case le32: return "le32"; case le64: return "le64"; @@ -126,6 +130,7 @@ const char *Triple::getArchTypePrefix(ArchType Kind) { case spir: case spir64: return "spir"; case kalimba: return "kalimba"; + case lanai: return "lanai"; case shave: return "shave"; case wasm32: case wasm64: return "wasm"; @@ -148,6 +153,8 @@ const char *Triple::getVendorTypeName(VendorType Kind) { case NVIDIA: return "nvidia"; case CSR: return "csr"; case Myriad: return "myriad"; + case AMD: return "amd"; + case Mesa: return "mesa"; } llvm_unreachable("Invalid VendorType!"); @@ -184,6 +191,7 @@ const char *Triple::getOSTypeName(OSType Kind) { case ELFIAMCU: return "elfiamcu"; case TvOS: return "tvos"; case WatchOS: return "watchos"; + case Mesa3D: return "mesa3d"; } llvm_unreachable("Invalid OSType"); @@ -193,6 +201,7 @@ const char *Triple::getEnvironmentTypeName(EnvironmentType Kind) { switch (Kind) { case UnknownEnvironment: return "unknown"; case GNU: return "gnu"; + case GNUABI64: return "gnuabi64"; case GNUEABIHF: return "gnueabihf"; case GNUEABI: return "gnueabi"; case GNUX32: return "gnux32"; @@ -200,6 +209,9 @@ const char *Triple::getEnvironmentTypeName(EnvironmentType Kind) { case EABI: return "eabi"; case EABIHF: return "eabihf"; case Android: return "android"; + case Musl: return "musl"; + case MuslEABI: return "musleabi"; + case MuslEABIHF: return "musleabihf"; case MSVC: return "msvc"; case Itanium: return "itanium"; case Cygnus: return "cygnus"; @@ -268,9 +280,12 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { .Case("spir", spir) .Case("spir64", spir64) .Case("kalimba", kalimba) + .Case("lanai", lanai) .Case("shave", shave) .Case("wasm32", wasm32) .Case("wasm64", wasm64) + .Case("renderscript32", renderscript32) + .Case("renderscript64", renderscript64) .Default(UnknownArch); } @@ -376,9 +391,12 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Case("spir", Triple::spir) .Case("spir64", Triple::spir64) .StartsWith("kalimba", Triple::kalimba) + .Case("lanai", Triple::lanai) .Case("shave", Triple::shave) .Case("wasm32", Triple::wasm32) .Case("wasm64", Triple::wasm64) + .Case("renderscript32", Triple::renderscript32) + .Case("renderscript64", Triple::renderscript64) .Default(Triple::UnknownArch); // Some architectures require special parsing logic just to compute the @@ -408,6 +426,8 @@ static Triple::VendorType parseVendor(StringRef VendorName) { .Case("nvidia", Triple::NVIDIA) .Case("csr", Triple::CSR) .Case("myriad", Triple::Myriad) + .Case("amd", Triple::AMD) + .Case("mesa", Triple::Mesa) .Default(Triple::UnknownVendor); } @@ -441,6 +461,7 @@ static Triple::OSType parseOS(StringRef OSName) { .StartsWith("elfiamcu", Triple::ELFIAMCU) .StartsWith("tvos", Triple::TvOS) .StartsWith("watchos", Triple::WatchOS) + .StartsWith("mesa3d", Triple::Mesa3D) .Default(Triple::UnknownOS); } @@ -448,12 +469,16 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { return StringSwitch<Triple::EnvironmentType>(EnvironmentName) .StartsWith("eabihf", Triple::EABIHF) .StartsWith("eabi", Triple::EABI) + .StartsWith("gnuabi64", Triple::GNUABI64) .StartsWith("gnueabihf", Triple::GNUEABIHF) .StartsWith("gnueabi", Triple::GNUEABI) .StartsWith("gnux32", Triple::GNUX32) .StartsWith("code16", Triple::CODE16) .StartsWith("gnu", Triple::GNU) .StartsWith("android", Triple::Android) + .StartsWith("musleabihf", Triple::MuslEABIHF) + .StartsWith("musleabi", Triple::MuslEABI) + .StartsWith("musl", Triple::Musl) .StartsWith("msvc", Triple::MSVC) .StartsWith("itanium", Triple::Itanium) .StartsWith("cygnus", Triple::Cygnus) @@ -521,6 +546,10 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) { return Triple::ARMSubArch_v8_1a; case ARM::AK_ARMV8_2A: return Triple::ARMSubArch_v8_2a; + case ARM::AK_ARMV8MBaseline: + return Triple::ARMSubArch_v8m_baseline; + case ARM::AK_ARMV8MMainline: + return Triple::ARMSubArch_v8m_mainline; default: return Triple::NoSubArch; } @@ -559,6 +588,7 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { case Triple::bpfeb: case Triple::bpfel: case Triple::hexagon: + case Triple::lanai: case Triple::hsail: case Triple::hsail64: case Triple::kalimba: @@ -573,6 +603,8 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { case Triple::nvptx64: case Triple::ppc64le: case Triple::r600: + case Triple::renderscript32: + case Triple::renderscript64: case Triple::shave: case Triple::sparc: case Triple::sparcel: @@ -1111,8 +1143,10 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::hsail: case llvm::Triple::spir: case llvm::Triple::kalimba: + case llvm::Triple::lanai: case llvm::Triple::shave: case llvm::Triple::wasm32: + case llvm::Triple::renderscript32: return 32; case llvm::Triple::aarch64: @@ -1133,6 +1167,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::hsail64: case llvm::Triple::spir64: case llvm::Triple::wasm64: + case llvm::Triple::renderscript64: return 64; } llvm_unreachable("Invalid architecture value"); @@ -1184,24 +1219,27 @@ Triple Triple::get32BitArchVariant() const { case Triple::thumbeb: case Triple::x86: case Triple::xcore: + case Triple::lanai: case Triple::shave: case Triple::wasm32: + case Triple::renderscript32: // Already 32-bit. break; - case Triple::aarch64: T.setArch(Triple::arm); break; - case Triple::aarch64_be: T.setArch(Triple::armeb); break; - case Triple::le64: T.setArch(Triple::le32); break; - case Triple::mips64: T.setArch(Triple::mips); break; - case Triple::mips64el: T.setArch(Triple::mipsel); break; - case Triple::nvptx64: T.setArch(Triple::nvptx); break; - case Triple::ppc64: T.setArch(Triple::ppc); break; - case Triple::sparcv9: T.setArch(Triple::sparc); break; - case Triple::x86_64: T.setArch(Triple::x86); break; - case Triple::amdil64: T.setArch(Triple::amdil); break; - case Triple::hsail64: T.setArch(Triple::hsail); break; - case Triple::spir64: T.setArch(Triple::spir); break; - case Triple::wasm64: T.setArch(Triple::wasm32); break; + case Triple::aarch64: T.setArch(Triple::arm); break; + case Triple::aarch64_be: T.setArch(Triple::armeb); break; + case Triple::le64: T.setArch(Triple::le32); break; + case Triple::mips64: T.setArch(Triple::mips); break; + case Triple::mips64el: T.setArch(Triple::mipsel); break; + case Triple::nvptx64: T.setArch(Triple::nvptx); break; + case Triple::ppc64: T.setArch(Triple::ppc); break; + case Triple::sparcv9: T.setArch(Triple::sparc); break; + case Triple::x86_64: T.setArch(Triple::x86); break; + case Triple::amdil64: T.setArch(Triple::amdil); break; + case Triple::hsail64: T.setArch(Triple::hsail); break; + case Triple::spir64: T.setArch(Triple::spir); break; + case Triple::wasm64: T.setArch(Triple::wasm32); break; + case Triple::renderscript64: T.setArch(Triple::renderscript32); break; } return T; } @@ -1213,6 +1251,7 @@ Triple Triple::get64BitArchVariant() const { case Triple::avr: case Triple::hexagon: case Triple::kalimba: + case Triple::lanai: case Triple::msp430: case Triple::r600: case Triple::tce: @@ -1240,30 +1279,35 @@ Triple Triple::get64BitArchVariant() const { case Triple::systemz: case Triple::x86_64: case Triple::wasm64: + case Triple::renderscript64: // Already 64-bit. break; - case Triple::arm: T.setArch(Triple::aarch64); break; - case Triple::armeb: T.setArch(Triple::aarch64_be); break; - case Triple::le32: T.setArch(Triple::le64); break; - case Triple::mips: T.setArch(Triple::mips64); break; - case Triple::mipsel: T.setArch(Triple::mips64el); break; - case Triple::nvptx: T.setArch(Triple::nvptx64); break; - case Triple::ppc: T.setArch(Triple::ppc64); break; - case Triple::sparc: T.setArch(Triple::sparcv9); break; - case Triple::x86: T.setArch(Triple::x86_64); break; - case Triple::amdil: T.setArch(Triple::amdil64); break; - case Triple::hsail: T.setArch(Triple::hsail64); break; - case Triple::spir: T.setArch(Triple::spir64); break; - case Triple::thumb: T.setArch(Triple::aarch64); break; - case Triple::thumbeb: T.setArch(Triple::aarch64_be); break; - case Triple::wasm32: T.setArch(Triple::wasm64); break; + case Triple::arm: T.setArch(Triple::aarch64); break; + case Triple::armeb: T.setArch(Triple::aarch64_be); break; + case Triple::le32: T.setArch(Triple::le64); break; + case Triple::mips: T.setArch(Triple::mips64); break; + case Triple::mipsel: T.setArch(Triple::mips64el); break; + case Triple::nvptx: T.setArch(Triple::nvptx64); break; + case Triple::ppc: T.setArch(Triple::ppc64); break; + case Triple::sparc: T.setArch(Triple::sparcv9); break; + case Triple::x86: T.setArch(Triple::x86_64); break; + case Triple::amdil: T.setArch(Triple::amdil64); break; + case Triple::hsail: T.setArch(Triple::hsail64); break; + case Triple::spir: T.setArch(Triple::spir64); break; + case Triple::thumb: T.setArch(Triple::aarch64); break; + case Triple::thumbeb: T.setArch(Triple::aarch64_be); break; + case Triple::wasm32: T.setArch(Triple::wasm64); break; + case Triple::renderscript32: T.setArch(Triple::renderscript64); break; } return T; } Triple Triple::getBigEndianArchVariant() const { Triple T(*this); + // Already big endian. + if (!isLittleEndian()) + return T; switch (getArch()) { case Triple::UnknownArch: case Triple::amdgcn: @@ -1288,6 +1332,8 @@ Triple Triple::getBigEndianArchVariant() const { case Triple::x86: case Triple::x86_64: case Triple::xcore: + case Triple::renderscript32: + case Triple::renderscript64: // ARM is intentionally unsupported here, changing the architecture would // drop any arch suffixes. @@ -1296,35 +1342,26 @@ Triple Triple::getBigEndianArchVariant() const { T.setArch(UnknownArch); break; - case Triple::aarch64_be: - case Triple::armeb: - case Triple::bpfeb: - case Triple::mips64: - case Triple::mips: - case Triple::ppc64: - case Triple::ppc: - case Triple::sparc: - case Triple::sparcv9: - case Triple::systemz: - case Triple::tce: - case Triple::thumbeb: - // Already big endian. - break; - case Triple::aarch64: T.setArch(Triple::aarch64_be); break; case Triple::bpfel: T.setArch(Triple::bpfeb); break; case Triple::mips64el:T.setArch(Triple::mips64); break; case Triple::mipsel: T.setArch(Triple::mips); break; case Triple::ppc64le: T.setArch(Triple::ppc64); break; case Triple::sparcel: T.setArch(Triple::sparc); break; + default: + llvm_unreachable("getBigEndianArchVariant: unknown triple."); } return T; } Triple Triple::getLittleEndianArchVariant() const { Triple T(*this); + if (isLittleEndian()) + return T; + switch (getArch()) { case Triple::UnknownArch: + case Triple::lanai: case Triple::ppc: case Triple::sparcv9: case Triple::systemz: @@ -1337,6 +1374,20 @@ Triple Triple::getLittleEndianArchVariant() const { T.setArch(UnknownArch); break; + case Triple::aarch64_be: T.setArch(Triple::aarch64); break; + case Triple::bpfeb: T.setArch(Triple::bpfel); break; + case Triple::mips64: T.setArch(Triple::mips64el); break; + case Triple::mips: T.setArch(Triple::mipsel); break; + case Triple::ppc64: T.setArch(Triple::ppc64le); break; + case Triple::sparc: T.setArch(Triple::sparcel); break; + default: + llvm_unreachable("getLittleEndianArchVariant: unknown triple."); + } + return T; +} + +bool Triple::isLittleEndian() const { + switch (getArch()) { case Triple::aarch64: case Triple::amdgcn: case Triple::amdil64: @@ -1367,17 +1418,12 @@ Triple Triple::getLittleEndianArchVariant() const { case Triple::x86: case Triple::x86_64: case Triple::xcore: - // Already little endian. - break; - - case Triple::aarch64_be: T.setArch(Triple::aarch64); break; - case Triple::bpfeb: T.setArch(Triple::bpfel); break; - case Triple::mips64: T.setArch(Triple::mips64el); break; - case Triple::mips: T.setArch(Triple::mipsel); break; - case Triple::ppc64: T.setArch(Triple::ppc64le); break; - case Triple::sparc: T.setArch(Triple::sparcel); break; + case Triple::renderscript32: + case Triple::renderscript64: + return true; + default: + return false; } - return T; } StringRef Triple::getARMCPUForArch(StringRef MArch) const { @@ -1398,6 +1444,7 @@ StringRef Triple::getARMCPUForArch(StringRef MArch) const { case llvm::Triple::MacOSX: case llvm::Triple::IOS: case llvm::Triple::WatchOS: + case llvm::Triple::TvOS: if (MArch == "v7k") return "cortex-a7"; break; @@ -1431,6 +1478,7 @@ StringRef Triple::getARMCPUForArch(StringRef MArch) const { switch (getEnvironment()) { case llvm::Triple::EABIHF: case llvm::Triple::GNUEABIHF: + case llvm::Triple::MuslEABIHF: return "arm1176jzf-s"; default: return "arm7tdmi"; diff --git a/contrib/llvm/lib/Support/Twine.cpp b/contrib/llvm/lib/Support/Twine.cpp index 020dd95..5e989fb 100644 --- a/contrib/llvm/lib/Support/Twine.cpp +++ b/contrib/llvm/lib/Support/Twine.cpp @@ -161,7 +161,7 @@ void Twine::printRepr(raw_ostream &OS) const { OS << ")"; } -void Twine::dump() const { +LLVM_DUMP_METHOD void Twine::dump() const { print(dbgs()); } diff --git a/contrib/llvm/lib/Support/Unix/Memory.inc b/contrib/llvm/lib/Support/Unix/Memory.inc index d703191..f3463e5 100644 --- a/contrib/llvm/lib/Support/Unix/Memory.inc +++ b/contrib/llvm/lib/Support/Unix/Memory.inc @@ -73,7 +73,7 @@ int getPosixProtectionFlags(unsigned Flags) { return PROT_NONE; } -} // namespace +} // anonymous namespace namespace llvm { namespace sys { @@ -265,7 +265,7 @@ bool Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) { } bool Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { - if (M.Address == 0 || M.Size == 0) return false; + if (M.Address == nullptr || M.Size == 0) return false; Memory::InvalidateInstructionCache(M.Address, M.Size); #if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__)) kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, diff --git a/contrib/llvm/lib/Support/Unix/Path.inc b/contrib/llvm/lib/Support/Unix/Path.inc index d85c37a..84aafcb 100644 --- a/contrib/llvm/lib/Support/Unix/Path.inc +++ b/contrib/llvm/lib/Support/Unix/Path.inc @@ -25,6 +25,9 @@ #if HAVE_FCNTL_H #include <fcntl.h> #endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif #ifdef HAVE_SYS_MMAN_H #include <sys/mman.h> #endif @@ -47,6 +50,7 @@ #ifdef __APPLE__ #include <mach-o/dyld.h> +#include <sys/attr.h> #endif // Both stdio.h and cstdio are included via different pathes and @@ -60,6 +64,25 @@ # define PATH_MAX 4096 #endif +#include <sys/types.h> +#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) +#include <sys/statvfs.h> +#define STATVFS statvfs +#define STATVFS_F_FRSIZE(vfs) vfs.f_frsize +#else +#ifdef __OpenBSD__ +#include <sys/param.h> +#include <sys/mount.h> +#elif defined(__ANDROID__) +#include <sys/vfs.h> +#else +#include <sys/mount.h> +#endif +#define STATVFS statfs +#define STATVFS_F_FRSIZE(vfs) static_cast<uint64_t>(vfs.f_bsize) +#endif + + using namespace llvm; namespace llvm { @@ -70,7 +93,7 @@ namespace fs { defined(__linux__) || defined(__CYGWIN__) || defined(__DragonFly__) static int test_dir(char ret[PATH_MAX], const char *dir, const char *bin) -{ +{ struct stat sb; char fullpath[PATH_MAX]; @@ -174,6 +197,12 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) { return ""; } +TimeValue file_status::getLastAccessedTime() const { + TimeValue Ret; + Ret.fromEpochTime(fs_st_atime); + return Ret; +} + TimeValue file_status::getLastModificationTime() const { TimeValue Ret; Ret.fromEpochTime(fs_st_mtime); @@ -184,6 +213,18 @@ UniqueID file_status::getUniqueID() const { return UniqueID(fs_st_dev, fs_st_ino); } +ErrorOr<space_info> disk_space(const Twine &Path) { + struct STATVFS Vfs; + if (::STATVFS(Path.str().c_str(), &Vfs)) + return std::error_code(errno, std::generic_category()); + auto FrSize = STATVFS_F_FRSIZE(Vfs); + space_info SpaceInfo; + SpaceInfo.capacity = static_cast<uint64_t>(Vfs.f_blocks) * FrSize; + SpaceInfo.free = static_cast<uint64_t>(Vfs.f_bfree) * FrSize; + SpaceInfo.available = static_cast<uint64_t>(Vfs.f_bavail) * FrSize; + return SpaceInfo; +} + std::error_code current_path(SmallVectorImpl<char> &result) { result.clear(); @@ -373,8 +414,9 @@ static std::error_code fillStatus(int StatRet, const struct stat &Status, perms Perms = static_cast<perms>(Status.st_mode); Result = - file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_mtime, - Status.st_uid, Status.st_gid, Status.st_size); + file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_atime, + Status.st_mtime, Status.st_uid, Status.st_gid, + Status.st_size); return std::error_code(); } @@ -506,13 +548,47 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { return std::error_code(); } -std::error_code openFileForRead(const Twine &Name, int &ResultFD) { +#if !defined(F_GETPATH) +static bool hasProcSelfFD() { + // If we have a /proc filesystem mounted, we can quickly establish the + // real name of the file with readlink + static const bool Result = (::access("/proc/self/fd", R_OK) == 0); + return Result; +} +#endif + +std::error_code openFileForRead(const Twine &Name, int &ResultFD, + SmallVectorImpl<char> *RealPath) { SmallString<128> Storage; StringRef P = Name.toNullTerminatedStringRef(Storage); while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) { if (errno != EINTR) return std::error_code(errno, std::generic_category()); } + // Attempt to get the real name of the file, if the user asked + if(!RealPath) + return std::error_code(); + RealPath->clear(); +#if defined(F_GETPATH) + // When F_GETPATH is availble, it is the quickest way to get + // the real path name. + char Buffer[MAXPATHLEN]; + if (::fcntl(ResultFD, F_GETPATH, Buffer) != -1) + RealPath->append(Buffer, Buffer + strlen(Buffer)); +#else + char Buffer[PATH_MAX]; + if (hasProcSelfFD()) { + char ProcPath[64]; + snprintf(ProcPath, sizeof(ProcPath), "/proc/self/fd/%d", ResultFD); + ssize_t CharCount = ::readlink(ProcPath, Buffer, sizeof(Buffer)); + if (CharCount > 0) + RealPath->append(Buffer, Buffer + CharCount); + } else { + // Use ::realpath to get the real path name + if (::realpath(P.begin(), Buffer) != nullptr) + RealPath->append(Buffer, Buffer + strlen(Buffer)); + } +#endif return std::error_code(); } @@ -546,6 +622,53 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD, return std::error_code(); } +std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath) { + if (FD < 0) + return make_error_code(errc::bad_file_descriptor); + +#if defined(F_GETPATH) + // When F_GETPATH is availble, it is the quickest way to get + // the path from a file descriptor. + ResultPath.reserve(MAXPATHLEN); + if (::fcntl(FD, F_GETPATH, ResultPath.begin()) == -1) + return std::error_code(errno, std::generic_category()); + + ResultPath.set_size(strlen(ResultPath.begin())); +#else + // If we have a /proc filesystem mounted, we can quickly establish the + // real name of the file with readlink. Otherwise, we don't know how to + // get the filename from a file descriptor. Give up. + if (!fs::hasProcSelfFD()) + return make_error_code(errc::function_not_supported); + + ResultPath.reserve(PATH_MAX); + char ProcPath[64]; + snprintf(ProcPath, sizeof(ProcPath), "/proc/self/fd/%d", FD); + ssize_t CharCount = ::readlink(ProcPath, ResultPath.begin(), ResultPath.capacity()); + if (CharCount < 0) + return std::error_code(errno, std::generic_category()); + + // Was the filename truncated? + if (static_cast<size_t>(CharCount) == ResultPath.capacity()) { + // Use lstat to get the size of the filename + struct stat sb; + if (::lstat(ProcPath, &sb) < 0) + return std::error_code(errno, std::generic_category()); + + ResultPath.reserve(sb.st_size + 1); + CharCount = ::readlink(ProcPath, ResultPath.begin(), ResultPath.capacity()); + if (CharCount < 0) + return std::error_code(errno, std::generic_category()); + + // Test for race condition: did the link size change? + if (CharCount > sb.st_size) + return std::error_code(ENAMETOOLONG, std::generic_category()); + } + ResultPath.set_size(static_cast<size_t>(CharCount)); +#endif + return std::error_code(); +} + } // end namespace fs namespace path { @@ -586,12 +709,12 @@ static bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) { } static bool getUserCacheDir(SmallVectorImpl<char> &Result) { - // First try using XDS_CACHE_HOME env variable, + // First try using XDG_CACHE_HOME env variable, // as specified in XDG Base Directory Specification at // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html - if (const char *XdsCacheDir = std::getenv("XDS_CACHE_HOME")) { + if (const char *XdgCacheDir = std::getenv("XDG_CACHE_HOME")) { Result.clear(); - Result.append(XdsCacheDir, XdsCacheDir + strlen(XdsCacheDir)); + Result.append(XdgCacheDir, XdgCacheDir + strlen(XdgCacheDir)); return true; } diff --git a/contrib/llvm/lib/Support/Unix/Process.inc b/contrib/llvm/lib/Support/Unix/Process.inc index 27083ee..d81836b 100644 --- a/contrib/llvm/lib/Support/Unix/Process.inc +++ b/contrib/llvm/lib/Support/Unix/Process.inc @@ -169,6 +169,8 @@ void Process::PreventCoreFiles() { signal(SIGSEGV, _exit); signal(SIGBUS, _exit); #endif + + coreFilesPrevented = true; } Optional<std::string> Process::GetEnv(StringRef Name) { @@ -456,7 +458,7 @@ unsigned llvm::sys::Process::GetRandomNumber() { #if defined(HAVE_DECL_ARC4RANDOM) && HAVE_DECL_ARC4RANDOM return arc4random(); #else - static int x = (::srand(GetRandomNumberSeed()), 0); + static int x = (static_cast<void>(::srand(GetRandomNumberSeed())), 0); (void)x; return ::rand(); #endif diff --git a/contrib/llvm/lib/Support/Unix/Signals.inc b/contrib/llvm/lib/Support/Unix/Signals.inc index 061cdb3..55fd76d 100644 --- a/contrib/llvm/lib/Support/Unix/Signals.inc +++ b/contrib/llvm/lib/Support/Unix/Signals.inc @@ -45,6 +45,17 @@ #if HAVE_LINK_H #include <link.h> #endif +#if HAVE_UNWIND_BACKTRACE +// FIXME: We should be able to use <unwind.h> for any target that has an +// _Unwind_Backtrace function, but on FreeBSD the configure test passes +// despite the function not existing, and on Android, <unwind.h> conflicts +// with <link.h>. +#ifdef __GLIBC__ +#include <unwind.h> +#else +#undef HAVE_UNWIND_BACKTRACE +#endif +#endif using namespace llvm; @@ -57,6 +68,8 @@ static void (*InterruptFunction)() = nullptr; static ManagedStatic<std::vector<std::string>> FilesToRemove; +static StringRef Argv0; + // IntSigs - Signals that represent requested termination. There's no bug // or failure, or if there is, it's not our direct responsibility. For whatever // reason, our continued execution is no longer desirable. @@ -96,7 +109,7 @@ static void RegisterHandler(int Signal) { struct sigaction NewHandler; NewHandler.sa_handler = SignalHandler; - NewHandler.sa_flags = SA_NODEFER|SA_RESETHAND; + NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK; sigemptyset(&NewHandler.sa_mask); // Install the new handler, save the old one in RegisteredSignalInfo. @@ -106,6 +119,35 @@ static void RegisterHandler(int Signal) { ++NumRegisteredSignals; } +#if defined(HAVE_SIGALTSTACK) +// Hold onto the old alternate signal stack so that it's not reported as a leak. +// We don't make any attempt to remove our alt signal stack if we remove our +// signal handlers; that can't be done reliably if someone else is also trying +// to do the same thing. +static stack_t OldAltStack; + +static void CreateSigAltStack() { + const size_t AltStackSize = MINSIGSTKSZ + 8192; + + // If we're executing on the alternate stack, or we already have an alternate + // signal stack that we're happy with, there's nothing for us to do. Don't + // reduce the size, some other part of the process might need a larger stack + // than we do. + if (sigaltstack(nullptr, &OldAltStack) != 0 || + OldAltStack.ss_flags & SS_ONSTACK || + (OldAltStack.ss_sp && OldAltStack.ss_size >= AltStackSize)) + return; + + stack_t AltStack = {}; + AltStack.ss_sp = reinterpret_cast<char *>(malloc(AltStackSize)); + AltStack.ss_size = AltStackSize; + if (sigaltstack(&AltStack, &OldAltStack) != 0) + free(AltStack.ss_sp); +} +#else +static void CreateSigAltStack() {} +#endif + static void RegisterHandlers() { // We need to dereference the signals mutex during handler registration so // that we force its construction. This is to prevent the first use being @@ -116,6 +158,10 @@ static void RegisterHandlers() { // If the handlers are already registered, we're done. if (NumRegisteredSignals != 0) return; + // Create an alternate stack for signal handling. This is necessary for us to + // be able to reliably handle signals due to stack overflow. + CreateSigAltStack(); + for (auto S : IntSigs) RegisterHandler(S); for (auto S : KillSigs) RegisterHandler(S); } @@ -309,20 +355,64 @@ static bool findModulesAndOffsets(void **StackTrace, int Depth, } #endif // defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) && ... +#if defined(ENABLE_BACKTRACES) && defined(HAVE_UNWIND_BACKTRACE) +static int unwindBacktrace(void **StackTrace, int MaxEntries) { + if (MaxEntries < 0) + return 0; + + // Skip the first frame ('unwindBacktrace' itself). + int Entries = -1; + + auto HandleFrame = [&](_Unwind_Context *Context) -> _Unwind_Reason_Code { + // Apparently we need to detect reaching the end of the stack ourselves. + void *IP = (void *)_Unwind_GetIP(Context); + if (!IP) + return _URC_END_OF_STACK; + + assert(Entries < MaxEntries && "recursively called after END_OF_STACK?"); + if (Entries >= 0) + StackTrace[Entries] = IP; + + if (++Entries == MaxEntries) + return _URC_END_OF_STACK; + return _URC_NO_REASON; + }; + + _Unwind_Backtrace( + [](_Unwind_Context *Context, void *Handler) { + return (*static_cast<decltype(HandleFrame) *>(Handler))(Context); + }, + static_cast<void *>(&HandleFrame)); + return std::max(Entries, 0); +} +#endif + // PrintStackTrace - In the case of a program crash or fault, print out a stack // trace so that the user has an indication of why and where we died. // // On glibc systems we have the 'backtrace' function, which works nicely, but // doesn't demangle symbols. void llvm::sys::PrintStackTrace(raw_ostream &OS) { -#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) - static void* StackTrace[256]; +#if defined(ENABLE_BACKTRACES) + static void *StackTrace[256]; + int depth = 0; +#if defined(HAVE_BACKTRACE) // Use backtrace() to output a backtrace on Linux systems with glibc. - int depth = backtrace(StackTrace, + if (!depth) + depth = backtrace(StackTrace, static_cast<int>(array_lengthof(StackTrace))); +#endif +#if defined(HAVE_UNWIND_BACKTRACE) + // Try _Unwind_Backtrace() if backtrace() failed. + if (!depth) + depth = unwindBacktrace(StackTrace, static_cast<int>(array_lengthof(StackTrace))); - if (printSymbolizedStackTrace(StackTrace, depth, OS)) +#endif + if (!depth) + return; + + if (printSymbolizedStackTrace(Argv0, StackTrace, depth, OS)) return; -#if HAVE_DLFCN_H && __GNUG__ +#if HAVE_DLFCN_H && __GNUG__ && !defined(__CYGWIN__) int width = 0; for (int i = 0; i < depth; ++i) { Dl_info dlinfo; @@ -369,7 +459,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) { } OS << '\n'; } -#else +#elif defined(HAVE_BACKTRACE) backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); #endif #endif @@ -383,7 +473,10 @@ void llvm::sys::DisableSystemDialogsOnCrash() {} /// PrintStackTraceOnErrorSignal - When an error signal (such as SIGABRT or /// SIGSEGV) is delivered to the process, print a stack trace and then exit. -void llvm::sys::PrintStackTraceOnErrorSignal(bool DisableCrashReporting) { +void llvm::sys::PrintStackTraceOnErrorSignal(StringRef Argv0, + bool DisableCrashReporting) { + ::Argv0 = Argv0; + AddSignalHandler(PrintStackTraceSignalHandler, nullptr); #if defined(__APPLE__) && defined(ENABLE_CRASH_OVERRIDES) @@ -402,42 +495,3 @@ void llvm::sys::PrintStackTraceOnErrorSignal(bool DisableCrashReporting) { } #endif } - - -/***/ - -// On Darwin, raise sends a signal to the main thread instead of the current -// thread. This has the unfortunate effect that assert() and abort() will end up -// bypassing our crash recovery attempts. We work around this for anything in -// the same linkage unit by just defining our own versions of the assert handler -// and abort. - -#if defined(__APPLE__) && defined(ENABLE_CRASH_OVERRIDES) - -#include <signal.h> -#include <pthread.h> - -int raise(int sig) { - return pthread_kill(pthread_self(), sig); -} - -void __assert_rtn(const char *func, - const char *file, - int line, - const char *expr) { - if (func) - fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", - expr, func, file, line); - else - fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n", - expr, file, line); - abort(); -} - -void abort() { - raise(SIGABRT); - usleep(1000); - __builtin_trap(); -} - -#endif diff --git a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc index 17418b0..0506894 100644 --- a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc +++ b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc @@ -45,7 +45,7 @@ static bool loadDebugHelp(void) { } static BOOL CALLBACK -ELM_Callback(WIN32_ELMCB_PCSTR ModuleName, DWORD64 ModuleBase, +ELM_Callback(PCSTR ModuleName, DWORD64 ModuleBase, ULONG ModuleSize, PVOID UserContext) { OpenedHandles->insert((HMODULE)ModuleBase); return TRUE; diff --git a/contrib/llvm/lib/Support/Windows/Path.inc b/contrib/llvm/lib/Support/Windows/Path.inc index 5ef77b1..fab6aec 100644 --- a/contrib/llvm/lib/Support/Windows/Path.inc +++ b/contrib/llvm/lib/Support/Windows/Path.inc @@ -151,6 +151,29 @@ UniqueID file_status::getUniqueID() const { return UniqueID(VolumeSerialNumber, FileID); } +ErrorOr<space_info> disk_space(const Twine &Path) { + ULARGE_INTEGER Avail, Total, Free; + if (!::GetDiskFreeSpaceExA(Path.str().c_str(), &Avail, &Total, &Free)) + return mapWindowsError(::GetLastError()); + space_info SpaceInfo; + SpaceInfo.capacity = + (static_cast<uint64_t>(Total.HighPart) << 32) + Total.LowPart; + SpaceInfo.free = (static_cast<uint64_t>(Free.HighPart) << 32) + Free.LowPart; + SpaceInfo.available = + (static_cast<uint64_t>(Avail.HighPart) << 32) + Avail.LowPart; + return SpaceInfo; +} + +TimeValue file_status::getLastAccessedTime() const { + ULARGE_INTEGER UI; + UI.LowPart = LastAccessedTimeLow; + UI.HighPart = LastAccessedTimeHigh; + + TimeValue Ret; + Ret.fromWin32Time(UI.QuadPart); + return Ret; +} + TimeValue file_status::getLastModificationTime() const { ULARGE_INTEGER UI; UI.LowPart = LastWriteTimeLow; @@ -255,24 +278,43 @@ std::error_code rename(const Twine &from, const Twine &to) { std::error_code ec = std::error_code(); - // Retry while we see ERROR_ACCESS_DENIED. + // Retry while we see recoverable errors. // System scanners (eg. indexer) might open the source file when it is written // and closed. - for (int i = 0; i < 2000; i++) { - // Try ReplaceFile first, as it is able to associate a new data stream with - // the destination even if the destination file is currently open. - if (::ReplaceFileW(wide_to.begin(), wide_from.begin(), NULL, 0, NULL, NULL)) - return std::error_code(); + bool TryReplace = true; - // We get ERROR_FILE_NOT_FOUND if the destination file is missing. - // MoveFileEx can handle this case. - DWORD ReplaceError = ::GetLastError(); - ec = mapWindowsError(ReplaceError); - if (ReplaceError != ERROR_ACCESS_DENIED && - ReplaceError != ERROR_FILE_NOT_FOUND && - ReplaceError != ERROR_SHARING_VIOLATION) - break; + for (int i = 0; i < 2000; i++) { + if (i > 0) + ::Sleep(1); + + if (TryReplace) { + // Try ReplaceFile first, as it is able to associate a new data stream + // with the destination even if the destination file is currently open. + if (::ReplaceFileW(wide_to.data(), wide_from.data(), NULL, 0, NULL, NULL)) + return std::error_code(); + + DWORD ReplaceError = ::GetLastError(); + ec = mapWindowsError(ReplaceError); + + // If ReplaceFileW returned ERROR_UNABLE_TO_MOVE_REPLACEMENT or + // ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, retry but only use MoveFileExW(). + if (ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT || + ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2) { + TryReplace = false; + continue; + } + // If ReplaceFileW returned ERROR_UNABLE_TO_REMOVE_REPLACED, retry + // using ReplaceFileW(). + if (ReplaceError == ERROR_UNABLE_TO_REMOVE_REPLACED) + continue; + // We get ERROR_FILE_NOT_FOUND if the destination file is missing. + // MoveFileEx can handle this case. + if (ReplaceError != ERROR_ACCESS_DENIED && + ReplaceError != ERROR_FILE_NOT_FOUND && + ReplaceError != ERROR_SHARING_VIOLATION) + break; + } if (::MoveFileExW(wide_from.begin(), wide_to.begin(), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) @@ -281,8 +323,6 @@ std::error_code rename(const Twine &from, const Twine &to) { DWORD MoveError = ::GetLastError(); ec = mapWindowsError(MoveError); if (MoveError != ERROR_ACCESS_DENIED) break; - - ::Sleep(1); } return ec; @@ -327,13 +367,15 @@ bool can_execute(const Twine &Path) { bool equivalent(file_status A, file_status B) { assert(status_known(A) && status_known(B)); - return A.FileIndexHigh == B.FileIndexHigh && - A.FileIndexLow == B.FileIndexLow && - A.FileSizeHigh == B.FileSizeHigh && - A.FileSizeLow == B.FileSizeLow && - A.LastWriteTimeHigh == B.LastWriteTimeHigh && - A.LastWriteTimeLow == B.LastWriteTimeLow && - A.VolumeSerialNumber == B.VolumeSerialNumber; + return A.FileIndexHigh == B.FileIndexHigh && + A.FileIndexLow == B.FileIndexLow && + A.FileSizeHigh == B.FileSizeHigh && + A.FileSizeLow == B.FileSizeLow && + A.LastAccessedTimeHigh == B.LastAccessedTimeHigh && + A.LastAccessedTimeLow == B.LastAccessedTimeLow && + A.LastWriteTimeHigh == B.LastWriteTimeHigh && + A.LastWriteTimeLow == B.LastWriteTimeLow && + A.VolumeSerialNumber == B.VolumeSerialNumber; } std::error_code equivalent(const Twine &A, const Twine &B, bool &result) { @@ -361,7 +403,7 @@ static bool isReservedName(StringRef path) { if (path.startswith("\\\\.\\")) return true; - // Then compare against the list of ancient reserved names + // Then compare against the list of ancient reserved names. for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) { if (path.equals_lower(sReservedNames[i])) return true; @@ -404,7 +446,9 @@ static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { ? file_type::directory_file : file_type::regular_file; Result = - file_status(Type, Info.ftLastWriteTime.dwHighDateTime, + file_status(Type, Info.ftLastAccessTime.dwHighDateTime, + Info.ftLastAccessTime.dwLowDateTime, + Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime, Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow); @@ -663,7 +707,8 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { return std::error_code(); } -std::error_code openFileForRead(const Twine &Name, int &ResultFD) { +std::error_code openFileForRead(const Twine &Name, int &ResultFD, + SmallVectorImpl<char> *RealPath) { SmallVector<wchar_t, 128> PathUTF16; if (std::error_code EC = widenPath(Name, PathUTF16)) @@ -692,6 +737,22 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD) { return mapWindowsError(ERROR_INVALID_HANDLE); } + // Fetch the real name of the file, if the user asked + if (RealPath) { + RealPath->clear(); + wchar_t RealPathUTF16[MAX_PATH]; + DWORD CountChars = + ::GetFinalPathNameByHandleW(H, RealPathUTF16, MAX_PATH, + FILE_NAME_NORMALIZED); + if (CountChars > 0 && CountChars < MAX_PATH) { + // Convert the result from UTF-16 to UTF-8. + SmallString<MAX_PATH> RealPathUTF8; + if (!UTF16ToUTF8(RealPathUTF16, CountChars, RealPathUTF8)) + RealPath->append(RealPathUTF8.data(), + RealPathUTF8.data() + strlen(RealPathUTF8.data())); + } + } + ResultFD = FD; return std::error_code(); } @@ -752,6 +813,42 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD, ResultFD = FD; return std::error_code(); } + +std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath) { + HANDLE FileHandle = reinterpret_cast<HANDLE>(::_get_osfhandle(FD)); + if (FileHandle == INVALID_HANDLE_VALUE) + return make_error_code(errc::bad_file_descriptor); + + DWORD CharCount; + SmallVector<wchar_t, 1024> TempPath; + do { + CharCount = ::GetFinalPathNameByHandleW(FileHandle, TempPath.begin(), + TempPath.capacity(), + FILE_NAME_NORMALIZED); + if (CharCount < TempPath.capacity()) + break; + + // Reserve sufficient space for the path as well as the null character. Even + // though the API does not document that it is required, if we reserve just + // CharCount space, the function call will not store the resulting path and + // still report success. + TempPath.reserve(CharCount + 1); + } while (true); + + if (CharCount == 0) + return mapWindowsError(::GetLastError()); + + TempPath.set_size(CharCount); + + // On earlier Windows releases, the character count includes the terminating + // null. + if (TempPath.back() == L'\0') { + --CharCount; + TempPath.pop_back(); + } + + return windows::UTF16ToUTF8(TempPath.data(), CharCount, ResultPath); +} } // end namespace fs namespace path { @@ -886,6 +983,7 @@ std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, llvm::SmallVectorImpl<char> &utf8) { return UTF16ToCodePage(CP_ACP, utf16, utf16_len, utf8); } + } // end namespace windows } // end namespace sys } // end namespace llvm diff --git a/contrib/llvm/lib/Support/Windows/Process.inc b/contrib/llvm/lib/Support/Windows/Process.inc index dae35a8..b012991 100644 --- a/contrib/llvm/lib/Support/Windows/Process.inc +++ b/contrib/llvm/lib/Support/Windows/Process.inc @@ -123,6 +123,8 @@ void Process::PreventCoreFiles() { SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); + + coreFilesPrevented = true; } /// Returns the environment variable \arg Name's value as a string encoded in @@ -199,6 +201,9 @@ WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args, const int DirSize = Dir.size(); // Search for matching files. + // FIXME: This assumes the wildcard is only in the file name and not in the + // directory portion of the file path. For example, it doesn't handle + // "*\foo.c" nor "s?c\bar.cpp". WIN32_FIND_DATAW FileData; HANDLE FindHandle = FindFirstFileW(Arg, &FileData); if (FindHandle == INVALID_HANDLE_VALUE) { @@ -213,7 +218,7 @@ WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args, if (ec) break; - // Push the filename onto Dir, and remove it afterwards. + // Append FileName to Dir, and remove it afterwards. llvm::sys::path::append(Dir, StringRef(FileName.data(), FileName.size())); AllocateAndPush(Dir, Args, Allocator); Dir.resize(DirSize); @@ -223,6 +228,23 @@ WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args, return ec; } +static std::error_code +ExpandShortFileName(const wchar_t *Arg, SmallVectorImpl<const char *> &Args, + SpecificBumpPtrAllocator<char> &Allocator) { + SmallVector<wchar_t, MAX_PATH> LongPath; + DWORD Length = GetLongPathNameW(Arg, LongPath.data(), LongPath.capacity()); + if (Length == 0) + return mapWindowsError(GetLastError()); + if (Length > LongPath.capacity()) { + // We're not going to try to deal with paths longer than MAX_PATH, so we'll + // treat this as an error. GetLastError() returns ERROR_SUCCESS, which + // isn't useful, so we'll hardcode an appropriate error value. + return mapWindowsError(ERROR_INSUFFICIENT_BUFFER); + } + LongPath.set_size(Length); + return ConvertAndPushArg(LongPath.data(), Args, Allocator); +} + std::error_code Process::GetArgumentVector(SmallVectorImpl<const char *> &Args, ArrayRef<const char *>, @@ -236,7 +258,19 @@ Process::GetArgumentVector(SmallVectorImpl<const char *> &Args, Args.reserve(ArgCount); std::error_code ec; - for (int i = 0; i < ArgCount; ++i) { + // The first argument may contain just the name of the executable (e.g., + // "clang") rather than the full path, so swap it with the full path. + wchar_t ModuleName[MAX_PATH]; + int Length = ::GetModuleFileNameW(NULL, ModuleName, MAX_PATH); + if (0 < Length && Length < MAX_PATH) + UnicodeCommandLine[0] = ModuleName; + + // If the first argument is a shortened (8.3) name (which is possible even + // if we got the module name), the driver will have trouble distinguishing it + // (e.g., clang.exe v. clang++.exe), so expand it now. + ec = ExpandShortFileName(UnicodeCommandLine[0], Args, ArgAllocator); + + for (int i = 1; i < ArgCount && !ec; ++i) { ec = WildcardExpand(UnicodeCommandLine[i], Args, ArgAllocator); if (ec) break; diff --git a/contrib/llvm/lib/Support/Windows/Signals.inc b/contrib/llvm/lib/Support/Windows/Signals.inc index f40ca72..1e2fa42 100644 --- a/contrib/llvm/lib/Support/Windows/Signals.inc +++ b/contrib/llvm/lib/Support/Windows/Signals.inc @@ -11,7 +11,11 @@ // //===----------------------------------------------------------------------===// #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/WindowsError.h" #include <algorithm> +#include <io.h> #include <signal.h> #include <stdio.h> @@ -117,6 +121,12 @@ typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, HANDLE hThread, LPADDRESS64 lpaddr); +typedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, + PMINIDUMP_EXCEPTION_INFORMATION, + PMINIDUMP_USER_STREAM_INFORMATION, + PMINIDUMP_CALLBACK_INFORMATION); +static fpMiniDumpWriteDump fMiniDumpWriteDump; + typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, @@ -154,6 +164,8 @@ static fpEnumerateLoadedModules fEnumerateLoadedModules; static bool load64BitDebugHelp(void) { HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); if (hLib) { + fMiniDumpWriteDump = (fpMiniDumpWriteDump) + ::GetProcAddress(hLib, "MiniDumpWriteDump"); fStackWalk64 = (fpStackWalk64) ::GetProcAddress(hLib, "StackWalk64"); fSymGetModuleBase64 = (fpSymGetModuleBase64) @@ -171,7 +183,7 @@ static bool load64BitDebugHelp(void) { fEnumerateLoadedModules = (fpEnumerateLoadedModules) ::GetProcAddress(hLib, "EnumerateLoadedModules64"); } - return fStackWalk64 && fSymInitialize && fSymSetOptions; + return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump; } using namespace llvm; @@ -194,6 +206,8 @@ static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; static CRITICAL_SECTION CriticalSection; static bool CriticalSectionInitialized = false; +static StringRef Argv0; + enum { #if defined(_M_X64) NativeMachineType = IMAGE_FILE_MACHINE_AMD64 @@ -228,7 +242,7 @@ static bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS, break; } - return printSymbolizedStackTrace(&StackTrace[0], Depth, OS); + return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS); } namespace { @@ -241,7 +255,7 @@ struct FindModuleData { }; } -static BOOL CALLBACK findModuleCallback(WIN32_ELMCB_PCSTR ModuleName, +static BOOL CALLBACK findModuleCallback(PCSTR ModuleName, DWORD64 ModuleBase, ULONG ModuleSize, void *VoidData) { FindModuleData *Data = (FindModuleData*)VoidData; @@ -484,7 +498,13 @@ void sys::DisableSystemDialogsOnCrash() { /// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or /// SIGSEGV) is delivered to the process, print a stack trace and then exit. -void sys::PrintStackTraceOnErrorSignal(bool DisableCrashReporting) { +void sys::PrintStackTraceOnErrorSignal(StringRef Argv0, + bool DisableCrashReporting) { + ::Argv0 = Argv0; + + if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) + Process::PreventCoreFiles(); + DisableSystemDialogsOnCrash(); RegisterHandler(); LeaveCriticalSection(&CriticalSection); @@ -563,9 +583,209 @@ void llvm::sys::RunInterruptHandlers() { Cleanup(); } +/// \brief Find the Windows Registry Key for a given location. +/// +/// \returns a valid HKEY if the location exists, else NULL. +static HKEY FindWERKey(const llvm::Twine &RegistryLocation) { + HKEY Key; + if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE, + RegistryLocation.str().c_str(), 0, + KEY_QUERY_VALUE | KEY_READ, &Key)) + return NULL; + + return Key; +} + +/// \brief Populate ResultDirectory with the value for "DumpFolder" for a given +/// Windows Registry key. +/// +/// \returns true if a valid value for DumpFolder exists, false otherwise. +static bool GetDumpFolder(HKEY Key, + llvm::SmallVectorImpl<char> &ResultDirectory) { + using llvm::sys::windows::UTF16ToUTF8; + + if (!Key) + return false; + + DWORD BufferLengthBytes = 0; + + if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, + NULL, NULL, &BufferLengthBytes)) + return false; + + SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes); + + if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, + NULL, Buffer.data(), &BufferLengthBytes)) + return false; + + DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0); + + if (!ExpandBufferSize) + return false; + + SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize); + + if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(), + ExpandBuffer.data(), + ExpandBufferSize)) + return false; + + if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory)) + return false; + + return true; +} + +/// \brief Populate ResultType with a valid MINIDUMP_TYPE based on the value of +/// "DumpType" for a given Windows Registry key. +/// +/// According to +/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx +/// valid values for DumpType are: +/// * 0: Custom dump +/// * 1: Mini dump +/// * 2: Full dump +/// If "Custom dump" is specified then the "CustomDumpFlags" field is read +/// containing a bitwise combination of MINIDUMP_TYPE values. +/// +/// \returns true if a valid value for ResultType can be set, false otherwise. +static bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) { + if (!Key) + return false; + + DWORD DumpType; + DWORD TypeSize = sizeof(DumpType); + if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD, + NULL, &DumpType, + &TypeSize)) + return false; + + switch (DumpType) { + case 0: { + DWORD Flags = 0; + if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags", + RRF_RT_REG_DWORD, NULL, &Flags, + &TypeSize)) + return false; + + ResultType = static_cast<MINIDUMP_TYPE>(Flags); + break; + } + case 1: + ResultType = MiniDumpNormal; + break; + case 2: + ResultType = MiniDumpWithFullMemory; + break; + default: + return false; + } + return true; +} + +/// \brief Write a Windows dump file containing process information that can be +/// used for post-mortem debugging. +/// +/// \returns zero error code if a mini dump created, actual error code +/// otherwise. +static std::error_code WINAPI +WriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) { + using namespace llvm; + using namespace llvm::sys; + + std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr); + StringRef ProgramName; + + if (MainExecutableName.empty()) { + // If we can't get the executable filename, + // things are in worse shape than we realize + // and we should just bail out. + return mapWindowsError(::GetLastError()); + } + + ProgramName = path::filename(MainExecutableName.c_str()); + + // The Windows Registry location as specified at + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx + // "Collecting User-Mode Dumps" that may optionally be set to collect crash + // dumps in a specified location. + StringRef LocalDumpsRegistryLocation = + "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps"; + + // The key pointing to the Registry location that may contain global crash + // dump settings. This will be NULL if the location can not be found. + ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation)); + + // The key pointing to the Registry location that may contain + // application-specific crash dump settings. This will be NULL if the + // location can not be found. + ScopedRegHandle AppSpecificKey( + FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName)); + + // Look to see if a dump type is specified in the registry; first with the + // app-specific key and failing that with the global key. If none are found + // default to a normal dump (GetDumpType will return false either if the key + // is NULL or if there is no valid DumpType value at its location). + MINIDUMP_TYPE DumpType; + if (!GetDumpType(AppSpecificKey, DumpType)) + if (!GetDumpType(DefaultLocalDumpsKey, DumpType)) + DumpType = MiniDumpNormal; + + // Look to see if a dump location is specified in the registry; first with the + // app-specific key and failing that with the global key. If none are found + // we'll just create the dump file in the default temporary file location + // (GetDumpFolder will return false either if the key is NULL or if there is + // no valid DumpFolder value at its location). + bool ExplicitDumpDirectorySet = true; + SmallString<MAX_PATH> DumpDirectory; + if (!GetDumpFolder(AppSpecificKey, DumpDirectory)) + if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory)) + ExplicitDumpDirectorySet = false; + + int FD; + SmallString<MAX_PATH> DumpPath; + + if (ExplicitDumpDirectorySet) { + if (std::error_code EC = fs::create_directories(DumpDirectory)) + return EC; + if (std::error_code EC = fs::createUniqueFile( + Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD, + DumpPath)) + return EC; + } else if (std::error_code EC = + fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath)) + return EC; + + // Our support functions return a file descriptor but Windows wants a handle. + ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD))); + + if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), + FileHandle, DumpType, ExceptionInfo, NULL, NULL)) + return mapWindowsError(::GetLastError()); + + llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n"; + return std::error_code(); +} + static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { Cleanup(); + // We'll automatically write a Minidump file here to help diagnose + // the nasty sorts of crashes that aren't 100% reproducible from a set of + // inputs (or in the event that the user is unable or unwilling to provide a + // reproducible case). + if (!llvm::Process::AreCoreFilesPrevented()) { + MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo; + ExceptionInfo.ThreadId = ::GetCurrentThreadId(); + ExceptionInfo.ExceptionPointers = ep; + ExceptionInfo.ClientPointers = FALSE; + + if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo)) + llvm::errs() << "Could not write crash dump file: " << EC.message() + << "\n"; + } + // Initialize the STACKFRAME structure. STACKFRAME64 StackFrame = {}; diff --git a/contrib/llvm/lib/Support/Windows/WindowsSupport.h b/contrib/llvm/lib/Support/Windows/WindowsSupport.h index 60490f2..18ecdf4e 100644 --- a/contrib/llvm/lib/Support/Windows/WindowsSupport.h +++ b/contrib/llvm/lib/Support/Windows/WindowsSupport.h @@ -45,7 +45,6 @@ #include <wincrypt.h> #include <cassert> #include <string> -#include <vector> /// Determines if the program is running on Windows 8 or newer. This /// reimplements one of the helpers in the Windows 8.1 SDK, which are intended @@ -69,15 +68,15 @@ inline bool RunningWindows8OrGreater() { Mask) != FALSE; } -inline bool MakeErrMsg(std::string* ErrMsg, const std::string& prefix) { +inline bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix) { if (!ErrMsg) return true; char *buffer = NULL; DWORD LastError = GetLastError(); - DWORD R = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_MAX_WIDTH_MASK, - NULL, LastError, 0, (LPSTR)&buffer, 1, NULL); + DWORD R = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, LastError, 0, (LPSTR)&buffer, 1, NULL); if (R) *ErrMsg = prefix + ": " + buffer; else @@ -168,6 +167,22 @@ struct CryptContextTraits : CommonHandleTraits { } }; +struct RegTraits : CommonHandleTraits { + typedef HKEY handle_type; + + static handle_type GetInvalid() { + return NULL; + } + + static void Close(handle_type h) { + ::RegCloseKey(h); + } + + static bool IsValid(handle_type h) { + return h != GetInvalid(); + } +}; + struct FindHandleTraits : CommonHandleTraits { static void Close(handle_type h) { ::FindClose(h); @@ -179,6 +194,7 @@ struct FileHandleTraits : CommonHandleTraits {}; typedef ScopedHandle<CommonHandleTraits> ScopedCommonHandle; typedef ScopedHandle<FileHandleTraits> ScopedFileHandle; typedef ScopedHandle<CryptContextTraits> ScopedCryptContext; +typedef ScopedHandle<RegTraits> ScopedRegHandle; typedef ScopedHandle<FindHandleTraits> ScopedFindHandle; typedef ScopedHandle<JobHandleTraits> ScopedJobHandle; diff --git a/contrib/llvm/lib/Support/YAMLParser.cpp b/contrib/llvm/lib/Support/YAMLParser.cpp index c4384ca..620841c 100644 --- a/contrib/llvm/lib/Support/YAMLParser.cpp +++ b/contrib/llvm/lib/Support/YAMLParser.cpp @@ -1911,7 +1911,7 @@ StringRef ScalarNode::getValue(SmallVectorImpl<char> &Storage) const { return UnquotedValue; } // Plain or block. - return Value.rtrim(" "); + return Value.rtrim(' '); } StringRef ScalarNode::unescapeDoubleQuoted( StringRef UnquotedValue diff --git a/contrib/llvm/lib/Support/YAMLTraits.cpp b/contrib/llvm/lib/Support/YAMLTraits.cpp index 2aa6e9b..75fac20 100644 --- a/contrib/llvm/lib/Support/YAMLTraits.cpp +++ b/contrib/llvm/lib/Support/YAMLTraits.cpp @@ -423,8 +423,29 @@ void Output::beginMapping() { bool Output::mapTag(StringRef Tag, bool Use) { if (Use) { - this->output(" "); + // If this tag is being written inside a sequence we should write the start + // of the sequence before writing the tag, otherwise the tag won't be + // attached to the element in the sequence, but rather the sequence itself. + bool SequenceElement = + StateStack.size() > 1 && (StateStack[StateStack.size() - 2] == inSeq || + StateStack[StateStack.size() - 2] == inFlowSeq); + if (SequenceElement && StateStack.back() == inMapFirstKey) { + this->newLineCheck(); + } else { + this->output(" "); + } this->output(Tag); + if (SequenceElement) { + // If we're writing the tag during the first element of a map, the tag + // takes the place of the first element in the sequence. + if (StateStack.back() == inMapFirstKey) { + StateStack.pop_back(); + StateStack.push_back(inMapOtherKey); + } + // Tags inside maps in sequences should act as keys in the map from a + // formatting perspective, so we always want a newline in a sequence. + NeedsNewLine = true; + } } return Use; } diff --git a/contrib/llvm/lib/Support/raw_ostream.cpp b/contrib/llvm/lib/Support/raw_ostream.cpp index 15813fd..275fe1d 100644 --- a/contrib/llvm/lib/Support/raw_ostream.cpp +++ b/contrib/llvm/lib/Support/raw_ostream.cpp @@ -141,7 +141,7 @@ raw_ostream &raw_ostream::operator<<(unsigned long long N) { return this->operator<<(static_cast<unsigned long>(N)); char NumberBuffer[20]; - char *EndPtr = NumberBuffer+sizeof(NumberBuffer); + char *EndPtr = std::end(NumberBuffer); char *CurPtr = EndPtr; while (N) { @@ -166,13 +166,13 @@ raw_ostream &raw_ostream::write_hex(unsigned long long N) { if (N == 0) return *this << '0'; - char NumberBuffer[20]; - char *EndPtr = NumberBuffer+sizeof(NumberBuffer); + char NumberBuffer[16]; + char *EndPtr = std::end(NumberBuffer); char *CurPtr = EndPtr; while (N) { - uintptr_t x = N % 16; - *--CurPtr = (x < 10 ? '0' + x : 'a' + x - 10); + unsigned char x = static_cast<unsigned char>(N) % 16; + *--CurPtr = hexdigit(x, /*LowerCase*/true); N /= 16; } @@ -181,9 +181,7 @@ raw_ostream &raw_ostream::write_hex(unsigned long long N) { raw_ostream &raw_ostream::write_escaped(StringRef Str, bool UseHexEscapes) { - for (unsigned i = 0, e = Str.size(); i != e; ++i) { - unsigned char c = Str[i]; - + for (unsigned char c : Str) { switch (c) { case '\\': *this << '\\' << '\\'; @@ -232,7 +230,7 @@ raw_ostream &raw_ostream::operator<<(double N) { // On MSVCRT and compatible, output of %e is incompatible to Posix // by default. Number of exponent digits should be at least 2. "%+03d" // FIXME: Implement our formatter to here or Support/Format.h! -#if __cplusplus >= 201103L && defined(__MINGW32__) +#if defined(__MINGW32__) // FIXME: It should be generic to C++11. if (N == 0.0 && std::signbit(N)) return *this << "-0.000000e+00"; @@ -422,11 +420,10 @@ raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) { NumberBuffer[1] = '0'; char *EndPtr = NumberBuffer+Width; char *CurPtr = EndPtr; - const char A = FN.Upper ? 'A' : 'a'; unsigned long long N = FN.HexValue; while (N) { - uintptr_t x = N % 16; - *--CurPtr = (x < 10 ? '0' + x : A + x - 10); + unsigned char x = static_cast<unsigned char>(N) % 16; + *--CurPtr = hexdigit(x, !FN.Upper); N /= 16; } @@ -626,6 +623,7 @@ void raw_fd_ostream::close() { } uint64_t raw_fd_ostream::seek(uint64_t off) { + assert(SupportsSeeking && "Stream does not support seeking!"); flush(); pos = ::lseek(FD, off, SEEK_SET); if (pos == (uint64_t)-1) @@ -718,9 +716,10 @@ bool raw_fd_ostream::has_colors() const { /// outs() - This returns a reference to a raw_ostream for standard output. /// Use it like: outs() << "foo" << "bar"; raw_ostream &llvm::outs() { - // Set buffer settings to model stdout behavior. - // Delete the file descriptor when the program exits, forcing error - // detection. If you don't want this behavior, don't use outs(). + // Set buffer settings to model stdout behavior. Delete the file descriptor + // when the program exits, forcing error detection. This means that if you + // ever call outs(), you can't open another raw_fd_ostream on stdout, as we'll + // close stdout twice and print an error the second time. std::error_code EC; static raw_fd_ostream S("-", EC, sys::fs::F_None); assert(!EC); |