diff options
Diffstat (limited to 'contrib/llvm/lib/Support')
86 files changed, 3850 insertions, 1365 deletions
diff --git a/contrib/llvm/lib/Support/AMDGPUMetadata.cpp b/contrib/llvm/lib/Support/AMDGPUMetadata.cpp index ddb25935e0ef..a04bfc2ea299 100644 --- a/contrib/llvm/lib/Support/AMDGPUMetadata.cpp +++ b/contrib/llvm/lib/Support/AMDGPUMetadata.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // /// \file -/// \brief AMDGPU metadata definitions and in-memory representations. +/// AMDGPU metadata definitions and in-memory representations. /// // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/APFloat.cpp b/contrib/llvm/lib/Support/APFloat.cpp index 3489feb93a02..24005c1890c9 100644 --- a/contrib/llvm/lib/Support/APFloat.cpp +++ b/contrib/llvm/lib/Support/APFloat.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -3031,27 +3032,29 @@ double IEEEFloat::convertToDouble() const { /// does not support these bit patterns: /// exponent = all 1's, integer bit 0, significand 0 ("pseudoinfinity") /// exponent = all 1's, integer bit 0, significand nonzero ("pseudoNaN") -/// exponent = 0, integer bit 1 ("pseudodenormal") /// exponent!=0 nor all 1's, integer bit 0 ("unnormal") -/// At the moment, the first two are treated as NaNs, the second two as Normal. +/// exponent = 0, integer bit 1 ("pseudodenormal") +/// At the moment, the first three are treated as NaNs, the last one as Normal. void IEEEFloat::initFromF80LongDoubleAPInt(const APInt &api) { assert(api.getBitWidth()==80); uint64_t i1 = api.getRawData()[0]; uint64_t i2 = api.getRawData()[1]; uint64_t myexponent = (i2 & 0x7fff); uint64_t mysignificand = i1; + uint8_t myintegerbit = mysignificand >> 63; initialize(&semX87DoubleExtended); assert(partCount()==2); sign = static_cast<unsigned int>(i2>>15); - if (myexponent==0 && mysignificand==0) { + if (myexponent == 0 && mysignificand == 0) { // exponent, significand meaningless category = fcZero; } else if (myexponent==0x7fff && mysignificand==0x8000000000000000ULL) { // exponent, significand meaningless category = fcInfinity; - } else if (myexponent==0x7fff && mysignificand!=0x8000000000000000ULL) { + } else if ((myexponent == 0x7fff && mysignificand != 0x8000000000000000ULL) || + (myexponent != 0x7fff && myexponent != 0 && myintegerbit == 0)) { // exponent meaningless category = fcNaN; significandParts()[0] = mysignificand; @@ -4440,8 +4443,10 @@ APFloat::APFloat(const fltSemantics &Semantics, StringRef S) APFloat::opStatus APFloat::convert(const fltSemantics &ToSemantics, roundingMode RM, bool *losesInfo) { - if (&getSemantics() == &ToSemantics) + if (&getSemantics() == &ToSemantics) { + *losesInfo = false; return opOK; + } if (usesLayout<IEEEFloat>(getSemantics()) && usesLayout<IEEEFloat>(ToSemantics)) return U.IEEE.convert(ToSemantics, RM, losesInfo); diff --git a/contrib/llvm/lib/Support/APInt.cpp b/contrib/llvm/lib/Support/APInt.cpp index 1ea6319acfad..1fae0e9b8d6d 100644 --- a/contrib/llvm/lib/Support/APInt.cpp +++ b/contrib/llvm/lib/Support/APInt.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -33,8 +34,7 @@ using namespace llvm; /// A utility function for allocating memory, checking for allocation failures, /// and ensuring the contents are zeroed. inline static uint64_t* getClearedMemory(unsigned numWords) { - uint64_t * result = new uint64_t[numWords]; - assert(result && "APInt memory allocation fails!"); + uint64_t *result = new uint64_t[numWords]; memset(result, 0, numWords * sizeof(uint64_t)); return result; } @@ -42,9 +42,7 @@ inline static uint64_t* getClearedMemory(unsigned numWords) { /// A utility function for allocating memory and checking for allocation /// failure. The content is not zeroed. inline static uint64_t* getMemory(unsigned numWords) { - uint64_t * result = new uint64_t[numWords]; - assert(result && "APInt memory allocation fails!"); - return result; + return new uint64_t[numWords]; } /// A utility function that converts a character to a digit. @@ -170,7 +168,7 @@ void APInt::Profile(FoldingSetNodeID& ID) const { ID.AddInteger(U.pVal[i]); } -/// @brief Prefix increment operator. Increments the APInt by one. +/// Prefix increment operator. Increments the APInt by one. APInt& APInt::operator++() { if (isSingleWord()) ++U.VAL; @@ -179,7 +177,7 @@ APInt& APInt::operator++() { return clearUnusedBits(); } -/// @brief Prefix decrement operator. Decrements the APInt by one. +/// Prefix decrement operator. Decrements the APInt by one. APInt& APInt::operator--() { if (isSingleWord()) --U.VAL; @@ -190,7 +188,7 @@ APInt& APInt::operator--() { /// Adds the RHS APint to this APInt. /// @returns this, after addition of RHS. -/// @brief Addition assignment operator. +/// Addition assignment operator. APInt& APInt::operator+=(const APInt& RHS) { assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); if (isSingleWord()) @@ -210,7 +208,7 @@ APInt& APInt::operator+=(uint64_t RHS) { /// Subtracts the RHS APInt from this APInt /// @returns this, after subtraction -/// @brief Subtraction assignment operator. +/// Subtraction assignment operator. APInt& APInt::operator-=(const APInt& RHS) { assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); if (isSingleWord()) @@ -328,7 +326,7 @@ void APInt::setBitsSlowCase(unsigned loBit, unsigned hiBit) { U.pVal[word] = WORD_MAX; } -/// @brief Toggle every bit to its opposite value. +/// Toggle every bit to its opposite value. void APInt::flipAllBitsSlowCase() { tcComplement(U.pVal, getNumWords()); clearUnusedBits(); @@ -336,7 +334,7 @@ void APInt::flipAllBitsSlowCase() { /// Toggle a given bit to its opposite value whose position is given /// as "bitPosition". -/// @brief Toggles a given bit to its opposite value. +/// Toggles a given bit to its opposite value. void APInt::flipBit(unsigned bitPosition) { assert(bitPosition < BitWidth && "Out of the bit-width range!"); if ((*this)[bitPosition]) clearBit(bitPosition); @@ -428,11 +426,12 @@ APInt APInt::extractBits(unsigned numBits, unsigned bitPosition) const { unsigned NumSrcWords = getNumWords(); unsigned NumDstWords = Result.getNumWords(); + uint64_t *DestPtr = Result.isSingleWord() ? &Result.U.VAL : Result.U.pVal; for (unsigned word = 0; word < NumDstWords; ++word) { uint64_t w0 = U.pVal[loWord + word]; uint64_t w1 = (loWord + word + 1) < NumSrcWords ? U.pVal[loWord + word + 1] : 0; - Result.U.pVal[word] = (w0 >> loBit) | (w1 << (APINT_BITS_PER_WORD - loBit)); + DestPtr[word] = (w0 >> loBit) | (w1 << (APINT_BITS_PER_WORD - loBit)); } return Result.clearUnusedBits(); @@ -909,13 +908,13 @@ APInt APInt::sextOrSelf(unsigned width) const { } /// Arithmetic right-shift this APInt by shiftAmt. -/// @brief Arithmetic right-shift function. +/// Arithmetic right-shift function. void APInt::ashrInPlace(const APInt &shiftAmt) { ashrInPlace((unsigned)shiftAmt.getLimitedValue(BitWidth)); } /// Arithmetic right-shift this APInt by shiftAmt. -/// @brief Arithmetic right-shift function. +/// Arithmetic right-shift function. void APInt::ashrSlowCase(unsigned ShiftAmt) { // Don't bother performing a no-op shift. if (!ShiftAmt) @@ -924,7 +923,7 @@ void APInt::ashrSlowCase(unsigned ShiftAmt) { // Save the original sign bit for later. bool Negative = isNegative(); - // WordShift is the inter-part shift; BitShift is is intra-part shift. + // WordShift is the inter-part shift; BitShift is intra-part shift. unsigned WordShift = ShiftAmt / APINT_BITS_PER_WORD; unsigned BitShift = ShiftAmt % APINT_BITS_PER_WORD; @@ -958,19 +957,19 @@ void APInt::ashrSlowCase(unsigned ShiftAmt) { } /// Logical right-shift this APInt by shiftAmt. -/// @brief Logical right-shift function. +/// Logical right-shift function. void APInt::lshrInPlace(const APInt &shiftAmt) { lshrInPlace((unsigned)shiftAmt.getLimitedValue(BitWidth)); } /// Logical right-shift this APInt by shiftAmt. -/// @brief Logical right-shift function. +/// Logical right-shift function. void APInt::lshrSlowCase(unsigned ShiftAmt) { tcShiftRight(U.pVal, getNumWords(), ShiftAmt); } /// Left-shift this APInt by shiftAmt. -/// @brief Left-shift function. +/// Left-shift function. APInt &APInt::operator<<=(const APInt &shiftAmt) { // It's undefined behavior in C to shift by BitWidth or greater. *this <<= (unsigned)shiftAmt.getLimitedValue(BitWidth); @@ -1254,18 +1253,20 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, // The DEBUG macros here tend to be spam in the debug output if you're not // debugging this code. Disable them unless KNUTH_DEBUG is defined. -#pragma push_macro("DEBUG") +#pragma push_macro("LLVM_DEBUG") #ifndef KNUTH_DEBUG -#undef DEBUG -#define DEBUG(X) do {} while (false) +#undef LLVM_DEBUG +#define LLVM_DEBUG(X) \ + do { \ + } while (false) #endif - DEBUG(dbgs() << "KnuthDiv: m=" << m << " n=" << n << '\n'); - DEBUG(dbgs() << "KnuthDiv: original:"); - DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); - DEBUG(dbgs() << " by"); - DEBUG(for (int i = n; i >0; i--) dbgs() << " " << v[i-1]); - DEBUG(dbgs() << '\n'); + LLVM_DEBUG(dbgs() << "KnuthDiv: m=" << m << " n=" << n << '\n'); + LLVM_DEBUG(dbgs() << "KnuthDiv: original:"); + LLVM_DEBUG(for (int i = m + n; i >= 0; i--) dbgs() << " " << u[i]); + LLVM_DEBUG(dbgs() << " by"); + LLVM_DEBUG(for (int i = n; i > 0; i--) dbgs() << " " << v[i - 1]); + LLVM_DEBUG(dbgs() << '\n'); // D1. [Normalize.] Set d = b / (v[n-1] + 1) and multiply all the digits of // u and v by d. Note that we have taken Knuth's advice here to use a power // of 2 value for d such that d * v[n-1] >= b/2 (b is the base). A power of @@ -1291,16 +1292,16 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, } u[m+n] = u_carry; - DEBUG(dbgs() << "KnuthDiv: normal:"); - DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); - DEBUG(dbgs() << " by"); - DEBUG(for (int i = n; i >0; i--) dbgs() << " " << v[i-1]); - DEBUG(dbgs() << '\n'); + LLVM_DEBUG(dbgs() << "KnuthDiv: normal:"); + LLVM_DEBUG(for (int i = m + n; i >= 0; i--) dbgs() << " " << u[i]); + LLVM_DEBUG(dbgs() << " by"); + LLVM_DEBUG(for (int i = n; i > 0; i--) dbgs() << " " << v[i - 1]); + LLVM_DEBUG(dbgs() << '\n'); // D2. [Initialize j.] Set j to m. This is the loop counter over the places. int j = m; do { - DEBUG(dbgs() << "KnuthDiv: quotient digit #" << j << '\n'); + LLVM_DEBUG(dbgs() << "KnuthDiv: quotient digit #" << j << '\n'); // D3. [Calculate q'.]. // Set qp = (u[j+n]*b + u[j+n-1]) / v[n-1]. (qp=qprime=q') // Set rp = (u[j+n]*b + u[j+n-1]) % v[n-1]. (rp=rprime=r') @@ -1310,7 +1311,7 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, // value qp is one too large, and it eliminates all cases where qp is two // too large. uint64_t dividend = Make_64(u[j+n], u[j+n-1]); - DEBUG(dbgs() << "KnuthDiv: dividend == " << dividend << '\n'); + LLVM_DEBUG(dbgs() << "KnuthDiv: dividend == " << dividend << '\n'); uint64_t qp = dividend / v[n-1]; uint64_t rp = dividend % v[n-1]; if (qp == b || qp*v[n-2] > b*rp + u[j+n-2]) { @@ -1319,7 +1320,7 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, if (rp < b && (qp == b || qp*v[n-2] > b*rp + u[j+n-2])) qp--; } - DEBUG(dbgs() << "KnuthDiv: qp == " << qp << ", rp == " << rp << '\n'); + LLVM_DEBUG(dbgs() << "KnuthDiv: qp == " << qp << ", rp == " << rp << '\n'); // D4. [Multiply and subtract.] Replace (u[j+n]u[j+n-1]...u[j]) with // (u[j+n]u[j+n-1]..u[j]) - qp * (v[n-1]...v[1]v[0]). This computation @@ -1335,15 +1336,15 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, int64_t subres = int64_t(u[j+i]) - borrow - Lo_32(p); u[j+i] = Lo_32(subres); borrow = Hi_32(p) - Hi_32(subres); - DEBUG(dbgs() << "KnuthDiv: u[j+i] = " << u[j+i] - << ", borrow = " << borrow << '\n'); + LLVM_DEBUG(dbgs() << "KnuthDiv: u[j+i] = " << u[j + i] + << ", borrow = " << borrow << '\n'); } bool isNeg = u[j+n] < borrow; u[j+n] -= Lo_32(borrow); - DEBUG(dbgs() << "KnuthDiv: after subtraction:"); - DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); - DEBUG(dbgs() << '\n'); + LLVM_DEBUG(dbgs() << "KnuthDiv: after subtraction:"); + LLVM_DEBUG(for (int i = m + n; i >= 0; i--) dbgs() << " " << u[i]); + LLVM_DEBUG(dbgs() << '\n'); // D5. [Test remainder.] Set q[j] = qp. If the result of step D4 was // negative, go to step D6; otherwise go on to step D7. @@ -1364,16 +1365,16 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, } u[j+n] += carry; } - DEBUG(dbgs() << "KnuthDiv: after correction:"); - DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); - DEBUG(dbgs() << "\nKnuthDiv: digit result = " << q[j] << '\n'); + LLVM_DEBUG(dbgs() << "KnuthDiv: after correction:"); + LLVM_DEBUG(for (int i = m + n; i >= 0; i--) dbgs() << " " << u[i]); + LLVM_DEBUG(dbgs() << "\nKnuthDiv: digit result = " << q[j] << '\n'); - // D7. [Loop on j.] Decrease j by one. Now if j >= 0, go back to D3. + // D7. [Loop on j.] Decrease j by one. Now if j >= 0, go back to D3. } while (--j >= 0); - DEBUG(dbgs() << "KnuthDiv: quotient:"); - DEBUG(for (int i = m; i >=0; i--) dbgs() <<" " << q[i]); - DEBUG(dbgs() << '\n'); + LLVM_DEBUG(dbgs() << "KnuthDiv: quotient:"); + LLVM_DEBUG(for (int i = m; i >= 0; i--) dbgs() << " " << q[i]); + LLVM_DEBUG(dbgs() << '\n'); // D8. [Unnormalize]. Now q[...] is the desired quotient, and the desired // remainder may be obtained by dividing u[...] by d. If r is non-null we @@ -1384,23 +1385,23 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, // shift right here. if (shift) { uint32_t carry = 0; - DEBUG(dbgs() << "KnuthDiv: remainder:"); + LLVM_DEBUG(dbgs() << "KnuthDiv: remainder:"); for (int i = n-1; i >= 0; i--) { r[i] = (u[i] >> shift) | carry; carry = u[i] << (32 - shift); - DEBUG(dbgs() << " " << r[i]); + LLVM_DEBUG(dbgs() << " " << r[i]); } } else { for (int i = n-1; i >= 0; i--) { r[i] = u[i]; - DEBUG(dbgs() << " " << r[i]); + LLVM_DEBUG(dbgs() << " " << r[i]); } } - DEBUG(dbgs() << '\n'); + LLVM_DEBUG(dbgs() << '\n'); } - DEBUG(dbgs() << '\n'); + LLVM_DEBUG(dbgs() << '\n'); -#pragma pop_macro("DEBUG") +#pragma pop_macro("LLVM_DEBUG") } void APInt::divide(const WordType *LHS, unsigned lhsWords, const WordType *RHS, @@ -1734,25 +1735,25 @@ void APInt::udivrem(const APInt &LHS, const APInt &RHS, // Check the degenerate cases if (lhsWords == 0) { - Quotient = 0; // 0 / Y ===> 0 - Remainder = 0; // 0 % Y ===> 0 + Quotient = APInt(BitWidth, 0); // 0 / Y ===> 0 + Remainder = APInt(BitWidth, 0); // 0 % Y ===> 0 return; } if (rhsBits == 1) { - Quotient = LHS; // X / 1 ===> X - Remainder = 0; // X % 1 ===> 0 + Quotient = LHS; // X / 1 ===> X + Remainder = APInt(BitWidth, 0); // X % 1 ===> 0 } if (lhsWords < rhsWords || LHS.ult(RHS)) { - Remainder = LHS; // X % Y ===> X, iff X < Y - Quotient = 0; // X / Y ===> 0, iff X < Y + Remainder = LHS; // X % Y ===> X, iff X < Y + Quotient = APInt(BitWidth, 0); // X / Y ===> 0, iff X < Y return; } if (LHS == RHS) { - Quotient = 1; // X / X ===> 1 - Remainder = 0; // X % X ===> 0; + Quotient = APInt(BitWidth, 1); // X / X ===> 1 + Remainder = APInt(BitWidth, 0); // X % X ===> 0; return; } @@ -1800,25 +1801,26 @@ void APInt::udivrem(const APInt &LHS, uint64_t RHS, APInt &Quotient, // Check the degenerate cases if (lhsWords == 0) { - Quotient = 0; // 0 / Y ===> 0 - Remainder = 0; // 0 % Y ===> 0 + Quotient = APInt(BitWidth, 0); // 0 / Y ===> 0 + Remainder = 0; // 0 % Y ===> 0 return; } if (RHS == 1) { - Quotient = LHS; // X / 1 ===> X - Remainder = 0; // X % 1 ===> 0 + Quotient = LHS; // X / 1 ===> X + Remainder = 0; // X % 1 ===> 0 + return; } if (LHS.ult(RHS)) { - Remainder = LHS.getZExtValue(); // X % Y ===> X, iff X < Y - Quotient = 0; // X / Y ===> 0, iff X < Y + Remainder = LHS.getZExtValue(); // X % Y ===> X, iff X < Y + Quotient = APInt(BitWidth, 0); // X / Y ===> 0, iff X < Y return; } if (LHS == RHS) { - Quotient = 1; // X / X ===> 1 - Remainder = 0; // X % X ===> 0; + Quotient = APInt(BitWidth, 1); // X / X ===> 1 + Remainder = 0; // X % X ===> 0; return; } @@ -2657,3 +2659,51 @@ void APInt::tcSetLeastSignificantBits(WordType *dst, unsigned parts, while (i < parts) dst[i++] = 0; } + +APInt llvm::APIntOps::RoundingUDiv(const APInt &A, const APInt &B, + APInt::Rounding RM) { + // Currently udivrem always rounds down. + switch (RM) { + case APInt::Rounding::DOWN: + case APInt::Rounding::TOWARD_ZERO: + return A.udiv(B); + case APInt::Rounding::UP: { + APInt Quo, Rem; + APInt::udivrem(A, B, Quo, Rem); + if (Rem == 0) + return Quo; + return Quo + 1; + } + } + llvm_unreachable("Unknown APInt::Rounding enum"); +} + +APInt llvm::APIntOps::RoundingSDiv(const APInt &A, const APInt &B, + APInt::Rounding RM) { + switch (RM) { + case APInt::Rounding::DOWN: + case APInt::Rounding::UP: { + APInt Quo, Rem; + APInt::sdivrem(A, B, Quo, Rem); + if (Rem == 0) + return Quo; + // This algorithm deals with arbitrary rounding mode used by sdivrem. + // We want to check whether the non-integer part of the mathematical value + // is negative or not. If the non-integer part is negative, we need to round + // down from Quo; otherwise, if it's positive or 0, we return Quo, as it's + // already rounded down. + if (RM == APInt::Rounding::DOWN) { + if (Rem.isNegative() != B.isNegative()) + return Quo - 1; + return Quo; + } + if (Rem.isNegative() != B.isNegative()) + return Quo; + return Quo + 1; + } + // Currently sdiv rounds twards zero. + case APInt::Rounding::TOWARD_ZERO: + return A.sdiv(B); + } + llvm_unreachable("Unknown APInt::Rounding enum"); +} diff --git a/contrib/llvm/lib/Support/ARMAttributeParser.cpp b/contrib/llvm/lib/Support/ARMAttributeParser.cpp index e39bddc4e8f2..1f98ac2f40ba 100644 --- a/contrib/llvm/lib/Support/ARMAttributeParser.cpp +++ b/contrib/llvm/lib/Support/ARMAttributeParser.cpp @@ -705,4 +705,3 @@ void ARMAttributeParser::Parse(ArrayRef<uint8_t> Section, bool isLittle) { } } } - diff --git a/contrib/llvm/lib/Support/BinaryStreamRef.cpp b/contrib/llvm/lib/Support/BinaryStreamRef.cpp index 60a03fe9930f..bdc0f54bf25a 100644 --- a/contrib/llvm/lib/Support/BinaryStreamRef.cpp +++ b/contrib/llvm/lib/Support/BinaryStreamRef.cpp @@ -127,5 +127,5 @@ WritableBinaryStreamRef::operator BinaryStreamRef() const { return BinaryStreamRef(*BorrowedImpl, ViewOffset, Length); } -/// \brief For buffered streams, commits changes to the backing store. +/// For buffered streams, commits changes to the backing store. Error WritableBinaryStreamRef::commit() { return BorrowedImpl->commit(); } diff --git a/contrib/llvm/lib/Support/BranchProbability.cpp b/contrib/llvm/lib/Support/BranchProbability.cpp index 44ad110d456a..31dee9561f49 100644 --- a/contrib/llvm/lib/Support/BranchProbability.cpp +++ b/contrib/llvm/lib/Support/BranchProbability.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/BranchProbability.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" diff --git a/contrib/llvm/lib/Support/COM.cpp b/contrib/llvm/lib/Support/COM.cpp index cf3a133fd9b4..2e3ff66843d3 100644 --- a/contrib/llvm/lib/Support/COM.cpp +++ b/contrib/llvm/lib/Support/COM.cpp @@ -13,11 +13,11 @@ #include "llvm/Support/COM.h" -#include "llvm/Config/config.h" +#include "llvm/Config/llvm-config.h" // Include the platform-specific parts of this class. #ifdef LLVM_ON_UNIX #include "Unix/COM.inc" -#elif LLVM_ON_WIN32 +#elif _WIN32 #include "Windows/COM.inc" #endif diff --git a/contrib/llvm/lib/Support/CachePruning.cpp b/contrib/llvm/lib/Support/CachePruning.cpp index 141573c2a1c7..7326c4fc91fb 100644 --- a/contrib/llvm/lib/Support/CachePruning.cpp +++ b/contrib/llvm/lib/Support/CachePruning.cpp @@ -146,7 +146,7 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { if (Policy.Expiration == seconds(0) && Policy.MaxSizePercentageOfAvailableSpace == 0 && Policy.MaxSizeBytes == 0 && Policy.MaxSizeFiles == 0) { - DEBUG(dbgs() << "No pruning settings set, exit early\n"); + LLVM_DEBUG(dbgs() << "No pruning settings set, exit early\n"); // Nothing will be pruned, early exit return false; } @@ -173,9 +173,9 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { const auto TimeStampModTime = FileStatus.getLastModificationTime(); auto TimeStampAge = CurrentTime - TimeStampModTime; if (TimeStampAge <= *Policy.Interval) { - DEBUG(dbgs() << "Timestamp file too recent (" - << duration_cast<seconds>(TimeStampAge).count() - << "s old), do not prune.\n"); + LLVM_DEBUG(dbgs() << "Timestamp file too recent (" + << duration_cast<seconds>(TimeStampAge).count() + << "s old), do not prune.\n"); return false; } } @@ -207,7 +207,7 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { // there. ErrorOr<sys::fs::basic_file_status> StatusOrErr = File->status(); if (!StatusOrErr) { - DEBUG(dbgs() << "Ignore " << File->path() << " (can't stat)\n"); + LLVM_DEBUG(dbgs() << "Ignore " << File->path() << " (can't stat)\n"); continue; } @@ -215,8 +215,9 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { const auto FileAccessTime = StatusOrErr->getLastAccessedTime(); auto FileAge = CurrentTime - FileAccessTime; if (Policy.Expiration != seconds(0) && FileAge > Policy.Expiration) { - DEBUG(dbgs() << "Remove " << File->path() << " (" - << duration_cast<seconds>(FileAge).count() << "s old)\n"); + LLVM_DEBUG(dbgs() << "Remove " << File->path() << " (" + << duration_cast<seconds>(FileAge).count() + << "s old)\n"); sys::fs::remove(File->path()); continue; } @@ -235,9 +236,9 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { // Update size TotalSize -= FileAndSize->first; NumFiles--; - DEBUG(dbgs() << " - Remove " << FileAndSize->second << " (size " - << FileAndSize->first << "), new occupancy is " << TotalSize - << "%\n"); + LLVM_DEBUG(dbgs() << " - Remove " << FileAndSize->second << " (size " + << FileAndSize->first << "), new occupancy is " + << TotalSize << "%\n"); ++FileAndSize; }; @@ -263,9 +264,10 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { AvailableSpace * Policy.MaxSizePercentageOfAvailableSpace / 100ull, Policy.MaxSizeBytes); - DEBUG(dbgs() << "Occupancy: " << ((100 * TotalSize) / AvailableSpace) - << "% target is: " << Policy.MaxSizePercentageOfAvailableSpace - << "%, " << Policy.MaxSizeBytes << " bytes\n"); + LLVM_DEBUG(dbgs() << "Occupancy: " << ((100 * TotalSize) / AvailableSpace) + << "% target is: " + << Policy.MaxSizePercentageOfAvailableSpace << "%, " + << Policy.MaxSizeBytes << " bytes\n"); // Remove the oldest accessed files first, till we get below the threshold. while (TotalSize > TotalSizeTarget && FileAndSize != FileSizes.rend()) diff --git a/contrib/llvm/lib/Support/Chrono.cpp b/contrib/llvm/lib/Support/Chrono.cpp index 84f5aab6fc45..a2626a89eb63 100644 --- a/contrib/llvm/lib/Support/Chrono.cpp +++ b/contrib/llvm/lib/Support/Chrono.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Chrono.h" -#include "llvm/Config/config.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -32,7 +32,7 @@ static inline struct tm getStructTM(TimePoint<> TP) { assert(LT); (void)LT; #endif -#if defined(LLVM_ON_WIN32) +#if defined(_WIN32) int Error = ::localtime_s(&Storage, &OurTime); assert(!Error); (void)Error; diff --git a/contrib/llvm/lib/Support/CodeGenCoverage.cpp b/contrib/llvm/lib/Support/CodeGenCoverage.cpp index ebfe65a398c3..f0a53db4e32a 100644 --- a/contrib/llvm/lib/Support/CodeGenCoverage.cpp +++ b/contrib/llvm/lib/Support/CodeGenCoverage.cpp @@ -12,7 +12,7 @@ #include "llvm/Support/CodeGenCoverage.h" -#include "llvm/Config/config.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -22,7 +22,7 @@ #if LLVM_ON_UNIX #include <unistd.h> -#elif LLVM_ON_WIN32 +#elif _WIN32 #include <windows.h> #endif @@ -38,12 +38,17 @@ void CodeGenCoverage::setCovered(uint64_t RuleID) { RuleCoverage[RuleID] = true; } -bool CodeGenCoverage::isCovered(uint64_t RuleID) { +bool CodeGenCoverage::isCovered(uint64_t RuleID) const { if (RuleCoverage.size() <= RuleID) return false; return RuleCoverage[RuleID]; } +iterator_range<CodeGenCoverage::const_covered_iterator> +CodeGenCoverage::covered() const { + return RuleCoverage.set_bits(); +} + bool CodeGenCoverage::parse(MemoryBuffer &Buffer, StringRef BackendName) { const char *CurPtr = Buffer.getBufferStart(); @@ -88,7 +93,7 @@ bool CodeGenCoverage::emit(StringRef CoveragePrefix, std::string Pid = #if LLVM_ON_UNIX llvm::to_string(::getpid()); -#elif LLVM_ON_WIN32 +#elif _WIN32 llvm::to_string(::GetCurrentProcessId()); #else ""; diff --git a/contrib/llvm/lib/Support/CommandLine.cpp b/contrib/llvm/lib/Support/CommandLine.cpp index d95b791972c8..a1e659a01c8e 100644 --- a/contrib/llvm/lib/Support/CommandLine.cpp +++ b/contrib/llvm/lib/Support/CommandLine.cpp @@ -25,6 +25,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Config/config.h" #include "llvm/Support/ConvertUTF.h" @@ -973,7 +974,7 @@ static bool ExpandResponseFile(StringRef FName, StringSaver &Saver, return true; } -/// \brief Expand response files on a command line recursively using the given +/// Expand response files on a command line recursively using the given /// StringSaver and tokenization strategy. bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, SmallVectorImpl<const char *> &Argv, @@ -1080,7 +1081,10 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, SmallVector<const char *, 20> newArgv(argv, argv + argc); BumpPtrAllocator A; StringSaver Saver(A); - ExpandResponseFiles(Saver, TokenizeGNUCommandLine, newArgv); + ExpandResponseFiles(Saver, + Triple(sys::getProcessTriple()).isOSWindows() ? + cl::TokenizeWindowsCommandLine : cl::TokenizeGNUCommandLine, + newArgv); argv = &newArgv[0]; argc = static_cast<int>(newArgv.size()); @@ -1266,8 +1270,15 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, // If this is a named positional argument, just remember that it is the // active one... - if (Handler->getFormattingFlag() == cl::Positional) + if (Handler->getFormattingFlag() == cl::Positional) { + if ((Handler->getMiscFlags() & PositionalEatsArgs) && !Value.empty()) { + Handler->error("This argument does not take a value.\n" + "\tInstead, it consumes any positional arguments until " + "the next recognized option.", *Errs); + ErrorParsing = true; + } ActivePositionalArg = Handler; + } else ErrorParsing |= ProvideOption(Handler, ArgName, Value, argc, argv, i); } @@ -1371,9 +1382,9 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, // Now that we know if -debug is specified, we can use it. // Note that if ReadResponseFiles == true, this must be done before the // memory allocated for the expanded command line is free()d below. - DEBUG(dbgs() << "Args: "; - for (int i = 0; i < argc; ++i) dbgs() << argv[i] << ' '; - dbgs() << '\n';); + LLVM_DEBUG(dbgs() << "Args: "; + for (int i = 0; i < argc; ++i) dbgs() << argv[i] << ' '; + dbgs() << '\n';); // Free all of the memory allocated to the map. Command line options may only // be processed once! @@ -1392,15 +1403,15 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, // Option Base class implementation // -bool Option::error(const Twine &Message, StringRef ArgName) { +bool Option::error(const Twine &Message, StringRef ArgName, raw_ostream &Errs) { if (!ArgName.data()) ArgName = ArgStr; if (ArgName.empty()) - errs() << HelpStr; // Be nice for positional arguments + Errs << HelpStr; // Be nice for positional arguments else - errs() << GlobalParser->ProgramName << ": for the -" << ArgName; + Errs << GlobalParser->ProgramName << ": for the -" << ArgName; - errs() << " option: " << Message << "\n"; + Errs << " option: " << Message << "\n"; return true; } @@ -1470,8 +1481,12 @@ void alias::printOptionInfo(size_t GlobalWidth) const { size_t basic_parser_impl::getOptionWidth(const Option &O) const { size_t Len = O.ArgStr.size(); auto ValName = getValueName(); - if (!ValName.empty()) - Len += getValueStr(O, ValName).size() + 3; + if (!ValName.empty()) { + size_t FormattingLen = 3; + if (O.getMiscFlags() & PositionalEatsArgs) + FormattingLen = 6; + Len += getValueStr(O, ValName).size() + FormattingLen; + } return Len + 6; } @@ -1484,8 +1499,13 @@ void basic_parser_impl::printOptionInfo(const Option &O, outs() << " -" << O.ArgStr; auto ValName = getValueName(); - if (!ValName.empty()) - outs() << "=<" << getValueStr(O, ValName) << '>'; + if (!ValName.empty()) { + if (O.getMiscFlags() & PositionalEatsArgs) { + outs() << " <" << getValueStr(O, ValName) << ">..."; + } else { + outs() << "=<" << getValueStr(O, ValName) << '>'; + } + } Option::printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O)); } diff --git a/contrib/llvm/lib/Support/CrashRecoveryContext.cpp b/contrib/llvm/lib/Support/CrashRecoveryContext.cpp index bd38dd88201f..fd5d097d2b7e 100644 --- a/contrib/llvm/lib/Support/CrashRecoveryContext.cpp +++ b/contrib/llvm/lib/Support/CrashRecoveryContext.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/CrashRecoveryContext.h" -#include "llvm/Config/config.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Mutex.h" @@ -47,7 +47,7 @@ public: CurrentContext->set(Next); } - /// \brief Called when the separate crash-recovery thread was finished, to + /// Called when the separate crash-recovery thread was finished, to /// indicate that we don't need to clear the thread-local CurrentContext. void setSwitchedThread() { #if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0 @@ -189,7 +189,7 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) { #else // !_MSC_VER -#if defined(LLVM_ON_WIN32) +#if defined(_WIN32) // This is a non-MSVC compiler, probably mingw gcc or clang without // -fms-extensions. Use vectored exception handling (VEH). // @@ -272,7 +272,7 @@ static void uninstallExceptionOrSignalHandlers() { } } -#else // !LLVM_ON_WIN32 +#else // !_WIN32 // Generic POSIX implementation. // @@ -342,7 +342,7 @@ static void uninstallExceptionOrSignalHandlers() { sigaction(Signals[i], &PrevActions[i], nullptr); } -#endif // !LLVM_ON_WIN32 +#endif // !_WIN32 bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) { // If crash recovery is disabled, do nothing. diff --git a/contrib/llvm/lib/Support/DAGDeltaAlgorithm.cpp b/contrib/llvm/lib/Support/DAGDeltaAlgorithm.cpp index f1a334bfc7be..b82aec1423f5 100644 --- a/contrib/llvm/lib/Support/DAGDeltaAlgorithm.cpp +++ b/contrib/llvm/lib/Support/DAGDeltaAlgorithm.cpp @@ -124,13 +124,13 @@ private: /// ExecuteOneTest - Execute a single test predicate on the change set \p S. bool ExecuteOneTest(const changeset_ty &S) { // Check dependencies invariant. - DEBUG({ - for (changeset_ty::const_iterator it = S.begin(), - ie = S.end(); it != ie; ++it) - for (succ_iterator_ty it2 = succ_begin(*it), - ie2 = succ_end(*it); it2 != ie2; ++it2) - assert(S.count(*it2) && "Attempt to run invalid changeset!"); - }); + LLVM_DEBUG({ + for (changeset_ty::const_iterator it = S.begin(), ie = S.end(); it != ie; + ++it) + for (succ_iterator_ty it2 = succ_begin(*it), ie2 = succ_end(*it); + it2 != ie2; ++it2) + assert(S.count(*it2) && "Attempt to run invalid changeset!"); + }); return DDA.ExecuteOneTest(S); } @@ -224,60 +224,68 @@ DAGDeltaAlgorithmImpl::DAGDeltaAlgorithmImpl( PredClosure[*it2].insert(*it); // Dump useful debug info. - DEBUG({ - llvm::errs() << "-- DAGDeltaAlgorithmImpl --\n"; - llvm::errs() << "Changes: ["; - for (changeset_ty::const_iterator it = Changes.begin(), - ie = Changes.end(); it != ie; ++it) { - if (it != Changes.begin()) llvm::errs() << ", "; - llvm::errs() << *it; - - if (succ_begin(*it) != succ_end(*it)) { - llvm::errs() << "("; - for (succ_iterator_ty it2 = succ_begin(*it), - ie2 = succ_end(*it); it2 != ie2; ++it2) { - if (it2 != succ_begin(*it)) llvm::errs() << ", "; - llvm::errs() << "->" << *it2; - } - llvm::errs() << ")"; + LLVM_DEBUG({ + llvm::errs() << "-- DAGDeltaAlgorithmImpl --\n"; + llvm::errs() << "Changes: ["; + for (changeset_ty::const_iterator it = Changes.begin(), ie = Changes.end(); + it != ie; ++it) { + if (it != Changes.begin()) + llvm::errs() << ", "; + llvm::errs() << *it; + + if (succ_begin(*it) != succ_end(*it)) { + llvm::errs() << "("; + for (succ_iterator_ty it2 = succ_begin(*it), ie2 = succ_end(*it); + it2 != ie2; ++it2) { + if (it2 != succ_begin(*it)) + llvm::errs() << ", "; + llvm::errs() << "->" << *it2; } + llvm::errs() << ")"; } - llvm::errs() << "]\n"; - - llvm::errs() << "Roots: ["; - for (std::vector<change_ty>::const_iterator it = Roots.begin(), - ie = Roots.end(); it != ie; ++it) { - if (it != Roots.begin()) llvm::errs() << ", "; - llvm::errs() << *it; + } + llvm::errs() << "]\n"; + + llvm::errs() << "Roots: ["; + for (std::vector<change_ty>::const_iterator it = Roots.begin(), + ie = Roots.end(); + it != ie; ++it) { + if (it != Roots.begin()) + llvm::errs() << ", "; + llvm::errs() << *it; + } + llvm::errs() << "]\n"; + + llvm::errs() << "Predecessor Closure:\n"; + for (changeset_ty::const_iterator it = Changes.begin(), ie = Changes.end(); + it != ie; ++it) { + llvm::errs() << format(" %-4d: [", *it); + for (pred_closure_iterator_ty it2 = pred_closure_begin(*it), + ie2 = pred_closure_end(*it); + it2 != ie2; ++it2) { + if (it2 != pred_closure_begin(*it)) + llvm::errs() << ", "; + llvm::errs() << *it2; } llvm::errs() << "]\n"; + } - llvm::errs() << "Predecessor Closure:\n"; - for (changeset_ty::const_iterator it = Changes.begin(), - ie = Changes.end(); it != ie; ++it) { - llvm::errs() << format(" %-4d: [", *it); - for (pred_closure_iterator_ty it2 = pred_closure_begin(*it), - ie2 = pred_closure_end(*it); it2 != ie2; ++it2) { - if (it2 != pred_closure_begin(*it)) llvm::errs() << ", "; - llvm::errs() << *it2; - } - llvm::errs() << "]\n"; - } - - llvm::errs() << "Successor Closure:\n"; - for (changeset_ty::const_iterator it = Changes.begin(), - ie = Changes.end(); it != ie; ++it) { - llvm::errs() << format(" %-4d: [", *it); - for (succ_closure_iterator_ty it2 = succ_closure_begin(*it), - ie2 = succ_closure_end(*it); it2 != ie2; ++it2) { - if (it2 != succ_closure_begin(*it)) llvm::errs() << ", "; - llvm::errs() << *it2; - } - llvm::errs() << "]\n"; + llvm::errs() << "Successor Closure:\n"; + for (changeset_ty::const_iterator it = Changes.begin(), ie = Changes.end(); + it != ie; ++it) { + llvm::errs() << format(" %-4d: [", *it); + for (succ_closure_iterator_ty it2 = succ_closure_begin(*it), + ie2 = succ_closure_end(*it); + it2 != ie2; ++it2) { + if (it2 != succ_closure_begin(*it)) + llvm::errs() << ", "; + llvm::errs() << *it2; } + llvm::errs() << "]\n"; + } - llvm::errs() << "\n\n"; - }); + llvm::errs() << "\n\n"; + }); } bool DAGDeltaAlgorithmImpl::GetTestResult(const changeset_ty &Changes, @@ -312,10 +320,10 @@ DAGDeltaAlgorithmImpl::Run() { // Invariant: CurrentSet intersect Required == {} // Invariant: Required == (Required union succ*(Required)) while (!CurrentSet.empty()) { - DEBUG({ - llvm::errs() << "DAG_DD - " << CurrentSet.size() << " active changes, " - << Required.size() << " required changes\n"; - }); + LLVM_DEBUG({ + llvm::errs() << "DAG_DD - " << CurrentSet.size() << " active changes, " + << Required.size() << " required changes\n"; + }); // Minimize the current set of changes. DeltaActiveSetHelper Helper(*this, Required); diff --git a/contrib/llvm/lib/Support/DJB.cpp b/contrib/llvm/lib/Support/DJB.cpp new file mode 100644 index 000000000000..905dcf1b7e81 --- /dev/null +++ b/contrib/llvm/lib/Support/DJB.cpp @@ -0,0 +1,86 @@ +//===-- Support/DJB.cpp ---DJB Hash -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for the DJ Bernstein hash function. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/DJB.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Unicode.h" + +using namespace llvm; + +static UTF32 chopOneUTF32(StringRef &Buffer) { + UTF32 C; + const UTF8 *const Begin8Const = + reinterpret_cast<const UTF8 *>(Buffer.begin()); + const UTF8 *Begin8 = Begin8Const; + UTF32 *Begin32 = &C; + + // In lenient mode we will always end up with a "reasonable" value in C for + // non-empty input. + assert(!Buffer.empty()); + ConvertUTF8toUTF32(&Begin8, reinterpret_cast<const UTF8 *>(Buffer.end()), + &Begin32, &C + 1, lenientConversion); + Buffer = Buffer.drop_front(Begin8 - Begin8Const); + return C; +} + +static StringRef toUTF8(UTF32 C, MutableArrayRef<UTF8> Storage) { + const UTF32 *Begin32 = &C; + UTF8 *Begin8 = Storage.begin(); + + // The case-folded output should always be a valid unicode character, so use + // strict mode here. + ConversionResult CR = ConvertUTF32toUTF8(&Begin32, &C + 1, &Begin8, + Storage.end(), strictConversion); + assert(CR == conversionOK && "Case folding produced invalid char?"); + (void)CR; + return StringRef(reinterpret_cast<char *>(Storage.begin()), + Begin8 - Storage.begin()); +} + +static UTF32 foldCharDwarf(UTF32 C) { + // DWARF v5 addition to the unicode folding rules. + // Fold "Latin Small Letter Dotless I" and "Latin Capital Letter I With Dot + // Above" into "i". + if (C == 0x130 || C == 0x131) + return 'i'; + return sys::unicode::foldCharSimple(C); +} + +static uint32_t caseFoldingDjbHashCharSlow(StringRef &Buffer, uint32_t H) { + UTF32 C = chopOneUTF32(Buffer); + + C = foldCharDwarf(C); + + std::array<UTF8, UNI_MAX_UTF8_BYTES_PER_CODE_POINT> Storage; + StringRef Folded = toUTF8(C, Storage); + return djbHash(Folded, H); +} + +uint32_t llvm::caseFoldingDjbHash(StringRef Buffer, uint32_t H) { + while (!Buffer.empty()) { + unsigned char C = Buffer.front(); + if (LLVM_LIKELY(C <= 0x7f)) { + // US-ASCII, encoded as one character in utf-8. + // This is by far the most common case, so handle this specially. + if (C >= 'A' && C <= 'Z') + C = 'a' + (C - 'A'); // fold uppercase into lowercase + H = (H << 5) + H + C; + Buffer = Buffer.drop_front(); + continue; + } + H = caseFoldingDjbHashCharSlow(Buffer, H); + } + return H; +} diff --git a/contrib/llvm/lib/Support/Debug.cpp b/contrib/llvm/lib/Support/Debug.cpp index 9132911479a1..1a70017fee32 100644 --- a/contrib/llvm/lib/Support/Debug.cpp +++ b/contrib/llvm/lib/Support/Debug.cpp @@ -11,15 +11,16 @@ // code, without it being enabled all of the time, and without having to add // command line options to enable it. // -// In particular, just wrap your code with the DEBUG() macro, and it will be -// enabled automatically if you specify '-debug' on the command-line. +// In particular, just wrap your code with the LLVM_DEBUG() macro, and it will +// be enabled automatically if you specify '-debug' on the command-line. // Alternatively, you can also use the SET_DEBUG_TYPE("foo") macro to specify // that your debug code belongs to class "foo". Then, on the command line, you // can specify '-debug-only=foo' to enable JUST the debug information for the // foo class. // // When compiling without assertions, the -debug-* options and all code in -// DEBUG() statements disappears, so it does not affect the runtime of the code. +// LLVM_DEBUG() statements disappears, so it does not affect the runtime of the +// code. // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/DebugCounter.cpp b/contrib/llvm/lib/Support/DebugCounter.cpp index 1d46de04ee6a..5a9cecfc56d4 100644 --- a/contrib/llvm/lib/Support/DebugCounter.cpp +++ b/contrib/llvm/lib/Support/DebugCounter.cpp @@ -45,7 +45,7 @@ private: // Create our command line option. static DebugCounterList DebugCounterOption( - "debug-counter", + "debug-counter", cl::Hidden, cl::desc("Comma separated list of debug counter skip and count"), cl::CommaSeparated, cl::ZeroOrMore, cl::location(DebugCounter::instance())); @@ -66,7 +66,7 @@ void DebugCounter::push_back(const std::string &Val) { } // Now we have counter=value. // First, process value. - long CounterVal; + int64_t CounterVal; if (CounterPair.second.getAsInteger(0, CounterVal)) { errs() << "DebugCounter Error: " << CounterPair.second << " is not a number\n"; @@ -76,26 +76,24 @@ void DebugCounter::push_back(const std::string &Val) { // add it to the counter values. if (CounterPair.first.endswith("-skip")) { auto CounterName = CounterPair.first.drop_back(5); - unsigned CounterID = RegisteredCounters.idFor(CounterName); + unsigned CounterID = getCounterId(CounterName); if (!CounterID) { errs() << "DebugCounter Error: " << CounterName << " is not a registered counter\n"; return; } - - auto Res = Counters.insert({CounterID, {0, -1}}); - Res.first->second.first = CounterVal; + Counters[CounterID].Skip = CounterVal; + Counters[CounterID].IsSet = true; } else if (CounterPair.first.endswith("-count")) { auto CounterName = CounterPair.first.drop_back(6); - unsigned CounterID = RegisteredCounters.idFor(CounterName); + unsigned CounterID = getCounterId(CounterName); if (!CounterID) { errs() << "DebugCounter Error: " << CounterName << " is not a registered counter\n"; return; } - - auto Res = Counters.insert({CounterID, {0, -1}}); - Res.first->second.second = CounterVal; + Counters[CounterID].StopAfter = CounterVal; + Counters[CounterID].IsSet = true; } else { errs() << "DebugCounter Error: " << CounterPair.first << " does not end with -skip or -count\n"; @@ -106,7 +104,8 @@ void DebugCounter::print(raw_ostream &OS) const { OS << "Counters and values:\n"; for (const auto &KV : Counters) OS << left_justify(RegisteredCounters[KV.first], 32) << ": {" - << KV.second.first << "," << KV.second.second << "}\n"; + << KV.second.Count << "," << KV.second.Skip << "," + << KV.second.StopAfter << "}\n"; } LLVM_DUMP_METHOD void DebugCounter::dump() const { diff --git a/contrib/llvm/lib/Support/DynamicLibrary.cpp b/contrib/llvm/lib/Support/DynamicLibrary.cpp index d8422115eae8..530e92d99a90 100644 --- a/contrib/llvm/lib/Support/DynamicLibrary.cpp +++ b/contrib/llvm/lib/Support/DynamicLibrary.cpp @@ -49,7 +49,7 @@ public: } bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true) { -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle."); #endif @@ -61,7 +61,7 @@ public: } Handles.push_back(Handle); } else { -#ifndef LLVM_ON_WIN32 +#ifndef _WIN32 if (Process) { if (CanClose) DLClose(Process); @@ -121,7 +121,7 @@ static llvm::ManagedStatic<DynamicLibrary::HandleSet> OpenedHandles; static llvm::ManagedStatic<llvm::sys::SmartMutex<true>> SymbolsMutex; } -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 #include "Windows/DynamicLibrary.inc" diff --git a/contrib/llvm/lib/Support/Error.cpp b/contrib/llvm/lib/Support/Error.cpp index c43a1fa813e2..83345bf6edb9 100644 --- a/contrib/llvm/lib/Support/Error.cpp +++ b/contrib/llvm/lib/Support/Error.cpp @@ -112,6 +112,10 @@ std::error_code StringError::convertToErrorCode() const { return EC; } +Error createStringError(std::error_code EC, char const *Msg) { + return make_error<StringError>(Msg, EC); +} + void report_fatal_error(Error Err, bool GenCrashDiag) { assert(Err && "report_fatal_error called with success value"); std::string ErrMsg; diff --git a/contrib/llvm/lib/Support/ErrorHandling.cpp b/contrib/llvm/lib/Support/ErrorHandling.cpp index fb8ae4c1cd5e..21712c5c039e 100644 --- a/contrib/llvm/lib/Support/ErrorHandling.cpp +++ b/contrib/llvm/lib/Support/ErrorHandling.cpp @@ -175,6 +175,39 @@ void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) { #endif } +#ifdef LLVM_ENABLE_EXCEPTIONS +// Do not set custom new handler if exceptions are enabled. In this case OOM +// errors are handled by throwing 'std::bad_alloc'. +void llvm::install_out_of_memory_new_handler() { +} +#else +// Causes crash on allocation failure. It is called prior to the handler set by +// 'install_bad_alloc_error_handler'. +static void out_of_memory_new_handler() { + llvm::report_bad_alloc_error("Allocation failed"); +} + +// Installs new handler that causes crash on allocation failure. It does not +// need to be called explicitly, if this file is linked to application, because +// in this case it is called during construction of 'new_handler_installer'. +void llvm::install_out_of_memory_new_handler() { + static bool out_of_memory_new_handler_installed = false; + if (!out_of_memory_new_handler_installed) { + std::set_new_handler(out_of_memory_new_handler); + out_of_memory_new_handler_installed = true; + } +} + +// Static object that causes installation of 'out_of_memory_new_handler' before +// execution of 'main'. +static class NewHandlerInstaller { +public: + NewHandlerInstaller() { + install_out_of_memory_new_handler(); + } +} new_handler_installer; +#endif + void llvm::llvm_unreachable_internal(const char *msg, const char *file, unsigned line) { // This code intentionally doesn't call the ErrorHandler callback, because @@ -210,7 +243,7 @@ void LLVMResetFatalErrorHandler() { remove_fatal_error_handler(); } -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 #include <winerror.h> diff --git a/contrib/llvm/lib/Support/FileOutputBuffer.cpp b/contrib/llvm/lib/Support/FileOutputBuffer.cpp index c4ff563e5f44..1214b5a0ba1f 100644 --- a/contrib/llvm/lib/Support/FileOutputBuffer.cpp +++ b/contrib/llvm/lib/Support/FileOutputBuffer.cpp @@ -82,9 +82,11 @@ public: size_t getBufferSize() const override { return Buffer.size(); } Error commit() override { + using namespace sys::fs; int FD; std::error_code EC; - if (auto EC = openFileForWrite(FinalPath, FD, fs::F_None, Mode)) + if (auto EC = + openFileForWrite(FinalPath, FD, CD_CreateAlways, OF_None, Mode)) return errorCodeToError(EC); raw_fd_ostream OS(FD, /*shouldClose=*/true, /*unbuffered=*/true); OS << StringRef((const char *)Buffer.base(), Buffer.size()); @@ -108,24 +110,30 @@ createInMemoryBuffer(StringRef Path, size_t Size, unsigned Mode) { } static Expected<std::unique_ptr<OnDiskBuffer>> -createOnDiskBuffer(StringRef Path, size_t Size, unsigned Mode) { +createOnDiskBuffer(StringRef Path, size_t Size, bool InitExisting, + unsigned Mode) { Expected<fs::TempFile> FileOrErr = fs::TempFile::create(Path + ".tmp%%%%%%%", Mode); if (!FileOrErr) return FileOrErr.takeError(); fs::TempFile File = std::move(*FileOrErr); -#ifndef LLVM_ON_WIN32 - // On Windows, CreateFileMapping (the mmap function on Windows) - // automatically extends the underlying file. We don't need to - // extend the file beforehand. _chsize (ftruncate on Windows) is - // pretty slow just like it writes specified amount of bytes, - // so we should avoid calling that function. - if (auto EC = fs::resize_file(File.FD, Size)) { - consumeError(File.discard()); - return errorCodeToError(EC); - } + if (InitExisting) { + if (auto EC = sys::fs::copy_file(Path, File.FD)) + return errorCodeToError(EC); + } else { +#ifndef _WIN32 + // On Windows, CreateFileMapping (the mmap function on Windows) + // automatically extends the underlying file. We don't need to + // extend the file beforehand. _chsize (ftruncate on Windows) is + // pretty slow just like it writes specified amount of bytes, + // so we should avoid calling that function. + if (auto EC = fs::resize_file(File.FD, Size)) { + consumeError(File.discard()); + return errorCodeToError(EC); + } #endif + } // Mmap it. std::error_code EC; @@ -149,6 +157,15 @@ FileOutputBuffer::create(StringRef Path, size_t Size, unsigned Flags) { fs::file_status Stat; fs::status(Path, Stat); + if ((Flags & F_modify) && Size == size_t(-1)) { + if (Stat.type() == fs::file_type::regular_file) + Size = Stat.getSize(); + else if (Stat.type() == fs::file_type::file_not_found) + return errorCodeToError(errc::no_such_file_or_directory); + else + return errorCodeToError(errc::invalid_argument); + } + // Usually, we want to create OnDiskBuffer to create a temporary file in // the same directory as the destination file and atomically replaces it // by rename(2). @@ -163,7 +180,7 @@ FileOutputBuffer::create(StringRef Path, size_t Size, unsigned Flags) { case fs::file_type::regular_file: case fs::file_type::file_not_found: case fs::file_type::status_error: - return createOnDiskBuffer(Path, Size, Mode); + return createOnDiskBuffer(Path, Size, !!(Flags & F_modify), Mode); default: return createInMemoryBuffer(Path, Size, Mode); } diff --git a/contrib/llvm/lib/Support/FoldingSet.cpp b/contrib/llvm/lib/Support/FoldingSet.cpp index 942379549039..ec7d57586e8b 100644 --- a/contrib/llvm/lib/Support/FoldingSet.cpp +++ b/contrib/llvm/lib/Support/FoldingSet.cpp @@ -214,11 +214,8 @@ static void **GetBucketFor(unsigned Hash, void **Buckets, unsigned NumBuckets) { /// AllocateBuckets - Allocated initialized bucket memory. static void **AllocateBuckets(unsigned NumBuckets) { - void **Buckets = static_cast<void**>(calloc(NumBuckets+1, sizeof(void*))); - - if (Buckets == nullptr) - report_bad_alloc_error("Allocation of Buckets failed."); - + void **Buckets = static_cast<void**>(safe_calloc(NumBuckets + 1, + sizeof(void*))); // Set the very last bucket to be a non-null "pointer". Buckets[NumBuckets] = reinterpret_cast<void*>(-1); return Buckets; diff --git a/contrib/llvm/lib/Support/GraphWriter.cpp b/contrib/llvm/lib/Support/GraphWriter.cpp index fd7fab08278e..9335daffc3e2 100644 --- a/contrib/llvm/lib/Support/GraphWriter.cpp +++ b/contrib/llvm/lib/Support/GraphWriter.cpp @@ -66,7 +66,7 @@ std::string llvm::DOT::EscapeString(const std::string &Label) { return Str; } -/// \brief Get a color string for this node number. Simply round-robin selects +/// Get a color string for this node number. Simply round-robin selects /// from a reasonable number of colors. StringRef llvm::DOT::getColorString(unsigned ColorNumber) { static const int NumColors = 20; @@ -91,20 +91,18 @@ std::string llvm::createGraphFilename(const Twine &Name, int &FD) { } // Execute the graph viewer. Return true if there were errors. -static bool ExecGraphViewer(StringRef ExecPath, std::vector<const char *> &args, +static bool ExecGraphViewer(StringRef ExecPath, std::vector<StringRef> &args, StringRef Filename, bool wait, std::string &ErrMsg) { - assert(args.back() == nullptr); if (wait) { - if (sys::ExecuteAndWait(ExecPath, args.data(), nullptr, {}, 0, 0, - &ErrMsg)) { + if (sys::ExecuteAndWait(ExecPath, args, None, {}, 0, 0, &ErrMsg)) { errs() << "Error: " << ErrMsg << "\n"; return true; } sys::fs::remove(Filename); errs() << " done. \n"; } else { - sys::ExecuteNoWait(ExecPath, args.data(), nullptr, {}, 0, &ErrMsg); + sys::ExecuteNoWait(ExecPath, args, None, {}, 0, &ErrMsg); errs() << "Remember to erase graph file: " << Filename << "\n"; } return false; @@ -158,22 +156,20 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait, #ifdef __APPLE__ wait &= !ViewBackground; if (S.TryFindProgram("open", ViewerPath)) { - std::vector<const char *> args; - args.push_back(ViewerPath.c_str()); + std::vector<StringRef> args; + args.push_back(ViewerPath); if (wait) args.push_back("-W"); - args.push_back(Filename.c_str()); - args.push_back(nullptr); + args.push_back(Filename); errs() << "Trying 'open' program... "; if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg)) return false; } #endif if (S.TryFindProgram("xdg-open", ViewerPath)) { - std::vector<const char *> args; - args.push_back(ViewerPath.c_str()); - args.push_back(Filename.c_str()); - args.push_back(nullptr); + std::vector<StringRef> args; + args.push_back(ViewerPath); + args.push_back(Filename); errs() << "Trying 'xdg-open' program... "; if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg)) return false; @@ -181,10 +177,9 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait, // Graphviz if (S.TryFindProgram("Graphviz", ViewerPath)) { - std::vector<const char *> args; - args.push_back(ViewerPath.c_str()); - args.push_back(Filename.c_str()); - args.push_back(nullptr); + std::vector<StringRef> args; + args.push_back(ViewerPath); + args.push_back(Filename); errs() << "Running 'Graphviz' program... "; return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg); @@ -192,15 +187,13 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait, // xdot if (S.TryFindProgram("xdot|xdot.py", ViewerPath)) { - std::vector<const char *> args; - args.push_back(ViewerPath.c_str()); - args.push_back(Filename.c_str()); + std::vector<StringRef> args; + args.push_back(ViewerPath); + args.push_back(Filename); args.push_back("-f"); args.push_back(getProgramName(program)); - args.push_back(nullptr); - errs() << "Running 'xdot.py' program... "; return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg); } @@ -221,7 +214,7 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait, Viewer = VK_Ghostview; if (!Viewer && S.TryFindProgram("xdg-open", ViewerPath)) Viewer = VK_XDGOpen; -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 if (!Viewer && S.TryFindProgram("cmd", ViewerPath)) { Viewer = VK_CmdStart; } @@ -235,18 +228,17 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait, std::string OutputFilename = Filename + (Viewer == VK_CmdStart ? ".pdf" : ".ps"); - std::vector<const char *> args; - args.push_back(GeneratorPath.c_str()); + std::vector<StringRef> args; + args.push_back(GeneratorPath); if (Viewer == VK_CmdStart) args.push_back("-Tpdf"); else args.push_back("-Tps"); args.push_back("-Nfontname=Courier"); args.push_back("-Gsize=7.5,10"); - args.push_back(Filename.c_str()); + args.push_back(Filename); args.push_back("-o"); - args.push_back(OutputFilename.c_str()); - args.push_back(nullptr); + args.push_back(OutputFilename); errs() << "Running '" << GeneratorPath << "' program... "; @@ -258,31 +250,30 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait, std::string StartArg; args.clear(); - args.push_back(ViewerPath.c_str()); + args.push_back(ViewerPath); switch (Viewer) { case VK_OSXOpen: args.push_back("-W"); - args.push_back(OutputFilename.c_str()); + args.push_back(OutputFilename); break; case VK_XDGOpen: wait = false; - args.push_back(OutputFilename.c_str()); + args.push_back(OutputFilename); break; case VK_Ghostview: args.push_back("--spartan"); - args.push_back(OutputFilename.c_str()); + args.push_back(OutputFilename); break; case VK_CmdStart: args.push_back("/S"); args.push_back("/C"); StartArg = (StringRef("start ") + (wait ? "/WAIT " : "") + OutputFilename).str(); - args.push_back(StartArg.c_str()); + args.push_back(StartArg); break; case VK_None: llvm_unreachable("Invalid viewer"); } - args.push_back(nullptr); ErrMsg.clear(); return ExecGraphViewer(ViewerPath, args, OutputFilename, wait, ErrMsg); @@ -290,13 +281,12 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait, // dotty if (S.TryFindProgram("dotty", ViewerPath)) { - std::vector<const char *> args; - args.push_back(ViewerPath.c_str()); - args.push_back(Filename.c_str()); - args.push_back(nullptr); + std::vector<StringRef> args; + args.push_back(ViewerPath); + args.push_back(Filename); // Dotty spawns another app and doesn't wait until it returns -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 wait = false; #endif errs() << "Running 'dotty' program... "; diff --git a/contrib/llvm/lib/Support/Host.cpp b/contrib/llvm/lib/Support/Host.cpp index 6e65b5e6c807..2c718dd3f5a8 100644 --- a/contrib/llvm/lib/Support/Host.cpp +++ b/contrib/llvm/lib/Support/Host.cpp @@ -18,7 +18,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" -#include "llvm/Config/config.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -30,7 +30,7 @@ #ifdef LLVM_ON_UNIX #include "Unix/Host.inc" #endif -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 #include "Windows/Host.inc" #endif #ifdef _MSC_VER @@ -65,8 +65,7 @@ static std::unique_ptr<llvm::MemoryBuffer> return std::move(*Text); } -StringRef sys::detail::getHostCPUNameForPowerPC( - const StringRef &ProcCpuinfoContent) { +StringRef sys::detail::getHostCPUNameForPowerPC(StringRef ProcCpuinfoContent) { // Access to the Processor Version Register (PVR) on PowerPC is privileged, // and so we must use an operating-system interface to determine the current // processor type. On Linux, this is exposed through the /proc/cpuinfo file. @@ -145,8 +144,7 @@ StringRef sys::detail::getHostCPUNameForPowerPC( .Default(generic); } -StringRef sys::detail::getHostCPUNameForARM( - const StringRef &ProcCpuinfoContent) { +StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) { // The cpuid register on arm is not accessible from user space. On Linux, // it is exposed through the /proc/cpuinfo file. @@ -250,8 +248,7 @@ StringRef sys::detail::getHostCPUNameForARM( return "generic"; } -StringRef sys::detail::getHostCPUNameForS390x( - const StringRef &ProcCpuinfoContent) { +StringRef sys::detail::getHostCPUNameForS390x(StringRef ProcCpuinfoContent) { // STIDP is a privileged operation, so use /proc/cpuinfo instead. // The "processor 0:" line comes after a fair amount of other information, @@ -654,9 +651,11 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, // Goldmont: case 0x5c: // Apollo Lake case 0x5f: // Denverton - case 0x7a: // Gemini Lake *Type = X86::INTEL_GOLDMONT; break; // "goldmont" + case 0x7a: + *Type = X86::INTEL_GOLDMONT_PLUS; + break; case 0x57: *Type = X86::INTEL_KNL; // knl break; @@ -841,9 +840,9 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, *Subtype = X86::AMDFAM15H_BDVER3; break; // "bdver3"; 30h-3Fh: Steamroller } - if (Model >= 0x10 && Model <= 0x1f) { + if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) { *Subtype = X86::AMDFAM15H_BDVER2; - break; // "bdver2"; 10h-1Fh: Piledriver + break; // "bdver2"; 02h, 10h-1Fh: Piledriver } if (Model <= 0x0f) { *Subtype = X86::AMDFAM15H_BDVER1; @@ -1062,19 +1061,19 @@ StringRef sys::getHostCPUName() { #elif defined(__linux__) && (defined(__ppc__) || defined(__powerpc__)) StringRef sys::getHostCPUName() { std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); - const StringRef& Content = P ? P->getBuffer() : ""; + StringRef Content = P ? P->getBuffer() : ""; return detail::getHostCPUNameForPowerPC(Content); } #elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) StringRef sys::getHostCPUName() { std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); - const StringRef& Content = P ? P->getBuffer() : ""; + StringRef Content = P ? P->getBuffer() : ""; return detail::getHostCPUNameForARM(Content); } #elif defined(__linux__) && defined(__s390x__) StringRef sys::getHostCPUName() { std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); - const StringRef& Content = P ? P->getBuffer() : ""; + StringRef Content = P ? P->getBuffer() : ""; return detail::getHostCPUNameForS390x(Content); } #else @@ -1206,6 +1205,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 && !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + Features["sahf"] = HasExtLeaf1 && ((ECX >> 0) & 1); Features["lzcnt"] = HasExtLeaf1 && ((ECX >> 5) & 1); Features["sse4a"] = HasExtLeaf1 && ((ECX >> 6) & 1); Features["prfchw"] = HasExtLeaf1 && ((ECX >> 8) & 1); @@ -1215,9 +1215,12 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { Features["tbm"] = HasExtLeaf1 && ((ECX >> 21) & 1); Features["mwaitx"] = HasExtLeaf1 && ((ECX >> 29) & 1); + // Miscellaneous memory related features, detected by + // using the 0x80000008 leaf of the CPUID instruction bool HasExtLeaf8 = MaxExtLevel >= 0x80000008 && !getX86CpuIDAndInfo(0x80000008, &EAX, &EBX, &ECX, &EDX); - Features["clzero"] = HasExtLeaf8 && ((EBX >> 0) & 1); + Features["clzero"] = HasExtLeaf8 && ((EBX >> 0) & 1); + Features["wbnoinvd"] = HasExtLeaf8 && ((EBX >> 9) & 1); bool HasLeaf7 = MaxLevel >= 7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); @@ -1228,6 +1231,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { // AVX2 is only supported if we have the OS save support from AVX. Features["avx2"] = HasLeaf7 && ((EBX >> 5) & 1) && HasAVXSave; Features["bmi2"] = HasLeaf7 && ((EBX >> 8) & 1); + Features["invpcid"] = HasLeaf7 && ((EBX >> 10) & 1); Features["rtm"] = HasLeaf7 && ((EBX >> 11) & 1); // AVX512 is only supported if the OS supports the context save for it. Features["avx512f"] = HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save; @@ -1247,6 +1251,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { Features["prefetchwt1"] = HasLeaf7 && ((ECX >> 0) & 1); Features["avx512vbmi"] = HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save; Features["pku"] = HasLeaf7 && ((ECX >> 4) & 1); + Features["waitpkg"] = HasLeaf7 && ((ECX >> 5) & 1); Features["avx512vbmi2"] = HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save; Features["shstk"] = HasLeaf7 && ((ECX >> 7) & 1); Features["gfni"] = HasLeaf7 && ((ECX >> 8) & 1); @@ -1255,7 +1260,22 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { Features["avx512vnni"] = HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save; Features["avx512bitalg"] = HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save; Features["avx512vpopcntdq"] = HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save; - Features["ibt"] = HasLeaf7 && ((EDX >> 20) & 1); + Features["rdpid"] = HasLeaf7 && ((ECX >> 22) & 1); + Features["cldemote"] = HasLeaf7 && ((ECX >> 25) & 1); + Features["movdiri"] = HasLeaf7 && ((ECX >> 27) & 1); + Features["movdir64b"] = HasLeaf7 && ((ECX >> 28) & 1); + + // There are two CPUID leafs which information associated with the pconfig + // instruction: + // EAX=0x7, ECX=0x0 indicates the availability of the instruction (via the 18th + // bit of EDX), while the EAX=0x1b leaf returns information on the + // availability of specific pconfig leafs. + // The target feature here only refers to the the first of these two. + // Users might need to check for the availability of specific pconfig + // leaves using cpuid, since that information is ignored while + // detecting features using the "-march=native" flag. + // For more info, see X86 ISA docs. + Features["pconfig"] = HasLeaf7 && ((EDX >> 18) & 1); bool HasLeafD = MaxLevel >= 0xd && !getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX); @@ -1265,6 +1285,11 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { Features["xsavec"] = HasLeafD && ((EAX >> 1) & 1) && HasAVXSave; Features["xsaves"] = HasLeafD && ((EAX >> 3) & 1) && HasAVXSave; + bool HasLeaf14 = MaxLevel >= 0x14 && + !getX86CpuIDAndInfoEx(0x14, 0x0, &EAX, &EBX, &ECX, &EDX); + + Features["ptwrite"] = HasLeaf14 && ((EBX >> 4) & 1); + return true; } #elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) diff --git a/contrib/llvm/lib/Support/InitLLVM.cpp b/contrib/llvm/lib/Support/InitLLVM.cpp new file mode 100644 index 000000000000..c008d0455c99 --- /dev/null +++ b/contrib/llvm/lib/Support/InitLLVM.cpp @@ -0,0 +1,52 @@ +//===-- InitLLVM.cpp -----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Signals.h" +#include <string> + +#ifdef _WIN32 +#include "Windows/WindowsSupport.h" +#endif + +using namespace llvm; +using namespace llvm::sys; + +InitLLVM::InitLLVM(int &Argc, const char **&Argv) : StackPrinter(Argc, Argv) { + sys::PrintStackTraceOnErrorSignal(Argv[0]); + +#ifdef _WIN32 + // We use UTF-8 as the internal character encoding. On Windows, + // arguments passed to main() may not be encoded in UTF-8. In order + // to reliably detect encoding of command line arguments, we use an + // Windows API to obtain arguments, convert them to UTF-8, and then + // write them back to the Argv vector. + // + // There's probably other way to do the same thing (e.g. using + // wmain() instead of main()), but this way seems less intrusive + // than that. + std::string Banner = std::string(Argv[0]) + ": "; + ExitOnError ExitOnErr(Banner); + + ExitOnErr(errorCodeToError(windows::GetCommandLineArguments(Args, Alloc))); + + // GetCommandLineArguments doesn't terminate the vector with a + // nullptr. Do it to make it compatible with the real argv. + Args.push_back(nullptr); + + Argc = Args.size() - 1; + Argv = Args.data(); +#endif +} + +InitLLVM::~InitLLVM() { llvm_shutdown(); } diff --git a/contrib/llvm/lib/Support/JSON.cpp b/contrib/llvm/lib/Support/JSON.cpp new file mode 100644 index 000000000000..a5dae7a7c2e0 --- /dev/null +++ b/contrib/llvm/lib/Support/JSON.cpp @@ -0,0 +1,693 @@ +//=== JSON.cpp - JSON value, parsing and serialization - C++ -----------*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include "llvm/Support/JSON.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Format.h" +#include <cctype> + +namespace llvm { +namespace json { + +Value &Object::operator[](const ObjectKey &K) { + return try_emplace(K, nullptr).first->getSecond(); +} +Value &Object::operator[](ObjectKey &&K) { + return try_emplace(std::move(K), nullptr).first->getSecond(); +} +Value *Object::get(StringRef K) { + auto I = find(K); + if (I == end()) + return nullptr; + return &I->second; +} +const Value *Object::get(StringRef K) const { + auto I = find(K); + if (I == end()) + return nullptr; + return &I->second; +} +llvm::Optional<std::nullptr_t> Object::getNull(StringRef K) const { + if (auto *V = get(K)) + return V->getAsNull(); + return llvm::None; +} +llvm::Optional<bool> Object::getBoolean(StringRef K) const { + if (auto *V = get(K)) + return V->getAsBoolean(); + return llvm::None; +} +llvm::Optional<double> Object::getNumber(StringRef K) const { + if (auto *V = get(K)) + return V->getAsNumber(); + return llvm::None; +} +llvm::Optional<int64_t> Object::getInteger(StringRef K) const { + if (auto *V = get(K)) + return V->getAsInteger(); + return llvm::None; +} +llvm::Optional<llvm::StringRef> Object::getString(StringRef K) const { + if (auto *V = get(K)) + return V->getAsString(); + return llvm::None; +} +const json::Object *Object::getObject(StringRef K) const { + if (auto *V = get(K)) + return V->getAsObject(); + return nullptr; +} +json::Object *Object::getObject(StringRef K) { + if (auto *V = get(K)) + return V->getAsObject(); + return nullptr; +} +const json::Array *Object::getArray(StringRef K) const { + if (auto *V = get(K)) + return V->getAsArray(); + return nullptr; +} +json::Array *Object::getArray(StringRef K) { + if (auto *V = get(K)) + return V->getAsArray(); + return nullptr; +} +bool operator==(const Object &LHS, const Object &RHS) { + if (LHS.size() != RHS.size()) + return false; + for (const auto &L : LHS) { + auto R = RHS.find(L.first); + if (R == RHS.end() || L.second != R->second) + return false; + } + return true; +} + +Array::Array(std::initializer_list<Value> Elements) { + V.reserve(Elements.size()); + for (const Value &V : Elements) { + emplace_back(nullptr); + back().moveFrom(std::move(V)); + } +} + +Value::Value(std::initializer_list<Value> Elements) + : Value(json::Array(Elements)) {} + +void Value::copyFrom(const Value &M) { + Type = M.Type; + switch (Type) { + case T_Null: + case T_Boolean: + case T_Double: + case T_Integer: + memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer)); + break; + case T_StringRef: + create<StringRef>(M.as<StringRef>()); + break; + case T_String: + create<std::string>(M.as<std::string>()); + break; + case T_Object: + create<json::Object>(M.as<json::Object>()); + break; + case T_Array: + create<json::Array>(M.as<json::Array>()); + break; + } +} + +void Value::moveFrom(const Value &&M) { + Type = M.Type; + switch (Type) { + case T_Null: + case T_Boolean: + case T_Double: + case T_Integer: + memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer)); + break; + case T_StringRef: + create<StringRef>(M.as<StringRef>()); + break; + case T_String: + create<std::string>(std::move(M.as<std::string>())); + M.Type = T_Null; + break; + case T_Object: + create<json::Object>(std::move(M.as<json::Object>())); + M.Type = T_Null; + break; + case T_Array: + create<json::Array>(std::move(M.as<json::Array>())); + M.Type = T_Null; + break; + } +} + +void Value::destroy() { + switch (Type) { + case T_Null: + case T_Boolean: + case T_Double: + case T_Integer: + break; + case T_StringRef: + as<StringRef>().~StringRef(); + break; + case T_String: + as<std::string>().~basic_string(); + break; + case T_Object: + as<json::Object>().~Object(); + break; + case T_Array: + as<json::Array>().~Array(); + break; + } +} + +bool operator==(const Value &L, const Value &R) { + if (L.kind() != R.kind()) + return false; + switch (L.kind()) { + case Value::Null: + return *L.getAsNull() == *R.getAsNull(); + case Value::Boolean: + return *L.getAsBoolean() == *R.getAsBoolean(); + case Value::Number: + return *L.getAsNumber() == *R.getAsNumber(); + case Value::String: + return *L.getAsString() == *R.getAsString(); + case Value::Array: + return *L.getAsArray() == *R.getAsArray(); + case Value::Object: + return *L.getAsObject() == *R.getAsObject(); + } + llvm_unreachable("Unknown value kind"); +} + +namespace { +// Simple recursive-descent JSON parser. +class Parser { +public: + Parser(StringRef JSON) + : Start(JSON.begin()), P(JSON.begin()), End(JSON.end()) {} + + bool checkUTF8() { + size_t ErrOffset; + if (isUTF8(StringRef(Start, End - Start), &ErrOffset)) + return true; + P = Start + ErrOffset; // For line/column calculation. + return parseError("Invalid UTF-8 sequence"); + } + + bool parseValue(Value &Out); + + bool assertEnd() { + eatWhitespace(); + if (P == End) + return true; + return parseError("Text after end of document"); + } + + Error takeError() { + assert(Err); + return std::move(*Err); + } + +private: + void eatWhitespace() { + while (P != End && (*P == ' ' || *P == '\r' || *P == '\n' || *P == '\t')) + ++P; + } + + // On invalid syntax, parseX() functions return false and set Err. + bool parseNumber(char First, Value &Out); + bool parseString(std::string &Out); + bool parseUnicode(std::string &Out); + bool parseError(const char *Msg); // always returns false + + char next() { return P == End ? 0 : *P++; } + char peek() { return P == End ? 0 : *P; } + static bool isNumber(char C) { + return C == '0' || C == '1' || C == '2' || C == '3' || C == '4' || + C == '5' || C == '6' || C == '7' || C == '8' || C == '9' || + C == 'e' || C == 'E' || C == '+' || C == '-' || C == '.'; + } + + Optional<Error> Err; + const char *Start, *P, *End; +}; + +bool Parser::parseValue(Value &Out) { + eatWhitespace(); + if (P == End) + return parseError("Unexpected EOF"); + switch (char C = next()) { + // Bare null/true/false are easy - first char identifies them. + case 'n': + Out = nullptr; + return (next() == 'u' && next() == 'l' && next() == 'l') || + parseError("Invalid JSON value (null?)"); + case 't': + Out = true; + return (next() == 'r' && next() == 'u' && next() == 'e') || + parseError("Invalid JSON value (true?)"); + case 'f': + Out = false; + return (next() == 'a' && next() == 'l' && next() == 's' && next() == 'e') || + parseError("Invalid JSON value (false?)"); + case '"': { + std::string S; + if (parseString(S)) { + Out = std::move(S); + return true; + } + return false; + } + case '[': { + Out = Array{}; + Array &A = *Out.getAsArray(); + eatWhitespace(); + if (peek() == ']') { + ++P; + return true; + } + for (;;) { + A.emplace_back(nullptr); + if (!parseValue(A.back())) + return false; + eatWhitespace(); + switch (next()) { + case ',': + eatWhitespace(); + continue; + case ']': + return true; + default: + return parseError("Expected , or ] after array element"); + } + } + } + case '{': { + Out = Object{}; + Object &O = *Out.getAsObject(); + eatWhitespace(); + if (peek() == '}') { + ++P; + return true; + } + for (;;) { + if (next() != '"') + return parseError("Expected object key"); + std::string K; + if (!parseString(K)) + return false; + eatWhitespace(); + if (next() != ':') + return parseError("Expected : after object key"); + eatWhitespace(); + if (!parseValue(O[std::move(K)])) + return false; + eatWhitespace(); + switch (next()) { + case ',': + eatWhitespace(); + continue; + case '}': + return true; + default: + return parseError("Expected , or } after object property"); + } + } + } + default: + if (isNumber(C)) + return parseNumber(C, Out); + return parseError("Invalid JSON value"); + } +} + +bool Parser::parseNumber(char First, Value &Out) { + // Read the number into a string. (Must be null-terminated for strto*). + SmallString<24> S; + S.push_back(First); + while (isNumber(peek())) + S.push_back(next()); + char *End; + // Try first to parse as integer, and if so preserve full 64 bits. + // strtoll returns long long >= 64 bits, so check it's in range too. + auto I = std::strtoll(S.c_str(), &End, 10); + if (End == S.end() && I >= std::numeric_limits<int64_t>::min() && + I <= std::numeric_limits<int64_t>::max()) { + Out = int64_t(I); + return true; + } + // If it's not an integer + Out = std::strtod(S.c_str(), &End); + return End == S.end() || parseError("Invalid JSON value (number?)"); +} + +bool Parser::parseString(std::string &Out) { + // leading quote was already consumed. + for (char C = next(); C != '"'; C = next()) { + if (LLVM_UNLIKELY(P == End)) + return parseError("Unterminated string"); + if (LLVM_UNLIKELY((C & 0x1f) == C)) + return parseError("Control character in string"); + if (LLVM_LIKELY(C != '\\')) { + Out.push_back(C); + continue; + } + // Handle escape sequence. + switch (C = next()) { + case '"': + case '\\': + case '/': + Out.push_back(C); + break; + case 'b': + Out.push_back('\b'); + break; + case 'f': + Out.push_back('\f'); + break; + case 'n': + Out.push_back('\n'); + break; + case 'r': + Out.push_back('\r'); + break; + case 't': + Out.push_back('\t'); + break; + case 'u': + if (!parseUnicode(Out)) + return false; + break; + default: + return parseError("Invalid escape sequence"); + } + } + return true; +} + +static void encodeUtf8(uint32_t Rune, std::string &Out) { + if (Rune < 0x80) { + Out.push_back(Rune & 0x7F); + } else if (Rune < 0x800) { + uint8_t FirstByte = 0xC0 | ((Rune & 0x7C0) >> 6); + uint8_t SecondByte = 0x80 | (Rune & 0x3F); + Out.push_back(FirstByte); + Out.push_back(SecondByte); + } else if (Rune < 0x10000) { + uint8_t FirstByte = 0xE0 | ((Rune & 0xF000) >> 12); + uint8_t SecondByte = 0x80 | ((Rune & 0xFC0) >> 6); + uint8_t ThirdByte = 0x80 | (Rune & 0x3F); + Out.push_back(FirstByte); + Out.push_back(SecondByte); + Out.push_back(ThirdByte); + } else if (Rune < 0x110000) { + uint8_t FirstByte = 0xF0 | ((Rune & 0x1F0000) >> 18); + uint8_t SecondByte = 0x80 | ((Rune & 0x3F000) >> 12); + uint8_t ThirdByte = 0x80 | ((Rune & 0xFC0) >> 6); + uint8_t FourthByte = 0x80 | (Rune & 0x3F); + Out.push_back(FirstByte); + Out.push_back(SecondByte); + Out.push_back(ThirdByte); + Out.push_back(FourthByte); + } else { + llvm_unreachable("Invalid codepoint"); + } +} + +// Parse a UTF-16 \uNNNN escape sequence. "\u" has already been consumed. +// May parse several sequential escapes to ensure proper surrogate handling. +// We do not use ConvertUTF.h, it can't accept and replace unpaired surrogates. +// These are invalid Unicode but valid JSON (RFC 8259, section 8.2). +bool Parser::parseUnicode(std::string &Out) { + // Invalid UTF is not a JSON error (RFC 8529§8.2). It gets replaced by U+FFFD. + auto Invalid = [&] { Out.append(/* UTF-8 */ {'\xef', '\xbf', '\xbd'}); }; + // Decodes 4 hex digits from the stream into Out, returns false on error. + auto Parse4Hex = [this](uint16_t &Out) -> bool { + Out = 0; + char Bytes[] = {next(), next(), next(), next()}; + for (unsigned char C : Bytes) { + if (!std::isxdigit(C)) + return parseError("Invalid \\u escape sequence"); + Out <<= 4; + Out |= (C > '9') ? (C & ~0x20) - 'A' + 10 : (C - '0'); + } + return true; + }; + uint16_t First; // UTF-16 code unit from the first \u escape. + if (!Parse4Hex(First)) + return false; + + // We loop to allow proper surrogate-pair error handling. + while (true) { + // Case 1: the UTF-16 code unit is already a codepoint in the BMP. + if (LLVM_LIKELY(First < 0xD800 || First >= 0xE000)) { + encodeUtf8(First, Out); + return true; + } + + // Case 2: it's an (unpaired) trailing surrogate. + if (LLVM_UNLIKELY(First >= 0xDC00)) { + Invalid(); + return true; + } + + // Case 3: it's a leading surrogate. We expect a trailing one next. + // Case 3a: there's no trailing \u escape. Don't advance in the stream. + if (LLVM_UNLIKELY(P + 2 > End || *P != '\\' || *(P + 1) != 'u')) { + Invalid(); // Leading surrogate was unpaired. + return true; + } + P += 2; + uint16_t Second; + if (!Parse4Hex(Second)) + return false; + // Case 3b: there was another \u escape, but it wasn't a trailing surrogate. + if (LLVM_UNLIKELY(Second < 0xDC00 || Second >= 0xE000)) { + Invalid(); // Leading surrogate was unpaired. + First = Second; // Second escape still needs to be processed. + continue; + } + // Case 3c: a valid surrogate pair encoding an astral codepoint. + encodeUtf8(0x10000 | ((First - 0xD800) << 10) | (Second - 0xDC00), Out); + return true; + } +} + +bool Parser::parseError(const char *Msg) { + int Line = 1; + const char *StartOfLine = Start; + for (const char *X = Start; X < P; ++X) { + if (*X == 0x0A) { + ++Line; + StartOfLine = X + 1; + } + } + Err.emplace( + llvm::make_unique<ParseError>(Msg, Line, P - StartOfLine, P - Start)); + return false; +} +} // namespace + +Expected<Value> parse(StringRef JSON) { + Parser P(JSON); + Value E = nullptr; + if (P.checkUTF8()) + if (P.parseValue(E)) + if (P.assertEnd()) + return std::move(E); + return P.takeError(); +} +char ParseError::ID = 0; + +static std::vector<const Object::value_type *> sortedElements(const Object &O) { + std::vector<const Object::value_type *> Elements; + for (const auto &E : O) + Elements.push_back(&E); + llvm::sort(Elements.begin(), Elements.end(), + [](const Object::value_type *L, const Object::value_type *R) { + return L->first < R->first; + }); + return Elements; +} + +bool isUTF8(llvm::StringRef S, size_t *ErrOffset) { + // Fast-path for ASCII, which is valid UTF-8. + if (LLVM_LIKELY(isASCII(S))) + return true; + + const UTF8 *Data = reinterpret_cast<const UTF8 *>(S.data()), *Rest = Data; + if (LLVM_LIKELY(isLegalUTF8String(&Rest, Data + S.size()))) + return true; + + if (ErrOffset) + *ErrOffset = Rest - Data; + return false; +} + +std::string fixUTF8(llvm::StringRef S) { + // This isn't particularly efficient, but is only for error-recovery. + std::vector<UTF32> Codepoints(S.size()); // 1 codepoint per byte suffices. + const UTF8 *In8 = reinterpret_cast<const UTF8 *>(S.data()); + UTF32 *Out32 = Codepoints.data(); + ConvertUTF8toUTF32(&In8, In8 + S.size(), &Out32, Out32 + Codepoints.size(), + lenientConversion); + Codepoints.resize(Out32 - Codepoints.data()); + std::string Res(4 * Codepoints.size(), 0); // 4 bytes per codepoint suffice + const UTF32 *In32 = Codepoints.data(); + UTF8 *Out8 = reinterpret_cast<UTF8 *>(&Res[0]); + ConvertUTF32toUTF8(&In32, In32 + Codepoints.size(), &Out8, Out8 + Res.size(), + strictConversion); + Res.resize(reinterpret_cast<char *>(Out8) - Res.data()); + return Res; +} + +} // namespace json +} // namespace llvm + +static void quote(llvm::raw_ostream &OS, llvm::StringRef S) { + OS << '\"'; + for (unsigned char C : S) { + if (C == 0x22 || C == 0x5C) + OS << '\\'; + if (C >= 0x20) { + OS << C; + continue; + } + OS << '\\'; + switch (C) { + // A few characters are common enough to make short escapes worthwhile. + case '\t': + OS << 't'; + break; + case '\n': + OS << 'n'; + break; + case '\r': + OS << 'r'; + break; + default: + OS << 'u'; + llvm::write_hex(OS, C, llvm::HexPrintStyle::Lower, 4); + break; + } + } + OS << '\"'; +} + +enum IndenterAction { + Indent, + Outdent, + Newline, + Space, +}; + +// Prints JSON. The indenter can be used to control formatting. +template <typename Indenter> +void llvm::json::Value::print(raw_ostream &OS, const Indenter &I) const { + switch (Type) { + case T_Null: + OS << "null"; + break; + case T_Boolean: + OS << (as<bool>() ? "true" : "false"); + break; + case T_Double: + OS << format("%.*g", std::numeric_limits<double>::max_digits10, + as<double>()); + break; + case T_Integer: + OS << as<int64_t>(); + break; + case T_StringRef: + quote(OS, as<StringRef>()); + break; + case T_String: + quote(OS, as<std::string>()); + break; + case T_Object: { + bool Comma = false; + OS << '{'; + I(Indent); + for (const auto *P : sortedElements(as<json::Object>())) { + if (Comma) + OS << ','; + Comma = true; + I(Newline); + quote(OS, P->first); + OS << ':'; + I(Space); + P->second.print(OS, I); + } + I(Outdent); + if (Comma) + I(Newline); + OS << '}'; + break; + } + case T_Array: { + bool Comma = false; + OS << '['; + I(Indent); + for (const auto &E : as<json::Array>()) { + if (Comma) + OS << ','; + Comma = true; + I(Newline); + E.print(OS, I); + } + I(Outdent); + if (Comma) + I(Newline); + OS << ']'; + break; + } + } +} + +void llvm::format_provider<llvm::json::Value>::format( + const llvm::json::Value &E, raw_ostream &OS, StringRef Options) { + if (Options.empty()) { + OS << E; + return; + } + unsigned IndentAmount = 0; + if (Options.getAsInteger(/*Radix=*/10, IndentAmount)) + llvm_unreachable("json::Value format options should be an integer"); + unsigned IndentLevel = 0; + E.print(OS, [&](IndenterAction A) { + switch (A) { + case Newline: + OS << '\n'; + OS.indent(IndentLevel); + break; + case Space: + OS << ' '; + break; + case Indent: + IndentLevel += IndentAmount; + break; + case Outdent: + IndentLevel -= IndentAmount; + break; + }; + }); +} + +llvm::raw_ostream &llvm::json::operator<<(raw_ostream &OS, const Value &E) { + E.print(OS, [](IndenterAction A) { /*ignore*/ }); + return OS; +} diff --git a/contrib/llvm/lib/Support/Locale.cpp b/contrib/llvm/lib/Support/Locale.cpp index e24a28be4306..e57d377c9ab5 100644 --- a/contrib/llvm/lib/Support/Locale.cpp +++ b/contrib/llvm/lib/Support/Locale.cpp @@ -1,6 +1,5 @@ #include "llvm/Support/Locale.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Config/llvm-config.h" #include "llvm/Support/Unicode.h" namespace llvm { @@ -8,7 +7,7 @@ namespace sys { namespace locale { int columnWidth(StringRef Text) { -#if LLVM_ON_WIN32 +#if _WIN32 return Text.size(); #else return llvm::sys::unicode::columnWidthUTF8(Text); @@ -16,7 +15,7 @@ int columnWidth(StringRef Text) { } bool isPrint(int UCS) { -#if LLVM_ON_WIN32 +#if _WIN32 // Restrict characters that we'll try to print to the lower part of ASCII // except for the control characters (0x20 - 0x7E). In general one can not // reliably output code points U+0080 and higher using narrow character C/C++ diff --git a/contrib/llvm/lib/Support/LockFileManager.cpp b/contrib/llvm/lib/Support/LockFileManager.cpp index ec951f33a36a..77baf7ac4bdd 100644 --- a/contrib/llvm/lib/Support/LockFileManager.cpp +++ b/contrib/llvm/lib/Support/LockFileManager.cpp @@ -24,7 +24,7 @@ #include <sys/types.h> #include <system_error> #include <tuple> -#if LLVM_ON_WIN32 +#if _WIN32 #include <windows.h> #endif #if LLVM_ON_UNIX @@ -43,7 +43,7 @@ using namespace llvm; -/// \brief Attempt to read the lock file with the given name, if it exists. +/// Attempt to read the lock file with the given name, if it exists. /// /// \param LockFileName The name of the lock file to read. /// @@ -123,21 +123,33 @@ bool LockFileManager::processStillExecuting(StringRef HostID, int PID) { namespace { -/// An RAII helper object for cleanups. -class RAIICleanup { - std::function<void()> Fn; - bool Canceled = false; - +/// An RAII helper object ensure that the unique lock file is removed. +/// +/// Ensures that if there is an error or a signal before we finish acquiring the +/// lock, the unique file will be removed. And if we successfully take the lock, +/// the signal handler is left in place so that signals while the lock is held +/// will remove the unique lock file. The caller should ensure there is a +/// matching call to sys::DontRemoveFileOnSignal when the lock is released. +class RemoveUniqueLockFileOnSignal { + StringRef Filename; + bool RemoveImmediately; public: - RAIICleanup(std::function<void()> Fn) : Fn(Fn) {} + RemoveUniqueLockFileOnSignal(StringRef Name) + : Filename(Name), RemoveImmediately(true) { + sys::RemoveFileOnSignal(Filename, nullptr); + } - ~RAIICleanup() { - if (Canceled) + ~RemoveUniqueLockFileOnSignal() { + if (!RemoveImmediately) { + // Leave the signal handler enabled. It will be removed when the lock is + // released. return; - Fn(); + } + sys::fs::remove(Filename); + sys::DontRemoveFileOnSignal(Filename); } - void cancel() { Canceled = true; } + void lockAcquired() { RemoveImmediately = false; } }; } // end anonymous namespace @@ -160,22 +172,16 @@ LockFileManager::LockFileManager(StringRef FileName) return; // Create a lock file that is unique to this instance. - Expected<sys::fs::TempFile> Temp = - sys::fs::TempFile::create(LockFileName + "-%%%%%%%%"); - if (!Temp) { - std::error_code EC = errorToErrorCode(Temp.takeError()); - std::string S("failed to create unique file with prefix "); - S.append(LockFileName.str()); + UniqueLockFileName = LockFileName; + UniqueLockFileName += "-%%%%%%%%"; + int UniqueLockFileID; + if (std::error_code EC = sys::fs::createUniqueFile( + UniqueLockFileName, UniqueLockFileID, UniqueLockFileName)) { + std::string S("failed to create unique file "); + S.append(UniqueLockFileName.str()); setError(EC, S); return; } - UniqueLockFile = std::move(*Temp); - - // Make sure we discard the temporary file on exit. - RAIICleanup RemoveTempFile([&]() { - if (Error E = UniqueLockFile->discard()) - setError(errorToErrorCode(std::move(E))); - }); // Write our process ID to our unique lock file. { @@ -185,46 +191,54 @@ LockFileManager::LockFileManager(StringRef FileName) return; } - raw_fd_ostream Out(UniqueLockFile->FD, /*shouldClose=*/false); + raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true); Out << HostID << ' '; #if LLVM_ON_UNIX Out << getpid(); #else Out << "1"; #endif - Out.flush(); + Out.close(); if (Out.has_error()) { // We failed to write out PID, so report the error, remove the // unique lock file, and fail. std::string S("failed to write to "); - S.append(UniqueLockFile->TmpName); + S.append(UniqueLockFileName.str()); setError(Out.error(), S); + sys::fs::remove(UniqueLockFileName); return; } } + // Clean up the unique file on signal, which also releases the lock if it is + // held since the .lock symlink will point to a nonexistent file. + RemoveUniqueLockFileOnSignal RemoveUniqueFile(UniqueLockFileName); + while (true) { // Create a link from the lock file name. If this succeeds, we're done. std::error_code EC = - sys::fs::create_link(UniqueLockFile->TmpName, LockFileName); + sys::fs::create_link(UniqueLockFileName, LockFileName); if (!EC) { - RemoveTempFile.cancel(); + RemoveUniqueFile.lockAcquired(); return; } if (EC != errc::file_exists) { std::string S("failed to create link "); raw_string_ostream OSS(S); - OSS << LockFileName.str() << " to " << UniqueLockFile->TmpName; + OSS << LockFileName.str() << " to " << UniqueLockFileName.str(); setError(EC, OSS.str()); return; } // Someone else managed to create the lock file first. Read the process ID // from the lock file. - if ((Owner = readLockFile(LockFileName))) - return; // RemoveTempFile will delete out our unique lock file. + if ((Owner = readLockFile(LockFileName))) { + // Wipe out our unique lock file (it's useless now) + sys::fs::remove(UniqueLockFileName); + return; + } if (!sys::fs::exists(LockFileName)) { // The previous owner released the lock file before we could read it. @@ -236,7 +250,7 @@ LockFileManager::LockFileManager(StringRef FileName) // ownership. if ((EC = sys::fs::remove(LockFileName))) { std::string S("failed to remove lockfile "); - S.append(LockFileName.str()); + S.append(UniqueLockFileName.str()); setError(EC, S); return; } @@ -271,14 +285,17 @@ LockFileManager::~LockFileManager() { // Since we own the lock, remove the lock file and our own unique lock file. sys::fs::remove(LockFileName); - consumeError(UniqueLockFile->discard()); + sys::fs::remove(UniqueLockFileName); + // The unique file is now gone, so remove it from the signal handler. This + // matches a sys::RemoveFileOnSignal() in LockFileManager(). + sys::DontRemoveFileOnSignal(UniqueLockFileName); } LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() { if (getState() != LFS_Shared) return Res_Success; -#if LLVM_ON_WIN32 +#if _WIN32 unsigned long Interval = 1; #else struct timespec Interval; @@ -293,7 +310,7 @@ LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() { // finish up and remove the lock file. // FIXME: Should we hook in to system APIs to get a notification when the // lock file is deleted? -#if LLVM_ON_WIN32 +#if _WIN32 Sleep(Interval); #else nanosleep(&Interval, nullptr); @@ -312,7 +329,7 @@ LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() { return Res_OwnerDied; // Exponentially increase the time we wait for the lock to be removed. -#if LLVM_ON_WIN32 +#if _WIN32 Interval *= 2; #else Interval.tv_sec *= 2; @@ -323,7 +340,7 @@ LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() { } #endif } while ( -#if LLVM_ON_WIN32 +#if _WIN32 Interval < MaxSeconds * 1000 #else Interval.tv_sec < (time_t)MaxSeconds diff --git a/contrib/llvm/lib/Support/MD5.cpp b/contrib/llvm/lib/Support/MD5.cpp index a53172279236..9b02f62912fa 100644 --- a/contrib/llvm/lib/Support/MD5.cpp +++ b/contrib/llvm/lib/Support/MD5.cpp @@ -74,7 +74,7 @@ using namespace llvm; -/// \brief This processes one or more 64-byte data blocks, but does NOT update +/// This processes one or more 64-byte data blocks, but does NOT update ///the bit counters. There are no alignment requirements. const uint8_t *MD5::body(ArrayRef<uint8_t> Data) { const uint8_t *ptr; @@ -229,7 +229,7 @@ void MD5::update(StringRef Str) { update(SVal); } -/// \brief Finish the hash and place the resulting hash into \p result. +/// Finish the hash and place the resulting hash into \p result. /// \param Result is assumed to be a minimum of 16-bytes in size. void MD5::final(MD5Result &Result) { unsigned long used, free; diff --git a/contrib/llvm/lib/Support/ManagedStatic.cpp b/contrib/llvm/lib/Support/ManagedStatic.cpp index fb7cd070c42d..1c884dc70fc9 100644 --- a/contrib/llvm/lib/Support/ManagedStatic.cpp +++ b/contrib/llvm/lib/Support/ManagedStatic.cpp @@ -28,9 +28,6 @@ static void initializeMutex() { } 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. llvm::call_once(mutex_init_flag, initializeMutex); return ManagedStaticMutex; } diff --git a/contrib/llvm/lib/Support/Memory.cpp b/contrib/llvm/lib/Support/Memory.cpp index f9a4903ad015..c245eedd2c16 100644 --- a/contrib/llvm/lib/Support/Memory.cpp +++ b/contrib/llvm/lib/Support/Memory.cpp @@ -13,13 +13,13 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Memory.h" -#include "llvm/Config/config.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Valgrind.h" // Include the platform-specific parts of this class. #ifdef LLVM_ON_UNIX #include "Unix/Memory.inc" #endif -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 #include "Windows/Memory.inc" #endif diff --git a/contrib/llvm/lib/Support/MemoryBuffer.cpp b/contrib/llvm/lib/Support/MemoryBuffer.cpp index c709fc416df6..4428c2f24e32 100644 --- a/contrib/llvm/lib/Support/MemoryBuffer.cpp +++ b/contrib/llvm/lib/Support/MemoryBuffer.cpp @@ -21,6 +21,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" +#include "llvm/Support/SmallVectorMemoryBuffer.h" #include <cassert> #include <cerrno> #include <cstring> @@ -139,15 +140,6 @@ MemoryBuffer::getMemBufferCopy(StringRef InputData, const Twine &BufferName) { return nullptr; } -std::unique_ptr<MemoryBuffer> -MemoryBuffer::getNewMemBuffer(size_t Size, StringRef BufferName) { - auto SB = WritableMemoryBuffer::getNewUninitMemBuffer(Size, BufferName); - if (!SB) - return nullptr; - memset(SB->getBufferStart(), 0, Size); - return std::move(SB); -} - ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getFileOrSTDIN(const Twine &Filename, int64_t FileSize, bool RequiresNullTerminator) { @@ -171,7 +163,7 @@ MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize, //===----------------------------------------------------------------------===// namespace { -/// \brief Memory maps a file descriptor using sys::fs::mapped_file_region. +/// Memory maps a file descriptor using sys::fs::mapped_file_region. /// /// This handles converting the offset into a legal offset on the platform. template<typename MB> @@ -193,10 +185,8 @@ class MemoryBufferMMapFile : public MB { public: MemoryBufferMMapFile(bool RequiresNullTerminator, int FD, uint64_t Len, uint64_t Offset, std::error_code &EC) - : MFR(FD, - MB::Writable ? sys::fs::mapped_file_region::priv - : sys::fs::mapped_file_region::readonly, - getLegalMapSize(Len, Offset), getLegalMapOffset(Offset), EC) { + : MFR(FD, MB::Mapmode, getLegalMapSize(Len, Offset), + getLegalMapOffset(Offset), EC) { if (!EC) { const char *Start = getStart(Len, Offset); MemoryBuffer::init(Start, Start + Len, RequiresNullTerminator); @@ -226,7 +216,7 @@ getMemoryBufferForStream(int FD, const Twine &BufferName) { // Read into Buffer until we hit EOF. do { Buffer.reserve(Buffer.size() + ChunkSize); - ReadBytes = sys::RetryAfterSignal(-1, read, FD, Buffer.end(), ChunkSize); + ReadBytes = sys::RetryAfterSignal(-1, ::read, FD, Buffer.end(), ChunkSize); if (ReadBytes == -1) return std::error_code(errno, std::generic_category()); Buffer.set_size(Buffer.size() + ReadBytes); @@ -254,7 +244,7 @@ static ErrorOr<std::unique_ptr<MB>> getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile) { int FD; - std::error_code EC = sys::fs::openFileForRead(Filename, FD); + std::error_code EC = sys::fs::openFileForRead(Filename, FD, sys::fs::OF_None); if (EC) return EC; @@ -306,6 +296,15 @@ WritableMemoryBuffer::getNewUninitMemBuffer(size_t Size, const Twine &BufferName return std::unique_ptr<WritableMemoryBuffer>(Ret); } +std::unique_ptr<WritableMemoryBuffer> +WritableMemoryBuffer::getNewMemBuffer(size_t Size, const Twine &BufferName) { + auto SB = WritableMemoryBuffer::getNewUninitMemBuffer(Size, BufferName); + if (!SB) + return nullptr; + memset(SB->getBufferStart(), 0, Size); + return SB; +} + static bool shouldUseMmap(int FD, size_t FileSize, size_t MapSize, @@ -361,6 +360,59 @@ static bool shouldUseMmap(int FD, return true; } +static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> +getReadWriteFile(const Twine &Filename, uint64_t FileSize, uint64_t MapSize, + uint64_t Offset) { + int FD; + std::error_code EC = sys::fs::openFileForReadWrite( + Filename, FD, sys::fs::CD_OpenExisting, sys::fs::OF_None); + + if (EC) + return EC; + + // Default is to map the full file. + if (MapSize == uint64_t(-1)) { + // If we don't know the file size, use fstat to find out. fstat on an open + // file descriptor is cheaper than stat on a random path. + if (FileSize == uint64_t(-1)) { + sys::fs::file_status Status; + std::error_code EC = sys::fs::status(FD, Status); + if (EC) + return EC; + + // If this not a file or a block device (e.g. it's a named pipe + // or character device), we can't mmap it, so error out. + sys::fs::file_type Type = Status.type(); + if (Type != sys::fs::file_type::regular_file && + Type != sys::fs::file_type::block_file) + return make_error_code(errc::invalid_argument); + + FileSize = Status.getSize(); + } + MapSize = FileSize; + } + + std::unique_ptr<WriteThroughMemoryBuffer> Result( + new (NamedBufferAlloc(Filename)) + MemoryBufferMMapFile<WriteThroughMemoryBuffer>(false, FD, MapSize, + Offset, EC)); + if (EC) + return EC; + return std::move(Result); +} + +ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> +WriteThroughMemoryBuffer::getFile(const Twine &Filename, int64_t FileSize) { + return getReadWriteFile(Filename, FileSize, FileSize, 0); +} + +/// Map a subrange of the specified file as a WritableMemoryBuffer. +ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> +WriteThroughMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize, + uint64_t Offset) { + return getReadWriteFile(Filename, -1, MapSize, Offset); +} + template <typename MB> static ErrorOr<std::unique_ptr<MB>> getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, @@ -466,7 +518,7 @@ ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() { ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getFileAsStream(const Twine &Filename) { int FD; - std::error_code EC = sys::fs::openFileForRead(Filename, FD); + std::error_code EC = sys::fs::openFileForRead(Filename, FD, sys::fs::OF_None); if (EC) return EC; ErrorOr<std::unique_ptr<MemoryBuffer>> Ret = @@ -480,3 +532,6 @@ MemoryBufferRef MemoryBuffer::getMemBufferRef() const { StringRef Identifier = getBufferIdentifier(); return MemoryBufferRef(Data, Identifier); } + +void MemoryBuffer::anchor() {} +void SmallVectorMemoryBuffer::anchor() {} diff --git a/contrib/llvm/lib/Support/Mutex.cpp b/contrib/llvm/lib/Support/Mutex.cpp index b1d5e7c0d991..7138c7a4b984 100644 --- a/contrib/llvm/lib/Support/Mutex.cpp +++ b/contrib/llvm/lib/Support/Mutex.cpp @@ -12,8 +12,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Mutex.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Config/config.h" +#include "llvm/Support/ErrorHandling.h" //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only TRULY operating system @@ -47,10 +47,7 @@ MutexImpl::MutexImpl( bool recursive) { // Declare the pthread_mutex data structures pthread_mutex_t* mutex = - static_cast<pthread_mutex_t*>(malloc(sizeof(pthread_mutex_t))); - - if (mutex == nullptr) - report_bad_alloc_error("Mutex allocation failed"); + static_cast<pthread_mutex_t*>(safe_malloc(sizeof(pthread_mutex_t))); pthread_mutexattr_t attr; @@ -119,9 +116,9 @@ MutexImpl::tryacquire() #elif defined(LLVM_ON_UNIX) #include "Unix/Mutex.inc" -#elif defined( LLVM_ON_WIN32) +#elif defined( _WIN32) #include "Windows/Mutex.inc" #else -#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in Support/Mutex.cpp +#warning Neither LLVM_ON_UNIX nor _WIN32 was set in Support/Mutex.cpp #endif #endif diff --git a/contrib/llvm/lib/Support/NativeFormatting.cpp b/contrib/llvm/lib/Support/NativeFormatting.cpp index b951a88a38db..85b4bfb81568 100644 --- a/contrib/llvm/lib/Support/NativeFormatting.cpp +++ b/contrib/llvm/lib/Support/NativeFormatting.cpp @@ -14,6 +14,8 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Format.h" +#include <float.h> + using namespace llvm; template<typename T, std::size_t N> diff --git a/contrib/llvm/lib/Support/Parallel.cpp b/contrib/llvm/lib/Support/Parallel.cpp index 010e42916f95..1844003b9d3d 100644 --- a/contrib/llvm/lib/Support/Parallel.cpp +++ b/contrib/llvm/lib/Support/Parallel.cpp @@ -9,6 +9,9 @@ #include "llvm/Support/Parallel.h" #include "llvm/Config/llvm-config.h" + +#if LLVM_ENABLE_THREADS + #include "llvm/Support/Threading.h" #include <atomic> @@ -19,7 +22,7 @@ using namespace llvm; namespace { -/// \brief An abstract class that takes closures and runs them asynchronously. +/// An abstract class that takes closures and runs them asynchronously. class Executor { public: virtual ~Executor() = default; @@ -28,19 +31,8 @@ public: static Executor *getDefaultExecutor(); }; -#if !LLVM_ENABLE_THREADS -class SyncExecutor : public Executor { -public: - virtual void add(std::function<void()> F) { F(); } -}; - -Executor *Executor::getDefaultExecutor() { - static SyncExecutor Exec; - return &Exec; -} - -#elif defined(_MSC_VER) -/// \brief An Executor that runs tasks via ConcRT. +#if defined(_MSC_VER) +/// An Executor that runs tasks via ConcRT. class ConcRTExecutor : public Executor { struct Taskish { Taskish(std::function<void()> Task) : Task(Task) {} @@ -67,7 +59,7 @@ Executor *Executor::getDefaultExecutor() { } #else -/// \brief An implementation of an Executor that runs closures on a thread pool +/// An implementation of an Executor that runs closures on a thread pool /// in filo order. class ThreadPoolExecutor : public Executor { public: @@ -127,7 +119,6 @@ Executor *Executor::getDefaultExecutor() { #endif } -#if LLVM_ENABLE_THREADS void parallel::detail::TaskGroup::spawn(std::function<void()> F) { L.inc(); Executor::getDefaultExecutor()->add([&, F] { @@ -135,4 +126,4 @@ void parallel::detail::TaskGroup::spawn(std::function<void()> F) { L.dec(); }); } -#endif +#endif // LLVM_ENABLE_THREADS diff --git a/contrib/llvm/lib/Support/Path.cpp b/contrib/llvm/lib/Support/Path.cpp index f229f23a4f84..a806da23ec50 100644 --- a/contrib/llvm/lib/Support/Path.cpp +++ b/contrib/llvm/lib/Support/Path.cpp @@ -13,6 +13,7 @@ #include "llvm/Support/Path.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" @@ -37,7 +38,7 @@ namespace { using llvm::sys::path::Style; inline Style real_style(Style style) { -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 return (style == Style::posix) ? Style::posix : Style::windows; #else return (style == Style::windows) ? Style::windows : Style::posix; @@ -90,10 +91,9 @@ namespace { return path.substr(0, end); } + // Returns the first character of the filename in str. For paths ending in + // '/', it returns the position of the '/'. size_t filename_pos(StringRef str, Style style) { - if (str.size() == 2 && is_separator(str[0], style) && str[0] == str[1]) - return 0; - if (str.size() > 0 && is_separator(str[str.size() - 1], style)) return str.size() - 1; @@ -110,6 +110,8 @@ namespace { return pos + 1; } + // Returns the position of the root directory in str. If there is no root + // directory in str, it returns StringRef::npos. size_t root_dir_start(StringRef str, Style style) { // case "c:/" if (real_style(style) == Style::windows) { @@ -117,10 +119,6 @@ namespace { return 2; } - // case "//" - if (str.size() == 2 && is_separator(str[0], style) && str[0] == str[1]) - return StringRef::npos; - // case "//net" if (str.size() > 3 && is_separator(str[0], style) && str[0] == str[1] && !is_separator(str[2], style)) { @@ -134,22 +132,29 @@ namespace { return StringRef::npos; } + // Returns the position past the end of the "parent path" of path. The parent + // path will not end in '/', unless the parent is the root directory. If the + // path has no parent, 0 is returned. size_t parent_path_end(StringRef path, Style style) { size_t end_pos = filename_pos(path, style); bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos], style); - // Skip separators except for root dir. - size_t root_dir_pos = root_dir_start(path.substr(0, end_pos), style); - - while (end_pos > 0 && (end_pos - 1) != root_dir_pos && + // Skip separators until we reach root dir (or the start of the string). + size_t root_dir_pos = root_dir_start(path, style); + while (end_pos > 0 && + (root_dir_pos == StringRef::npos || end_pos > root_dir_pos) && is_separator(path[end_pos - 1], style)) --end_pos; - if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) - return StringRef::npos; + if (end_pos == root_dir_pos && !filename_was_sep) { + // We've reached the root dir and the input path was *not* ending in a + // sequence of slashes. Include the root dir in the parent path. + return root_dir_pos + 1; + } + // Otherwise, just include before the last slash. return end_pos; } } // end unnamed namespace @@ -164,7 +169,7 @@ static std::error_code createUniqueEntity(const Twine &Model, int &ResultFD, SmallVectorImpl<char> &ResultPath, bool MakeAbsolute, unsigned Mode, FSEntity Type, - sys::fs::OpenFlags Flags = sys::fs::F_None) { + sys::fs::OpenFlags Flags = sys::fs::OF_None) { SmallString<128> ModelStorage; Model.toVector(ModelStorage); @@ -196,8 +201,8 @@ retry_random_path: switch (Type) { case FS_File: { if (std::error_code EC = - sys::fs::openFileForWrite(Twine(ResultPath.begin()), ResultFD, - Flags | sys::fs::F_Excl, Mode)) { + sys::fs::openFileForReadWrite(Twine(ResultPath.begin()), ResultFD, + sys::fs::CD_CreateNew, Flags, Mode)) { if (EC == errc::file_exists) goto retry_random_path; return EC; @@ -281,8 +286,8 @@ const_iterator &const_iterator::operator++() { ++Position; } - // Treat trailing '/' as a '.'. - if (Position == Path.size()) { + // Treat trailing '/' as a '.', unless it is the root dir. + if (Position == Path.size() && Component != "/") { --Position; Component = "."; return *this; @@ -321,23 +326,23 @@ reverse_iterator rend(StringRef Path) { } reverse_iterator &reverse_iterator::operator++() { - // If we're at the end and the previous char was a '/', return '.' unless - // we are the root path. size_t root_dir_pos = root_dir_start(Path, S); - if (Position == Path.size() && Path.size() > root_dir_pos + 1 && - is_separator(Path[Position - 1], S)) { - --Position; - Component = "."; - return *this; - } // Skip separators unless it's the root directory. size_t end_pos = Position; - while (end_pos > 0 && (end_pos - 1) != root_dir_pos && is_separator(Path[end_pos - 1], S)) --end_pos; + // Treat trailing '/' as a '.', unless it is the root dir. + if (Position == Path.size() && !Path.empty() && + is_separator(Path.back(), S) && + (root_dir_pos == StringRef::npos || end_pos - 1 > root_dir_pos)) { + --Position; + Component = "."; + return *this; + } + // Find next separator. size_t start_pos = filename_pos(Path.substr(0, end_pos), S); Component = Path.slice(start_pos, end_pos); @@ -751,51 +756,64 @@ std::error_code getUniqueID(const Twine Path, UniqueID &Result) { std::error_code createUniqueFile(const Twine &Model, int &ResultFd, SmallVectorImpl<char> &ResultPath, - unsigned Mode, sys::fs::OpenFlags Flags) { + unsigned Mode) { + return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File); +} + +static std::error_code createUniqueFile(const Twine &Model, int &ResultFd, + SmallVectorImpl<char> &ResultPath, + unsigned Mode, OpenFlags Flags) { return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File, Flags); } std::error_code createUniqueFile(const Twine &Model, - SmallVectorImpl<char> &ResultPath) { - int Dummy; - return createUniqueEntity(Model, Dummy, ResultPath, false, 0, FS_Name); + SmallVectorImpl<char> &ResultPath, + unsigned Mode) { + int FD; + auto EC = createUniqueFile(Model, FD, ResultPath, Mode); + if (EC) + return EC; + // FD is only needed to avoid race conditions. Close it right away. + close(FD); + return EC; } static std::error_code createTemporaryFile(const Twine &Model, int &ResultFD, - llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type, - sys::fs::OpenFlags Flags) { + llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) { SmallString<128> Storage; StringRef P = Model.toNullTerminatedStringRef(Storage); assert(P.find_first_of(separators(Style::native)) == StringRef::npos && "Model must be a simple filename."); // Use P.begin() so that createUniqueEntity doesn't need to recreate Storage. return createUniqueEntity(P.begin(), ResultFD, ResultPath, true, - owner_read | owner_write, Type, Flags); + owner_read | owner_write, Type); } static std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD, - llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type, - sys::fs::OpenFlags Flags = sys::fs::F_None) { + llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) { const char *Middle = Suffix.empty() ? "-%%%%%%" : "-%%%%%%."; return createTemporaryFile(Prefix + Middle + Suffix, ResultFD, ResultPath, - Type, Flags); + Type); } std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD, - SmallVectorImpl<char> &ResultPath, - sys::fs::OpenFlags Flags) { - return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File, - Flags); + SmallVectorImpl<char> &ResultPath) { + return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File); } std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, SmallVectorImpl<char> &ResultPath) { - int Dummy; - return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name); + int FD; + auto EC = createTemporaryFile(Prefix, Suffix, FD, ResultPath); + if (EC) + return EC; + // FD is only needed to avoid race conditions. Close it right away. + close(FD); + return EC; } @@ -804,8 +822,22 @@ std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, std::error_code createUniqueDirectory(const Twine &Prefix, SmallVectorImpl<char> &ResultPath) { int Dummy; - return createUniqueEntity(Prefix + "-%%%%%%", Dummy, ResultPath, - true, 0, FS_Dir); + return createUniqueEntity(Prefix + "-%%%%%%", Dummy, ResultPath, true, 0, + FS_Dir); +} + +std::error_code +getPotentiallyUniqueFileName(const Twine &Model, + SmallVectorImpl<char> &ResultPath) { + int Dummy; + return createUniqueEntity(Model, Dummy, ResultPath, false, 0, FS_Name); +} + +std::error_code +getPotentiallyUniqueTempFileName(const Twine &Prefix, StringRef Suffix, + SmallVectorImpl<char> &ResultPath) { + int Dummy; + return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name); } static std::error_code make_absolute(const Twine ¤t_directory, @@ -895,15 +927,7 @@ std::error_code create_directories(const Twine &Path, bool IgnoreExisting, return create_directory(P, IgnoreExisting, Perms); } -std::error_code copy_file(const Twine &From, const Twine &To) { - int ReadFD, WriteFD; - if (std::error_code EC = openFileForRead(From, ReadFD)) - return EC; - if (std::error_code EC = openFileForWrite(To, WriteFD, F_None)) { - close(ReadFD); - return EC; - } - +static std::error_code copy_file_internal(int ReadFD, int WriteFD) { const size_t BufSize = 4096; char *Buf = new char[BufSize]; int BytesRead = 0, BytesWritten = 0; @@ -920,8 +944,6 @@ std::error_code copy_file(const Twine &From, const Twine &To) { if (BytesWritten < 0) break; } - close(ReadFD); - close(WriteFD); delete[] Buf; if (BytesRead < 0 || BytesWritten < 0) @@ -929,6 +951,36 @@ std::error_code copy_file(const Twine &From, const Twine &To) { return std::error_code(); } +std::error_code copy_file(const Twine &From, const Twine &To) { + int ReadFD, WriteFD; + if (std::error_code EC = openFileForRead(From, ReadFD, OF_None)) + return EC; + if (std::error_code EC = + openFileForWrite(To, WriteFD, CD_CreateAlways, OF_None)) { + close(ReadFD); + return EC; + } + + std::error_code EC = copy_file_internal(ReadFD, WriteFD); + + close(ReadFD); + close(WriteFD); + + return EC; +} + +std::error_code copy_file(const Twine &From, int ToFD) { + int ReadFD; + if (std::error_code EC = openFileForRead(From, ReadFD, OF_None)) + return EC; + + std::error_code EC = copy_file_internal(ReadFD, ToFD); + + close(ReadFD); + + return EC; +} + ErrorOr<MD5::MD5Result> md5_contents(int FD) { MD5 Hash; @@ -951,7 +1003,7 @@ ErrorOr<MD5::MD5Result> md5_contents(int FD) { ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path) { int FD; - if (auto EC = openFileForRead(Path, FD)) + if (auto EC = openFileForRead(Path, FD, OF_None)) return EC; auto Result = md5_contents(FD); @@ -1048,7 +1100,7 @@ ErrorOr<perms> getPermissions(const Twine &Path) { #if defined(LLVM_ON_UNIX) #include "Unix/Path.inc" #endif -#if defined(LLVM_ON_WIN32) +#if defined(_WIN32) #include "Windows/Path.inc" #endif @@ -1070,7 +1122,7 @@ Error TempFile::discard() { Done = true; std::error_code RemoveEC; // On windows closing will remove the file. -#ifndef LLVM_ON_WIN32 +#ifndef _WIN32 // Always try to close and remove. if (!TmpName.empty()) { RemoveEC = fs::remove(TmpName); @@ -1094,14 +1146,15 @@ Error TempFile::keep(const Twine &Name) { assert(!Done); Done = true; // Always try to close and rename. -#ifdef LLVM_ON_WIN32 - // If we cant't cancel the delete don't rename. - std::error_code RenameEC = cancelDeleteOnClose(FD); +#ifdef _WIN32 + // If we can't cancel the delete don't rename. + auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + std::error_code RenameEC = setDeleteDisposition(H, false); if (!RenameEC) RenameEC = rename_fd(FD, Name); // If we can't rename, discard the temporary file. if (RenameEC) - removeFD(FD); + setDeleteDisposition(H, true); #else std::error_code RenameEC = fs::rename(TmpName, Name); // If we can't rename, discard the temporary file. @@ -1126,8 +1179,9 @@ Error TempFile::keep() { assert(!Done); Done = true; -#ifdef LLVM_ON_WIN32 - if (std::error_code EC = cancelDeleteOnClose(FD)) +#ifdef _WIN32 + auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + if (std::error_code EC = setDeleteDisposition(H, false)) return errorCodeToError(EC); #else sys::DontRemoveFileOnSignal(TmpName); @@ -1147,12 +1201,12 @@ Error TempFile::keep() { Expected<TempFile> TempFile::create(const Twine &Model, unsigned Mode) { int FD; SmallString<128> ResultPath; - if (std::error_code EC = createUniqueFile(Model, FD, ResultPath, Mode, - sys::fs::F_RW | sys::fs::F_Delete)) + if (std::error_code EC = + createUniqueFile(Model, FD, ResultPath, Mode, OF_Delete)) return errorCodeToError(EC); TempFile Ret(ResultPath, FD); -#ifndef LLVM_ON_WIN32 +#ifndef _WIN32 if (sys::RemoveFileOnSignal(ResultPath)) { // Make sure we delete the file when RemoveFileOnSignal fails. consumeError(Ret.discard()); diff --git a/contrib/llvm/lib/Support/PrettyStackTrace.cpp b/contrib/llvm/lib/Support/PrettyStackTrace.cpp index a18e9cc50040..f5b6e6f3652d 100644 --- a/contrib/llvm/lib/Support/PrettyStackTrace.cpp +++ b/contrib/llvm/lib/Support/PrettyStackTrace.cpp @@ -88,7 +88,11 @@ extern "C" { CRASH_REPORTER_CLIENT_HIDDEN struct crashreporter_annotations_t gCRAnnotations __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) +#if CRASHREPORTER_ANNOTATIONS_VERSION < 5 = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0 }; +#else + = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0, 0 }; +#endif } #elif defined(__APPLE__) && HAVE_CRASHREPORTER_INFO extern "C" const char *__crashreporter_info__ @@ -114,9 +118,9 @@ static void CrashHandler(void *) { if (!TmpStr.empty()) { #ifdef HAVE_CRASHREPORTERCLIENT_H // Cast to void to avoid warning. - (void)CRSetCrashLogMessage(std::string(TmpStr.str()).c_str()); + (void)CRSetCrashLogMessage(TmpStr.c_str()); #elif HAVE_CRASHREPORTER_INFO - __crashreporter_info__ = strdup(std::string(TmpStr.str()).c_str()); + __crashreporter_info__ = strdup(TmpStr.c_str()); #endif errs() << TmpStr.str(); } diff --git a/contrib/llvm/lib/Support/Process.cpp b/contrib/llvm/lib/Support/Process.cpp index 1c8cc6e83ad1..3f5a9d722ca0 100644 --- a/contrib/llvm/lib/Support/Process.cpp +++ b/contrib/llvm/lib/Support/Process.cpp @@ -14,7 +14,7 @@ #include "llvm/Support/Process.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Config/config.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" @@ -93,6 +93,6 @@ bool Process::AreCoreFilesPrevented() { #ifdef LLVM_ON_UNIX #include "Unix/Process.inc" #endif -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 #include "Windows/Process.inc" #endif diff --git a/contrib/llvm/lib/Support/Program.cpp b/contrib/llvm/lib/Support/Program.cpp index 4212323bc0e1..63cdcdaabee9 100644 --- a/contrib/llvm/lib/Support/Program.cpp +++ b/contrib/llvm/lib/Support/Program.cpp @@ -13,7 +13,7 @@ #include "llvm/Support/Program.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Config/config.h" +#include "llvm/Config/llvm-config.h" #include <system_error> using namespace llvm; using namespace sys; @@ -23,17 +23,19 @@ using namespace sys; //=== independent code. //===----------------------------------------------------------------------===// -static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, - const char **Env, ArrayRef<Optional<StringRef>> Redirects, +static bool Execute(ProcessInfo &PI, StringRef Program, + ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env, + ArrayRef<Optional<StringRef>> Redirects, unsigned MemoryLimit, std::string *ErrMsg); -int sys::ExecuteAndWait(StringRef Program, const char **Args, const char **Envp, +int sys::ExecuteAndWait(StringRef Program, ArrayRef<StringRef> Args, + Optional<ArrayRef<StringRef>> Env, ArrayRef<Optional<StringRef>> Redirects, unsigned SecondsToWait, unsigned MemoryLimit, std::string *ErrMsg, bool *ExecutionFailed) { assert(Redirects.empty() || Redirects.size() == 3); ProcessInfo PI; - if (Execute(PI, Program, Args, Envp, Redirects, MemoryLimit, ErrMsg)) { + if (Execute(PI, Program, Args, Env, Redirects, MemoryLimit, ErrMsg)) { if (ExecutionFailed) *ExecutionFailed = false; ProcessInfo Result = Wait( @@ -47,8 +49,8 @@ int sys::ExecuteAndWait(StringRef Program, const char **Args, const char **Envp, return -1; } -ProcessInfo sys::ExecuteNoWait(StringRef Program, const char **Args, - const char **Envp, +ProcessInfo sys::ExecuteNoWait(StringRef Program, ArrayRef<StringRef> Args, + Optional<ArrayRef<StringRef>> Env, ArrayRef<Optional<StringRef>> Redirects, unsigned MemoryLimit, std::string *ErrMsg, bool *ExecutionFailed) { @@ -56,17 +58,26 @@ ProcessInfo sys::ExecuteNoWait(StringRef Program, const char **Args, ProcessInfo PI; if (ExecutionFailed) *ExecutionFailed = false; - if (!Execute(PI, Program, Args, Envp, Redirects, MemoryLimit, ErrMsg)) + if (!Execute(PI, Program, Args, Env, Redirects, MemoryLimit, ErrMsg)) if (ExecutionFailed) *ExecutionFailed = true; return PI; } +bool sys::commandLineFitsWithinSystemLimits(StringRef Program, + ArrayRef<const char *> Args) { + SmallVector<StringRef, 8> StringRefArgs; + StringRefArgs.reserve(Args.size()); + for (const char *A : Args) + StringRefArgs.emplace_back(A); + return commandLineFitsWithinSystemLimits(Program, StringRefArgs); +} + // Include the platform-specific parts of this class. #ifdef LLVM_ON_UNIX #include "Unix/Program.inc" #endif -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 #include "Windows/Program.inc" #endif diff --git a/contrib/llvm/lib/Support/RWMutex.cpp b/contrib/llvm/lib/Support/RWMutex.cpp index 83c6d1d52b4c..8b6d74e49f31 100644 --- a/contrib/llvm/lib/Support/RWMutex.cpp +++ b/contrib/llvm/lib/Support/RWMutex.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Support/Allocator.h" #include "llvm/Support/RWMutex.h" #include "llvm/Config/config.h" @@ -49,7 +50,7 @@ RWMutexImpl::RWMutexImpl() { // Declare the pthread_rwlock data structures pthread_rwlock_t* rwlock = - static_cast<pthread_rwlock_t*>(malloc(sizeof(pthread_rwlock_t))); + static_cast<pthread_rwlock_t*>(safe_malloc(sizeof(pthread_rwlock_t))); #ifdef __APPLE__ // Workaround a bug/mis-feature in Darwin's pthread_rwlock_init. @@ -116,9 +117,9 @@ RWMutexImpl::writer_release() #elif defined(LLVM_ON_UNIX) #include "Unix/RWMutex.inc" -#elif defined( LLVM_ON_WIN32) +#elif defined( _WIN32) #include "Windows/RWMutex.inc" #else -#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in Support/Mutex.cpp +#warning Neither LLVM_ON_UNIX nor _WIN32 was set in Support/Mutex.cpp #endif #endif diff --git a/contrib/llvm/lib/Support/RandomNumberGenerator.cpp b/contrib/llvm/lib/Support/RandomNumberGenerator.cpp index 47d20159200b..f1f22af82a81 100644 --- a/contrib/llvm/lib/Support/RandomNumberGenerator.cpp +++ b/contrib/llvm/lib/Support/RandomNumberGenerator.cpp @@ -17,7 +17,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 #include "Windows/WindowsSupport.h" #else #include "Unix/Unix.h" @@ -36,10 +36,8 @@ static cl::opt<unsigned long long> cl::desc("Seed for the random number generator"), cl::init(0)); RandomNumberGenerator::RandomNumberGenerator(StringRef Salt) { - DEBUG( - if (Seed == 0) - dbgs() << "Warning! Using unseeded random number generator.\n" - ); + LLVM_DEBUG(if (Seed == 0) dbgs() + << "Warning! Using unseeded random number generator.\n"); // Combine seed and salts using std::seed_seq. // Data: Seed-low, Seed-high, Salt @@ -63,7 +61,7 @@ RandomNumberGenerator::result_type RandomNumberGenerator::operator()() { // Get random vector of specified size std::error_code llvm::getRandomBytes(void *Buffer, size_t Size) { -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 HCRYPTPROV hProvider; if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { diff --git a/contrib/llvm/lib/Support/Regex.cpp b/contrib/llvm/lib/Support/Regex.cpp index b1087fd8853c..48caab131526 100644 --- a/contrib/llvm/lib/Support/Regex.cpp +++ b/contrib/llvm/lib/Support/Regex.cpp @@ -12,11 +12,16 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Regex.h" -#include "regex_impl.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include <string> + +// Important this comes last because it defines "_REGEX_H_". At least on +// Darwin, if included before any header that (transitively) includes +// xlocale.h, this will cause trouble, because of missing regex-related types. +#include "regex_impl.h" + using namespace llvm; Regex::Regex() : preg(nullptr), error(REG_BADPAT) {} @@ -25,7 +30,7 @@ Regex::Regex(StringRef regex, unsigned Flags) { unsigned flags = 0; preg = new llvm_regex(); preg->re_endp = regex.end(); - if (Flags & IgnoreCase) + if (Flags & IgnoreCase) flags |= REG_ICASE; if (Flags & Newline) flags |= REG_NEWLINE; @@ -51,9 +56,9 @@ Regex::~Regex() { bool Regex::isValid(std::string &Error) const { if (!error) return true; - + size_t len = llvm_regerror(error, preg, nullptr, 0); - + Error.resize(len - 1); llvm_regerror(error, preg, &Error[0], len); return false; @@ -91,7 +96,7 @@ bool Regex::match(StringRef String, SmallVectorImpl<StringRef> *Matches){ if (Matches) { // match position requested Matches->clear(); - + for (unsigned i = 0; i != nmatch; ++i) { if (pm[i].rm_so == -1) { // this group didn't match diff --git a/contrib/llvm/lib/Support/SHA1.cpp b/contrib/llvm/lib/Support/SHA1.cpp index 20f41c5ff447..3007a78d5e22 100644 --- a/contrib/llvm/lib/Support/SHA1.cpp +++ b/contrib/llvm/lib/Support/SHA1.cpp @@ -1,4 +1,4 @@ -//======- SHA1.h - Private copy of the SHA1 implementation ---*- C++ -* ======// +//====- SHA1.cpp - Private copy of the SHA1 implementation ---*- C++ -* ======// // // The LLVM Compiler Infrastructure // diff --git a/contrib/llvm/lib/Support/Signals.cpp b/contrib/llvm/lib/Support/Signals.cpp index 661f4d649cdd..6534ff69b84c 100644 --- a/contrib/llvm/lib/Support/Signals.cpp +++ b/contrib/llvm/lib/Support/Signals.cpp @@ -15,7 +15,7 @@ #include "llvm/Support/Signals.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Config/config.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" @@ -36,19 +36,55 @@ using namespace llvm; -static cl::opt<bool> +// Use explicit storage to avoid accessing cl::opt in a signal handler. +static bool DisableSymbolicationFlag = false; +static cl::opt<bool, true> DisableSymbolication("disable-symbolication", cl::desc("Disable symbolizing crash backtraces."), - cl::init(false), cl::Hidden); - -static ManagedStatic<std::vector<std::pair<void (*)(void *), void *>>> - CallBacksToRun; + cl::location(DisableSymbolicationFlag), cl::Hidden); + +// Callbacks to run in signal handler must be lock-free because a signal handler +// could be running as we add new callbacks. We don't add unbounded numbers of +// callbacks, an array is therefore sufficient. +struct CallbackAndCookie { + sys::SignalHandlerCallback Callback; + void *Cookie; + enum class Status { Empty, Initializing, Initialized, Executing }; + std::atomic<Status> Flag; +}; +static constexpr size_t MaxSignalHandlerCallbacks = 8; +static CallbackAndCookie CallBacksToRun[MaxSignalHandlerCallbacks]; + +// Signal-safe. void sys::RunSignalHandlers() { - if (!CallBacksToRun.isConstructed()) + for (size_t I = 0; I < MaxSignalHandlerCallbacks; ++I) { + auto &RunMe = CallBacksToRun[I]; + auto Expected = CallbackAndCookie::Status::Initialized; + auto Desired = CallbackAndCookie::Status::Executing; + if (!RunMe.Flag.compare_exchange_strong(Expected, Desired)) + continue; + (*RunMe.Callback)(RunMe.Cookie); + RunMe.Callback = nullptr; + RunMe.Cookie = nullptr; + RunMe.Flag.store(CallbackAndCookie::Status::Empty); + } +} + +// Signal-safe. +static void insertSignalHandler(sys::SignalHandlerCallback FnPtr, + void *Cookie) { + for (size_t I = 0; I < MaxSignalHandlerCallbacks; ++I) { + auto &SetMe = CallBacksToRun[I]; + auto Expected = CallbackAndCookie::Status::Empty; + auto Desired = CallbackAndCookie::Status::Initializing; + if (!SetMe.Flag.compare_exchange_strong(Expected, Desired)) + continue; + SetMe.Callback = FnPtr; + SetMe.Cookie = Cookie; + SetMe.Flag.store(CallbackAndCookie::Status::Initialized); return; - for (auto &I : *CallBacksToRun) - I.first(I.second); - CallBacksToRun->clear(); + } + report_fatal_error("too many signal callbacks already registered"); } static bool findModulesAndOffsets(void **StackTrace, int Depth, @@ -64,16 +100,11 @@ static FormattedNumber format_ptr(void *PC) { return format_hex((uint64_t)PC, PtrWidth); } -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(StringRef Argv0, - void **StackTrace, int Depth, - llvm::raw_ostream &OS) { - if (DisableSymbolication) +LLVM_ATTRIBUTE_USED +static bool printSymbolizedStackTrace(StringRef Argv0, void **StackTrace, + int Depth, llvm::raw_ostream &OS) { + if (DisableSymbolicationFlag) return false; // Don't recursively invoke the llvm-symbolizer binary. @@ -123,17 +154,18 @@ static bool printSymbolizedStackTrace(StringRef Argv0, } } - Optional<StringRef> Redirects[] = {InputFile.str(), OutputFile.str(), llvm::None}; - const char *Args[] = {"llvm-symbolizer", "--functions=linkage", "--inlining", -#ifdef LLVM_ON_WIN32 - // Pass --relative-address on Windows so that we don't - // have to add ImageBase from PE file. - // FIXME: Make this the default for llvm-symbolizer. - "--relative-address", + Optional<StringRef> Redirects[] = {StringRef(InputFile), + StringRef(OutputFile), llvm::None}; + StringRef Args[] = {"llvm-symbolizer", "--functions=linkage", "--inlining", +#ifdef _WIN32 + // Pass --relative-address on Windows so that we don't + // have to add ImageBase from PE file. + // FIXME: Make this the default for llvm-symbolizer. + "--relative-address", #endif - "--demangle", nullptr}; + "--demangle"}; int RunResult = - sys::ExecuteAndWait(LLVMSymbolizerPath, Args, nullptr, Redirects); + sys::ExecuteAndWait(LLVMSymbolizerPath, Args, None, Redirects); if (RunResult != 0) return false; @@ -180,6 +212,6 @@ static bool printSymbolizedStackTrace(StringRef Argv0, #ifdef LLVM_ON_UNIX #include "Unix/Signals.inc" #endif -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 #include "Windows/Signals.inc" #endif diff --git a/contrib/llvm/lib/Support/SmallPtrSet.cpp b/contrib/llvm/lib/Support/SmallPtrSet.cpp index 119bb871d4c0..fed4a17d6635 100644 --- a/contrib/llvm/lib/Support/SmallPtrSet.cpp +++ b/contrib/llvm/lib/Support/SmallPtrSet.cpp @@ -32,9 +32,7 @@ void SmallPtrSetImplBase::shrink_and_clear() { NumNonEmpty = NumTombstones = 0; // Install the new array. Clear all the buckets to empty. - CurArray = (const void**)malloc(sizeof(void*) * CurArraySize); - if (CurArray == nullptr) - report_bad_alloc_error("Allocation of SmallPtrSet bucket array failed."); + CurArray = (const void**)safe_malloc(sizeof(void*) * CurArraySize); memset(CurArray, -1, CurArraySize*sizeof(void*)); } @@ -100,9 +98,7 @@ void SmallPtrSetImplBase::Grow(unsigned NewSize) { bool WasSmall = isSmall(); // Install the new array. Clear all the buckets to empty. - const void **NewBuckets = (const void**) malloc(sizeof(void*) * NewSize); - if (NewBuckets == nullptr) - report_bad_alloc_error("Allocation of SmallPtrSet bucket array failed."); + const void **NewBuckets = (const void**) safe_malloc(sizeof(void*) * NewSize); // Reset member only if memory was allocated successfully CurArray = NewBuckets; @@ -132,9 +128,7 @@ SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage, CurArray = SmallArray; // Otherwise, allocate new heap space (unless we were the same size) } else { - CurArray = (const void**)malloc(sizeof(void*) * that.CurArraySize); - if (CurArray == nullptr) - report_bad_alloc_error("Allocation of SmallPtrSet bucket array failed."); + CurArray = (const void**)safe_malloc(sizeof(void*) * that.CurArraySize); } // Copy over the that array. @@ -163,16 +157,12 @@ void SmallPtrSetImplBase::CopyFrom(const SmallPtrSetImplBase &RHS) { // Otherwise, allocate new heap space (unless we were the same size) } else if (CurArraySize != RHS.CurArraySize) { if (isSmall()) - CurArray = (const void**)malloc(sizeof(void*) * RHS.CurArraySize); + CurArray = (const void**)safe_malloc(sizeof(void*) * RHS.CurArraySize); else { - const void **T = (const void**)realloc(CurArray, + const void **T = (const void**)safe_realloc(CurArray, sizeof(void*) * RHS.CurArraySize); - if (!T) - free(CurArray); CurArray = T; } - if (CurArray == nullptr) - report_bad_alloc_error("Allocation of SmallPtrSet bucket array failed."); } CopyHelper(RHS); diff --git a/contrib/llvm/lib/Support/SmallVector.cpp b/contrib/llvm/lib/Support/SmallVector.cpp index 74313151c762..1070c6672edc 100644 --- a/contrib/llvm/lib/Support/SmallVector.cpp +++ b/contrib/llvm/lib/Support/SmallVector.cpp @@ -14,31 +14,53 @@ #include "llvm/ADT/SmallVector.h" using namespace llvm; +// Check that no bytes are wasted and everything is well-aligned. +namespace { +struct Struct16B { + alignas(16) void *X; +}; +struct Struct32B { + alignas(32) void *X; +}; +} +static_assert(sizeof(SmallVector<void *, 0>) == + sizeof(unsigned) * 2 + sizeof(void *), + "wasted space in SmallVector size 0"); +static_assert(alignof(SmallVector<Struct16B, 0>) >= alignof(Struct16B), + "wrong alignment for 16-byte aligned T"); +static_assert(alignof(SmallVector<Struct32B, 0>) >= alignof(Struct32B), + "wrong alignment for 32-byte aligned T"); +static_assert(sizeof(SmallVector<Struct16B, 0>) >= alignof(Struct16B), + "missing padding for 16-byte aligned T"); +static_assert(sizeof(SmallVector<Struct32B, 0>) >= alignof(Struct32B), + "missing padding for 32-byte aligned T"); +static_assert(sizeof(SmallVector<void *, 1>) == + sizeof(unsigned) * 2 + sizeof(void *) * 2, + "wasted space in SmallVector size 1"); + /// grow_pod - This is an implementation of the grow() method which only works /// on POD-like datatypes and is out of line to reduce code duplication. -void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSizeInBytes, +void SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity, size_t TSize) { - size_t CurSizeBytes = size_in_bytes(); - size_t NewCapacityInBytes = 2 * capacity_in_bytes() + TSize; // Always grow. - if (NewCapacityInBytes < MinSizeInBytes) - NewCapacityInBytes = MinSizeInBytes; + // Ensure we can fit the new capacity in 32 bits. + if (MinCapacity > UINT32_MAX) + report_bad_alloc_error("SmallVector capacity overflow during allocation"); + + size_t NewCapacity = 2 * capacity() + 1; // Always grow. + NewCapacity = + std::min(std::max(NewCapacity, MinCapacity), size_t(UINT32_MAX)); void *NewElts; if (BeginX == FirstEl) { - NewElts = malloc(NewCapacityInBytes); - if (NewElts == nullptr) - report_bad_alloc_error("Allocation of SmallVector element failed."); + NewElts = safe_malloc(NewCapacity * TSize); // Copy the elements over. No need to run dtors on PODs. - memcpy(NewElts, this->BeginX, CurSizeBytes); + memcpy(NewElts, this->BeginX, size() * TSize); } else { // If this wasn't grown from the inline copy, grow the allocated space. - NewElts = realloc(this->BeginX, NewCapacityInBytes); - if (NewElts == nullptr) - report_bad_alloc_error("Reallocation of SmallVector element failed."); + NewElts = safe_realloc(this->BeginX, NewCapacity * TSize); } - this->EndX = (char*)NewElts+CurSizeBytes; this->BeginX = NewElts; - this->CapacityX = (char*)this->BeginX + NewCapacityInBytes; + this->Capacity = NewCapacity; } diff --git a/contrib/llvm/lib/Support/SourceMgr.cpp b/contrib/llvm/lib/Support/SourceMgr.cpp index a8f6208a558c..bc15fd4e4014 100644 --- a/contrib/llvm/lib/Support/SourceMgr.cpp +++ b/contrib/llvm/lib/Support/SourceMgr.cpp @@ -28,6 +28,7 @@ #include <algorithm> #include <cassert> #include <cstddef> +#include <limits> #include <memory> #include <string> #include <utility> @@ -36,24 +37,6 @@ using namespace llvm; static const size_t TabStop = 8; -namespace { - - struct LineNoCacheTy { - const char *LastQuery; - unsigned LastQueryBufferID; - unsigned LineNoOfQuery; - }; - -} // end anonymous namespace - -static LineNoCacheTy *getCache(void *Ptr) { - return (LineNoCacheTy*)Ptr; -} - -SourceMgr::~SourceMgr() { - delete getCache(LineNoCache); -} - unsigned SourceMgr::AddIncludeFile(const std::string &Filename, SMLoc IncludeLoc, std::string &IncludedFile) { @@ -85,46 +68,85 @@ unsigned SourceMgr::FindBufferContainingLoc(SMLoc Loc) const { return 0; } -std::pair<unsigned, unsigned> -SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const { - if (!BufferID) - BufferID = FindBufferContainingLoc(Loc); - assert(BufferID && "Invalid Location!"); +template <typename T> +unsigned SourceMgr::SrcBuffer::getLineNumber(const char *Ptr) const { + + // Ensure OffsetCache is allocated and populated with offsets of all the + // '\n' bytes. + std::vector<T> *Offsets = nullptr; + if (OffsetCache.isNull()) { + Offsets = new std::vector<T>(); + OffsetCache = Offsets; + size_t Sz = Buffer->getBufferSize(); + assert(Sz <= std::numeric_limits<T>::max()); + StringRef S = Buffer->getBuffer(); + for (size_t N = 0; N < Sz; ++N) { + if (S[N] == '\n') { + Offsets->push_back(static_cast<T>(N)); + } + } + } else { + Offsets = OffsetCache.get<std::vector<T> *>(); + } - const MemoryBuffer *Buff = getMemoryBuffer(BufferID); + const char *BufStart = Buffer->getBufferStart(); + assert(Ptr >= BufStart && Ptr <= Buffer->getBufferEnd()); + ptrdiff_t PtrDiff = Ptr - BufStart; + assert(PtrDiff >= 0 && static_cast<size_t>(PtrDiff) <= std::numeric_limits<T>::max()); + T PtrOffset = static_cast<T>(PtrDiff); - // Count the number of \n's between the start of the file and the specified - // location. - unsigned LineNo = 1; + // std::lower_bound returns the first EOL offset that's not-less-than + // PtrOffset, meaning the EOL that _ends the line_ that PtrOffset is on + // (including if PtrOffset refers to the EOL itself). If there's no such + // EOL, returns end(). + auto EOL = std::lower_bound(Offsets->begin(), Offsets->end(), PtrOffset); - const char *BufStart = Buff->getBufferStart(); - const char *Ptr = BufStart; + // Lines count from 1, so add 1 to the distance from the 0th line. + return (1 + (EOL - Offsets->begin())); +} - // If we have a line number cache, and if the query is to a later point in the - // same file, start searching from the last query location. This optimizes - // for the case when multiple diagnostics come out of one file in order. - if (LineNoCacheTy *Cache = getCache(LineNoCache)) - if (Cache->LastQueryBufferID == BufferID && - Cache->LastQuery <= Loc.getPointer()) { - Ptr = Cache->LastQuery; - LineNo = Cache->LineNoOfQuery; - } +SourceMgr::SrcBuffer::SrcBuffer(SourceMgr::SrcBuffer &&Other) + : Buffer(std::move(Other.Buffer)), + OffsetCache(Other.OffsetCache), + IncludeLoc(Other.IncludeLoc) { + Other.OffsetCache = nullptr; +} - // Scan for the location being queried, keeping track of the number of lines - // we see. - for (; SMLoc::getFromPointer(Ptr) != Loc; ++Ptr) - if (*Ptr == '\n') ++LineNo; +SourceMgr::SrcBuffer::~SrcBuffer() { + if (!OffsetCache.isNull()) { + if (OffsetCache.is<std::vector<uint8_t>*>()) + delete OffsetCache.get<std::vector<uint8_t>*>(); + else if (OffsetCache.is<std::vector<uint16_t>*>()) + delete OffsetCache.get<std::vector<uint16_t>*>(); + else if (OffsetCache.is<std::vector<uint32_t>*>()) + delete OffsetCache.get<std::vector<uint32_t>*>(); + else + delete OffsetCache.get<std::vector<uint64_t>*>(); + OffsetCache = nullptr; + } +} - // Allocate the line number cache if it doesn't exist. - if (!LineNoCache) - LineNoCache = new LineNoCacheTy(); +std::pair<unsigned, unsigned> +SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const { + if (!BufferID) + BufferID = FindBufferContainingLoc(Loc); + assert(BufferID && "Invalid Location!"); - // Update the line # cache. - LineNoCacheTy &Cache = *getCache(LineNoCache); - Cache.LastQueryBufferID = BufferID; - Cache.LastQuery = Ptr; - Cache.LineNoOfQuery = LineNo; - + auto &SB = getBufferInfo(BufferID); + const char *Ptr = Loc.getPointer(); + + size_t Sz = SB.Buffer->getBufferSize(); + unsigned LineNo; + if (Sz <= std::numeric_limits<uint8_t>::max()) + LineNo = SB.getLineNumber<uint8_t>(Ptr); + else if (Sz <= std::numeric_limits<uint16_t>::max()) + LineNo = SB.getLineNumber<uint16_t>(Ptr); + else if (Sz <= std::numeric_limits<uint32_t>::max()) + LineNo = SB.getLineNumber<uint32_t>(Ptr); + else + LineNo = SB.getLineNumber<uint64_t>(Ptr); + + const char *BufStart = SB.Buffer->getBufferStart(); size_t NewlineOffs = StringRef(BufStart, Ptr-BufStart).find_last_of("\n\r"); if (NewlineOffs == StringRef::npos) NewlineOffs = ~(size_t)0; return std::make_pair(LineNo, Ptr-BufStart-NewlineOffs); @@ -247,7 +269,7 @@ SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN, : SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Kind(Kind), Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()), FixIts(Hints.begin(), Hints.end()) { - std::sort(FixIts.begin(), FixIts.end()); + llvm::sort(FixIts.begin(), FixIts.end()); } static void buildFixItLine(std::string &CaretLine, std::string &FixItLine, diff --git a/contrib/llvm/lib/Support/Statistic.cpp b/contrib/llvm/lib/Support/Statistic.cpp index 544ae2d0983c..d57300a75d1d 100644 --- a/contrib/llvm/lib/Support/Statistic.cpp +++ b/contrib/llvm/lib/Support/Statistic.cpp @@ -52,11 +52,14 @@ static bool Enabled; static bool PrintOnExit; 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 -/// llvm_shutdown is called. We print statistics from the destructor. +/// This class is used in a ManagedStatic so that it is created on demand (when +/// the first statistic is bumped) and destroyed only when llvm_shutdown is +/// called. We print statistics from the destructor. +/// This class is also used to look up statistic values from applications that +/// use LLVM. class StatisticInfo { - std::vector<const Statistic*> Stats; + std::vector<Statistic*> Stats; + friend void llvm::PrintStatistics(); friend void llvm::PrintStatistics(raw_ostream &OS); friend void llvm::PrintStatisticsJSON(raw_ostream &OS); @@ -64,14 +67,24 @@ class StatisticInfo { /// Sort statistics by debugtype,name,description. void sort(); public: + using const_iterator = std::vector<Statistic *>::const_iterator; + StatisticInfo(); ~StatisticInfo(); - void addStatistic(const Statistic *S) { + void addStatistic(Statistic *S) { Stats.push_back(S); } + + const_iterator begin() const { return Stats.begin(); } + const_iterator end() const { return Stats.end(); } + iterator_range<const_iterator> statistics() const { + return {begin(), end()}; + } + + void reset(); }; -} +} // end anonymous namespace static ManagedStatic<StatisticInfo> StatInfo; static ManagedStatic<sys::SmartMutex<true> > StatLock; @@ -81,17 +94,24 @@ static ManagedStatic<sys::SmartMutex<true> > StatLock; void Statistic::RegisterStatistic() { // If stats are enabled, inform StatInfo that this statistic should be // printed. - sys::SmartScopedLock<true> Writer(*StatLock); - if (!Initialized) { + // llvm_shutdown calls destructors while holding the ManagedStatic mutex. + // These destructors end up calling PrintStatistics, which takes StatLock. + // Since dereferencing StatInfo and StatLock can require taking the + // ManagedStatic mutex, doing so with StatLock held would lead to a lock + // order inversion. To avoid that, we dereference the ManagedStatics first, + // and only take StatLock afterwards. + if (!Initialized.load(std::memory_order_relaxed)) { + sys::SmartMutex<true> &Lock = *StatLock; + StatisticInfo &SI = *StatInfo; + sys::SmartScopedLock<true> Writer(Lock); + // Check Initialized again after acquiring the lock. + if (Initialized.load(std::memory_order_relaxed)) + return; if (Stats || Enabled) - StatInfo->addStatistic(this); + SI.addStatistic(this); - TsanHappensBefore(this); - sys::MemoryFence(); // Remember we have been registered. - TsanIgnoreWritesBegin(); - Initialized = true; - TsanIgnoreWritesEnd(); + Initialized.store(true, std::memory_order_release); } } @@ -128,6 +148,28 @@ void StatisticInfo::sort() { }); } +void StatisticInfo::reset() { + sys::SmartScopedLock<true> Writer(*StatLock); + + // Tell each statistic that it isn't registered so it has to register + // again. We're holding the lock so it won't be able to do so until we're + // finished. Once we've forced it to re-register (after we return), then zero + // the value. + for (auto *Stat : Stats) { + // Value updates to a statistic that complete before this statement in the + // iteration for that statistic will be lost as intended. + Stat->Initialized = false; + Stat->Value = 0; + } + + // Clear the registration list and release the lock once we're done. Any + // pending updates from other threads will safely take effect after we return. + // That might not be what the user wants if they're measuring a compilation + // but it's their responsibility to prevent concurrent compilations to make + // a single compilation measurable. + Stats.clear(); +} + void llvm::PrintStatistics(raw_ostream &OS) { StatisticInfo &Stats = *StatInfo; @@ -159,6 +201,7 @@ void llvm::PrintStatistics(raw_ostream &OS) { } void llvm::PrintStatisticsJSON(raw_ostream &OS) { + sys::SmartScopedLock<true> Reader(*StatLock); StatisticInfo &Stats = *StatInfo; Stats.sort(); @@ -184,7 +227,8 @@ void llvm::PrintStatisticsJSON(raw_ostream &OS) { } void llvm::PrintStatistics() { -#if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS) +#if LLVM_ENABLE_STATS + sys::SmartScopedLock<true> Reader(*StatLock); StatisticInfo &Stats = *StatInfo; // Statistics not enabled? @@ -209,3 +253,16 @@ void llvm::PrintStatistics() { } #endif } + +const std::vector<std::pair<StringRef, unsigned>> llvm::GetStatistics() { + sys::SmartScopedLock<true> Reader(*StatLock); + std::vector<std::pair<StringRef, unsigned>> ReturnStats; + + for (const auto &Stat : StatInfo->statistics()) + ReturnStats.emplace_back(Stat->getName(), Stat->getValue()); + return ReturnStats; +} + +void llvm::ResetStatistics() { + StatInfo->reset(); +} diff --git a/contrib/llvm/lib/Support/StringExtras.cpp b/contrib/llvm/lib/Support/StringExtras.cpp index 21157a14086d..386d74a47983 100644 --- a/contrib/llvm/lib/Support/StringExtras.cpp +++ b/contrib/llvm/lib/Support/StringExtras.cpp @@ -58,6 +58,33 @@ void llvm::SplitString(StringRef Source, } } +void llvm::printEscapedString(StringRef Name, raw_ostream &Out) { + for (unsigned i = 0, e = Name.size(); i != e; ++i) { + unsigned char C = Name[i]; + if (isPrint(C) && C != '\\' && C != '"') + Out << C; + else + Out << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F); + } +} + +void llvm::printHTMLEscaped(StringRef String, raw_ostream &Out) { + for (char C : String) { + if (C == '&') + Out << "&"; + else if (C == '<') + Out << "<"; + else if (C == '>') + Out << ">"; + else if (C == '\"') + Out << """; + else if (C == '\'') + Out << "'"; + else + Out << C; + } +} + void llvm::printLowerCase(StringRef String, raw_ostream &Out) { for (const char C : String) Out << toLower(C); diff --git a/contrib/llvm/lib/Support/StringMap.cpp b/contrib/llvm/lib/Support/StringMap.cpp index 4341da2d97bd..c1f707ce50a5 100644 --- a/contrib/llvm/lib/Support/StringMap.cpp +++ b/contrib/llvm/lib/Support/StringMap.cpp @@ -14,6 +14,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/DJB.h" #include "llvm/Support/MathExtras.h" #include <cassert> @@ -32,7 +33,7 @@ static unsigned getMinBucketToReserveForEntries(unsigned NumEntries) { StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) { ItemSize = itemSize; - + // If a size is specified, initialize the table with that many buckets. if (InitSize) { // The table will grow when the number of entries reach 3/4 of the number of @@ -41,7 +42,7 @@ StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) { init(getMinBucketToReserveForEntries(InitSize)); return; } - + // Otherwise, initialize it with zero buckets to avoid the allocation. TheTable = nullptr; NumBuckets = 0; @@ -56,13 +57,10 @@ void StringMapImpl::init(unsigned InitSize) { unsigned NewNumBuckets = InitSize ? InitSize : 16; NumItems = 0; NumTombstones = 0; - - TheTable = (StringMapEntryBase **)calloc(NewNumBuckets+1, - sizeof(StringMapEntryBase **) + - sizeof(unsigned)); - if (TheTable == nullptr) - report_bad_alloc_error("Allocation of StringMap table failed."); + TheTable = static_cast<StringMapEntryBase **>( + safe_calloc(NewNumBuckets+1, + sizeof(StringMapEntryBase **) + sizeof(unsigned))); // Set the member only if TheTable was successfully allocated NumBuckets = NewNumBuckets; @@ -83,7 +81,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) { init(16); HTSize = NumBuckets; } - unsigned FullHashValue = HashString(Name); + unsigned FullHashValue = djbHash(Name, 0); unsigned BucketNo = FullHashValue & (HTSize-1); unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1); @@ -99,11 +97,11 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) { HashTable[FirstTombstone] = FullHashValue; return FirstTombstone; } - + HashTable[BucketNo] = FullHashValue; return BucketNo; } - + if (BucketItem == getTombstoneVal()) { // Skip over tombstones. However, remember the first one we see. if (FirstTombstone == -1) FirstTombstone = BucketNo; @@ -112,7 +110,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) { // case here is that we are only looking at the buckets (for item info // being non-null and for the full hash value) not at the items. This // is important for cache locality. - + // Do the comparison like this because Name isn't necessarily // null-terminated! char *ItemStr = (char*)BucketItem+ItemSize; @@ -121,10 +119,10 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) { return BucketNo; } } - + // Okay, we didn't find the item. Probe to the next bucket. BucketNo = (BucketNo+ProbeAmt) & (HTSize-1); - + // Use quadratic probing, it has fewer clumping artifacts than linear // probing and has good cache behavior in the common case. ++ProbeAmt; @@ -137,7 +135,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) { int StringMapImpl::FindKey(StringRef Key) const { unsigned HTSize = NumBuckets; if (HTSize == 0) return -1; // Really empty table? - unsigned FullHashValue = HashString(Key); + unsigned FullHashValue = djbHash(Key, 0); unsigned BucketNo = FullHashValue & (HTSize-1); unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1); @@ -147,7 +145,7 @@ int StringMapImpl::FindKey(StringRef Key) const { // If we found an empty bucket, this key isn't in the table yet, return. if (LLVM_LIKELY(!BucketItem)) return -1; - + if (BucketItem == getTombstoneVal()) { // Ignore tombstones. } else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) { @@ -155,7 +153,7 @@ int StringMapImpl::FindKey(StringRef Key) const { // case here is that we are only looking at the buckets (for item info // being non-null and for the full hash value) not at the items. This // is important for cache locality. - + // Do the comparison like this because NameStart isn't necessarily // null-terminated! char *ItemStr = (char*)BucketItem+ItemSize; @@ -164,10 +162,10 @@ int StringMapImpl::FindKey(StringRef Key) const { return BucketNo; } } - + // Okay, we didn't find the item. Probe to the next bucket. BucketNo = (BucketNo+ProbeAmt) & (HTSize-1); - + // Use quadratic probing, it has fewer clumping artifacts than linear // probing and has good cache behavior in the common case. ++ProbeAmt; @@ -188,7 +186,7 @@ void StringMapImpl::RemoveKey(StringMapEntryBase *V) { StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) { int Bucket = FindKey(Key); if (Bucket == -1) return nullptr; - + StringMapEntryBase *Result = TheTable[Bucket]; TheTable[Bucket] = getTombstoneVal(); --NumItems; @@ -219,12 +217,8 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) { unsigned NewBucketNo = BucketNo; // Allocate one extra bucket which will always be non-empty. This allows the // iterators to stop at end. - StringMapEntryBase **NewTableArray = - (StringMapEntryBase **)calloc(NewSize+1, sizeof(StringMapEntryBase *) + - sizeof(unsigned)); - - if (NewTableArray == nullptr) - report_bad_alloc_error("Allocation of StringMap hash table failed."); + auto NewTableArray = static_cast<StringMapEntryBase **>( + safe_calloc(NewSize+1, sizeof(StringMapEntryBase *) + sizeof(unsigned))); unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1); NewTableArray[NewSize] = (StringMapEntryBase*)2; @@ -244,13 +238,13 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) { NewBucketNo = NewBucket; continue; } - + // Otherwise probe for a spot. unsigned ProbeSize = 1; do { NewBucket = (NewBucket + ProbeSize++) & (NewSize-1); } while (NewTableArray[NewBucket]); - + // Finally found a slot. Fill it in. NewTableArray[NewBucket] = Bucket; NewHashArray[NewBucket] = FullHash; @@ -258,9 +252,9 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) { NewBucketNo = NewBucket; } } - + free(TheTable); - + TheTable = NewTableArray; NumBuckets = NewSize; NumTombstones = 0; diff --git a/contrib/llvm/lib/Support/StringSaver.cpp b/contrib/llvm/lib/Support/StringSaver.cpp index 335fce3a7bbd..1ded2bdb09de 100644 --- a/contrib/llvm/lib/Support/StringSaver.cpp +++ b/contrib/llvm/lib/Support/StringSaver.cpp @@ -17,3 +17,10 @@ StringRef StringSaver::save(StringRef S) { P[S.size()] = '\0'; return StringRef(P, S.size()); } + +StringRef UniqueStringSaver::save(StringRef S) { + auto R = Unique.insert(S); + if (R.second) // cache miss, need to actually save the string + *R.first = Strings.save(S); // safe replacement with equal value + return *R.first; +} diff --git a/contrib/llvm/lib/Support/TarWriter.cpp b/contrib/llvm/lib/Support/TarWriter.cpp index abc46d076576..5b4d554befe4 100644 --- a/contrib/llvm/lib/Support/TarWriter.cpp +++ b/contrib/llvm/lib/Support/TarWriter.cpp @@ -159,8 +159,10 @@ static void writeUstarHeader(raw_fd_ostream &OS, StringRef Prefix, // Creates a TarWriter instance and returns it. Expected<std::unique_ptr<TarWriter>> TarWriter::create(StringRef OutputPath, StringRef BaseDir) { + using namespace sys::fs; int FD; - if (std::error_code EC = openFileForWrite(OutputPath, FD, sys::fs::F_None)) + if (std::error_code EC = + openFileForWrite(OutputPath, FD, CD_CreateAlways, OF_None)) return make_error<StringError>("cannot open " + OutputPath, EC); return std::unique_ptr<TarWriter>(new TarWriter(FD, BaseDir)); } diff --git a/contrib/llvm/lib/Support/TargetParser.cpp b/contrib/llvm/lib/Support/TargetParser.cpp index b96ca084e9bf..2c167a4d086c 100644 --- a/contrib/llvm/lib/Support/TargetParser.cpp +++ b/contrib/llvm/lib/Support/TargetParser.cpp @@ -433,6 +433,17 @@ unsigned llvm::AArch64::getDefaultExtensions(StringRef CPU, ArchKind AK) { .Default(AArch64::AEK_INVALID); } +AArch64::ArchKind llvm::AArch64::getCPUArchKind(StringRef CPU) { + if (CPU == "generic") + return AArch64::ArchKind::ARMV8A; + + return StringSwitch<AArch64::ArchKind>(CPU) +#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ + .Case(NAME, AArch64::ArchKind:: ID) +#include "llvm/Support/AArch64TargetParser.def" + .Default(AArch64::ArchKind::INVALID); +} + bool llvm::AArch64::getExtensionFeatures(unsigned Extensions, std::vector<StringRef> &Features) { @@ -480,6 +491,8 @@ bool llvm::AArch64::getArchFeatures(AArch64::ArchKind AK, Features.push_back("+v8.2a"); if (AK == AArch64::ArchKind::ARMV8_3A) Features.push_back("+v8.3a"); + if (AK == AArch64::ArchKind::ARMV8_4A) + Features.push_back("+v8.4a"); return AK != AArch64::ArchKind::INVALID; } @@ -581,10 +594,11 @@ static StringRef getArchSynonym(StringRef Arch) { .Case("v7r", "v7-r") .Case("v7m", "v7-m") .Case("v7em", "v7e-m") - .Cases("v8", "v8a", "aarch64", "arm64", "v8-a") + .Cases("v8", "v8a", "v8l", "aarch64", "arm64", "v8-a") .Case("v8.1a", "v8.1-a") .Case("v8.2a", "v8.2-a") .Case("v8.3a", "v8.3-a") + .Case("v8.4a", "v8.4-a") .Case("v8r", "v8-r") .Case("v8m.base", "v8-m.base") .Case("v8m.main", "v8-m.main") @@ -689,6 +703,20 @@ ARM::ArchKind llvm::ARM::parseCPUArch(StringRef CPU) { return ARM::ArchKind::INVALID; } +void llvm::ARM::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) { + for (const CpuNames<ARM::ArchKind> &Arch : CPUNames) { + if (Arch.ArchID != ARM::ArchKind::INVALID) + Values.push_back(Arch.getName()); + } +} + +void llvm::AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) { + for (const CpuNames<AArch64::ArchKind> &Arch : AArch64CPUNames) { + if (Arch.ArchID != AArch64::ArchKind::INVALID) + Values.push_back(Arch.getName()); + } +} + // ARM, Thumb, AArch64 ARM::ISAKind ARM::parseArchISA(StringRef Arch) { return StringSwitch<ARM::ISAKind>(Arch) @@ -738,6 +766,7 @@ ARM::ProfileKind ARM::parseArchProfile(StringRef Arch) { case ARM::ArchKind::ARMV8_1A: case ARM::ArchKind::ARMV8_2A: case ARM::ArchKind::ARMV8_3A: + case ARM::ArchKind::ARMV8_4A: return ARM::ProfileKind::A; case ARM::ArchKind::ARMV2: case ARM::ArchKind::ARMV2A: @@ -800,6 +829,7 @@ unsigned llvm::ARM::parseArchVersion(StringRef Arch) { case ARM::ArchKind::ARMV8_1A: case ARM::ArchKind::ARMV8_2A: case ARM::ArchKind::ARMV8_3A: + case ARM::ArchKind::ARMV8_4A: case ARM::ArchKind::ARMV8R: case ARM::ArchKind::ARMV8MBaseline: case ARM::ArchKind::ARMV8MMainline: @@ -868,10 +898,10 @@ AArch64::ArchKind AArch64::parseArch(StringRef Arch) { return ArchKind::INVALID; } -unsigned llvm::AArch64::parseArchExt(StringRef ArchExt) { +AArch64::ArchExtKind llvm::AArch64::parseArchExt(StringRef ArchExt) { for (const auto A : AArch64ARCHExtNames) { if (ArchExt == A.getName()) - return A.ID; + return static_cast<ArchExtKind>(A.ID); } return AArch64::AEK_INVALID; } @@ -903,3 +933,7 @@ ARM::ProfileKind AArch64::parseArchProfile(StringRef Arch) { unsigned llvm::AArch64::parseArchVersion(StringRef Arch) { return ARM::parseArchVersion(Arch); } + +bool llvm::AArch64::isX18ReservedByDefault(const Triple &TT) { + return TT.isOSDarwin() || TT.isOSFuchsia() || TT.isOSWindows(); +} diff --git a/contrib/llvm/lib/Support/ThreadLocal.cpp b/contrib/llvm/lib/Support/ThreadLocal.cpp index 9a75c02b351f..f6e4a652302c 100644 --- a/contrib/llvm/lib/Support/ThreadLocal.cpp +++ b/contrib/llvm/lib/Support/ThreadLocal.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/ThreadLocal.h" -#include "llvm/Config/config.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Compiler.h" //===----------------------------------------------------------------------===// @@ -41,8 +41,8 @@ void ThreadLocalImpl::removeInstance() { } #elif defined(LLVM_ON_UNIX) #include "Unix/ThreadLocal.inc" -#elif defined( LLVM_ON_WIN32) +#elif defined( _WIN32) #include "Windows/ThreadLocal.inc" #else -#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 set in Support/ThreadLocal.cpp +#warning Neither LLVM_ON_UNIX nor _WIN32 set in Support/ThreadLocal.cpp #endif diff --git a/contrib/llvm/lib/Support/Threading.cpp b/contrib/llvm/lib/Support/Threading.cpp index 473c84808af1..fcb1030e1ab4 100644 --- a/contrib/llvm/lib/Support/Threading.cpp +++ b/contrib/llvm/lib/Support/Threading.cpp @@ -37,7 +37,7 @@ bool llvm::llvm_is_multithreaded() { } #if LLVM_ENABLE_THREADS == 0 || \ - (!defined(LLVM_ON_WIN32) && !defined(HAVE_PTHREAD_H)) + (!defined(_WIN32) && !defined(HAVE_PTHREAD_H)) // Support for non-Win32, non-pthread implementation. void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData, unsigned RequestedStackSize) { @@ -89,7 +89,7 @@ unsigned llvm::hardware_concurrency() { #ifdef LLVM_ON_UNIX #include "Unix/Threading.inc" #endif -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 #include "Windows/Threading.inc" #endif diff --git a/contrib/llvm/lib/Support/Timer.cpp b/contrib/llvm/lib/Support/Timer.cpp index 0c85faecca84..61d3b6c6e319 100644 --- a/contrib/llvm/lib/Support/Timer.cpp +++ b/contrib/llvm/lib/Support/Timer.cpp @@ -22,6 +22,8 @@ #include "llvm/Support/Process.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" +#include <limits> + using namespace llvm; // This ugly hack is brought to you courtesy of constructor/destructor ordering @@ -234,6 +236,15 @@ TimerGroup::TimerGroup(StringRef Name, StringRef Description) TimerGroupList = this; } +TimerGroup::TimerGroup(StringRef Name, StringRef Description, + const StringMap<TimeRecord> &Records) + : TimerGroup(Name, Description) { + TimersToPrint.reserve(Records.size()); + for (const auto &P : Records) + TimersToPrint.emplace_back(P.getValue(), P.getKey(), P.getKey()); + assert(TimersToPrint.size() == Records.size() && "Size mismatch"); +} + TimerGroup::~TimerGroup() { // If the timer group is destroyed before the timers it owns, accumulate and // print the timing data. @@ -284,7 +295,7 @@ 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()); + llvm::sort(TimersToPrint.begin(), TimersToPrint.end()); TimeRecord Total; for (const PrintRecord &Record : TimersToPrint) @@ -336,10 +347,14 @@ void TimerGroup::prepareToPrintList() { // reset them. for (Timer *T = FirstTimer; T; T = T->Next) { if (!T->hasTriggered()) continue; + bool WasRunning = T->isRunning(); + if (WasRunning) + T->stopTimer(); + TimersToPrint.emplace_back(T->Time, T->Name, T->Description); - // Clear out the time. - T->clear(); + if (WasRunning) + T->startTimer(); } } @@ -363,13 +378,17 @@ void TimerGroup::printAll(raw_ostream &OS) { void TimerGroup::printJSONValue(raw_ostream &OS, const PrintRecord &R, const char *suffix, double Value) { assert(yaml::needsQuotes(Name) == yaml::QuotingType::None && - "TimerGroup name needs no quotes"); + "TimerGroup name should not need quotes"); assert(yaml::needsQuotes(R.Name) == yaml::QuotingType::None && - "Timer name needs no quotes"); - OS << "\t\"time." << Name << '.' << R.Name << suffix << "\": " << Value; + "Timer name should not need quotes"); + constexpr auto max_digits10 = std::numeric_limits<double>::max_digits10; + OS << "\t\"time." << Name << '.' << R.Name << suffix + << "\": " << format("%.*e", max_digits10 - 1, Value); } const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) { + sys::SmartScopedLock<true> L(*TimerLock); + prepareToPrintList(); for (const PrintRecord &R : TimersToPrint) { OS << delim; @@ -381,6 +400,10 @@ const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) { printJSONValue(OS, R, ".user", T.getUserTime()); OS << delim; printJSONValue(OS, R, ".sys", T.getSystemTime()); + if (T.getMemUsed()) { + OS << delim; + printJSONValue(OS, R, ".mem", T.getMemUsed()); + } } TimersToPrint.clear(); return delim; diff --git a/contrib/llvm/lib/Support/Triple.cpp b/contrib/llvm/lib/Support/Triple.cpp index 4f0a30042b76..b14d6492b1ed 100644 --- a/contrib/llvm/lib/Support/Triple.cpp +++ b/contrib/llvm/lib/Support/Triple.cpp @@ -168,6 +168,7 @@ StringRef Triple::getVendorTypeName(VendorType Kind) { case AMD: return "amd"; case Mesa: return "mesa"; case SUSE: return "suse"; + case OpenEmbedded: return "oe"; } llvm_unreachable("Invalid VendorType!"); @@ -232,9 +233,7 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) { case MSVC: return "msvc"; case Itanium: return "itanium"; case Cygnus: return "cygnus"; - case AMDOpenCL: return "amdopencl"; case CoreCLR: return "coreclr"; - case OpenCL: return "opencl"; case Simulator: return "simulator"; } @@ -384,7 +383,7 @@ static Triple::ArchType parseArch(StringRef ArchName) { // FIXME: Do we need to support these? .Cases("i786", "i886", "i986", Triple::x86) .Cases("amd64", "x86_64", "x86_64h", Triple::x86_64) - .Cases("powerpc", "ppc32", Triple::ppc) + .Cases("powerpc", "ppc", "ppc32", Triple::ppc) .Cases("powerpc64", "ppu", "ppc64", Triple::ppc64) .Cases("powerpc64le", "ppc64le", Triple::ppc64le) .Case("xscale", Triple::arm) @@ -465,6 +464,7 @@ static Triple::VendorType parseVendor(StringRef VendorName) { .Case("amd", Triple::AMD) .Case("mesa", Triple::Mesa) .Case("suse", Triple::SUSE) + .Case("oe", Triple::OpenEmbedded) .Default(Triple::UnknownVendor); } @@ -523,9 +523,7 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { .StartsWith("msvc", Triple::MSVC) .StartsWith("itanium", Triple::Itanium) .StartsWith("cygnus", Triple::Cygnus) - .StartsWith("amdopencl", Triple::AMDOpenCL) .StartsWith("coreclr", Triple::CoreCLR) - .StartsWith("opencl", Triple::OpenCL) .StartsWith("simulator", Triple::Simulator) .Default(Triple::UnknownEnvironment); } @@ -594,6 +592,8 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) { return Triple::ARMSubArch_v8_2a; case ARM::ArchKind::ARMV8_3A: return Triple::ARMSubArch_v8_3a; + case ARM::ArchKind::ARMV8_4A: + return Triple::ARMSubArch_v8_4a; case ARM::ArchKind::ARMV8R: return Triple::ARMSubArch_v8r; case ARM::ArchKind::ARMV8MBaseline: @@ -670,8 +670,6 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { case Triple::tce: case Triple::tcele: case Triple::thumbeb: - case Triple::wasm32: - case Triple::wasm64: case Triple::xcore: return Triple::ELF; @@ -680,11 +678,15 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { if (T.isOSDarwin()) return Triple::MachO; return Triple::ELF; + + case Triple::wasm32: + case Triple::wasm64: + return Triple::Wasm; } llvm_unreachable("unknown architecture"); } -/// \brief Construct a triple from the string representation provided. +/// Construct a triple from the string representation provided. /// /// This stores the string representation and parses the various pieces into /// enum members. @@ -713,7 +715,7 @@ Triple::Triple(const Twine &Str) ObjectFormat = getDefaultFormat(*this); } -/// \brief Construct a triple from string representations of the architecture, +/// Construct a triple from string representations of the architecture, /// vendor, and OS. /// /// This joins each argument into a canonical string representation and parses @@ -729,7 +731,7 @@ Triple::Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr) ObjectFormat = getDefaultFormat(*this); } -/// \brief Construct a triple from string representations of the architecture, +/// Construct a triple from string representations of the architecture, /// vendor, OS, and environment. /// /// This joins each argument into a canonical string representation and parses diff --git a/contrib/llvm/lib/Support/Twine.cpp b/contrib/llvm/lib/Support/Twine.cpp index d17cd4e66439..4726c8ab7494 100644 --- a/contrib/llvm/lib/Support/Twine.cpp +++ b/contrib/llvm/lib/Support/Twine.cpp @@ -9,6 +9,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" diff --git a/contrib/llvm/lib/Support/UnicodeCaseFold.cpp b/contrib/llvm/lib/Support/UnicodeCaseFold.cpp new file mode 100644 index 000000000000..b18d49dbafb0 --- /dev/null +++ b/contrib/llvm/lib/Support/UnicodeCaseFold.cpp @@ -0,0 +1,742 @@ +//===---------- Support/UnicodeCaseFold.cpp -------------------------------===// +// +// This file was generated by utils/unicode-case-fold.py from the Unicode +// case folding database at +// http://www.unicode.org/Public/9.0.0/ucd/CaseFolding.txt +// +// To regenerate this file, run: +// utils/unicode-case-fold.py \ +// "http://www.unicode.org/Public/9.0.0/ucd/CaseFolding.txt" \ +// > lib/Support/UnicodeCaseFold.cpp +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Unicode.h" + +int llvm::sys::unicode::foldCharSimple(int C) { + if (C < 0x0041) + return C; + // 26 characters + if (C <= 0x005a) + return C + 32; + // MICRO SIGN + if (C == 0x00b5) + return 0x03bc; + if (C < 0x00c0) + return C; + // 23 characters + if (C <= 0x00d6) + return C + 32; + if (C < 0x00d8) + return C; + // 7 characters + if (C <= 0x00de) + return C + 32; + if (C < 0x0100) + return C; + // 24 characters + if (C <= 0x012e) + return C | 1; + if (C < 0x0132) + return C; + // 3 characters + if (C <= 0x0136) + return C | 1; + if (C < 0x0139) + return C; + // 8 characters + if (C <= 0x0147 && C % 2 == 1) + return C + 1; + if (C < 0x014a) + return C; + // 23 characters + if (C <= 0x0176) + return C | 1; + // LATIN CAPITAL LETTER Y WITH DIAERESIS + if (C == 0x0178) + return 0x00ff; + if (C < 0x0179) + return C; + // 3 characters + if (C <= 0x017d && C % 2 == 1) + return C + 1; + // LATIN SMALL LETTER LONG S + if (C == 0x017f) + return 0x0073; + // LATIN CAPITAL LETTER B WITH HOOK + if (C == 0x0181) + return 0x0253; + if (C < 0x0182) + return C; + // 2 characters + if (C <= 0x0184) + return C | 1; + // LATIN CAPITAL LETTER OPEN O + if (C == 0x0186) + return 0x0254; + // LATIN CAPITAL LETTER C WITH HOOK + if (C == 0x0187) + return 0x0188; + if (C < 0x0189) + return C; + // 2 characters + if (C <= 0x018a) + return C + 205; + // LATIN CAPITAL LETTER D WITH TOPBAR + if (C == 0x018b) + return 0x018c; + // LATIN CAPITAL LETTER REVERSED E + if (C == 0x018e) + return 0x01dd; + // LATIN CAPITAL LETTER SCHWA + if (C == 0x018f) + return 0x0259; + // LATIN CAPITAL LETTER OPEN E + if (C == 0x0190) + return 0x025b; + // LATIN CAPITAL LETTER F WITH HOOK + if (C == 0x0191) + return 0x0192; + // LATIN CAPITAL LETTER G WITH HOOK + if (C == 0x0193) + return 0x0260; + // LATIN CAPITAL LETTER GAMMA + if (C == 0x0194) + return 0x0263; + // LATIN CAPITAL LETTER IOTA + if (C == 0x0196) + return 0x0269; + // LATIN CAPITAL LETTER I WITH STROKE + if (C == 0x0197) + return 0x0268; + // LATIN CAPITAL LETTER K WITH HOOK + if (C == 0x0198) + return 0x0199; + // LATIN CAPITAL LETTER TURNED M + if (C == 0x019c) + return 0x026f; + // LATIN CAPITAL LETTER N WITH LEFT HOOK + if (C == 0x019d) + return 0x0272; + // LATIN CAPITAL LETTER O WITH MIDDLE TILDE + if (C == 0x019f) + return 0x0275; + if (C < 0x01a0) + return C; + // 3 characters + if (C <= 0x01a4) + return C | 1; + // LATIN LETTER YR + if (C == 0x01a6) + return 0x0280; + // LATIN CAPITAL LETTER TONE TWO + if (C == 0x01a7) + return 0x01a8; + // LATIN CAPITAL LETTER ESH + if (C == 0x01a9) + return 0x0283; + // LATIN CAPITAL LETTER T WITH HOOK + if (C == 0x01ac) + return 0x01ad; + // LATIN CAPITAL LETTER T WITH RETROFLEX HOOK + if (C == 0x01ae) + return 0x0288; + // LATIN CAPITAL LETTER U WITH HORN + if (C == 0x01af) + return 0x01b0; + if (C < 0x01b1) + return C; + // 2 characters + if (C <= 0x01b2) + return C + 217; + if (C < 0x01b3) + return C; + // 2 characters + if (C <= 0x01b5 && C % 2 == 1) + return C + 1; + // LATIN CAPITAL LETTER EZH + if (C == 0x01b7) + return 0x0292; + if (C < 0x01b8) + return C; + // 2 characters + if (C <= 0x01bc && C % 4 == 0) + return C + 1; + // LATIN CAPITAL LETTER DZ WITH CARON + if (C == 0x01c4) + return 0x01c6; + // LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON + if (C == 0x01c5) + return 0x01c6; + // LATIN CAPITAL LETTER LJ + if (C == 0x01c7) + return 0x01c9; + // LATIN CAPITAL LETTER L WITH SMALL LETTER J + if (C == 0x01c8) + return 0x01c9; + // LATIN CAPITAL LETTER NJ + if (C == 0x01ca) + return 0x01cc; + if (C < 0x01cb) + return C; + // 9 characters + if (C <= 0x01db && C % 2 == 1) + return C + 1; + if (C < 0x01de) + return C; + // 9 characters + if (C <= 0x01ee) + return C | 1; + // LATIN CAPITAL LETTER DZ + if (C == 0x01f1) + return 0x01f3; + if (C < 0x01f2) + return C; + // 2 characters + if (C <= 0x01f4) + return C | 1; + // LATIN CAPITAL LETTER HWAIR + if (C == 0x01f6) + return 0x0195; + // LATIN CAPITAL LETTER WYNN + if (C == 0x01f7) + return 0x01bf; + if (C < 0x01f8) + return C; + // 20 characters + if (C <= 0x021e) + return C | 1; + // LATIN CAPITAL LETTER N WITH LONG RIGHT LEG + if (C == 0x0220) + return 0x019e; + if (C < 0x0222) + return C; + // 9 characters + if (C <= 0x0232) + return C | 1; + // LATIN CAPITAL LETTER A WITH STROKE + if (C == 0x023a) + return 0x2c65; + // LATIN CAPITAL LETTER C WITH STROKE + if (C == 0x023b) + return 0x023c; + // LATIN CAPITAL LETTER L WITH BAR + if (C == 0x023d) + return 0x019a; + // LATIN CAPITAL LETTER T WITH DIAGONAL STROKE + if (C == 0x023e) + return 0x2c66; + // LATIN CAPITAL LETTER GLOTTAL STOP + if (C == 0x0241) + return 0x0242; + // LATIN CAPITAL LETTER B WITH STROKE + if (C == 0x0243) + return 0x0180; + // LATIN CAPITAL LETTER U BAR + if (C == 0x0244) + return 0x0289; + // LATIN CAPITAL LETTER TURNED V + if (C == 0x0245) + return 0x028c; + if (C < 0x0246) + return C; + // 5 characters + if (C <= 0x024e) + return C | 1; + // COMBINING GREEK YPOGEGRAMMENI + if (C == 0x0345) + return 0x03b9; + if (C < 0x0370) + return C; + // 2 characters + if (C <= 0x0372) + return C | 1; + // GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA + if (C == 0x0376) + return 0x0377; + // GREEK CAPITAL LETTER YOT + if (C == 0x037f) + return 0x03f3; + // GREEK CAPITAL LETTER ALPHA WITH TONOS + if (C == 0x0386) + return 0x03ac; + if (C < 0x0388) + return C; + // 3 characters + if (C <= 0x038a) + return C + 37; + // GREEK CAPITAL LETTER OMICRON WITH TONOS + if (C == 0x038c) + return 0x03cc; + if (C < 0x038e) + return C; + // 2 characters + if (C <= 0x038f) + return C + 63; + if (C < 0x0391) + return C; + // 17 characters + if (C <= 0x03a1) + return C + 32; + if (C < 0x03a3) + return C; + // 9 characters + if (C <= 0x03ab) + return C + 32; + // GREEK SMALL LETTER FINAL SIGMA + if (C == 0x03c2) + return 0x03c3; + // GREEK CAPITAL KAI SYMBOL + if (C == 0x03cf) + return 0x03d7; + // GREEK BETA SYMBOL + if (C == 0x03d0) + return 0x03b2; + // GREEK THETA SYMBOL + if (C == 0x03d1) + return 0x03b8; + // GREEK PHI SYMBOL + if (C == 0x03d5) + return 0x03c6; + // GREEK PI SYMBOL + if (C == 0x03d6) + return 0x03c0; + if (C < 0x03d8) + return C; + // 12 characters + if (C <= 0x03ee) + return C | 1; + // GREEK KAPPA SYMBOL + if (C == 0x03f0) + return 0x03ba; + // GREEK RHO SYMBOL + if (C == 0x03f1) + return 0x03c1; + // GREEK CAPITAL THETA SYMBOL + if (C == 0x03f4) + return 0x03b8; + // GREEK LUNATE EPSILON SYMBOL + if (C == 0x03f5) + return 0x03b5; + // GREEK CAPITAL LETTER SHO + if (C == 0x03f7) + return 0x03f8; + // GREEK CAPITAL LUNATE SIGMA SYMBOL + if (C == 0x03f9) + return 0x03f2; + // GREEK CAPITAL LETTER SAN + if (C == 0x03fa) + return 0x03fb; + if (C < 0x03fd) + return C; + // 3 characters + if (C <= 0x03ff) + return C + -130; + if (C < 0x0400) + return C; + // 16 characters + if (C <= 0x040f) + return C + 80; + if (C < 0x0410) + return C; + // 32 characters + if (C <= 0x042f) + return C + 32; + if (C < 0x0460) + return C; + // 17 characters + if (C <= 0x0480) + return C | 1; + if (C < 0x048a) + return C; + // 27 characters + if (C <= 0x04be) + return C | 1; + // CYRILLIC LETTER PALOCHKA + if (C == 0x04c0) + return 0x04cf; + if (C < 0x04c1) + return C; + // 7 characters + if (C <= 0x04cd && C % 2 == 1) + return C + 1; + if (C < 0x04d0) + return C; + // 48 characters + if (C <= 0x052e) + return C | 1; + if (C < 0x0531) + return C; + // 38 characters + if (C <= 0x0556) + return C + 48; + if (C < 0x10a0) + return C; + // 38 characters + if (C <= 0x10c5) + return C + 7264; + if (C < 0x10c7) + return C; + // 2 characters + if (C <= 0x10cd && C % 6 == 5) + return C + 7264; + if (C < 0x13f8) + return C; + // 6 characters + if (C <= 0x13fd) + return C + -8; + // CYRILLIC SMALL LETTER ROUNDED VE + if (C == 0x1c80) + return 0x0432; + // CYRILLIC SMALL LETTER LONG-LEGGED DE + if (C == 0x1c81) + return 0x0434; + // CYRILLIC SMALL LETTER NARROW O + if (C == 0x1c82) + return 0x043e; + if (C < 0x1c83) + return C; + // 2 characters + if (C <= 0x1c84) + return C + -6210; + // CYRILLIC SMALL LETTER THREE-LEGGED TE + if (C == 0x1c85) + return 0x0442; + // CYRILLIC SMALL LETTER TALL HARD SIGN + if (C == 0x1c86) + return 0x044a; + // CYRILLIC SMALL LETTER TALL YAT + if (C == 0x1c87) + return 0x0463; + // CYRILLIC SMALL LETTER UNBLENDED UK + if (C == 0x1c88) + return 0xa64b; + if (C < 0x1e00) + return C; + // 75 characters + if (C <= 0x1e94) + return C | 1; + // LATIN SMALL LETTER LONG S WITH DOT ABOVE + if (C == 0x1e9b) + return 0x1e61; + // LATIN CAPITAL LETTER SHARP S + if (C == 0x1e9e) + return 0x00df; + if (C < 0x1ea0) + return C; + // 48 characters + if (C <= 0x1efe) + return C | 1; + if (C < 0x1f08) + return C; + // 8 characters + if (C <= 0x1f0f) + return C + -8; + if (C < 0x1f18) + return C; + // 6 characters + if (C <= 0x1f1d) + return C + -8; + if (C < 0x1f28) + return C; + // 8 characters + if (C <= 0x1f2f) + return C + -8; + if (C < 0x1f38) + return C; + // 8 characters + if (C <= 0x1f3f) + return C + -8; + if (C < 0x1f48) + return C; + // 6 characters + if (C <= 0x1f4d) + return C + -8; + if (C < 0x1f59) + return C; + // 4 characters + if (C <= 0x1f5f && C % 2 == 1) + return C + -8; + if (C < 0x1f68) + return C; + // 8 characters + if (C <= 0x1f6f) + return C + -8; + if (C < 0x1f88) + return C; + // 8 characters + if (C <= 0x1f8f) + return C + -8; + if (C < 0x1f98) + return C; + // 8 characters + if (C <= 0x1f9f) + return C + -8; + if (C < 0x1fa8) + return C; + // 8 characters + if (C <= 0x1faf) + return C + -8; + if (C < 0x1fb8) + return C; + // 2 characters + if (C <= 0x1fb9) + return C + -8; + if (C < 0x1fba) + return C; + // 2 characters + if (C <= 0x1fbb) + return C + -74; + // GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI + if (C == 0x1fbc) + return 0x1fb3; + // GREEK PROSGEGRAMMENI + if (C == 0x1fbe) + return 0x03b9; + if (C < 0x1fc8) + return C; + // 4 characters + if (C <= 0x1fcb) + return C + -86; + // GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI + if (C == 0x1fcc) + return 0x1fc3; + if (C < 0x1fd8) + return C; + // 2 characters + if (C <= 0x1fd9) + return C + -8; + if (C < 0x1fda) + return C; + // 2 characters + if (C <= 0x1fdb) + return C + -100; + if (C < 0x1fe8) + return C; + // 2 characters + if (C <= 0x1fe9) + return C + -8; + if (C < 0x1fea) + return C; + // 2 characters + if (C <= 0x1feb) + return C + -112; + // GREEK CAPITAL LETTER RHO WITH DASIA + if (C == 0x1fec) + return 0x1fe5; + if (C < 0x1ff8) + return C; + // 2 characters + if (C <= 0x1ff9) + return C + -128; + if (C < 0x1ffa) + return C; + // 2 characters + if (C <= 0x1ffb) + return C + -126; + // GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI + if (C == 0x1ffc) + return 0x1ff3; + // OHM SIGN + if (C == 0x2126) + return 0x03c9; + // KELVIN SIGN + if (C == 0x212a) + return 0x006b; + // ANGSTROM SIGN + if (C == 0x212b) + return 0x00e5; + // TURNED CAPITAL F + if (C == 0x2132) + return 0x214e; + if (C < 0x2160) + return C; + // 16 characters + if (C <= 0x216f) + return C + 16; + // ROMAN NUMERAL REVERSED ONE HUNDRED + if (C == 0x2183) + return 0x2184; + if (C < 0x24b6) + return C; + // 26 characters + if (C <= 0x24cf) + return C + 26; + if (C < 0x2c00) + return C; + // 47 characters + if (C <= 0x2c2e) + return C + 48; + // LATIN CAPITAL LETTER L WITH DOUBLE BAR + if (C == 0x2c60) + return 0x2c61; + // LATIN CAPITAL LETTER L WITH MIDDLE TILDE + if (C == 0x2c62) + return 0x026b; + // LATIN CAPITAL LETTER P WITH STROKE + if (C == 0x2c63) + return 0x1d7d; + // LATIN CAPITAL LETTER R WITH TAIL + if (C == 0x2c64) + return 0x027d; + if (C < 0x2c67) + return C; + // 3 characters + if (C <= 0x2c6b && C % 2 == 1) + return C + 1; + // LATIN CAPITAL LETTER ALPHA + if (C == 0x2c6d) + return 0x0251; + // LATIN CAPITAL LETTER M WITH HOOK + if (C == 0x2c6e) + return 0x0271; + // LATIN CAPITAL LETTER TURNED A + if (C == 0x2c6f) + return 0x0250; + // LATIN CAPITAL LETTER TURNED ALPHA + if (C == 0x2c70) + return 0x0252; + if (C < 0x2c72) + return C; + // 2 characters + if (C <= 0x2c75 && C % 3 == 2) + return C + 1; + if (C < 0x2c7e) + return C; + // 2 characters + if (C <= 0x2c7f) + return C + -10815; + if (C < 0x2c80) + return C; + // 50 characters + if (C <= 0x2ce2) + return C | 1; + if (C < 0x2ceb) + return C; + // 2 characters + if (C <= 0x2ced && C % 2 == 1) + return C + 1; + if (C < 0x2cf2) + return C; + // 2 characters + if (C <= 0xa640 && C % 31054 == 11506) + return C + 1; + if (C < 0xa642) + return C; + // 22 characters + if (C <= 0xa66c) + return C | 1; + if (C < 0xa680) + return C; + // 14 characters + if (C <= 0xa69a) + return C | 1; + if (C < 0xa722) + return C; + // 7 characters + if (C <= 0xa72e) + return C | 1; + if (C < 0xa732) + return C; + // 31 characters + if (C <= 0xa76e) + return C | 1; + if (C < 0xa779) + return C; + // 2 characters + if (C <= 0xa77b && C % 2 == 1) + return C + 1; + // LATIN CAPITAL LETTER INSULAR G + if (C == 0xa77d) + return 0x1d79; + if (C < 0xa77e) + return C; + // 5 characters + if (C <= 0xa786) + return C | 1; + // LATIN CAPITAL LETTER SALTILLO + if (C == 0xa78b) + return 0xa78c; + // LATIN CAPITAL LETTER TURNED H + if (C == 0xa78d) + return 0x0265; + if (C < 0xa790) + return C; + // 2 characters + if (C <= 0xa792) + return C | 1; + if (C < 0xa796) + return C; + // 10 characters + if (C <= 0xa7a8) + return C | 1; + // LATIN CAPITAL LETTER H WITH HOOK + if (C == 0xa7aa) + return 0x0266; + // LATIN CAPITAL LETTER REVERSED OPEN E + if (C == 0xa7ab) + return 0x025c; + // LATIN CAPITAL LETTER SCRIPT G + if (C == 0xa7ac) + return 0x0261; + // LATIN CAPITAL LETTER L WITH BELT + if (C == 0xa7ad) + return 0x026c; + // LATIN CAPITAL LETTER SMALL CAPITAL I + if (C == 0xa7ae) + return 0x026a; + // LATIN CAPITAL LETTER TURNED K + if (C == 0xa7b0) + return 0x029e; + // LATIN CAPITAL LETTER TURNED T + if (C == 0xa7b1) + return 0x0287; + // LATIN CAPITAL LETTER J WITH CROSSED-TAIL + if (C == 0xa7b2) + return 0x029d; + // LATIN CAPITAL LETTER CHI + if (C == 0xa7b3) + return 0xab53; + if (C < 0xa7b4) + return C; + // 2 characters + if (C <= 0xa7b6) + return C | 1; + if (C < 0xab70) + return C; + // 80 characters + if (C <= 0xabbf) + return C + -38864; + if (C < 0xff21) + return C; + // 26 characters + if (C <= 0xff3a) + return C + 32; + if (C < 0x10400) + return C; + // 40 characters + if (C <= 0x10427) + return C + 40; + if (C < 0x104b0) + return C; + // 36 characters + if (C <= 0x104d3) + return C + 40; + if (C < 0x10c80) + return C; + // 51 characters + if (C <= 0x10cb2) + return C + 64; + if (C < 0x118a0) + return C; + // 32 characters + if (C <= 0x118bf) + return C + 32; + if (C < 0x1e900) + return C; + // 34 characters + if (C <= 0x1e921) + return C + 34; + + return C; +} diff --git a/contrib/llvm/lib/Support/Unix/Host.inc b/contrib/llvm/lib/Support/Unix/Host.inc index 5580e63893c6..b65f84bf4444 100644 --- a/contrib/llvm/lib/Support/Unix/Host.inc +++ b/contrib/llvm/lib/Support/Unix/Host.inc @@ -64,5 +64,5 @@ std::string sys::getDefaultTargetTriple() { TargetTripleString = EnvTriple; #endif - return Triple::normalize(TargetTripleString); + return TargetTripleString; } diff --git a/contrib/llvm/lib/Support/Unix/Memory.inc b/contrib/llvm/lib/Support/Unix/Memory.inc index 848548d18177..adbfff2f59a5 100644 --- a/contrib/llvm/lib/Support/Unix/Memory.inc +++ b/contrib/llvm/lib/Support/Unix/Memory.inc @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Unix.h" +#include "llvm/Config/config.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Process.h" @@ -24,6 +25,10 @@ #include <mach/mach.h> #endif +#ifdef __Fuchsia__ +#include <zircon/syscalls.h> +#endif + #if defined(__mips__) # if defined(__OpenBSD__) # include <mips64/sysarch.h> @@ -32,7 +37,7 @@ # endif #endif -#ifdef __APPLE__ +#if defined(__APPLE__) extern "C" void sys_icache_invalidate(const void *Addr, size_t len); #else extern "C" void __clear_cache(void *, void*); @@ -205,6 +210,11 @@ void Memory::InvalidateInstructionCache(const void *Addr, sys_icache_invalidate(const_cast<void *>(Addr), Len); # endif +#elif defined(__Fuchsia__) + + zx_status_t Status = zx_cache_flush(Addr, Len, ZX_CACHE_FLUSH_INSN); + assert(Status == ZX_OK && "cannot invalidate instruction cache"); + #else # if (defined(__POWERPC__) || defined (__ppc__) || \ diff --git a/contrib/llvm/lib/Support/Unix/Path.inc b/contrib/llvm/lib/Support/Unix/Path.inc index 2ecb97316c87..7ad57d892ff1 100644 --- a/contrib/llvm/lib/Support/Unix/Path.inc +++ b/contrib/llvm/lib/Support/Unix/Path.inc @@ -31,23 +31,8 @@ #ifdef HAVE_SYS_MMAN_H #include <sys/mman.h> #endif -#if HAVE_DIRENT_H -# include <dirent.h> -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# if HAVE_SYS_NDIR_H -# include <sys/ndir.h> -# endif -# if HAVE_SYS_DIR_H -# include <sys/dir.h> -# endif -# if HAVE_NDIR_H -# include <ndir.h> -# endif -#endif +#include <dirent.h> #include <pwd.h> #ifdef __APPLE__ @@ -108,6 +93,9 @@ using namespace llvm; namespace llvm { namespace sys { namespace fs { + +const file_t kInvalidFile = -1; + #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ defined(__minix) || defined(__FreeBSD_kernel__) || defined(__linux__) || \ defined(__CYGWIN__) || defined(__DragonFly__) || defined(_AIX) @@ -380,6 +368,12 @@ static bool is_local_impl(struct STATVFS &Vfs) { #elif defined(__CYGWIN__) // Cygwin doesn't expose this information; would need to use Win32 API. return false; +#elif defined(__Fuchsia__) + // Fuchsia doesn't yet support remote filesystem mounts. + return true; +#elif defined(__HAIKU__) + // Haiku doesn't expose this information. + return false; #elif defined(__sun) // statvfs::f_basetype contains a null-terminated FSType name of the mounted target StringRef fstype(Vfs.f_basetype); @@ -530,7 +524,7 @@ static void expandTildeExpr(SmallVectorImpl<char> &Path) { } static std::error_code fillStatus(int StatRet, const struct stat &Status, - file_status &Result) { + file_status &Result) { if (StatRet != 0) { std::error_code ec(errno, std::generic_category()); if (ec == errc::no_such_file_or_directory) @@ -643,7 +637,8 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length, uint64_t offset, std::error_code &ec) - : Size(length), Mapping() { + : Size(length), Mapping(), Mode(mode) { + (void)Mode; ec = init(fd, offset, mode); if (ec) Mapping = nullptr; @@ -702,7 +697,7 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { if (cur_dir == nullptr && errno != 0) { return std::error_code(errno, std::generic_category()); } else if (cur_dir != nullptr) { - StringRef name(cur_dir->d_name, NAMLEN(cur_dir)); + StringRef name(cur_dir->d_name); if ((name.size() == 1 && name[0] == '.') || (name.size() == 2 && name[0] == '.' && name[1] == '.')) return directory_iterator_increment(it); @@ -729,21 +724,83 @@ static bool hasProcSelfFD() { } #endif -std::error_code openFileForRead(const Twine &Name, int &ResultFD, - SmallVectorImpl<char> *RealPath) { - SmallString<128> Storage; - StringRef P = Name.toNullTerminatedStringRef(Storage); - int OpenFlags = O_RDONLY; +static int nativeOpenFlags(CreationDisposition Disp, OpenFlags Flags, + FileAccess Access) { + int Result = 0; + if (Access == FA_Read) + Result |= O_RDONLY; + else if (Access == FA_Write) + Result |= O_WRONLY; + else if (Access == (FA_Read | FA_Write)) + Result |= O_RDWR; + + // This is for compatibility with old code that assumed F_Append implied + // would open an existing file. See Windows/Path.inc for a longer comment. + if (Flags & F_Append) + Disp = CD_OpenAlways; + + if (Disp == CD_CreateNew) { + Result |= O_CREAT; // Create if it doesn't exist. + Result |= O_EXCL; // Fail if it does. + } else if (Disp == CD_CreateAlways) { + Result |= O_CREAT; // Create if it doesn't exist. + Result |= O_TRUNC; // Truncate if it does. + } else if (Disp == CD_OpenAlways) { + Result |= O_CREAT; // Create if it doesn't exist. + } else if (Disp == CD_OpenExisting) { + // Nothing special, just don't add O_CREAT and we get these semantics. + } + + if (Flags & F_Append) + Result |= O_APPEND; + #ifdef O_CLOEXEC - OpenFlags |= O_CLOEXEC; + if (!(Flags & OF_ChildInherit)) + Result |= O_CLOEXEC; #endif - if ((ResultFD = sys::RetryAfterSignal(-1, open, P.begin(), OpenFlags)) < 0) + + return Result; +} + +std::error_code openFile(const Twine &Name, int &ResultFD, + CreationDisposition Disp, FileAccess Access, + OpenFlags Flags, unsigned Mode) { + int OpenFlags = nativeOpenFlags(Disp, Flags, Access); + + SmallString<128> Storage; + StringRef P = Name.toNullTerminatedStringRef(Storage); + if ((ResultFD = sys::RetryAfterSignal(-1, ::open, P.begin(), OpenFlags, Mode)) < + 0) return std::error_code(errno, std::generic_category()); #ifndef O_CLOEXEC - int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC); - (void)r; - assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed"); + if (!(Flags & OF_ChildInherit)) { + int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC); + (void)r; + assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed"); + } #endif + return std::error_code(); +} + +Expected<int> openNativeFile(const Twine &Name, CreationDisposition Disp, + FileAccess Access, OpenFlags Flags, + unsigned Mode) { + + int FD; + std::error_code EC = openFile(Name, FD, Disp, Access, Flags, Mode); + if (EC) + return errorCodeToError(EC); + return FD; +} + +std::error_code openFileForRead(const Twine &Name, int &ResultFD, + OpenFlags Flags, + SmallVectorImpl<char> *RealPath) { + std::error_code EC = + openFile(Name, ResultFD, CD_OpenExisting, FA_Read, Flags, 0666); + if (EC) + return EC; + // Attempt to get the real name of the file, if the user asked if(!RealPath) return std::error_code(); @@ -763,6 +820,9 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD, if (CharCount > 0) RealPath->append(Buffer, Buffer + CharCount); } else { + SmallString<128> Storage; + StringRef P = Name.toNullTerminatedStringRef(Storage); + // Use ::realpath to get the real path name if (::realpath(P.begin(), Buffer) != nullptr) RealPath->append(Buffer, Buffer + strlen(Buffer)); @@ -771,41 +831,18 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD, return std::error_code(); } -std::error_code openFileForWrite(const Twine &Name, int &ResultFD, - sys::fs::OpenFlags Flags, unsigned Mode) { - // Verify that we don't have both "append" and "excl". - assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && - "Cannot specify both 'excl' and 'append' file creation flags!"); - - int OpenFlags = O_CREAT; - -#ifdef O_CLOEXEC - OpenFlags |= O_CLOEXEC; -#endif - - if (Flags & F_RW) - OpenFlags |= O_RDWR; - else - OpenFlags |= O_WRONLY; - - if (Flags & F_Append) - OpenFlags |= O_APPEND; - else - OpenFlags |= O_TRUNC; - - if (Flags & F_Excl) - OpenFlags |= O_EXCL; +Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags, + SmallVectorImpl<char> *RealPath) { + file_t ResultFD; + std::error_code EC = openFileForRead(Name, ResultFD, Flags, RealPath); + if (EC) + return errorCodeToError(EC); + return ResultFD; +} - SmallString<128> Storage; - StringRef P = Name.toNullTerminatedStringRef(Storage); - if ((ResultFD = sys::RetryAfterSignal(-1, open, P.begin(), OpenFlags, Mode)) < 0) - return std::error_code(errno, std::generic_category()); -#ifndef O_CLOEXEC - int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC); - (void)r; - assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed"); -#endif - return std::error_code(); +void closeFile(file_t &F) { + ::close(F); + F = kInvalidFile; } template <typename T> @@ -860,12 +897,12 @@ std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest, return real_path(Storage, dest, false); } - int fd; - std::error_code EC = openFileForRead(path, fd, &dest); - - if (EC) - return EC; - ::close(fd); + SmallString<128> Storage; + StringRef P = path.toNullTerminatedStringRef(Storage); + char Buffer[PATH_MAX]; + if (::realpath(P.begin(), Buffer) == nullptr) + return std::error_code(errno, std::generic_category()); + dest.append(Buffer, Buffer + strlen(Buffer)); return std::error_code(); } diff --git a/contrib/llvm/lib/Support/Unix/Process.inc b/contrib/llvm/lib/Support/Unix/Process.inc index e43650d707e3..fa515d44f3f2 100644 --- a/contrib/llvm/lib/Support/Unix/Process.inc +++ b/contrib/llvm/lib/Support/Unix/Process.inc @@ -14,6 +14,7 @@ #include "Unix.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Config/config.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/MutexGuard.h" @@ -78,7 +79,7 @@ unsigned Process::getPageSize() { #elif defined(HAVE_SYSCONF) static long page_size = ::sysconf(_SC_PAGE_SIZE); #else -#warning Cannot get the page size on this machine +#error Cannot get the page size on this machine #endif return static_cast<unsigned>(page_size); } @@ -172,15 +173,6 @@ Optional<std::string> Process::GetEnv(StringRef Name) { return std::string(Val); } -std::error_code -Process::GetArgumentVector(SmallVectorImpl<const char *> &ArgsOut, - ArrayRef<const char *> ArgsIn, - SpecificBumpPtrAllocator<char> &) { - ArgsOut.append(ArgsIn.begin(), ArgsIn.end()); - - return std::error_code(); -} - namespace { class FDCloser { public: @@ -207,7 +199,7 @@ std::error_code Process::FixupStandardFileDescriptors() { for (int StandardFD : StandardFDs) { struct stat st; errno = 0; - if (RetryAfterSignal(-1, fstat, StandardFD, &st) < 0) { + if (RetryAfterSignal(-1, ::fstat, StandardFD, &st) < 0) { assert(errno && "expected errno to be set if fstat failed!"); // fstat should return EBADF if the file descriptor is closed. if (errno != EBADF) @@ -219,7 +211,7 @@ std::error_code Process::FixupStandardFileDescriptors() { assert(errno == EBADF && "expected errno to have EBADF at this point!"); if (NullFD < 0) { - if ((NullFD = RetryAfterSignal(-1, open, "/dev/null", O_RDWR)) < 0) + if ((NullFD = RetryAfterSignal(-1, ::open, "/dev/null", O_RDWR)) < 0) return std::error_code(errno, std::generic_category()); } @@ -369,6 +361,21 @@ static bool terminalHasColors(int fd) { // Return true if we found a color capabilities for the current terminal. if (HasColors) return true; +#else + // When the terminfo database is not available, check if the current terminal + // is one of terminals that are known to support ANSI color escape codes. + if (const char *TermStr = std::getenv("TERM")) { + return StringSwitch<bool>(TermStr) + .Case("ansi", true) + .Case("cygwin", true) + .Case("linux", true) + .StartsWith("screen", true) + .StartsWith("xterm", true) + .StartsWith("vt100", true) + .StartsWith("rxvt", true) + .EndsWith("color", true) + .Default(false); + } #endif // Otherwise, be conservative. diff --git a/contrib/llvm/lib/Support/Unix/Program.inc b/contrib/llvm/lib/Support/Unix/Program.inc index 4f791991f3e8..d0abc3763e82 100644 --- a/contrib/llvm/lib/Support/Unix/Program.inc +++ b/contrib/llvm/lib/Support/Unix/Program.inc @@ -23,6 +23,7 @@ #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/StringSaver.h" #include "llvm/Support/raw_ostream.h" #if HAVE_SYS_STAT_H #include <sys/stat.h> @@ -164,8 +165,18 @@ static void SetMemoryLimits(unsigned size) { } -static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, - const char **Envp, ArrayRef<Optional<StringRef>> Redirects, +static std::vector<const char *> +toNullTerminatedCStringArray(ArrayRef<StringRef> Strings, StringSaver &Saver) { + std::vector<const char *> Result; + for (StringRef S : Strings) + Result.push_back(Saver.save(S).data()); + Result.push_back(nullptr); + return Result; +} + +static bool Execute(ProcessInfo &PI, StringRef Program, + ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env, + ArrayRef<Optional<StringRef>> Redirects, unsigned MemoryLimit, std::string *ErrMsg) { if (!llvm::sys::fs::exists(Program)) { if (ErrMsg) @@ -174,6 +185,18 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, return false; } + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + std::vector<const char *> ArgVector, EnvVector; + const char **Argv = nullptr; + const char **Envp = nullptr; + ArgVector = toNullTerminatedCStringArray(Args, Saver); + Argv = ArgVector.data(); + if (Env) { + EnvVector = toNullTerminatedCStringArray(*Env, Saver); + Envp = EnvVector.data(); + } + // If this OS has posix_spawn and there is no memory limit being implied, use // posix_spawn. It is more efficient than fork/exec. #ifdef HAVE_POSIX_SPAWN @@ -227,7 +250,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, // positive. pid_t PID = 0; int Err = posix_spawn(&PID, Program.str().c_str(), FileActions, - /*attrp*/nullptr, const_cast<char **>(Args), + /*attrp*/ nullptr, const_cast<char **>(Argv), const_cast<char **>(Envp)); if (FileActions) @@ -237,6 +260,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err); PI.Pid = PID; + PI.Process = PID; return true; } @@ -279,12 +303,10 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, // Execute! std::string PathStr = Program; if (Envp != nullptr) - execve(PathStr.c_str(), - const_cast<char **>(Args), + execve(PathStr.c_str(), const_cast<char **>(Argv), const_cast<char **>(Envp)); else - execv(PathStr.c_str(), - const_cast<char **>(Args)); + execv(PathStr.c_str(), const_cast<char **>(Argv)); // If the execve() failed, we should exit. Follow Unix protocol and // return 127 if the executable was not found, and 126 otherwise. // Use _exit rather than exit so that atexit functions and static @@ -300,6 +322,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, } PI.Pid = child; + PI.Process = child; return true; } @@ -404,14 +427,14 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, return WaitResult; } - std::error_code sys::ChangeStdinToBinary(){ +std::error_code sys::ChangeStdinToBinary() { // Do nothing, as Unix doesn't differentiate between text and binary. - return std::error_code(); + return std::error_code(); } - std::error_code sys::ChangeStdoutToBinary(){ +std::error_code sys::ChangeStdoutToBinary() { // Do nothing, as Unix doesn't differentiate between text and binary. - return std::error_code(); + return std::error_code(); } std::error_code @@ -432,29 +455,38 @@ llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents, } bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, - ArrayRef<const char *> Args) { + ArrayRef<StringRef> Args) { static long ArgMax = sysconf(_SC_ARG_MAX); + // POSIX requires that _POSIX_ARG_MAX is 4096, which is the lowest possible + // value for ARG_MAX on a POSIX compliant system. + static long ArgMin = _POSIX_ARG_MAX; + + // This the same baseline used by xargs. + long EffectiveArgMax = 128 * 1024; + + if (EffectiveArgMax > ArgMax) + EffectiveArgMax = ArgMax; + else if (EffectiveArgMax < ArgMin) + EffectiveArgMax = ArgMin; // System says no practical limit. if (ArgMax == -1) return true; // Conservatively account for space required by environment variables. - long HalfArgMax = ArgMax / 2; + long HalfArgMax = EffectiveArgMax / 2; size_t ArgLength = Program.size() + 1; - for (const char* Arg : Args) { - size_t length = strlen(Arg); - + for (StringRef Arg : Args) { // Ensure that we do not exceed the MAX_ARG_STRLEN constant on Linux, which // does not have a constant unlike what the man pages would have you // believe. Since this limit is pretty high, perform the check // unconditionally rather than trying to be aggressive and limiting it to // Linux only. - if (length >= (32 * 4096)) + if (Arg.size() >= (32 * 4096)) return false; - ArgLength += length + 1; + ArgLength += Arg.size() + 1; if (ArgLength > size_t(HalfArgMax)) { return false; } diff --git a/contrib/llvm/lib/Support/Unix/Signals.inc b/contrib/llvm/lib/Support/Unix/Signals.inc index aaf760c5b616..de26695d64ea 100644 --- a/contrib/llvm/lib/Support/Unix/Signals.inc +++ b/contrib/llvm/lib/Support/Unix/Signals.inc @@ -11,9 +11,31 @@ // Unix signals occurring while your program is running. // //===----------------------------------------------------------------------===// +// +// This file is extremely careful to only do signal-safe things while in a +// signal handler. In particular, memory allocation and acquiring a mutex +// while in a signal handler should never occur. ManagedStatic isn't usable from +// a signal handler for 2 reasons: +// +// 1. Creating a new one allocates. +// 2. The signal handler could fire while llvm_shutdown is being processed, in +// which case the ManagedStatic is in an unknown state because it could +// already have been destroyed, or be in the process of being destroyed. +// +// Modifying the behavior of the signal handlers (such as registering new ones) +// can acquire a mutex, but all this guarantees is that the signal handler +// behavior is only modified by one thread at a time. A signal handler can still +// fire while this occurs! +// +// Adding work to a signal handler requires lock-freedom (and assume atomics are +// always lock-free) because the signal handler could fire while new work is +// being added. +// +//===----------------------------------------------------------------------===// #include "Unix.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Config/config.h" #include "llvm/Demangle/Demangle.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" @@ -59,24 +81,133 @@ using namespace llvm; static RETSIGTYPE SignalHandler(int Sig); // defined below. -static ManagedStatic<sys::SmartMutex<true> > SignalsMutex; +/// The function to call if ctrl-c is pressed. +using InterruptFunctionType = void (*)(); +static std::atomic<InterruptFunctionType> InterruptFunction = + ATOMIC_VAR_INIT(nullptr); + +namespace { +/// Signal-safe removal of files. +/// Inserting and erasing from the list isn't signal-safe, but removal of files +/// themselves is signal-safe. Memory is freed when the head is freed, deletion +/// is therefore not signal-safe either. +class FileToRemoveList { + std::atomic<char *> Filename = ATOMIC_VAR_INIT(nullptr); + std::atomic<FileToRemoveList *> Next = ATOMIC_VAR_INIT(nullptr); + + FileToRemoveList() = default; + // Not signal-safe. + FileToRemoveList(const std::string &str) : Filename(strdup(str.c_str())) {} + +public: + // Not signal-safe. + ~FileToRemoveList() { + if (FileToRemoveList *N = Next.exchange(nullptr)) + delete N; + if (char *F = Filename.exchange(nullptr)) + free(F); + } + + // Not signal-safe. + static void insert(std::atomic<FileToRemoveList *> &Head, + const std::string &Filename) { + // Insert the new file at the end of the list. + FileToRemoveList *NewHead = new FileToRemoveList(Filename); + std::atomic<FileToRemoveList *> *InsertionPoint = &Head; + FileToRemoveList *OldHead = nullptr; + while (!InsertionPoint->compare_exchange_strong(OldHead, NewHead)) { + InsertionPoint = &OldHead->Next; + OldHead = nullptr; + } + } + + // Not signal-safe. + static void erase(std::atomic<FileToRemoveList *> &Head, + const std::string &Filename) { + // Use a lock to avoid concurrent erase: the comparison would access + // free'd memory. + static ManagedStatic<sys::SmartMutex<true>> Lock; + sys::SmartScopedLock<true> Writer(*Lock); + + for (FileToRemoveList *Current = Head.load(); Current; + Current = Current->Next.load()) { + if (char *OldFilename = Current->Filename.load()) { + if (OldFilename != Filename) + continue; + // Leave an empty filename. + OldFilename = Current->Filename.exchange(nullptr); + // The filename might have become null between the time we + // compared it and we exchanged it. + if (OldFilename) + free(OldFilename); + } + } + } -/// InterruptFunction - The function to call if ctrl-c is pressed. -static void (*InterruptFunction)() = nullptr; + // Signal-safe. + static void removeAllFiles(std::atomic<FileToRemoveList *> &Head) { + // If cleanup were to occur while we're removing files we'd have a bad time. + // Make sure we're OK by preventing cleanup from doing anything while we're + // removing files. If cleanup races with us and we win we'll have a leak, + // but we won't crash. + FileToRemoveList *OldHead = Head.exchange(nullptr); + + for (FileToRemoveList *currentFile = OldHead; currentFile; + currentFile = currentFile->Next.load()) { + // If erasing was occuring while we're trying to remove files we'd look + // at free'd data. Take away the path and put it back when done. + if (char *path = currentFile->Filename.exchange(nullptr)) { + // Get the status so we can determine if it's a file or directory. If we + // can't stat the file, ignore it. + struct stat buf; + if (stat(path, &buf) != 0) + continue; + + // If this is not a regular file, ignore it. We want to prevent removal + // of special files like /dev/null, even if the compiler is being run + // with the super-user permissions. + if (!S_ISREG(buf.st_mode)) + continue; + + // Otherwise, remove the file. We ignore any errors here as there is + // nothing else we can do. + unlink(path); + + // We're done removing the file, erasing can safely proceed. + currentFile->Filename.exchange(path); + } + } -static ManagedStatic<std::vector<std::string>> FilesToRemove; + // We're done removing files, cleanup can safely proceed. + Head.exchange(OldHead); + } +}; +static std::atomic<FileToRemoveList *> FilesToRemove = ATOMIC_VAR_INIT(nullptr); + +/// Clean up the list in a signal-friendly manner. +/// Recall that signals can fire during llvm_shutdown. If this occurs we should +/// either clean something up or nothing at all, but we shouldn't crash! +struct FilesToRemoveCleanup { + // Not signal-safe. + ~FilesToRemoveCleanup() { + FileToRemoveList *Head = FilesToRemove.exchange(nullptr); + if (Head) + delete Head; + } +}; +} // namespace 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. +// 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. static const int IntSigs[] = { SIGHUP, SIGINT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2 }; -// KillSigs - Signals that represent that we have a bug, and our prompt -// termination has been ordered. +// Signals that represent that we have a bug, and our prompt termination has +// been ordered. static const int KillSigs[] = { SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGQUIT #ifdef SIGSYS @@ -93,30 +224,12 @@ static const int KillSigs[] = { #endif }; -static unsigned NumRegisteredSignals = 0; +static std::atomic<unsigned> NumRegisteredSignals = ATOMIC_VAR_INIT(0); static struct { struct sigaction SA; int SigNo; } RegisteredSignalInfo[array_lengthof(IntSigs) + array_lengthof(KillSigs)]; - -static void RegisterHandler(int Signal) { - assert(NumRegisteredSignals < array_lengthof(RegisteredSignalInfo) && - "Out of space for signal handlers!"); - - struct sigaction NewHandler; - - NewHandler.sa_handler = SignalHandler; - NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK; - sigemptyset(&NewHandler.sa_mask); - - // Install the new handler, save the old one in RegisteredSignalInfo. - sigaction(Signal, &NewHandler, - &RegisteredSignalInfo[NumRegisteredSignals].SA); - RegisteredSignalInfo[NumRegisteredSignals].SigNo = Signal; - ++NumRegisteredSignals; -} - #if defined(HAVE_SIGALTSTACK) // Hold onto both the old and new alternate signal stack so that it's not // reported as a leak. We don't make any attempt to remove our alt signal @@ -138,7 +251,7 @@ static void CreateSigAltStack() { return; stack_t AltStack = {}; - AltStack.ss_sp = reinterpret_cast<char *>(malloc(AltStackSize)); + AltStack.ss_sp = static_cast<char *>(safe_malloc(AltStackSize)); NewAltStackPointer = AltStack.ss_sp; // Save to avoid reporting a leak. AltStack.ss_size = AltStackSize; if (sigaltstack(&AltStack, &OldAltStack) != 0) @@ -148,64 +261,59 @@ static void CreateSigAltStack() { static void CreateSigAltStack() {} #endif -static void RegisterHandlers() { - sys::SmartScopedLock<true> Guard(*SignalsMutex); +static void RegisterHandlers() { // Not signal-safe. + // The mutex prevents other threads from registering handlers while we're + // doing it. We also have to protect the handlers and their count because + // a signal handler could fire while we're registeting handlers. + static ManagedStatic<sys::SmartMutex<true>> SignalHandlerRegistrationMutex; + sys::SmartScopedLock<true> Guard(*SignalHandlerRegistrationMutex); // If the handlers are already registered, we're done. - if (NumRegisteredSignals != 0) return; + if (NumRegisteredSignals.load() != 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); + auto registerHandler = [&](int Signal) { + unsigned Index = NumRegisteredSignals.load(); + assert(Index < array_lengthof(RegisteredSignalInfo) && + "Out of space for signal handlers!"); + + struct sigaction NewHandler; + + NewHandler.sa_handler = SignalHandler; + NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK; + sigemptyset(&NewHandler.sa_mask); + + // Install the new handler, save the old one in RegisteredSignalInfo. + sigaction(Signal, &NewHandler, &RegisteredSignalInfo[Index].SA); + RegisteredSignalInfo[Index].SigNo = Signal; + ++NumRegisteredSignals; + }; + + for (auto S : IntSigs) + registerHandler(S); + for (auto S : KillSigs) + registerHandler(S); } static void UnregisterHandlers() { // Restore all of the signal handlers to how they were before we showed up. - for (unsigned i = 0, e = NumRegisteredSignals; i != e; ++i) + for (unsigned i = 0, e = NumRegisteredSignals.load(); i != e; ++i) { sigaction(RegisteredSignalInfo[i].SigNo, &RegisteredSignalInfo[i].SA, nullptr); - NumRegisteredSignals = 0; + --NumRegisteredSignals; + } } - -/// RemoveFilesToRemove - Process the FilesToRemove list. This function -/// should be called with the SignalsMutex lock held. -/// NB: This must be an async signal safe function. It cannot allocate or free -/// memory, even in debug builds. +/// Process the FilesToRemove list. static void RemoveFilesToRemove() { - // Avoid constructing ManagedStatic in the signal handler. - // If FilesToRemove is not constructed, there are no files to remove. - if (!FilesToRemove.isConstructed()) - return; - - // We avoid iterators in case of debug iterators that allocate or release - // memory. - std::vector<std::string>& FilesToRemoveRef = *FilesToRemove; - for (unsigned i = 0, e = FilesToRemoveRef.size(); i != e; ++i) { - const char *path = FilesToRemoveRef[i].c_str(); - - // Get the status so we can determine if it's a file or directory. If we - // can't stat the file, ignore it. - struct stat buf; - if (stat(path, &buf) != 0) - continue; - - // If this is not a regular file, ignore it. We want to prevent removal of - // special files like /dev/null, even if the compiler is being run with the - // super-user permissions. - if (!S_ISREG(buf.st_mode)) - continue; - - // Otherwise, remove the file. We ignore any errors here as there is nothing - // else we can do. - unlink(path); - } + FileToRemoveList::removeAllFiles(FilesToRemove); } -// SignalHandler - The signal handler that runs. +// The signal handler that runs. static RETSIGTYPE SignalHandler(int Sig) { // Restore the signal behavior to default, so that the program actually // crashes when we return and the signal reissues. This also ensures that if @@ -219,20 +327,13 @@ static RETSIGTYPE SignalHandler(int Sig) { sigprocmask(SIG_UNBLOCK, &SigMask, nullptr); { - unique_lock<sys::SmartMutex<true>> Guard(*SignalsMutex); RemoveFilesToRemove(); if (std::find(std::begin(IntSigs), std::end(IntSigs), Sig) != std::end(IntSigs)) { - if (InterruptFunction) { - void (*IF)() = InterruptFunction; - Guard.unlock(); - InterruptFunction = nullptr; - IF(); // run the interrupt function. - return; - } + if (auto OldInterruptFunction = InterruptFunction.exchange(nullptr)) + return OldInterruptFunction(); - Guard.unlock(); raise(Sig); // Execute the default handler. return; } @@ -252,45 +353,36 @@ static RETSIGTYPE SignalHandler(int Sig) { } void llvm::sys::RunInterruptHandlers() { - sys::SmartScopedLock<true> Guard(*SignalsMutex); RemoveFilesToRemove(); } void llvm::sys::SetInterruptFunction(void (*IF)()) { - { - sys::SmartScopedLock<true> Guard(*SignalsMutex); - InterruptFunction = IF; - } + InterruptFunction.exchange(IF); RegisterHandlers(); } -// RemoveFileOnSignal - The public API +// The public API bool llvm::sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { - { - sys::SmartScopedLock<true> Guard(*SignalsMutex); - FilesToRemove->push_back(Filename); - } - + // Ensure that cleanup will occur as soon as one file is added. + static ManagedStatic<FilesToRemoveCleanup> FilesToRemoveCleanup; + *FilesToRemoveCleanup; + FileToRemoveList::insert(FilesToRemove, Filename.str()); RegisterHandlers(); return false; } -// DontRemoveFileOnSignal - The public API +// The public API void llvm::sys::DontRemoveFileOnSignal(StringRef Filename) { - sys::SmartScopedLock<true> Guard(*SignalsMutex); - std::vector<std::string>::reverse_iterator RI = - find(reverse(*FilesToRemove), Filename); - std::vector<std::string>::iterator I = FilesToRemove->end(); - if (RI != FilesToRemove->rend()) - I = FilesToRemove->erase(RI.base()-1); + FileToRemoveList::erase(FilesToRemove, Filename.str()); } -/// AddSignalHandler - Add a function to be called when a signal is delivered -/// to the process. The handler can have a cookie passed to it to identify -/// what instance of the handler it is. -void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { - CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); +/// Add a function to be called when a signal is delivered to the process. The +/// handler can have a cookie passed to it to identify what instance of the +/// handler it is. +void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, + void *Cookie) { // Signal-safe. + insertSignalHandler(FnPtr, Cookie); RegisterHandlers(); } @@ -383,8 +475,8 @@ static int unwindBacktrace(void **StackTrace, int MaxEntries) { } #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. +// 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. @@ -463,8 +555,8 @@ static void PrintStackTraceSignalHandler(void *) { 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. +/// 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(StringRef Argv0, bool DisableCrashReporting) { ::Argv0 = Argv0; diff --git a/contrib/llvm/lib/Support/Unix/ThreadLocal.inc b/contrib/llvm/lib/Support/Unix/ThreadLocal.inc index 31c3f3835b29..a6564f0fa281 100644 --- a/contrib/llvm/lib/Support/Unix/ThreadLocal.inc +++ b/contrib/llvm/lib/Support/Unix/ThreadLocal.inc @@ -16,6 +16,8 @@ //=== is guaranteed to work on *all* UNIX variants. //===----------------------------------------------------------------------===// +#include "llvm/Config/config.h" + #if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_GETSPECIFIC) #include <cassert> diff --git a/contrib/llvm/lib/Support/Unix/Threading.inc b/contrib/llvm/lib/Support/Unix/Threading.inc index 7369cff8466c..2d49ce1ad747 100644 --- a/contrib/llvm/lib/Support/Unix/Threading.inc +++ b/contrib/llvm/lib/Support/Unix/Threading.inc @@ -21,8 +21,8 @@ #include <pthread.h> -#if defined(__FreeBSD__) -#include <pthread_np.h> // For pthread_getthreadid_np() +#if defined(__FreeBSD__) || defined(__OpenBSD__) +#include <pthread_np.h> // For pthread_getthreadid_np() / pthread_set_name_np() #endif #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) @@ -98,8 +98,6 @@ uint64_t llvm::get_threadid() { return uint64_t(gettid()); #elif defined(__linux__) return uint64_t(syscall(SYS_gettid)); -#elif defined(LLVM_ON_WIN32) - return uint64_t(::GetCurrentThreadId()); #else return uint64_t(pthread_self()); #endif @@ -119,6 +117,8 @@ static constexpr uint32_t get_max_thread_name_length_impl() { #endif #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) return 16; +#elif defined(__OpenBSD__) + return 32; #else return 0; #endif @@ -138,8 +138,9 @@ void llvm::set_thread_name(const Twine &Name) { // terminated, but additionally the end of a long thread name will usually // be more unique than the beginning, since a common pattern is for similar // threads to share a common prefix. + // Note that the name length includes the null terminator. if (get_max_thread_name_length() > 0) - NameStr = NameStr.take_back(get_max_thread_name_length()); + NameStr = NameStr.take_back(get_max_thread_name_length() - 1); (void)NameStr; #if defined(__linux__) #if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__) @@ -147,7 +148,7 @@ void llvm::set_thread_name(const Twine &Name) { ::pthread_setname_np(::pthread_self(), NameStr.data()); #endif #endif -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__OpenBSD__) ::pthread_set_name_np(::pthread_self(), NameStr.data()); #elif defined(__NetBSD__) ::pthread_setname_np(::pthread_self(), "%s", @@ -175,7 +176,7 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) { if (kp == nullptr || (error != 0 && errno == ENOMEM)) { // Add extra space in case threads are added before next call. len += sizeof(*kp) + len / 10; - nkp = (struct kinfo_proc *)realloc(kp, len); + nkp = (struct kinfo_proc *)::realloc(kp, len); if (nkp == nullptr) { free(kp); return; @@ -203,7 +204,6 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) { Name.append(buf, buf + strlen(buf)); #elif defined(__linux__) -#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__) #if HAVE_PTHREAD_GETNAME_NP constexpr uint32_t len = get_max_thread_name_length_impl(); char Buffer[len] = {'\0'}; // FIXME: working around MSan false positive. @@ -211,5 +211,4 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) { Name.append(Buffer, Buffer + strlen(Buffer)); #endif #endif -#endif } diff --git a/contrib/llvm/lib/Support/Unix/Unix.h b/contrib/llvm/lib/Support/Unix/Unix.h index 239a6d60aaef..0c5d4de556d5 100644 --- a/contrib/llvm/lib/Support/Unix/Unix.h +++ b/contrib/llvm/lib/Support/Unix/Unix.h @@ -56,7 +56,7 @@ /// This function builds an error message into \p ErrMsg using the \p prefix /// string and the Unix error number given by \p errnum. If errnum is -1, the /// default then the value of errno is used. -/// @brief Make an error message +/// Make an error message /// /// If the error number can be converted to a string, it will be /// separated from prefix by ": ". diff --git a/contrib/llvm/lib/Support/Unix/Watchdog.inc b/contrib/llvm/lib/Support/Unix/Watchdog.inc index 5d89c0e51b11..f4253391d952 100644 --- a/contrib/llvm/lib/Support/Unix/Watchdog.inc +++ b/contrib/llvm/lib/Support/Unix/Watchdog.inc @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Config/config.h" + #ifdef HAVE_UNISTD_H #include <unistd.h> #endif diff --git a/contrib/llvm/lib/Support/VersionTuple.cpp b/contrib/llvm/lib/Support/VersionTuple.cpp new file mode 100644 index 000000000000..3f219bfbedfa --- /dev/null +++ b/contrib/llvm/lib/Support/VersionTuple.cpp @@ -0,0 +1,110 @@ +//===- VersionTuple.cpp - Version Number Handling ---------------*- C++ -*-===// +// +// 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 VersionTuple class, which represents a version in +// the form major[.minor[.subminor]]. +// +//===----------------------------------------------------------------------===// +#include "llvm/Support/VersionTuple.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +std::string VersionTuple::getAsString() const { + std::string Result; + { + llvm::raw_string_ostream Out(Result); + Out << *this; + } + return Result; +} + +raw_ostream &llvm::operator<<(raw_ostream &Out, const VersionTuple &V) { + Out << V.getMajor(); + if (Optional<unsigned> Minor = V.getMinor()) + Out << '.' << *Minor; + if (Optional<unsigned> Subminor = V.getSubminor()) + Out << '.' << *Subminor; + if (Optional<unsigned> Build = V.getBuild()) + Out << '.' << *Build; + return Out; +} + +static bool parseInt(StringRef &input, unsigned &value) { + assert(value == 0); + if (input.empty()) + return true; + + char next = input[0]; + input = input.substr(1); + if (next < '0' || next > '9') + return true; + value = (unsigned)(next - '0'); + + while (!input.empty()) { + next = input[0]; + if (next < '0' || next > '9') + return false; + input = input.substr(1); + value = value * 10 + (unsigned)(next - '0'); + } + + return false; +} + +bool VersionTuple::tryParse(StringRef input) { + unsigned major = 0, minor = 0, micro = 0, build = 0; + + // Parse the major version, [0-9]+ + if (parseInt(input, major)) + return true; + + if (input.empty()) { + *this = VersionTuple(major); + return false; + } + + // If we're not done, parse the minor version, \.[0-9]+ + if (input[0] != '.') + return true; + input = input.substr(1); + if (parseInt(input, minor)) + return true; + + if (input.empty()) { + *this = VersionTuple(major, minor); + return false; + } + + // If we're not done, parse the micro version, \.[0-9]+ + if (input[0] != '.') + return true; + input = input.substr(1); + if (parseInt(input, micro)) + return true; + + if (input.empty()) { + *this = VersionTuple(major, minor, micro); + return false; + } + + // If we're not done, parse the micro version, \.[0-9]+ + if (input[0] != '.') + return true; + input = input.substr(1); + if (parseInt(input, build)) + return true; + + // If we have characters left over, it's an error. + if (!input.empty()) + return true; + + *this = VersionTuple(major, minor, micro, build); + return false; +} diff --git a/contrib/llvm/lib/Support/Watchdog.cpp b/contrib/llvm/lib/Support/Watchdog.cpp index 724aa001f16e..be55e3122e70 100644 --- a/contrib/llvm/lib/Support/Watchdog.cpp +++ b/contrib/llvm/lib/Support/Watchdog.cpp @@ -12,12 +12,12 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Watchdog.h" -#include "llvm/Config/config.h" +#include "llvm/Config/llvm-config.h" // Include the platform-specific parts of this class. #ifdef LLVM_ON_UNIX #include "Unix/Watchdog.inc" #endif -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 #include "Windows/Watchdog.inc" #endif diff --git a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc index 083ea902eeb2..1d47f0848a6d 100644 --- a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc +++ b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "WindowsSupport.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/raw_ostream.h" #include <psapi.h> diff --git a/contrib/llvm/lib/Support/Windows/Host.inc b/contrib/llvm/lib/Support/Windows/Host.inc index 90a6fb316703..58c4dc5d678f 100644 --- a/contrib/llvm/lib/Support/Windows/Host.inc +++ b/contrib/llvm/lib/Support/Windows/Host.inc @@ -30,5 +30,5 @@ std::string sys::getDefaultTargetTriple() { Triple = EnvTriple; #endif - return Triple::normalize(Triple); + return Triple; } diff --git a/contrib/llvm/lib/Support/Windows/Path.inc b/contrib/llvm/lib/Support/Windows/Path.inc index f81790b17df5..f425d607af47 100644 --- a/contrib/llvm/lib/Support/Windows/Path.inc +++ b/contrib/llvm/lib/Support/Windows/Path.inc @@ -17,6 +17,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/WindowsError.h" #include <fcntl.h> #include <io.h> @@ -45,6 +46,7 @@ typedef int errno_t; using namespace llvm; using llvm::sys::windows::UTF8ToUTF16; +using llvm::sys::windows::CurCPToUTF16; using llvm::sys::windows::UTF16ToUTF8; using llvm::sys::path::widenPath; @@ -121,6 +123,8 @@ std::error_code widenPath(const Twine &Path8, namespace fs { +const file_t kInvalidFile = INVALID_HANDLE_VALUE; + std::string getMainExecutable(const char *argv0, void *MainExecAddr) { SmallVector<wchar_t, MAX_PATH> PathName; DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity()); @@ -400,56 +404,6 @@ static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) { return std::error_code(); } -static std::error_code removeFD(int FD) { - HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); - return setDeleteDisposition(Handle, true); -} - -/// In order to handle temporary files we want the following properties -/// -/// * The temporary file is deleted on crashes -/// * We can use (read, rename, etc) the temporary file. -/// * We can cancel the delete to keep the file. -/// -/// Using FILE_DISPOSITION_INFO with DeleteFile=true will create a file that is -/// deleted on close, but it has a few problems: -/// -/// * The file cannot be used. An attempt to open or rename the file will fail. -/// This makes the temporary file almost useless, as it cannot be part of -/// any other CreateFileW call in the current or in another process. -/// * It is not atomic. A crash just after CreateFileW or just after canceling -/// the delete will leave the file on disk. -/// -/// Using FILE_FLAG_DELETE_ON_CLOSE solves the first issues and the first part -/// of the second one, but there is no way to cancel it in place. What works is -/// to create a second handle to prevent the deletion, close the first one and -/// then clear DeleteFile with SetFileInformationByHandle. This requires -/// changing the handle and file descriptor the caller uses. -static std::error_code cancelDeleteOnClose(int &FD) { - HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); - SmallVector<wchar_t, MAX_PATH> Name; - if (std::error_code EC = realPathFromHandle(Handle, Name)) - return EC; - HANDLE NewHandle = - ::CreateFileW(Name.data(), GENERIC_READ | GENERIC_WRITE | DELETE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (NewHandle == INVALID_HANDLE_VALUE) - return mapWindowsError(::GetLastError()); - if (close(FD)) - return mapWindowsError(::GetLastError()); - - if (std::error_code EC = setDeleteDisposition(NewHandle, false)) - return EC; - - FD = ::_open_osfhandle(intptr_t(NewHandle), 0); - if (FD == -1) { - ::CloseHandle(NewHandle); - return mapWindowsError(ERROR_INVALID_HANDLE); - } - return std::error_code(); -} - static std::error_code rename_internal(HANDLE FromHandle, const Twine &To, bool ReplaceIfExists) { SmallVector<wchar_t, 0> ToWide; @@ -822,8 +776,9 @@ std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) { std::error_code mapped_file_region::init(int FD, uint64_t Offset, mapmode Mode) { - HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); - if (FileHandle == INVALID_HANDLE_VALUE) + this->Mode = Mode; + HANDLE OrigFileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + if (OrigFileHandle == INVALID_HANDLE_VALUE) return make_error_code(errc::bad_file_descriptor); DWORD flprotect; @@ -834,7 +789,7 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, } HANDLE FileMappingHandle = - ::CreateFileMappingW(FileHandle, 0, flprotect, + ::CreateFileMappingW(OrigFileHandle, 0, flprotect, Hi_32(Size), Lo_32(Size), 0); @@ -872,9 +827,20 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, Size = mbi.RegionSize; } - // Close all the handles except for the view. It will keep the other handles - // alive. + // Close the file mapping handle, as it's kept alive by the file mapping. But + // neither the file mapping nor the file mapping handle keep the file handle + // alive, so we need to keep a reference to the file in case all other handles + // are closed and the file is deleted, which may cause invalid data to be read + // from the file. ::CloseHandle(FileMappingHandle); + if (!::DuplicateHandle(::GetCurrentProcess(), OrigFileHandle, + ::GetCurrentProcess(), &FileHandle, 0, 0, + DUPLICATE_SAME_ACCESS)) { + std::error_code ec = mapWindowsError(GetLastError()); + ::UnmapViewOfFile(Mapping); + return ec; + } + return std::error_code(); } @@ -887,8 +853,20 @@ mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length, } mapped_file_region::~mapped_file_region() { - if (Mapping) + if (Mapping) { ::UnmapViewOfFile(Mapping); + + if (Mode == mapmode::readwrite) { + // There is a Windows kernel bug, the exact trigger conditions of which + // are not well understood. When triggered, dirty pages are not properly + // flushed and subsequent process's attempts to read a file can return + // invalid data. Calling FlushFileBuffers on the write handle is + // sufficient to ensure that this bug is not triggered. + ::FlushFileBuffers(FileHandle); + } + + ::CloseHandle(FileHandle); + } } size_t mapped_file_region::size() const { @@ -1017,35 +995,82 @@ ErrorOr<basic_file_status> directory_entry::status() const { return Status; } -static std::error_code directoryRealPath(const Twine &Name, - SmallVectorImpl<char> &RealPath) { - SmallVector<wchar_t, 128> PathUTF16; +static std::error_code nativeFileToFd(Expected<HANDLE> H, int &ResultFD, + OpenFlags Flags) { + int CrtOpenFlags = 0; + if (Flags & OF_Append) + CrtOpenFlags |= _O_APPEND; - if (std::error_code EC = widenPath(Name, PathUTF16)) - return EC; + if (Flags & OF_Text) + CrtOpenFlags |= _O_TEXT; - HANDLE H = - ::CreateFileW(PathUTF16.begin(), GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (H == INVALID_HANDLE_VALUE) - return mapWindowsError(GetLastError()); - std::error_code EC = realPathFromHandle(H, RealPath); - ::CloseHandle(H); - return EC; + ResultFD = -1; + if (!H) + return errorToErrorCode(H.takeError()); + + ResultFD = ::_open_osfhandle(intptr_t(*H), CrtOpenFlags); + if (ResultFD == -1) { + ::CloseHandle(*H); + return mapWindowsError(ERROR_INVALID_HANDLE); + } + return std::error_code(); } -std::error_code openFileForRead(const Twine &Name, int &ResultFD, - SmallVectorImpl<char> *RealPath) { +static DWORD nativeDisposition(CreationDisposition Disp, OpenFlags Flags) { + // This is a compatibility hack. Really we should respect the creation + // disposition, but a lot of old code relied on the implicit assumption that + // OF_Append implied it would open an existing file. Since the disposition is + // now explicit and defaults to CD_CreateAlways, this assumption would cause + // any usage of OF_Append to append to a new file, even if the file already + // existed. A better solution might have two new creation dispositions: + // CD_AppendAlways and CD_AppendNew. This would also address the problem of + // OF_Append being used on a read-only descriptor, which doesn't make sense. + if (Flags & OF_Append) + return OPEN_ALWAYS; + + switch (Disp) { + case CD_CreateAlways: + return CREATE_ALWAYS; + case CD_CreateNew: + return CREATE_NEW; + case CD_OpenAlways: + return OPEN_ALWAYS; + case CD_OpenExisting: + return OPEN_EXISTING; + } + llvm_unreachable("unreachable!"); +} + +static DWORD nativeAccess(FileAccess Access, OpenFlags Flags) { + DWORD Result = 0; + if (Access & FA_Read) + Result |= GENERIC_READ; + if (Access & FA_Write) + Result |= GENERIC_WRITE; + if (Flags & OF_Delete) + Result |= DELETE; + if (Flags & OF_UpdateAtime) + Result |= FILE_WRITE_ATTRIBUTES; + return Result; +} + +static std::error_code openNativeFileInternal(const Twine &Name, + file_t &ResultFile, DWORD Disp, + DWORD Access, DWORD Flags, + bool Inherit = false) { SmallVector<wchar_t, 128> PathUTF16; - if (std::error_code EC = widenPath(Name, PathUTF16)) return EC; + SECURITY_ATTRIBUTES SA; + SA.nLength = sizeof(SA); + SA.lpSecurityDescriptor = nullptr; + SA.bInheritHandle = Inherit; + HANDLE H = - ::CreateFileW(PathUTF16.begin(), GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + ::CreateFileW(PathUTF16.begin(), Access, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &SA, + Disp, Flags, NULL); if (H == INVALID_HANDLE_VALUE) { DWORD LastError = ::GetLastError(); std::error_code EC = mapWindowsError(LastError); @@ -1058,82 +1083,96 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD, return make_error_code(errc::is_a_directory); return EC; } + ResultFile = H; + return std::error_code(); +} - int FD = ::_open_osfhandle(intptr_t(H), 0); - if (FD == -1) { - ::CloseHandle(H); - return mapWindowsError(ERROR_INVALID_HANDLE); +Expected<file_t> openNativeFile(const Twine &Name, CreationDisposition Disp, + FileAccess Access, OpenFlags Flags, + unsigned Mode) { + // Verify that we don't have both "append" and "excl". + assert((!(Disp == CD_CreateNew) || !(Flags & OF_Append)) && + "Cannot specify both 'CreateNew' and 'Append' file creation flags!"); + + DWORD NativeDisp = nativeDisposition(Disp, Flags); + DWORD NativeAccess = nativeAccess(Access, Flags); + + bool Inherit = false; + if (Flags & OF_ChildInherit) + Inherit = true; + + file_t Result; + std::error_code EC = openNativeFileInternal( + Name, Result, NativeDisp, NativeAccess, FILE_ATTRIBUTE_NORMAL, Inherit); + if (EC) + return errorCodeToError(EC); + + if (Flags & OF_UpdateAtime) { + FILETIME FileTime; + SYSTEMTIME SystemTime; + GetSystemTime(&SystemTime); + if (SystemTimeToFileTime(&SystemTime, &FileTime) == 0 || + SetFileTime(Result, NULL, &FileTime, NULL) == 0) { + DWORD LastError = ::GetLastError(); + ::CloseHandle(Result); + return errorCodeToError(mapWindowsError(LastError)); + } } - // Fetch the real name of the file, if the user asked - if (RealPath) - realPathFromHandle(H, *RealPath); - - ResultFD = FD; - return std::error_code(); + if (Flags & OF_Delete) { + if ((EC = setDeleteDisposition(Result, true))) { + ::CloseHandle(Result); + return errorCodeToError(EC); + } + } + return Result; } -std::error_code openFileForWrite(const Twine &Name, int &ResultFD, - sys::fs::OpenFlags Flags, unsigned Mode) { - // Verify that we don't have both "append" and "excl". - assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && - "Cannot specify both 'excl' and 'append' file creation flags!"); +std::error_code openFile(const Twine &Name, int &ResultFD, + CreationDisposition Disp, FileAccess Access, + OpenFlags Flags, unsigned int Mode) { + Expected<file_t> Result = openNativeFile(Name, Disp, Access, Flags); + if (!Result) + return errorToErrorCode(Result.takeError()); - SmallVector<wchar_t, 128> PathUTF16; + return nativeFileToFd(*Result, ResultFD, Flags); +} - if (std::error_code EC = widenPath(Name, PathUTF16)) +static std::error_code directoryRealPath(const Twine &Name, + SmallVectorImpl<char> &RealPath) { + file_t File; + std::error_code EC = openNativeFileInternal( + Name, File, OPEN_EXISTING, GENERIC_READ, FILE_FLAG_BACKUP_SEMANTICS); + if (EC) return EC; - DWORD CreationDisposition; - if (Flags & F_Excl) - CreationDisposition = CREATE_NEW; - else if (Flags & F_Append) - CreationDisposition = OPEN_ALWAYS; - else - CreationDisposition = CREATE_ALWAYS; - - DWORD Access = GENERIC_WRITE; - DWORD Attributes = FILE_ATTRIBUTE_NORMAL; - if (Flags & F_RW) - Access |= GENERIC_READ; - if (Flags & F_Delete) { - Access |= DELETE; - Attributes |= FILE_FLAG_DELETE_ON_CLOSE; - } - - HANDLE H = - ::CreateFileW(PathUTF16.data(), Access, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, CreationDisposition, Attributes, NULL); + EC = realPathFromHandle(File, RealPath); + ::CloseHandle(File); + return EC; +} - if (H == INVALID_HANDLE_VALUE) { - DWORD LastError = ::GetLastError(); - std::error_code EC = mapWindowsError(LastError); - // Provide a better error message when trying to open directories. - // This only runs if we failed to open the file, so there is probably - // no performances issues. - if (LastError != ERROR_ACCESS_DENIED) - return EC; - if (is_directory(Name)) - return make_error_code(errc::is_a_directory); - return EC; - } +std::error_code openFileForRead(const Twine &Name, int &ResultFD, + OpenFlags Flags, + SmallVectorImpl<char> *RealPath) { + Expected<HANDLE> NativeFile = openNativeFileForRead(Name, Flags, RealPath); + return nativeFileToFd(std::move(NativeFile), ResultFD, OF_None); +} - int OpenFlags = 0; - if (Flags & F_Append) - OpenFlags |= _O_APPEND; +Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags, + SmallVectorImpl<char> *RealPath) { + Expected<file_t> Result = + openNativeFile(Name, CD_OpenExisting, FA_Read, Flags); - if (Flags & F_Text) - OpenFlags |= _O_TEXT; + // Fetch the real name of the file, if the user asked + if (Result && RealPath) + realPathFromHandle(*Result, *RealPath); - int FD = ::_open_osfhandle(intptr_t(H), OpenFlags); - if (FD == -1) { - ::CloseHandle(H); - return mapWindowsError(ERROR_INVALID_HANDLE); - } + return Result; +} - ResultFD = FD; - return std::error_code(); +void closeFile(file_t &F) { + ::CloseHandle(F); + F = kInvalidFile; } std::error_code remove_directories(const Twine &path, bool IgnoreErrors) { @@ -1204,7 +1243,8 @@ std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest, return directoryRealPath(path, dest); int fd; - if (std::error_code EC = llvm::sys::fs::openFileForRead(path, fd, &dest)) + if (std::error_code EC = + llvm::sys::fs::openFileForRead(path, fd, OF_None, &dest)) return EC; ::close(fd); return std::error_code(); @@ -1279,23 +1319,26 @@ void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) { } // end namespace path namespace windows { -std::error_code UTF8ToUTF16(llvm::StringRef utf8, - llvm::SmallVectorImpl<wchar_t> &utf16) { - if (!utf8.empty()) { - int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), - utf8.size(), utf16.begin(), 0); - - if (len == 0) +std::error_code CodePageToUTF16(unsigned codepage, + llvm::StringRef original, + llvm::SmallVectorImpl<wchar_t> &utf16) { + if (!original.empty()) { + int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(), + original.size(), utf16.begin(), 0); + + if (len == 0) { return mapWindowsError(::GetLastError()); + } utf16.reserve(len + 1); utf16.set_size(len); - len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), - utf8.size(), utf16.begin(), utf16.size()); + len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(), + original.size(), utf16.begin(), utf16.size()); - if (len == 0) + if (len == 0) { return mapWindowsError(::GetLastError()); + } } // Make utf16 null terminated. @@ -1305,32 +1348,44 @@ std::error_code UTF8ToUTF16(llvm::StringRef utf8, return std::error_code(); } +std::error_code UTF8ToUTF16(llvm::StringRef utf8, + llvm::SmallVectorImpl<wchar_t> &utf16) { + return CodePageToUTF16(CP_UTF8, utf8, utf16); +} + +std::error_code CurCPToUTF16(llvm::StringRef curcp, + llvm::SmallVectorImpl<wchar_t> &utf16) { + return CodePageToUTF16(CP_ACP, curcp, utf16); +} + static std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16, size_t utf16_len, - llvm::SmallVectorImpl<char> &utf8) { + llvm::SmallVectorImpl<char> &converted) { if (utf16_len) { // Get length. - int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.begin(), + int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.begin(), 0, NULL, NULL); - if (len == 0) + if (len == 0) { return mapWindowsError(::GetLastError()); + } - utf8.reserve(len); - utf8.set_size(len); + converted.reserve(len); + converted.set_size(len); // Now do the actual conversion. - len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.data(), - utf8.size(), NULL, NULL); + len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.data(), + converted.size(), NULL, NULL); - if (len == 0) + if (len == 0) { return mapWindowsError(::GetLastError()); + } } - // Make utf8 null terminated. - utf8.push_back(0); - utf8.pop_back(); + // Make the new string null terminated. + converted.push_back(0); + converted.pop_back(); return std::error_code(); } @@ -1341,8 +1396,8 @@ std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, } std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, - llvm::SmallVectorImpl<char> &utf8) { - return UTF16ToCodePage(CP_ACP, utf16, utf16_len, utf8); + llvm::SmallVectorImpl<char> &curcp) { + return UTF16ToCodePage(CP_ACP, utf16, utf16_len, curcp); } } // end namespace windows diff --git a/contrib/llvm/lib/Support/Windows/Process.inc b/contrib/llvm/lib/Support/Windows/Process.inc index 3fe9f89f1ef5..30126568769c 100644 --- a/contrib/llvm/lib/Support/Windows/Process.inc +++ b/contrib/llvm/lib/Support/Windows/Process.inc @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Allocator.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/WindowsError.h" #include <malloc.h> @@ -24,14 +25,7 @@ #include <psapi.h> #include <shellapi.h> -#ifdef __MINGW32__ - #if (HAVE_LIBPSAPI != 1) - #error "libpsapi.a should be present" - #endif - #if (HAVE_LIBSHELL32 != 1) - #error "libshell32.a should be present" - #endif -#else +#if !defined(__MINGW32__) #pragma comment(lib, "psapi.lib") #pragma comment(lib, "shell32.lib") #endif @@ -146,39 +140,38 @@ Optional<std::string> Process::GetEnv(StringRef Name) { return std::string(Res.data()); } -static void AllocateAndPush(const SmallVectorImpl<char> &S, - SmallVectorImpl<const char *> &Vector, - SpecificBumpPtrAllocator<char> &Allocator) { - char *Buffer = Allocator.Allocate(S.size() + 1); - ::memcpy(Buffer, S.data(), S.size()); - Buffer[S.size()] = '\0'; - Vector.push_back(Buffer); +static const char *AllocateString(const SmallVectorImpl<char> &S, + BumpPtrAllocator &Alloc) { + char *Buf = reinterpret_cast<char *>(Alloc.Allocate(S.size() + 1, 1)); + ::memcpy(Buf, S.data(), S.size()); + Buf[S.size()] = '\0'; + return Buf; } /// Convert Arg from UTF-16 to UTF-8 and push it onto Args. -static std::error_code -ConvertAndPushArg(const wchar_t *Arg, SmallVectorImpl<const char *> &Args, - SpecificBumpPtrAllocator<char> &Allocator) { +static std::error_code ConvertAndPushArg(const wchar_t *Arg, + SmallVectorImpl<const char *> &Args, + BumpPtrAllocator &Alloc) { SmallVector<char, MAX_PATH> ArgString; if (std::error_code ec = windows::UTF16ToUTF8(Arg, wcslen(Arg), ArgString)) return ec; - AllocateAndPush(ArgString, Args, Allocator); + Args.push_back(AllocateString(ArgString, Alloc)); return std::error_code(); } -/// \brief Perform wildcard expansion of Arg, or just push it into Args if it +/// Perform wildcard expansion of Arg, or just push it into Args if it /// doesn't have wildcards or doesn't match any files. -static std::error_code -WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args, - SpecificBumpPtrAllocator<char> &Allocator) { +static std::error_code WildcardExpand(const wchar_t *Arg, + SmallVectorImpl<const char *> &Args, + BumpPtrAllocator &Alloc) { if (!wcspbrk(Arg, L"*?")) { // Arg does not contain any wildcard characters. This is the common case. - return ConvertAndPushArg(Arg, Args, Allocator); + return ConvertAndPushArg(Arg, Args, Alloc); } if (wcscmp(Arg, L"/?") == 0 || wcscmp(Arg, L"-?") == 0) { // Don't wildcard expand /?. Always treat it as an option. - return ConvertAndPushArg(Arg, Args, Allocator); + return ConvertAndPushArg(Arg, Args, Alloc); } // Extract any directory part of the argument. @@ -195,7 +188,7 @@ WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args, WIN32_FIND_DATAW FileData; HANDLE FindHandle = FindFirstFileW(Arg, &FileData); if (FindHandle == INVALID_HANDLE_VALUE) { - return ConvertAndPushArg(Arg, Args, Allocator); + return ConvertAndPushArg(Arg, Args, Alloc); } std::error_code ec; @@ -208,7 +201,7 @@ WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args, // Append FileName to Dir, and remove it afterwards. llvm::sys::path::append(Dir, StringRef(FileName.data(), FileName.size())); - AllocateAndPush(Dir, Args, Allocator); + Args.push_back(AllocateString(Dir, Alloc)); Dir.resize(DirSize); } while (FindNextFileW(FindHandle, &FileData)); @@ -216,56 +209,65 @@ 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()); +static std::error_code GetExecutableName(SmallVectorImpl<char> &Filename) { + // 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]; + size_t Length = ::GetModuleFileNameW(NULL, ModuleName, MAX_PATH); + if (Length == 0 || Length == MAX_PATH) { + return mapWindowsError(GetLastError()); + } + + // 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. + Length = GetLongPathNameW(ModuleName, ModuleName, MAX_PATH); if (Length == 0) return mapWindowsError(GetLastError()); - if (Length > LongPath.capacity()) { + if (Length > MAX_PATH) { // 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 EC = windows::UTF16ToUTF8(ModuleName, Length, Filename); + if (EC) + return EC; + + StringRef Base = sys::path::filename(Filename.data()); + Filename.assign(Base.begin(), Base.end()); + return std::error_code(); } std::error_code -Process::GetArgumentVector(SmallVectorImpl<const char *> &Args, - ArrayRef<const char *>, - SpecificBumpPtrAllocator<char> &ArgAllocator) { +windows::GetCommandLineArguments(SmallVectorImpl<const char *> &Args, + BumpPtrAllocator &Alloc) { int ArgCount; - wchar_t **UnicodeCommandLine = - CommandLineToArgvW(GetCommandLineW(), &ArgCount); + std::unique_ptr<wchar_t *[], decltype(&LocalFree)> UnicodeCommandLine{ + CommandLineToArgvW(GetCommandLineW(), &ArgCount), &LocalFree}; if (!UnicodeCommandLine) return mapWindowsError(::GetLastError()); - Args.reserve(ArgCount); - std::error_code ec; + std::error_code EC; - // 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); + Args.reserve(ArgCount); - for (int i = 1; i < ArgCount && !ec; ++i) { - ec = WildcardExpand(UnicodeCommandLine[i], Args, ArgAllocator); - if (ec) - break; + for (int I = 0; I < ArgCount; ++I) { + EC = WildcardExpand(UnicodeCommandLine[I], Args, Alloc); + if (EC) + return EC; } - LocalFree(UnicodeCommandLine); - return ec; + SmallVector<char, MAX_PATH> Arg0(Args[0], Args[0] + strlen(Args[0])); + SmallVector<char, MAX_PATH> Filename; + sys::path::remove_filename(Arg0); + EC = GetExecutableName(Filename); + if (EC) + return EC; + sys::path::append(Arg0, Filename); + Args[0] = AllocateString(Arg0, Alloc); + return std::error_code(); } std::error_code Process::FixupStandardFileDescriptors() { diff --git a/contrib/llvm/lib/Support/Windows/Program.inc b/contrib/llvm/lib/Support/Windows/Program.inc index 52921cd6a203..cb68c5b10e52 100644 --- a/contrib/llvm/lib/Support/Windows/Program.inc +++ b/contrib/llvm/lib/Support/Windows/Program.inc @@ -16,12 +16,14 @@ #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/WindowsError.h" #include "llvm/Support/raw_ostream.h" #include <cstdio> #include <fcntl.h> #include <io.h> #include <malloc.h> +#include <numeric> //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only Win32 specific code @@ -30,7 +32,7 @@ namespace llvm { -ProcessInfo::ProcessInfo() : ProcessHandle(0), Pid(0), ReturnCode(0) {} +ProcessInfo::ProcessInfo() : Pid(0), Process(0), ReturnCode(0) {} ErrorOr<std::string> sys::findProgramByName(StringRef Name, ArrayRef<StringRef> Paths) { @@ -145,112 +147,11 @@ static HANDLE RedirectIO(Optional<StringRef> Path, int fd, return h; } -/// ArgNeedsQuotes - Check whether argument needs to be quoted when calling -/// CreateProcess. -static bool ArgNeedsQuotes(const char *Str) { - return Str[0] == '\0' || strpbrk(Str, "\t \"&\'()*<>\\`^|") != 0; } -/// CountPrecedingBackslashes - Returns the number of backslashes preceding Cur -/// in the C string Start. -static unsigned int CountPrecedingBackslashes(const char *Start, - const char *Cur) { - unsigned int Count = 0; - --Cur; - while (Cur >= Start && *Cur == '\\') { - ++Count; - --Cur; - } - return Count; -} - -/// EscapePrecedingEscapes - Append a backslash to Dst for every backslash -/// preceding Cur in the Start string. Assumes Dst has enough space. -static char *EscapePrecedingEscapes(char *Dst, const char *Start, - const char *Cur) { - unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Cur); - while (PrecedingEscapes > 0) { - *Dst++ = '\\'; - --PrecedingEscapes; - } - return Dst; -} - -/// ArgLenWithQuotes - Check whether argument needs to be quoted when calling -/// CreateProcess and returns length of quoted arg with escaped quotes -static unsigned int ArgLenWithQuotes(const char *Str) { - const char *Start = Str; - bool Quoted = ArgNeedsQuotes(Str); - unsigned int len = Quoted ? 2 : 0; - - while (*Str != '\0') { - if (*Str == '\"') { - // We need to add a backslash, but ensure that it isn't escaped. - unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Str); - len += PrecedingEscapes + 1; - } - // Note that we *don't* need to escape runs of backslashes that don't - // precede a double quote! See MSDN: - // http://msdn.microsoft.com/en-us/library/17w5ykft%28v=vs.85%29.aspx - - ++len; - ++Str; - } - - if (Quoted) { - // Make sure the closing quote doesn't get escaped by a trailing backslash. - unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Str); - len += PrecedingEscapes + 1; - } - - return len; -} - -} - -static std::unique_ptr<char[]> flattenArgs(const char **Args) { - // First, determine the length of the command line. - unsigned len = 0; - for (unsigned i = 0; Args[i]; i++) { - len += ArgLenWithQuotes(Args[i]) + 1; - } - - // Now build the command line. - std::unique_ptr<char[]> command(new char[len+1]); - char *p = command.get(); - - for (unsigned i = 0; Args[i]; i++) { - const char *arg = Args[i]; - const char *start = arg; - - bool needsQuoting = ArgNeedsQuotes(arg); - if (needsQuoting) - *p++ = '"'; - - while (*arg != '\0') { - if (*arg == '\"') { - // Escape all preceding escapes (if any), and then escape the quote. - p = EscapePrecedingEscapes(p, start, arg); - *p++ = '\\'; - } - - *p++ = *arg++; - } - - if (needsQuoting) { - // Make sure our quote doesn't get escaped by a trailing backslash. - p = EscapePrecedingEscapes(p, start, arg); - *p++ = '"'; - } - *p++ = ' '; - } - - *p = 0; - return command; -} - -static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, - const char **Envp, ArrayRef<Optional<StringRef>> Redirects, +static bool Execute(ProcessInfo &PI, StringRef Program, + ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env, + ArrayRef<Optional<StringRef>> Redirects, unsigned MemoryLimit, std::string *ErrMsg) { if (!sys::fs::can_execute(Program)) { if (ErrMsg) @@ -269,18 +170,18 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, // Windows wants a command line, not an array of args, to pass to the new // process. We have to concatenate them all, while quoting the args that // have embedded spaces (or are empty). - std::unique_ptr<char[]> command = flattenArgs(Args); + std::string Command = flattenWindowsCommandLine(Args); // The pointer to the environment block for the new process. std::vector<wchar_t> EnvBlock; - if (Envp) { + if (Env) { // An environment block consists of a null-terminated block of // null-terminated strings. Convert the array of environment variables to // an environment block by concatenating them. - for (unsigned i = 0; Envp[i]; ++i) { + for (const auto E : *Env) { SmallVector<wchar_t, MAX_PATH> EnvString; - if (std::error_code ec = windows::UTF8ToUTF16(Envp[i], EnvString)) { + if (std::error_code ec = windows::UTF8ToUTF16(E, EnvString)) { SetLastError(ec.value()); MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16"); return false; @@ -352,7 +253,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, } SmallVector<wchar_t, MAX_PATH> CommandUtf16; - if (std::error_code ec = windows::UTF8ToUTF16(command.get(), CommandUtf16)) { + if (std::error_code ec = windows::UTF8ToUTF16(Command, CommandUtf16)) { SetLastError(ec.value()); MakeErrMsg(ErrMsg, std::string("Unable to convert command-line to UTF-16")); @@ -380,7 +281,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, } PI.Pid = pi.dwProcessId; - PI.ProcessHandle = pi.hProcess; + PI.Process = pi.hProcess; // Make sure these get closed no matter what. ScopedCommonHandle hThread(pi.hThread); @@ -413,11 +314,67 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, return true; } +static bool argNeedsQuotes(StringRef Arg) { + if (Arg.empty()) + return true; + return StringRef::npos != Arg.find_first_of("\t \"&\'()*<>\\`^|"); +} + +static std::string quoteSingleArg(StringRef Arg) { + std::string Result; + Result.push_back('"'); + + while (!Arg.empty()) { + size_t FirstNonBackslash = Arg.find_first_not_of('\\'); + size_t BackslashCount = FirstNonBackslash; + if (FirstNonBackslash == StringRef::npos) { + // The entire remainder of the argument is backslashes. Escape all of + // them and just early out. + BackslashCount = Arg.size(); + Result.append(BackslashCount * 2, '\\'); + break; + } + + if (Arg[FirstNonBackslash] == '\"') { + // This is an embedded quote. Escape all preceding backslashes, then + // add one additional backslash to escape the quote. + Result.append(BackslashCount * 2 + 1, '\\'); + Result.push_back('\"'); + } else { + // This is just a normal character. Don't escape any of the preceding + // backslashes, just append them as they are and then append the + // character. + Result.append(BackslashCount, '\\'); + Result.push_back(Arg[FirstNonBackslash]); + } + + // Drop all the backslashes, plus the following character. + Arg = Arg.drop_front(FirstNonBackslash + 1); + } + + Result.push_back('"'); + return Result; +} + namespace llvm { +std::string sys::flattenWindowsCommandLine(ArrayRef<StringRef> Args) { + std::string Command; + for (StringRef Arg : Args) { + if (argNeedsQuotes(Arg)) + Command += quoteSingleArg(Arg); + else + Command += Arg; + + Command.push_back(' '); + } + + return Command; +} + ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, bool WaitUntilChildTerminates, std::string *ErrMsg) { assert(PI.Pid && "invalid pid to wait on, process not started?"); - assert(PI.ProcessHandle && + assert((PI.Process && PI.Process != INVALID_HANDLE_VALUE) && "invalid process handle to wait on, process not started?"); DWORD milliSecondsToWait = 0; if (WaitUntilChildTerminates) @@ -426,20 +383,20 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, milliSecondsToWait = SecondsToWait * 1000; ProcessInfo WaitResult = PI; - DWORD WaitStatus = WaitForSingleObject(PI.ProcessHandle, milliSecondsToWait); + DWORD WaitStatus = WaitForSingleObject(PI.Process, milliSecondsToWait); if (WaitStatus == WAIT_TIMEOUT) { if (SecondsToWait) { - if (!TerminateProcess(PI.ProcessHandle, 1)) { + if (!TerminateProcess(PI.Process, 1)) { if (ErrMsg) MakeErrMsg(ErrMsg, "Failed to terminate timed-out program"); // -2 indicates a crash or timeout as opposed to failure to execute. WaitResult.ReturnCode = -2; - CloseHandle(PI.ProcessHandle); + CloseHandle(PI.Process); return WaitResult; } - WaitForSingleObject(PI.ProcessHandle, INFINITE); - CloseHandle(PI.ProcessHandle); + WaitForSingleObject(PI.Process, INFINITE); + CloseHandle(PI.Process); } else { // Non-blocking wait. return ProcessInfo(); @@ -448,10 +405,10 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, // Get its exit status. DWORD status; - BOOL rc = GetExitCodeProcess(PI.ProcessHandle, &status); + BOOL rc = GetExitCodeProcess(PI.Process, &status); DWORD err = GetLastError(); if (err != ERROR_INVALID_HANDLE) - CloseHandle(PI.ProcessHandle); + CloseHandle(PI.Process); if (!rc) { SetLastError(err); @@ -495,7 +452,7 @@ std::error_code llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents, WindowsEncodingMethod Encoding) { std::error_code EC; - llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OpenFlags::F_Text); + llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::F_Text); if (EC) return EC; @@ -536,19 +493,13 @@ llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents, } bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, - ArrayRef<const char *> Args) { + ArrayRef<StringRef> Args) { // The documented max length of the command line passed to CreateProcess. static const size_t MaxCommandStringLength = 32768; - // Account for the trailing space for the program path and the - // trailing NULL of the last argument. - size_t ArgLength = ArgLenWithQuotes(Program.str().c_str()) + 2; - for (const char* Arg : Args) { - // Account for the trailing space for every arg - ArgLength += ArgLenWithQuotes(Arg) + 1; - if (ArgLength > MaxCommandStringLength) { - return false; - } - } - return true; + SmallVector<StringRef, 8> FullArgs; + FullArgs.push_back(Program); + FullArgs.append(Args.begin(), Args.end()); + std::string Result = flattenWindowsCommandLine(FullArgs); + return (Result.size() + 1) <= MaxCommandStringLength; } } diff --git a/contrib/llvm/lib/Support/Windows/RWMutex.inc b/contrib/llvm/lib/Support/Windows/RWMutex.inc index ac60c2fc05be..5eb9351eee52 100644 --- a/contrib/llvm/lib/Support/Windows/RWMutex.inc +++ b/contrib/llvm/lib/Support/Windows/RWMutex.inc @@ -74,10 +74,10 @@ static bool loadSRW() { sys::RWMutexImpl::RWMutexImpl() { if (loadSRW()) { - data_ = calloc(1, sizeof(SRWLOCK)); + data_ = safe_calloc(1, sizeof(SRWLOCK)); fpInitializeSRWLock(static_cast<PSRWLOCK>(data_)); } else { - data_ = calloc(1, sizeof(CRITICAL_SECTION)); + data_ = safe_calloc(1, sizeof(CRITICAL_SECTION)); InitializeCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); } } diff --git a/contrib/llvm/lib/Support/Windows/Signals.inc b/contrib/llvm/lib/Support/Windows/Signals.inc index 21dd2dd13754..41eb5e593aa5 100644 --- a/contrib/llvm/lib/Support/Windows/Signals.inc +++ b/contrib/llvm/lib/Support/Windows/Signals.inc @@ -10,6 +10,7 @@ // This file provides the Win32 specific implementation of the Signals class. // //===----------------------------------------------------------------------===// +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" @@ -36,9 +37,6 @@ #ifdef _MSC_VER #pragma comment(lib, "psapi.lib") #elif __MINGW32__ - #if (HAVE_LIBPSAPI != 1) - #error "libpsapi.a should be present" - #endif // The version of g++ that comes with MinGW does *not* properly understand // the ll format specifier for printf. However, MinGW passes the format // specifiers on to the MSVCRT entirely, and the CRT understands the ll @@ -193,7 +191,7 @@ using namespace llvm; static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); -// InterruptFunction - The function to call if ctrl-c is pressed. +// The function to call if ctrl-c is pressed. static void (*InterruptFunction)() = 0; static std::vector<std::string> *FilesToRemove = NULL; @@ -390,9 +388,9 @@ namespace llvm { //===----------------------------------------------------------------------===// #ifdef _MSC_VER -/// AvoidMessageBoxHook - Emulates hitting "retry" from an "abort, retry, -/// ignore" CRT debug report dialog. "retry" raises an exception which -/// ultimately triggers our stack dumper. +/// Emulates hitting "retry" from an "abort, retry, ignore" CRT debug report +/// dialog. "retry" raises an exception which ultimately triggers our stack +/// dumper. static LLVM_ATTRIBUTE_UNUSED int AvoidMessageBoxHook(int ReportType, char *Message, int *Return) { // Set *Return to the retry code for the return value of _CrtDbgReport: @@ -450,7 +448,7 @@ static void RegisterHandler() { // else multi-threading problems will ensue. } -// RemoveFileOnSignal - The public API +// The public API bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { RegisterHandler(); @@ -469,7 +467,7 @@ bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { return false; } -// DontRemoveFileOnSignal - The public API +// The public API void sys::DontRemoveFileOnSignal(StringRef Filename) { if (FilesToRemove == NULL) return; @@ -503,8 +501,8 @@ void sys::DisableSystemDialogsOnCrash() { _set_error_mode(_OUT_TO_STDERR); } -/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or -/// SIGSEGV) is delivered to the process, print a stack trace and then exit. +/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the +/// process, print a stack trace and then exit. void sys::PrintStackTraceOnErrorSignal(StringRef Argv0, bool DisableCrashReporting) { ::Argv0 = Argv0; @@ -536,10 +534,14 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) { StackFrame.AddrPC.Offset = Context.Eip; StackFrame.AddrStack.Offset = Context.Esp; StackFrame.AddrFrame.Offset = Context.Ebp; -#elif defined(_M_ARM64) || defined(_M_ARM) +#elif defined(_M_ARM64) StackFrame.AddrPC.Offset = Context.Pc; StackFrame.AddrStack.Offset = Context.Sp; StackFrame.AddrFrame.Offset = Context.Fp; +#elif defined(_M_ARM) + StackFrame.AddrPC.Offset = Context.Pc; + StackFrame.AddrStack.Offset = Context.Sp; + StackFrame.AddrFrame.Offset = Context.R11; #endif StackFrame.AddrPC.Mode = AddrModeFlat; StackFrame.AddrStack.Mode = AddrModeFlat; @@ -556,11 +558,12 @@ void llvm::sys::SetInterruptFunction(void (*IF)()) { } -/// AddSignalHandler - Add a function to be called when a signal is delivered -/// to the process. The handler can have a cookie passed to it to identify -/// what instance of the handler it is. -void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { - CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); +/// Add a function to be called when a signal is delivered to the process. The +/// handler can have a cookie passed to it to identify what instance of the +/// handler it is. +void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, + void *Cookie) { + insertSignalHandler(FnPtr, Cookie); RegisterHandler(); LeaveCriticalSection(&CriticalSection); } @@ -594,7 +597,7 @@ void llvm::sys::RunInterruptHandlers() { Cleanup(); } -/// \brief Find the Windows Registry Key for a given location. +/// 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) { @@ -607,7 +610,7 @@ static HKEY FindWERKey(const llvm::Twine &RegistryLocation) { return Key; } -/// \brief Populate ResultDirectory with the value for "DumpFolder" for a given +/// Populate ResultDirectory with the value for "DumpFolder" for a given /// Windows Registry key. /// /// \returns true if a valid value for DumpFolder exists, false otherwise. @@ -648,7 +651,7 @@ static bool GetDumpFolder(HKEY Key, return true; } -/// \brief Populate ResultType with a valid MINIDUMP_TYPE based on the value of +/// Populate ResultType with a valid MINIDUMP_TYPE based on the value of /// "DumpType" for a given Windows Registry key. /// /// According to @@ -695,7 +698,7 @@ static bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) { return true; } -/// \brief Write a Windows dump file containing process information that can be +/// 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 @@ -819,7 +822,11 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { StackFrame.AddrPC.Mode = AddrModeFlat; StackFrame.AddrStack.Offset = ep->ContextRecord->Sp; StackFrame.AddrStack.Mode = AddrModeFlat; +#if defined(_M_ARM64) StackFrame.AddrFrame.Offset = ep->ContextRecord->Fp; +#else + StackFrame.AddrFrame.Offset = ep->ContextRecord->R11; +#endif StackFrame.AddrFrame.Mode = AddrModeFlat; #endif diff --git a/contrib/llvm/lib/Support/Windows/WindowsSupport.h b/contrib/llvm/lib/Support/Windows/WindowsSupport.h index d4599dca044e..c2fd6bb982d4 100644 --- a/contrib/llvm/lib/Support/Windows/WindowsSupport.h +++ b/contrib/llvm/lib/Support/Windows/WindowsSupport.h @@ -247,18 +247,12 @@ inline FILETIME toFILETIME(TimePoint<> TP) { return Time; } -namespace path { -std::error_code widenPath(const Twine &Path8, - SmallVectorImpl<wchar_t> &Path16); -} // end namespace path - namespace windows { -std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16); -std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, - SmallVectorImpl<char> &utf8); -/// Convert from UTF16 to the current code page used in the system -std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, - SmallVectorImpl<char> &utf8); +// Returns command line arguments. Unlike arguments given to main(), +// this function guarantees that the returned arguments are encoded in +// UTF-8 regardless of the current code page setting. +std::error_code GetCommandLineArguments(SmallVectorImpl<const char *> &Args, + BumpPtrAllocator &Alloc); } // end namespace windows } // end namespace sys } // end namespace llvm. diff --git a/contrib/llvm/lib/Support/WithColor.cpp b/contrib/llvm/lib/Support/WithColor.cpp new file mode 100644 index 000000000000..d2e13f0e86de --- /dev/null +++ b/contrib/llvm/lib/Support/WithColor.cpp @@ -0,0 +1,90 @@ +//===- WithColor.cpp ------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +cl::OptionCategory llvm::ColorCategory("Color Options"); + +static cl::opt<cl::boolOrDefault> + UseColor("color", cl::cat(ColorCategory), + cl::desc("Use colors in output (default=autodetect)"), + cl::init(cl::BOU_UNSET)); + +bool WithColor::colorsEnabled(raw_ostream &OS) { + if (UseColor == cl::BOU_UNSET) + return OS.has_colors(); + return UseColor == cl::BOU_TRUE; +} + +WithColor::WithColor(raw_ostream &OS, HighlightColor Color) : OS(OS) { + // Detect color from terminal type unless the user passed the --color option. + if (colorsEnabled(OS)) { + switch (Color) { + case HighlightColor::Address: + OS.changeColor(raw_ostream::YELLOW); + break; + case HighlightColor::String: + OS.changeColor(raw_ostream::GREEN); + break; + case HighlightColor::Tag: + OS.changeColor(raw_ostream::BLUE); + break; + case HighlightColor::Attribute: + OS.changeColor(raw_ostream::CYAN); + break; + case HighlightColor::Enumerator: + OS.changeColor(raw_ostream::MAGENTA); + break; + case HighlightColor::Macro: + OS.changeColor(raw_ostream::RED); + break; + case HighlightColor::Error: + OS.changeColor(raw_ostream::RED, true); + break; + case HighlightColor::Warning: + OS.changeColor(raw_ostream::MAGENTA, true); + break; + case HighlightColor::Note: + OS.changeColor(raw_ostream::BLACK, true); + break; + } + } +} + +raw_ostream &WithColor::error() { return error(errs()); } + +raw_ostream &WithColor::warning() { return warning(errs()); } + +raw_ostream &WithColor::note() { return note(errs()); } + +raw_ostream &WithColor::error(raw_ostream &OS, StringRef Prefix) { + if (!Prefix.empty()) + OS << Prefix << ": "; + return WithColor(OS, HighlightColor::Error).get() << "error: "; +} + +raw_ostream &WithColor::warning(raw_ostream &OS, StringRef Prefix) { + if (!Prefix.empty()) + OS << Prefix << ": "; + return WithColor(OS, HighlightColor::Warning).get() << "warning: "; +} + +raw_ostream &WithColor::note(raw_ostream &OS, StringRef Prefix) { + if (!Prefix.empty()) + OS << Prefix << ": "; + return WithColor(OS, HighlightColor::Note).get() << "note: "; +} + +WithColor::~WithColor() { + if (colorsEnabled(OS)) + OS.resetColor(); +} diff --git a/contrib/llvm/lib/Support/YAMLParser.cpp b/contrib/llvm/lib/Support/YAMLParser.cpp index e2f21a56a810..354b7d0740de 100644 --- a/contrib/llvm/lib/Support/YAMLParser.cpp +++ b/contrib/llvm/lib/Support/YAMLParser.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/Unicode.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> @@ -167,7 +168,7 @@ using TokenQueueT = BumpPtrList<Token>; namespace { -/// @brief This struct is used to track simple keys. +/// This struct is used to track simple keys. /// /// Simple keys are handled by creating an entry in SimpleKeys for each Token /// which could legally be the start of a simple key. When peekNext is called, @@ -190,7 +191,7 @@ struct SimpleKey { } // end anonymous namespace -/// @brief The Unicode scalar value of a UTF-8 minimal well-formed code unit +/// The Unicode scalar value of a UTF-8 minimal well-formed code unit /// subsequence and the subsequence's length in code units (uint8_t). /// A length of 0 represents an error. using UTF8Decoded = std::pair<uint32_t, unsigned>; @@ -248,7 +249,7 @@ static UTF8Decoded decodeUTF8(StringRef Range) { namespace llvm { namespace yaml { -/// @brief Scans YAML tokens from a MemoryBuffer. +/// Scans YAML tokens from a MemoryBuffer. class Scanner { public: Scanner(StringRef Input, SourceMgr &SM, bool ShowColors = true, @@ -256,10 +257,10 @@ public: Scanner(MemoryBufferRef Buffer, SourceMgr &SM_, bool ShowColors = true, std::error_code *EC = nullptr); - /// @brief Parse the next token and return it without popping it. + /// Parse the next token and return it without popping it. Token &peekNext(); - /// @brief Parse the next token and pop it from the queue. + /// Parse the next token and pop it from the queue. Token getNext(); void printError(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Message, @@ -286,7 +287,7 @@ public: setError(Message, Current); } - /// @brief Returns true if an error occurred while parsing. + /// Returns true if an error occurred while parsing. bool failed() { return Failed; } @@ -298,7 +299,7 @@ private: return StringRef(Current, End - Current); } - /// @brief Decode a UTF-8 minimal well-formed code unit subsequence starting + /// Decode a UTF-8 minimal well-formed code unit subsequence starting /// at \a Position. /// /// If the UTF-8 code units starting at Position do not form a well-formed @@ -328,7 +329,7 @@ private: // l- // A production matching complete line(s). - /// @brief Skip a single nb-char[27] starting at Position. + /// Skip a single nb-char[27] starting at Position. /// /// A nb-char is 0x9 | [0x20-0x7E] | 0x85 | [0xA0-0xD7FF] | [0xE000-0xFEFE] /// | [0xFF00-0xFFFD] | [0x10000-0x10FFFF] @@ -337,7 +338,7 @@ private: /// nb-char. StringRef::iterator skip_nb_char(StringRef::iterator Position); - /// @brief Skip a single b-break[28] starting at Position. + /// Skip a single b-break[28] starting at Position. /// /// A b-break is 0xD 0xA | 0xD | 0xA /// @@ -353,7 +354,7 @@ private: /// s-space. StringRef::iterator skip_s_space(StringRef::iterator Position); - /// @brief Skip a single s-white[33] starting at Position. + /// Skip a single s-white[33] starting at Position. /// /// A s-white is 0x20 | 0x9 /// @@ -361,7 +362,7 @@ private: /// s-white. StringRef::iterator skip_s_white(StringRef::iterator Position); - /// @brief Skip a single ns-char[34] starting at Position. + /// Skip a single ns-char[34] starting at Position. /// /// A ns-char is nb-char - s-white /// @@ -371,7 +372,7 @@ private: using SkipWhileFunc = StringRef::iterator (Scanner::*)(StringRef::iterator); - /// @brief Skip minimal well-formed code unit subsequences until Func + /// Skip minimal well-formed code unit subsequences until Func /// returns its input. /// /// @returns The code unit after the last minimal well-formed code unit @@ -383,20 +384,20 @@ private: /// input. void advanceWhile(SkipWhileFunc Func); - /// @brief Scan ns-uri-char[39]s starting at Cur. + /// Scan ns-uri-char[39]s starting at Cur. /// /// This updates Cur and Column while scanning. void scan_ns_uri_char(); - /// @brief Consume a minimal well-formed code unit subsequence starting at + /// Consume a minimal well-formed code unit subsequence starting at /// \a Cur. Return false if it is not the same Unicode scalar value as /// \a Expected. This updates \a Column. bool consume(uint32_t Expected); - /// @brief Skip \a Distance UTF-8 code units. Updates \a Cur and \a Column. + /// Skip \a Distance UTF-8 code units. Updates \a Cur and \a Column. void skip(uint32_t Distance); - /// @brief Return true if the minimal well-formed code unit subsequence at + /// Return true if the minimal well-formed code unit subsequence at /// Pos is whitespace or a new line bool isBlankOrBreak(StringRef::iterator Position); @@ -405,77 +406,77 @@ private: /// Return false if the code unit at the current position isn't a line break. bool consumeLineBreakIfPresent(); - /// @brief If IsSimpleKeyAllowed, create and push_back a new SimpleKey. + /// If IsSimpleKeyAllowed, create and push_back a new SimpleKey. void saveSimpleKeyCandidate( TokenQueueT::iterator Tok , unsigned AtColumn , bool IsRequired); - /// @brief Remove simple keys that can no longer be valid simple keys. + /// Remove simple keys that can no longer be valid simple keys. /// /// Invalid simple keys are not on the current line or are further than 1024 /// columns back. void removeStaleSimpleKeyCandidates(); - /// @brief Remove all simple keys on FlowLevel \a Level. + /// Remove all simple keys on FlowLevel \a Level. void removeSimpleKeyCandidatesOnFlowLevel(unsigned Level); - /// @brief Unroll indentation in \a Indents back to \a Col. Creates BlockEnd + /// Unroll indentation in \a Indents back to \a Col. Creates BlockEnd /// tokens if needed. bool unrollIndent(int ToColumn); - /// @brief Increase indent to \a Col. Creates \a Kind token at \a InsertPoint + /// Increase indent to \a Col. Creates \a Kind token at \a InsertPoint /// if needed. bool rollIndent( int ToColumn , Token::TokenKind Kind , TokenQueueT::iterator InsertPoint); - /// @brief Skip a single-line comment when the comment starts at the current + /// Skip a single-line comment when the comment starts at the current /// position of the scanner. void skipComment(); - /// @brief Skip whitespace and comments until the start of the next token. + /// Skip whitespace and comments until the start of the next token. void scanToNextToken(); - /// @brief Must be the first token generated. + /// Must be the first token generated. bool scanStreamStart(); - /// @brief Generate tokens needed to close out the stream. + /// Generate tokens needed to close out the stream. bool scanStreamEnd(); - /// @brief Scan a %BLAH directive. + /// Scan a %BLAH directive. bool scanDirective(); - /// @brief Scan a ... or ---. + /// Scan a ... or ---. bool scanDocumentIndicator(bool IsStart); - /// @brief Scan a [ or { and generate the proper flow collection start token. + /// Scan a [ or { and generate the proper flow collection start token. bool scanFlowCollectionStart(bool IsSequence); - /// @brief Scan a ] or } and generate the proper flow collection end token. + /// Scan a ] or } and generate the proper flow collection end token. bool scanFlowCollectionEnd(bool IsSequence); - /// @brief Scan the , that separates entries in a flow collection. + /// Scan the , that separates entries in a flow collection. bool scanFlowEntry(); - /// @brief Scan the - that starts block sequence entries. + /// Scan the - that starts block sequence entries. bool scanBlockEntry(); - /// @brief Scan an explicit ? indicating a key. + /// Scan an explicit ? indicating a key. bool scanKey(); - /// @brief Scan an explicit : indicating a value. + /// Scan an explicit : indicating a value. bool scanValue(); - /// @brief Scan a quoted scalar. + /// Scan a quoted scalar. bool scanFlowScalar(bool IsDoubleQuoted); - /// @brief Scan an unquoted scalar. + /// Scan an unquoted scalar. bool scanPlainScalar(); - /// @brief Scan an Alias or Anchor starting with * or &. + /// Scan an Alias or Anchor starting with * or &. bool scanAliasOrAnchor(bool IsAlias); - /// @brief Scan a block scalar starting with | or >. + /// Scan a block scalar starting with | or >. bool scanBlockScalar(bool IsLiteral); /// Scan a chomping indicator in a block scalar header. @@ -502,57 +503,57 @@ private: bool scanBlockScalarIndent(unsigned BlockIndent, unsigned BlockExitIndent, bool &IsDone); - /// @brief Scan a tag of the form !stuff. + /// Scan a tag of the form !stuff. bool scanTag(); - /// @brief Dispatch to the next scanning function based on \a *Cur. + /// Dispatch to the next scanning function based on \a *Cur. bool fetchMoreTokens(); - /// @brief The SourceMgr used for diagnostics and buffer management. + /// The SourceMgr used for diagnostics and buffer management. SourceMgr &SM; - /// @brief The original input. + /// The original input. MemoryBufferRef InputBuffer; - /// @brief The current position of the scanner. + /// The current position of the scanner. StringRef::iterator Current; - /// @brief The end of the input (one past the last character). + /// The end of the input (one past the last character). StringRef::iterator End; - /// @brief Current YAML indentation level in spaces. + /// Current YAML indentation level in spaces. int Indent; - /// @brief Current column number in Unicode code points. + /// Current column number in Unicode code points. unsigned Column; - /// @brief Current line number. + /// Current line number. unsigned Line; - /// @brief How deep we are in flow style containers. 0 Means at block level. + /// How deep we are in flow style containers. 0 Means at block level. unsigned FlowLevel; - /// @brief Are we at the start of the stream? + /// Are we at the start of the stream? bool IsStartOfStream; - /// @brief Can the next token be the start of a simple key? + /// Can the next token be the start of a simple key? bool IsSimpleKeyAllowed; - /// @brief True if an error has occurred. + /// True if an error has occurred. bool Failed; - /// @brief Should colors be used when printing out the diagnostic messages? + /// Should colors be used when printing out the diagnostic messages? bool ShowColors; - /// @brief Queue of tokens. This is required to queue up tokens while looking + /// Queue of tokens. This is required to queue up tokens while looking /// for the end of a simple key. And for cases where a single character /// can produce multiple tokens (e.g. BlockEnd). TokenQueueT TokenQueue; - /// @brief Indentation levels. + /// Indentation levels. SmallVector<int, 4> Indents; - /// @brief Potential simple keys. + /// Potential simple keys. SmallVector<SimpleKey, 4> SimpleKeys; std::error_code *EC; @@ -687,7 +688,7 @@ bool yaml::scanTokens(StringRef Input) { return true; } -std::string yaml::escape(StringRef Input) { +std::string yaml::escape(StringRef Input, bool EscapePrintable) { std::string EscapedInput; for (StringRef::iterator i = Input.begin(), e = Input.end(); i != e; ++i) { if (*i == '\\') @@ -734,6 +735,9 @@ std::string yaml::escape(StringRef Input) { EscapedInput += "\\L"; else if (UnicodeScalarValue.first == 0x2029) EscapedInput += "\\P"; + else if (!EscapePrintable && + sys::unicode::isPrintable(UnicodeScalarValue.first)) + EscapedInput += StringRef(i, UnicodeScalarValue.second); else { std::string HexStr = utohexstr(UnicodeScalarValue.first); if (HexStr.size() <= 2) diff --git a/contrib/llvm/lib/Support/YAMLTraits.cpp b/contrib/llvm/lib/Support/YAMLTraits.cpp index f8a80ba87873..d6345efd00cd 100644 --- a/contrib/llvm/lib/Support/YAMLTraits.cpp +++ b/contrib/llvm/lib/Support/YAMLTraits.cpp @@ -638,39 +638,22 @@ void Output::scalarString(StringRef &S, QuotingType MustQuote) { const char *Base = S.data(); const char *const Quote = MustQuote == QuotingType::Single ? "'" : "\""; - const char QuoteChar = MustQuote == QuotingType::Single ? '\'' : '"'; - output(Quote); // Starting quote. - // When using single-quoted strings, any single quote ' must be doubled to be - // escaped. - // When using double-quoted strings, print \x + hex for non-printable ASCII - // characters, and escape double quotes. - while (j < End) { - if (S[j] == QuoteChar) { // Escape quotes. - output(StringRef(&Base[i], j - i)); // "flush". - if (MustQuote == QuotingType::Double) { // Print it as \" - output(StringLiteral("\\")); - output(StringRef(Quote, 1)); - } else { // Single - output(StringLiteral("''")); // Print it as '' - } - i = j + 1; - } else if (MustQuote == QuotingType::Double && - !sys::unicode::isPrintable(S[j]) && (S[j] & 0x80) == 0) { - // If we're double quoting non-printable characters, we prefer printing - // them as "\x" + their hex representation. Note that special casing is - // needed for UTF-8, where a byte may be part of a UTF-8 sequence and - // appear as non-printable, in which case we want to print the correct - // unicode character and not its hex representation. - output(StringRef(&Base[i], j - i)); // "flush" - output(StringLiteral("\\x")); - - // Output the byte 0x0F as \x0f. - auto FormattedHex = format_hex_no_prefix(S[j], 2); - Out << FormattedHex; - Column += 4; // one for the '\', one for the 'x', and two for the hex + // When using double-quoted strings (and only in that case), non-printable characters may be + // present, and will be escaped using a variety of unicode-scalar and special short-form + // escapes. This is handled in yaml::escape. + if (MustQuote == QuotingType::Double) { + output(yaml::escape(Base, /* EscapePrintable= */ false)); + this->outputUpToEndOfLine(Quote); + return; + } + // When using single-quoted strings, any single quote ' must be doubled to be escaped. + while (j < End) { + if (S[j] == '\'') { // Escape quotes. + output(StringRef(&Base[i], j - i)); // "flush". + output(StringLiteral("''")); // Print it as '' i = j + 1; } ++j; diff --git a/contrib/llvm/lib/Support/circular_raw_ostream.cpp b/contrib/llvm/lib/Support/circular_raw_ostream.cpp index ca0d30db388c..e768f17cd00d 100644 --- a/contrib/llvm/lib/Support/circular_raw_ostream.cpp +++ b/contrib/llvm/lib/Support/circular_raw_ostream.cpp @@ -33,7 +33,7 @@ void circular_raw_ostream::write_impl(const char *Ptr, size_t Size) { Cur = BufferArray; Filled = true; } - } + } } void circular_raw_ostream::flushBufferWithBanner() { diff --git a/contrib/llvm/lib/Support/raw_ostream.cpp b/contrib/llvm/lib/Support/raw_ostream.cpp index e02611103080..038ad00bd608 100644 --- a/contrib/llvm/lib/Support/raw_ostream.cpp +++ b/contrib/llvm/lib/Support/raw_ostream.cpp @@ -41,9 +41,6 @@ #if defined(HAVE_UNISTD_H) # include <unistd.h> #endif -#if defined(HAVE_SYS_UIO_H) && defined(HAVE_WRITEV) -# include <sys/uio.h> -#endif #if defined(__CYGWIN__) #include <io.h> @@ -62,7 +59,7 @@ #endif #endif -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 #include "Windows/WindowsSupport.h" #endif @@ -78,9 +75,6 @@ raw_ostream::~raw_ostream() { delete [] OutBufStart; } -// An out of line virtual method to provide a home for the class vtable. -void raw_ostream::handle() {} - size_t raw_ostream::preferred_buffer_size() const { // BUFSIZ is intended to be a reasonable default. return BUFSIZ; @@ -166,7 +160,7 @@ raw_ostream &raw_ostream::write_escaped(StringRef Str, *this << '\\' << '"'; break; default: - if (std::isprint(c)) { + if (isPrint(c)) { *this << c; break; } @@ -442,7 +436,7 @@ raw_ostream &raw_ostream::operator<<(const FormattedBytes &FB) { // Print the ASCII char values for each byte on this line for (uint8_t Byte : Line) { - if (isprint(Byte)) + if (isPrint(Byte)) *this << static_cast<char>(Byte); else *this << '.'; @@ -458,25 +452,39 @@ raw_ostream &raw_ostream::operator<<(const FormattedBytes &FB) { return *this; } -/// indent - Insert 'NumSpaces' spaces. -raw_ostream &raw_ostream::indent(unsigned NumSpaces) { - static const char Spaces[] = " " - " " - " "; +template <char C> +static raw_ostream &write_padding(raw_ostream &OS, unsigned NumChars) { + static const char Chars[] = {C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, + C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, + C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, + C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, + C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C}; // Usually the indentation is small, handle it with a fastpath. - if (NumSpaces < array_lengthof(Spaces)) - return write(Spaces, NumSpaces); - - while (NumSpaces) { - unsigned NumToWrite = std::min(NumSpaces, - (unsigned)array_lengthof(Spaces)-1); - write(Spaces, NumToWrite); - NumSpaces -= NumToWrite; + if (NumChars < array_lengthof(Chars)) + return OS.write(Chars, NumChars); + + while (NumChars) { + unsigned NumToWrite = std::min(NumChars, + (unsigned)array_lengthof(Chars)-1); + OS.write(Chars, NumToWrite); + NumChars -= NumToWrite; } - return *this; + return OS; +} + +/// indent - Insert 'NumSpaces' spaces. +raw_ostream &raw_ostream::indent(unsigned NumSpaces) { + return write_padding<' '>(*this, NumSpaces); } +/// write_zeros - Insert 'NumZeros' nulls. +raw_ostream &raw_ostream::write_zeros(unsigned NumZeros) { + return write_padding<'\0'>(*this, NumZeros); +} + +void raw_ostream::anchor() {} + //===----------------------------------------------------------------------===// // Formatted Output //===----------------------------------------------------------------------===// @@ -490,29 +498,56 @@ void format_object_base::home() { //===----------------------------------------------------------------------===// static int getFD(StringRef Filename, std::error_code &EC, + sys::fs::CreationDisposition Disp, sys::fs::FileAccess Access, sys::fs::OpenFlags Flags) { + assert((Access & sys::fs::FA_Write) && + "Cannot make a raw_ostream from a read-only descriptor!"); + // Handle "-" as stdout. Note that when we do this, we consider ourself // the owner of stdout and may set the "binary" flag globally based on Flags. if (Filename == "-") { EC = std::error_code(); // If user requested binary then put stdout into binary mode if // possible. - if (!(Flags & sys::fs::F_Text)) + if (!(Flags & sys::fs::OF_Text)) sys::ChangeStdoutToBinary(); return STDOUT_FILENO; } int FD; - EC = sys::fs::openFileForWrite(Filename, FD, Flags); + if (Access & sys::fs::FA_Read) + EC = sys::fs::openFileForReadWrite(Filename, FD, Disp, Flags); + else + EC = sys::fs::openFileForWrite(Filename, FD, Disp, Flags); if (EC) return -1; return FD; } +raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC) + : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, sys::fs::FA_Write, + sys::fs::OF_None) {} + +raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC, + sys::fs::CreationDisposition Disp) + : raw_fd_ostream(Filename, EC, Disp, sys::fs::FA_Write, sys::fs::OF_None) {} + +raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC, + sys::fs::FileAccess Access) + : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, Access, + sys::fs::OF_None) {} + +raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC, + sys::fs::OpenFlags Flags) + : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, sys::fs::FA_Write, + Flags) {} + raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC, + sys::fs::CreationDisposition Disp, + sys::fs::FileAccess Access, sys::fs::OpenFlags Flags) - : raw_fd_ostream(getFD(Filename, EC, Flags), true) {} + : raw_fd_ostream(getFD(Filename, EC, Disp, Access, Flags), true) {} /// FD is the file descriptor that this writes to. If ShouldClose is true, this /// closes the file when the stream is destroyed. @@ -534,7 +569,7 @@ raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered) // Get the starting position. off_t loc = ::lseek(FD, 0, SEEK_CUR); -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 // MSVCRT's _lseek(SEEK_CUR) doesn't return -1 for pipes. sys::fs::file_status Status; std::error_code EC = status(FD, Status); @@ -587,7 +622,7 @@ void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) { // It is observed that Linux returns EINVAL for a very large write (>2G). // Make it a reasonably small value. MaxWriteSize = 1024 * 1024 * 1024; -#elif defined(LLVM_ON_WIN32) +#elif defined(_WIN32) // Writing a large size of output to Windows console returns ENOMEM. It seems // that, prior to Windows 8, WriteFile() is redirecting to WriteConsole(), and // the latter has a size limit (66000 bytes or less, depending on heap usage). @@ -640,7 +675,7 @@ void raw_fd_ostream::close() { uint64_t raw_fd_ostream::seek(uint64_t off) { assert(SupportsSeeking && "Stream does not support seeking!"); flush(); -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 pos = ::_lseeki64(FD, off, SEEK_SET); #elif defined(HAVE_LSEEK64) pos = ::lseek64(FD, off, SEEK_SET); @@ -730,6 +765,8 @@ bool raw_fd_ostream::has_colors() const { return sys::Process::FileDescriptorHasColors(FD); } +void raw_fd_ostream::anchor() {} + //===----------------------------------------------------------------------===// // outs(), errs(), nulls() //===----------------------------------------------------------------------===// @@ -807,3 +844,5 @@ uint64_t raw_null_ostream::current_pos() const { void raw_null_ostream::pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) {} + +void raw_pwrite_stream::anchor() {} diff --git a/contrib/llvm/lib/Support/regcomp.c b/contrib/llvm/lib/Support/regcomp.c index 354e359f676b..12669ab75d1a 100644 --- a/contrib/llvm/lib/Support/regcomp.c +++ b/contrib/llvm/lib/Support/regcomp.c @@ -36,6 +36,7 @@ */ #include <sys/types.h> +#include <stdint.h> #include <stdio.h> #include <string.h> #include <ctype.h> @@ -47,12 +48,6 @@ #include "regex2.h" #include "llvm/Config/config.h" -#if HAVE_STDINT_H -#include <stdint.h> -#else -/* Pessimistically bound memory use */ -#define SIZE_MAX UINT_MAX -#endif /* character-class table */ static struct cclass { diff --git a/contrib/llvm/lib/Support/regengine.inc b/contrib/llvm/lib/Support/regengine.inc index 62d8c267f22f..41787aff1242 100644 --- a/contrib/llvm/lib/Support/regengine.inc +++ b/contrib/llvm/lib/Support/regengine.inc @@ -1013,7 +1013,7 @@ pchar(int ch) { static char pbuf[10]; - if (isprint(ch) || ch == ' ') + if (isPrint(ch) || ch == ' ') (void)snprintf(pbuf, sizeof pbuf, "%c", ch); else (void)snprintf(pbuf, sizeof pbuf, "\\%o", ch); diff --git a/contrib/llvm/lib/Support/xxhash.cpp b/contrib/llvm/lib/Support/xxhash.cpp index a7d990bf6a4b..df643f9bd639 100644 --- a/contrib/llvm/lib/Support/xxhash.cpp +++ b/contrib/llvm/lib/Support/xxhash.cpp @@ -71,12 +71,12 @@ static uint64_t mergeRound(uint64_t Acc, uint64_t Val) { uint64_t llvm::xxHash64(StringRef Data) { size_t Len = Data.size(); uint64_t Seed = 0; - const char *P = Data.data(); - const char *const BEnd = P + Len; + const unsigned char *P = Data.bytes_begin(); + const unsigned char *const BEnd = Data.bytes_end(); uint64_t H64; if (Len >= 32) { - const char *const Limit = BEnd - 32; + const unsigned char *const Limit = BEnd - 32; uint64_t V1 = Seed + PRIME64_1 + PRIME64_2; uint64_t V2 = Seed + PRIME64_2; uint64_t V3 = Seed + 0; |