diff options
Diffstat (limited to 'lib/Support')
58 files changed, 4407 insertions, 1302 deletions
diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index f2388944929b..409d4fbd0ae5 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -14,8 +14,9 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include <limits.h> @@ -1150,9 +1151,6 @@ APFloat::roundAwayFromZero(roundingMode rounding_mode, assert(lost_fraction != lfExactlyZero); switch (rounding_mode) { - default: - llvm_unreachable(0); - case rmNearestTiesToAway: return lost_fraction == lfExactlyHalf || lost_fraction == lfMoreThanHalf; @@ -1175,6 +1173,7 @@ APFloat::roundAwayFromZero(roundingMode rounding_mode, case rmTowardNegative: return sign == true; } + llvm_unreachable("Invalid rounding mode found"); } APFloat::opStatus @@ -1854,20 +1853,33 @@ APFloat::convert(const fltSemantics &toSemantics, lostFraction lostFraction; unsigned int newPartCount, oldPartCount; opStatus fs; + int shift; + const fltSemantics &fromSemantics = *semantics; - assertArithmeticOK(*semantics); + assertArithmeticOK(fromSemantics); assertArithmeticOK(toSemantics); lostFraction = lfExactlyZero; newPartCount = partCountForBits(toSemantics.precision + 1); oldPartCount = partCount(); + shift = toSemantics.precision - fromSemantics.precision; - /* Handle storage complications. If our new form is wider, - re-allocate our bit pattern into wider storage. If it is - narrower, we ignore the excess parts, but if narrowing to a - single part we need to free the old storage. - Be careful not to reference significandParts for zeroes - and infinities, since it aborts. */ + bool X86SpecialNan = false; + if (&fromSemantics == &APFloat::x87DoubleExtended && + &toSemantics != &APFloat::x87DoubleExtended && category == fcNaN && + (!(*significandParts() & 0x8000000000000000ULL) || + !(*significandParts() & 0x4000000000000000ULL))) { + // x86 has some unusual NaNs which cannot be represented in any other + // format; note them here. + X86SpecialNan = true; + } + + // If this is a truncation, perform the shift before we narrow the storage. + if (shift < 0 && (category==fcNormal || category==fcNaN)) + lostFraction = shiftRight(significandParts(), oldPartCount, -shift); + + // Fix the storage so it can hold to new value. if (newPartCount > oldPartCount) { + // The new type requires more storage; make it available. integerPart *newParts; newParts = new integerPart[newPartCount]; APInt::tcSet(newParts, 0, newPartCount); @@ -1875,61 +1887,36 @@ APFloat::convert(const fltSemantics &toSemantics, APInt::tcAssign(newParts, significandParts(), oldPartCount); freeSignificand(); significand.parts = newParts; - } else if (newPartCount < oldPartCount) { - /* Capture any lost fraction through truncation of parts so we get - correct rounding whilst normalizing. */ - if (category==fcNormal) - lostFraction = lostFractionThroughTruncation - (significandParts(), oldPartCount, toSemantics.precision); - if (newPartCount == 1) { - integerPart newPart = 0; - if (category==fcNormal || category==fcNaN) - newPart = significandParts()[0]; - freeSignificand(); - significand.part = newPart; - } + } else if (newPartCount == 1 && oldPartCount != 1) { + // Switch to built-in storage for a single part. + integerPart newPart = 0; + if (category==fcNormal || category==fcNaN) + newPart = significandParts()[0]; + freeSignificand(); + significand.part = newPart; } + // Now that we have the right storage, switch the semantics. + semantics = &toSemantics; + + // If this is an extension, perform the shift now that the storage is + // available. + if (shift > 0 && (category==fcNormal || category==fcNaN)) + APInt::tcShiftLeft(significandParts(), newPartCount, shift); + if (category == fcNormal) { - /* Re-interpret our bit-pattern. */ - exponent += toSemantics.precision - semantics->precision; - semantics = &toSemantics; fs = normalize(rounding_mode, lostFraction); *losesInfo = (fs != opOK); } else if (category == fcNaN) { - int shift = toSemantics.precision - semantics->precision; - // Do this now so significandParts gets the right answer - const fltSemantics *oldSemantics = semantics; - semantics = &toSemantics; - *losesInfo = false; - // No normalization here, just truncate - if (shift>0) - APInt::tcShiftLeft(significandParts(), newPartCount, shift); - else if (shift < 0) { - unsigned ushift = -shift; - // Figure out if we are losing information. This happens - // if are shifting out something other than 0s, or if the x87 long - // double input did not have its integer bit set (pseudo-NaN), or if the - // x87 long double input did not have its QNan bit set (because the x87 - // hardware sets this bit when converting a lower-precision NaN to - // x87 long double). - if (APInt::tcLSB(significandParts(), newPartCount) < ushift) - *losesInfo = true; - if (oldSemantics == &APFloat::x87DoubleExtended && - (!(*significandParts() & 0x8000000000000000ULL) || - !(*significandParts() & 0x4000000000000000ULL))) - *losesInfo = true; - APInt::tcShiftRight(significandParts(), newPartCount, ushift); - } + *losesInfo = lostFraction != lfExactlyZero || X86SpecialNan; // gcc forces the Quiet bit on, which means (float)(double)(float_sNan) // does not give you back the same bits. This is dubious, and we // don't currently do it. You're really supposed to get // an invalid operation signal at runtime, but nobody does that. fs = opOK; } else { - semantics = &toSemantics; - fs = opOK; *losesInfo = false; + fs = opOK; } return fs; @@ -2695,21 +2682,19 @@ APFloat::convertNormalToHexString(char *dst, unsigned int hexDigits, return writeSignedDecimal (dst, exponent); } -// For good performance it is desirable for different APFloats -// to produce different integers. -uint32_t -APFloat::getHashValue() const -{ - if (category==fcZero) return sign<<8 | semantics->precision ; - else if (category==fcInfinity) return sign<<9 | semantics->precision; - else if (category==fcNaN) return 1<<10 | semantics->precision; - else { - uint32_t hash = sign<<11 | semantics->precision | exponent<<12; - const integerPart* p = significandParts(); - for (int i=partCount(); i>0; i--, p++) - hash ^= ((uint32_t)*p) ^ (uint32_t)((*p)>>32); - return hash; - } +hash_code llvm::hash_value(const APFloat &Arg) { + if (Arg.category != APFloat::fcNormal) + return hash_combine((uint8_t)Arg.category, + // NaN has no sign, fix it at zero. + Arg.isNaN() ? (uint8_t)0 : (uint8_t)Arg.sign, + Arg.semantics->precision); + + // Normal floats need their exponent and significand hashed. + return hash_combine((uint8_t)Arg.category, (uint8_t)Arg.sign, + Arg.semantics->precision, Arg.exponent, + hash_combine_range( + Arg.significandParts(), + Arg.significandParts() + Arg.partCount())); } // Conversion from APFloat to/from host float/double. It may eventually be @@ -3354,7 +3339,7 @@ namespace { // Rounding down is just a truncation, except we also want to drop // trailing zeros from the new result. if (buffer[FirstSignificant - 1] < '5') { - while (buffer[FirstSignificant] == '0') + while (FirstSignificant < N && buffer[FirstSignificant] == '0') FirstSignificant++; exp += FirstSignificant; diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index 3774c5223c46..9b81fe776a61 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -14,9 +14,10 @@ #define DEBUG_TYPE "apint" #include "llvm/ADT/APInt.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -456,16 +457,6 @@ APInt APInt::XorSlowCase(const APInt& RHS) const { return APInt(val, getBitWidth()).clearUnusedBits(); } -bool APInt::operator !() const { - if (isSingleWord()) - return !VAL; - - for (unsigned i = 0; i < getNumWords(); ++i) - if (pVal[i]) - return false; - return true; -} - APInt APInt::operator*(const APInt& RHS) const { assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); if (isSingleWord()) @@ -493,12 +484,6 @@ APInt APInt::operator-(const APInt& RHS) const { return Result.clearUnusedBits(); } -bool APInt::operator[](unsigned bitPosition) const { - assert(bitPosition < getBitWidth() && "Bit position out of bounds!"); - return (maskBit(bitPosition) & - (isSingleWord() ? VAL : pVal[whichWord(bitPosition)])) != 0; -} - bool APInt::EqualSlowCase(const APInt& RHS) const { // Get some facts about the number of bits used in the two operands. unsigned n1 = getActiveBits(); @@ -675,93 +660,11 @@ unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) { } } -// From http://www.burtleburtle.net, byBob Jenkins. -// When targeting x86, both GCC and LLVM seem to recognize this as a -// rotate instruction. -#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) - -// From http://www.burtleburtle.net, by Bob Jenkins. -#define mix(a,b,c) \ - { \ - a -= c; a ^= rot(c, 4); c += b; \ - b -= a; b ^= rot(a, 6); a += c; \ - c -= b; c ^= rot(b, 8); b += a; \ - a -= c; a ^= rot(c,16); c += b; \ - b -= a; b ^= rot(a,19); a += c; \ - c -= b; c ^= rot(b, 4); b += a; \ - } - -// From http://www.burtleburtle.net, by Bob Jenkins. -#define final(a,b,c) \ - { \ - c ^= b; c -= rot(b,14); \ - a ^= c; a -= rot(c,11); \ - b ^= a; b -= rot(a,25); \ - c ^= b; c -= rot(b,16); \ - a ^= c; a -= rot(c,4); \ - b ^= a; b -= rot(a,14); \ - c ^= b; c -= rot(b,24); \ - } - -// hashword() was adapted from http://www.burtleburtle.net, by Bob -// Jenkins. k is a pointer to an array of uint32_t values; length is -// the length of the key, in 32-bit chunks. This version only handles -// keys that are a multiple of 32 bits in size. -static inline uint32_t hashword(const uint64_t *k64, size_t length) -{ - const uint32_t *k = reinterpret_cast<const uint32_t *>(k64); - uint32_t a,b,c; - - /* Set up the internal state */ - a = b = c = 0xdeadbeef + (((uint32_t)length)<<2); - - /*------------------------------------------------- handle most of the key */ - while (length > 3) { - a += k[0]; - b += k[1]; - c += k[2]; - mix(a,b,c); - length -= 3; - k += 3; - } - - /*------------------------------------------- handle the last 3 uint32_t's */ - switch (length) { /* all the case statements fall through */ - case 3 : c+=k[2]; - case 2 : b+=k[1]; - case 1 : a+=k[0]; - final(a,b,c); - case 0: /* case 0: nothing left to add */ - break; - } - /*------------------------------------------------------ report the result */ - return c; -} - -// hashword8() was adapted from http://www.burtleburtle.net, by Bob -// Jenkins. This computes a 32-bit hash from one 64-bit word. When -// targeting x86 (32 or 64 bit), both LLVM and GCC compile this -// function into about 35 instructions when inlined. -static inline uint32_t hashword8(const uint64_t k64) -{ - uint32_t a,b,c; - a = b = c = 0xdeadbeef + 4; - b += k64 >> 32; - a += k64 & 0xffffffff; - final(a,b,c); - return c; -} -#undef final -#undef mix -#undef rot +hash_code llvm::hash_value(const APInt &Arg) { + if (Arg.isSingleWord()) + return hash_combine(Arg.VAL); -uint64_t APInt::getHashValue() const { - uint64_t hash; - if (isSingleWord()) - hash = hashword8(VAL); - else - hash = hashword(pVal, getNumWords()*2); - return hash; + return hash_combine_range(Arg.pVal, Arg.pVal + Arg.getNumWords()); } /// HiBits - This function returns the high "numBits" bits of this APInt. @@ -803,20 +706,9 @@ unsigned APInt::countLeadingZerosSlowCase() const { return Count; } -static unsigned countLeadingOnes_64(uint64_t V, unsigned skip) { - unsigned Count = 0; - if (skip) - V <<= skip; - while (V && (V & (1ULL << 63))) { - Count++; - V <<= 1; - } - return Count; -} - unsigned APInt::countLeadingOnes() const { if (isSingleWord()) - return countLeadingOnes_64(VAL, APINT_BITS_PER_WORD - BitWidth); + return CountLeadingOnes_64(VAL << (APINT_BITS_PER_WORD - BitWidth)); unsigned highWordBits = BitWidth % APINT_BITS_PER_WORD; unsigned shift; @@ -827,13 +719,13 @@ unsigned APInt::countLeadingOnes() const { shift = APINT_BITS_PER_WORD - highWordBits; } int i = getNumWords() - 1; - unsigned Count = countLeadingOnes_64(pVal[i], shift); + unsigned Count = CountLeadingOnes_64(pVal[i] << shift); if (Count == highWordBits) { for (i--; i >= 0; --i) { if (pVal[i] == -1ULL) Count += APINT_BITS_PER_WORD; else { - Count += countLeadingOnes_64(pVal[i], 0); + Count += CountLeadingOnes_64(pVal[i]); break; } } @@ -870,30 +762,43 @@ unsigned APInt::countPopulationSlowCase() const { return Count; } +/// Perform a logical right-shift from Src to Dst, which must be equal or +/// non-overlapping, of Words words, by Shift, which must be less than 64. +static void lshrNear(uint64_t *Dst, uint64_t *Src, unsigned Words, + unsigned Shift) { + uint64_t Carry = 0; + for (int I = Words - 1; I >= 0; --I) { + uint64_t Tmp = Src[I]; + Dst[I] = (Tmp >> Shift) | Carry; + Carry = Tmp << (64 - Shift); + } +} + APInt APInt::byteSwap() const { assert(BitWidth >= 16 && BitWidth % 16 == 0 && "Cannot byteswap!"); if (BitWidth == 16) return APInt(BitWidth, ByteSwap_16(uint16_t(VAL))); - else if (BitWidth == 32) + if (BitWidth == 32) return APInt(BitWidth, ByteSwap_32(unsigned(VAL))); - else if (BitWidth == 48) { + if (BitWidth == 48) { unsigned Tmp1 = unsigned(VAL >> 16); Tmp1 = ByteSwap_32(Tmp1); uint16_t Tmp2 = uint16_t(VAL); Tmp2 = ByteSwap_16(Tmp2); return APInt(BitWidth, (uint64_t(Tmp2) << 32) | Tmp1); - } else if (BitWidth == 64) + } + if (BitWidth == 64) return APInt(BitWidth, ByteSwap_64(VAL)); - else { - APInt Result(BitWidth, 0); - char *pByte = (char*)Result.pVal; - for (unsigned i = 0; i < BitWidth / APINT_WORD_SIZE / 2; ++i) { - char Tmp = pByte[i]; - pByte[i] = pByte[BitWidth / APINT_WORD_SIZE - 1 - i]; - pByte[BitWidth / APINT_WORD_SIZE - i - 1] = Tmp; - } - return Result; + + APInt Result(getNumWords() * APINT_BITS_PER_WORD, 0); + for (unsigned I = 0, N = getNumWords(); I != N; ++I) + Result.pVal[I] = ByteSwap_64(pVal[N - I - 1]); + if (Result.BitWidth != BitWidth) { + lshrNear(Result.pVal, Result.pVal, getNumWords(), + Result.BitWidth - BitWidth); + Result.BitWidth = BitWidth; } + return Result; } APInt llvm::APIntOps::GreatestCommonDivisor(const APInt& API1, @@ -1110,6 +1015,18 @@ APInt APInt::sextOrTrunc(unsigned width) const { return *this; } +APInt APInt::zextOrSelf(unsigned width) const { + if (BitWidth < width) + return zext(width); + return *this; +} + +APInt APInt::sextOrSelf(unsigned width) const { + if (BitWidth < width) + return sext(width); + return *this; +} + /// Arithmetic right-shift this APInt by shiftAmt. /// @brief Arithmetic right-shift function. APInt APInt::ashr(const APInt &shiftAmt) const { @@ -1209,7 +1126,7 @@ APInt APInt::lshr(const APInt &shiftAmt) const { /// @brief Logical right-shift function. APInt APInt::lshr(unsigned shiftAmt) const { if (isSingleWord()) { - if (shiftAmt == BitWidth) + if (shiftAmt >= BitWidth) return APInt(BitWidth, 0); else return APInt(BitWidth, this->VAL >> shiftAmt); @@ -1232,11 +1149,7 @@ APInt APInt::lshr(unsigned shiftAmt) const { // If we are shifting less than a word, compute the shift with a simple carry if (shiftAmt < APINT_BITS_PER_WORD) { - uint64_t carry = 0; - for (int i = getNumWords()-1; i >= 0; --i) { - val[i] = (pVal[i] >> shiftAmt) | carry; - carry = pVal[i] << (APINT_BITS_PER_WORD - shiftAmt); - } + lshrNear(val, pVal, getNumWords(), shiftAmt); return APInt(val, BitWidth).clearUnusedBits(); } @@ -1329,14 +1242,10 @@ APInt APInt::rotl(const APInt &rotateAmt) const { } APInt APInt::rotl(unsigned rotateAmt) const { + rotateAmt %= BitWidth; if (rotateAmt == 0) return *this; - // Don't get too fancy, just use existing shift/or facilities - APInt hi(*this); - APInt lo(*this); - hi.shl(rotateAmt); - lo.lshr(BitWidth - rotateAmt); - return hi | lo; + return shl(rotateAmt) | lshr(BitWidth - rotateAmt); } APInt APInt::rotr(const APInt &rotateAmt) const { @@ -1344,14 +1253,10 @@ APInt APInt::rotr(const APInt &rotateAmt) const { } APInt APInt::rotr(unsigned rotateAmt) const { + rotateAmt %= BitWidth; if (rotateAmt == 0) return *this; - // Don't get too fancy, just use existing shift/or facilities - APInt hi(*this); - APInt lo(*this); - lo.lshr(rotateAmt); - hi.shl(BitWidth - rotateAmt); - return hi | lo; + return lshr(rotateAmt) | shl(BitWidth - rotateAmt); } // Square Root - this method computes and returns the square root of "this". @@ -1431,15 +1336,11 @@ APInt APInt::sqrt() const { APInt nextSquare((x_old + 1) * (x_old +1)); if (this->ult(square)) return x_old; - else if (this->ule(nextSquare)) { - APInt midpoint((nextSquare - square).udiv(two)); - APInt offset(*this - square); - if (offset.ult(midpoint)) - return x_old; - else - return x_old + 1; - } else - llvm_unreachable("Error in APInt::sqrt computation"); + assert(this->ule(nextSquare) && "Error in APInt::sqrt computation"); + APInt midpoint((nextSquare - square).udiv(two)); + APInt offset(*this - square); + if (offset.ult(midpoint)) + return x_old; return x_old + 1; } @@ -2184,7 +2085,7 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, bool Signed, bool formatAsCLiteral) const { assert((Radix == 10 || Radix == 8 || Radix == 16 || Radix == 2 || Radix == 36) && - "Radix should be 2, 8, 10, or 16!"); + "Radix should be 2, 8, 10, 16, or 36!"); const char *Prefix = ""; if (formatAsCLiteral) { @@ -2197,9 +2098,13 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, case 8: Prefix = "0"; break; + case 10: + break; // No prefix case 16: Prefix = "0x"; break; + default: + llvm_unreachable("Invalid radix!"); } } diff --git a/lib/Support/Allocator.cpp b/lib/Support/Allocator.cpp index 215b0f249d96..b8978302e746 100644 --- a/lib/Support/Allocator.cpp +++ b/lib/Support/Allocator.cpp @@ -22,8 +22,8 @@ namespace llvm { BumpPtrAllocator::BumpPtrAllocator(size_t size, size_t threshold, SlabAllocator &allocator) - : SlabSize(size), SizeThreshold(threshold), Allocator(allocator), - CurSlab(0), BytesAllocated(0) { } + : SlabSize(size), SizeThreshold(std::min(size, threshold)), + Allocator(allocator), CurSlab(0), BytesAllocated(0) { } BumpPtrAllocator::~BumpPtrAllocator() { DeallocateSlabs(CurSlab); diff --git a/lib/Support/Atomic.cpp b/lib/Support/Atomic.cpp index 94760cc069fc..3001f6c468aa 100644 --- a/lib/Support/Atomic.cpp +++ b/lib/Support/Atomic.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Atomic.h" -#include "llvm/Config/config.h" +#include "llvm/Config/llvm-config.h" using namespace llvm; diff --git a/lib/Support/BlockFrequency.cpp b/lib/Support/BlockFrequency.cpp index a63bf83f2039..84a993e3e5b6 100644 --- a/lib/Support/BlockFrequency.cpp +++ b/lib/Support/BlockFrequency.cpp @@ -70,8 +70,13 @@ BlockFrequency &BlockFrequency::operator*=(const BranchProbability &Prob) { assert(n <= d && "Probability must be less or equal to 1."); - // If we can overflow use 96-bit operations. - if (n > 0 && Frequency > UINT64_MAX / n) { + // Calculate Frequency * n. + uint64_t mulLo = (Frequency & UINT32_MAX) * n; + uint64_t mulHi = (Frequency >> 32) * n; + uint64_t mulRes = (mulHi << 32) + mulLo; + + // If there was overflow use 96-bit operations. + if (mulHi > UINT32_MAX || mulRes < mulLo) { // 96-bit value represented as W[1]:W[0]. uint64_t W[2]; @@ -82,8 +87,7 @@ BlockFrequency &BlockFrequency::operator*=(const BranchProbability &Prob) { return *this; } - Frequency *= n; - Frequency /= d; + Frequency = mulRes / d; return *this; } diff --git a/lib/Support/BranchProbability.cpp b/lib/Support/BranchProbability.cpp index 49d04ed83653..e8b83e59802d 100644 --- a/lib/Support/BranchProbability.cpp +++ b/lib/Support/BranchProbability.cpp @@ -13,24 +13,17 @@ #include "llvm/Support/BranchProbability.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; -BranchProbability::BranchProbability(uint32_t n, uint32_t d) { - assert(d > 0 && "Denomiator cannot be 0!"); - assert(n <= d && "Probability cannot be bigger than 1!"); - N = n; - D = d; -} - void BranchProbability::print(raw_ostream &OS) const { - OS << N << " / " << D << " = " << ((double)N / D); + OS << N << " / " << D << " = " << format("%g%%", ((double)N / D) * 100.0); } void BranchProbability::dump() const { - print(dbgs()); - dbgs() << "\n"; + dbgs() << *this << '\n'; } namespace llvm { diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt index 63a833c38046..9b3b6c801dd0 100644 --- a/lib/Support/CMakeLists.txt +++ b/lib/Support/CMakeLists.txt @@ -16,6 +16,7 @@ add_llvm_library(LLVMSupport ConstantRange.cpp CrashRecoveryContext.cpp DataExtractor.cpp + DataStream.cpp Debug.cpp DeltaAlgorithm.cpp DAGDeltaAlgorithm.cpp @@ -25,10 +26,14 @@ add_llvm_library(LLVMSupport FoldingSet.cpp FormattedStream.cpp GraphWriter.cpp + Hashing.cpp IntEqClasses.cpp IntervalMap.cpp + IntrusiveRefCntPtr.cpp IsInf.cpp IsNAN.cpp + JSONParser.cpp + LockFileManager.cpp ManagedStatic.cpp MemoryBuffer.cpp MemoryObject.cpp @@ -39,6 +44,7 @@ add_llvm_library(LLVMSupport SmallVector.cpp SourceMgr.cpp Statistic.cpp + StreamableMemoryObject.cpp StringExtras.cpp StringMap.cpp StringPool.cpp @@ -48,6 +54,7 @@ add_llvm_library(LLVMSupport ToolOutputFile.cpp Triple.cpp Twine.cpp + YAMLParser.cpp raw_os_ostream.cpp raw_ostream.cpp regcomp.c diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index 238adcce0a12..e6fdf16a82de 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -57,6 +57,9 @@ TEMPLATE_INSTANTIATION(class opt<char>); TEMPLATE_INSTANTIATION(class opt<bool>); } } // end namespace llvm::cl +void GenericOptionValue::anchor() {} +void OptionValue<boolOrDefault>::anchor() {} +void OptionValue<std::string>::anchor() {} void Option::anchor() {} void basic_parser_impl::anchor() {} void parser<bool>::anchor() {} @@ -263,8 +266,8 @@ static bool CommaSeparateAndAddOccurence(Option *Handler, unsigned pos, /// and a null value (StringRef()). The later is accepted for arguments that /// don't allow a value (-foo) the former is rejected (-foo=). static inline bool ProvideOption(Option *Handler, StringRef ArgName, - StringRef Value, int argc, char **argv, - int &i) { + StringRef Value, int argc, + const char *const *argv, int &i) { // Is this a multi-argument option? unsigned NumAdditionalVals = Handler->getNumAdditionalVals(); @@ -289,12 +292,6 @@ static inline bool ProvideOption(Option *Handler, StringRef ArgName, break; case ValueOptional: break; - - default: - errs() << ProgramName - << ": Bad ValueMask flag! CommandLine usage error:" - << Handler->getValueExpectedFlag() << "\n"; - llvm_unreachable(0); } // If this isn't a multi-arg option, just run the handler. @@ -498,10 +495,10 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, /// ExpandResponseFiles - Copy the contents of argv into newArgv, /// substituting the contents of the response files for the arguments /// of type @file. -static void ExpandResponseFiles(unsigned argc, char** argv, +static void ExpandResponseFiles(unsigned argc, const char*const* argv, std::vector<char*>& newArgv) { for (unsigned i = 1; i != argc; ++i) { - char *arg = argv[i]; + const char *arg = argv[i]; if (arg[0] == '@') { sys::PathWithStatus respFile(++arg); @@ -531,7 +528,7 @@ static void ExpandResponseFiles(unsigned argc, char** argv, } } -void cl::ParseCommandLineOptions(int argc, char **argv, +void cl::ParseCommandLineOptions(int argc, const char * const *argv, const char *Overview, bool ReadResponseFiles) { // Process all registered options. SmallVector<Option*, 4> PositionalOpts; @@ -885,7 +882,6 @@ bool Option::addOccurrence(unsigned pos, StringRef ArgName, case OneOrMore: case ZeroOrMore: case ConsumeAfter: break; - default: return error("bad num occurrences flag value!"); } return handleOccurrence(pos, ArgName, Value); @@ -1195,7 +1191,7 @@ printOptionNoValue(const Option &O, size_t GlobalWidth) const { static int OptNameCompare(const void *LHS, const void *RHS) { typedef std::pair<const char *, Option*> pair_ty; - return strcmp(((pair_ty*)LHS)->first, ((pair_ty*)RHS)->first); + return strcmp(((const pair_ty*)LHS)->first, ((const pair_ty*)RHS)->first); } // Copy Options into a vector so we can sort them as we like. @@ -1349,7 +1345,7 @@ class VersionPrinter { public: void print() { raw_ostream &OS = outs(); - OS << "Low Level Virtual Machine (http://llvm.org/):\n" + OS << "LLVM (http://llvm.org/):\n" << " " << PACKAGE_NAME << " version " << PACKAGE_VERSION; #ifdef LLVM_VERSION_INFO OS << LLVM_VERSION_INFO; @@ -1369,7 +1365,7 @@ public: #if (ENABLE_TIMESTAMPS == 1) << " Built " << __DATE__ << " (" << __TIME__ << ").\n" #endif - << " Host: " << sys::getHostTriple() << '\n' + << " Default target: " << sys::getDefaultTargetTriple() << '\n' << " Host CPU: " << CPU << '\n'; } void operator=(bool OptionWasSpecified) { diff --git a/lib/Support/ConstantRange.cpp b/lib/Support/ConstantRange.cpp index c29cb53fb9c5..5206cf1f9b8c 100644 --- a/lib/Support/ConstantRange.cpp +++ b/lib/Support/ConstantRange.cpp @@ -55,7 +55,7 @@ ConstantRange ConstantRange::makeICmpRegion(unsigned Pred, uint32_t W = CR.getBitWidth(); switch (Pred) { - default: assert(0 && "Invalid ICmp predicate to makeICmpRegion()"); + default: llvm_unreachable("Invalid ICmp predicate to makeICmpRegion()"); case CmpInst::ICMP_EQ: return CR; case CmpInst::ICMP_NE: @@ -161,8 +161,7 @@ APInt ConstantRange::getSetSize() const { APInt ConstantRange::getUnsignedMax() const { if (isFullSet() || isWrappedSet()) return APInt::getMaxValue(getBitWidth()); - else - return getUpper() - 1; + return getUpper() - 1; } /// getUnsignedMin - Return the smallest unsigned value contained in the @@ -171,8 +170,7 @@ APInt ConstantRange::getUnsignedMax() const { APInt ConstantRange::getUnsignedMin() const { if (isFullSet() || (isWrappedSet() && getUpper() != 0)) return APInt::getMinValue(getBitWidth()); - else - return getLower(); + return getLower(); } /// getSignedMax - Return the largest signed value contained in the @@ -183,14 +181,11 @@ APInt ConstantRange::getSignedMax() const { if (!isWrappedSet()) { if (getLower().sle(getUpper() - 1)) return getUpper() - 1; - else - return SignedMax; - } else { - if (getLower().isNegative() == getUpper().isNegative()) - return SignedMax; - else - return getUpper() - 1; + return SignedMax; } + if (getLower().isNegative() == getUpper().isNegative()) + return SignedMax; + return getUpper() - 1; } /// getSignedMin - Return the smallest signed value contained in the @@ -201,18 +196,13 @@ APInt ConstantRange::getSignedMin() const { if (!isWrappedSet()) { if (getLower().sle(getUpper() - 1)) return getLower(); - else + return SignedMin; + } + if ((getUpper() - 1).slt(getLower())) { + if (getUpper() != SignedMin) return SignedMin; - } else { - if ((getUpper() - 1).slt(getLower())) { - if (getUpper() != SignedMin) - return SignedMin; - else - return getLower(); - } else { - return getLower(); - } } + return getLower(); } /// contains - Return true if the specified value is in the set. @@ -223,8 +213,7 @@ bool ConstantRange::contains(const APInt &V) const { if (!isWrappedSet()) return Lower.ule(V) && V.ult(Upper); - else - return Lower.ule(V) || V.ult(Upper); + return Lower.ule(V) || V.ult(Upper); } /// contains - Return true if the argument is a subset of this range. @@ -284,15 +273,14 @@ ConstantRange ConstantRange::intersectWith(const ConstantRange &CR) const { return ConstantRange(CR.Lower, Upper); return CR; - } else { - if (Upper.ult(CR.Upper)) - return *this; + } + if (Upper.ult(CR.Upper)) + return *this; - if (Lower.ult(CR.Upper)) - return ConstantRange(Lower, CR.Upper); + if (Lower.ult(CR.Upper)) + return ConstantRange(Lower, CR.Upper); - return ConstantRange(getBitWidth(), false); - } + return ConstantRange(getBitWidth(), false); } if (isWrappedSet() && !CR.isWrappedSet()) { @@ -305,9 +293,9 @@ ConstantRange ConstantRange::intersectWith(const ConstantRange &CR) const { if (getSetSize().ult(CR.getSetSize())) return *this; - else - return CR; - } else if (CR.Lower.ult(Lower)) { + return CR; + } + if (CR.Lower.ult(Lower)) { if (CR.Upper.ule(Lower)) return ConstantRange(getBitWidth(), false); @@ -320,15 +308,15 @@ ConstantRange ConstantRange::intersectWith(const ConstantRange &CR) const { if (CR.Lower.ult(Upper)) { if (getSetSize().ult(CR.getSetSize())) return *this; - else - return CR; + return CR; } if (CR.Lower.ult(Lower)) return ConstantRange(Lower, CR.Upper); return CR; - } else if (CR.Upper.ult(Lower)) { + } + if (CR.Upper.ult(Lower)) { if (CR.Lower.ult(Lower)) return *this; @@ -336,8 +324,7 @@ ConstantRange ConstantRange::intersectWith(const ConstantRange &CR) const { } if (getSetSize().ult(CR.getSetSize())) return *this; - else - return CR; + return CR; } @@ -362,8 +349,7 @@ ConstantRange ConstantRange::unionWith(const ConstantRange &CR) const { APInt d1 = CR.Lower - Upper, d2 = Lower - CR.Upper; if (d1.ult(d2)) return ConstantRange(Lower, CR.Upper); - else - return ConstantRange(CR.Lower, Upper); + return ConstantRange(CR.Lower, Upper); } APInt L = Lower, U = Upper; @@ -396,8 +382,7 @@ ConstantRange ConstantRange::unionWith(const ConstantRange &CR) const { APInt d1 = CR.Lower - Upper, d2 = Lower - CR.Upper; if (d1.ult(d2)) return ConstantRange(Lower, CR.Upper); - else - return ConstantRange(CR.Lower, Upper); + return ConstantRange(CR.Lower, Upper); } // ----U L----- : this @@ -407,13 +392,11 @@ ConstantRange ConstantRange::unionWith(const ConstantRange &CR) const { // ------U L---- : this // L-----U : CR - if (CR.Lower.ult(Upper) && CR.Upper.ult(Lower)) - return ConstantRange(Lower, CR.Upper); + assert(CR.Lower.ult(Upper) && CR.Upper.ult(Lower) && + "ConstantRange::unionWith missed a case with one range wrapped"); + return ConstantRange(Lower, CR.Upper); } - assert(isWrappedSet() && CR.isWrappedSet() && - "ConstantRange::unionWith missed wrapped union unwrapped case"); - // ------U L---- and ------U L---- : this // -U L----------- and ------------U L : CR if (CR.Lower.ule(Upper) || Lower.ule(CR.Upper)) @@ -466,10 +449,8 @@ ConstantRange ConstantRange::signExtend(uint32_t DstTySize) const { /// correspond to the possible range of values as if the source range had been /// truncated to the specified type. ConstantRange ConstantRange::truncate(uint32_t DstTySize) const { - unsigned SrcTySize = getBitWidth(); - assert(SrcTySize > DstTySize && "Not a value truncation"); - APInt Size(APInt::getLowBitsSet(SrcTySize, DstTySize)); - if (isFullSet() || getSetSize().ugt(Size)) + assert(getBitWidth() > DstTySize && "Not a value truncation"); + if (isFullSet() || getSetSize().getActiveBits() > DstTySize) return ConstantRange(DstTySize, /*isFullSet=*/true); return ConstantRange(Lower.trunc(DstTySize), Upper.trunc(DstTySize)); @@ -481,10 +462,9 @@ ConstantRange ConstantRange::zextOrTrunc(uint32_t DstTySize) const { unsigned SrcTySize = getBitWidth(); if (SrcTySize > DstTySize) return truncate(DstTySize); - else if (SrcTySize < DstTySize) + if (SrcTySize < DstTySize) return zeroExtend(DstTySize); - else - return *this; + return *this; } /// sextOrTrunc - make this range have the bit width given by \p DstTySize. The @@ -493,10 +473,9 @@ ConstantRange ConstantRange::sextOrTrunc(uint32_t DstTySize) const { unsigned SrcTySize = getBitWidth(); if (SrcTySize > DstTySize) return truncate(DstTySize); - else if (SrcTySize < DstTySize) + if (SrcTySize < DstTySize) return signExtend(DstTySize); - else - return *this; + return *this; } ConstantRange @@ -675,11 +654,10 @@ ConstantRange::lshr(const ConstantRange &Other) const { } ConstantRange ConstantRange::inverse() const { - if (isFullSet()) { + if (isFullSet()) return ConstantRange(getBitWidth(), /*isFullSet=*/false); - } else if (isEmptySet()) { + if (isEmptySet()) return ConstantRange(getBitWidth(), /*isFullSet=*/true); - } return ConstantRange(Upper, Lower); } diff --git a/lib/Support/CrashRecoveryContext.cpp b/lib/Support/CrashRecoveryContext.cpp index 263114c06f98..e2af0bc17655 100644 --- a/lib/Support/CrashRecoveryContext.cpp +++ b/lib/Support/CrashRecoveryContext.cpp @@ -165,7 +165,6 @@ static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) // Note that we don't actually get here because HandleCrash calls // longjmp, which means the HandleCrash function never returns. llvm_unreachable("Handled the crash, should have longjmp'ed out of here"); - return EXCEPTION_CONTINUE_SEARCH; } // Because the Enable and Disable calls are static, it means that diff --git a/lib/Support/DAGDeltaAlgorithm.cpp b/lib/Support/DAGDeltaAlgorithm.cpp index 814566494d30..1e89c6ad2ff2 100644 --- a/lib/Support/DAGDeltaAlgorithm.cpp +++ b/lib/Support/DAGDeltaAlgorithm.cpp @@ -350,6 +350,9 @@ DAGDeltaAlgorithmImpl::Run() { return Required; } +void DAGDeltaAlgorithm::anchor() { +} + DAGDeltaAlgorithm::changeset_ty DAGDeltaAlgorithm::Run(const changeset_ty &Changes, const std::vector<edge_ty> &Dependencies) { diff --git a/lib/Support/DataExtractor.cpp b/lib/Support/DataExtractor.cpp index b946c1df8363..dc21155a0624 100644 --- a/lib/Support/DataExtractor.cpp +++ b/lib/Support/DataExtractor.cpp @@ -75,7 +75,7 @@ uint32_t DataExtractor::getU32(uint32_t *offset_ptr) const { uint32_t *DataExtractor::getU32(uint32_t *offset_ptr, uint32_t *dst, uint32_t count) const { return getUs<uint32_t>(offset_ptr, dst, count, this, IsLittleEndian, - Data.data());; + Data.data()); } uint64_t DataExtractor::getU64(uint32_t *offset_ptr) const { diff --git a/lib/Support/DataStream.cpp b/lib/Support/DataStream.cpp new file mode 100644 index 000000000000..94d14a5e36b0 --- /dev/null +++ b/lib/Support/DataStream.cpp @@ -0,0 +1,98 @@ +//===--- llvm/Support/DataStream.cpp - Lazy streamed data -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements DataStreamer, which fetches bytes of Data from +// a stream source. It provides support for streaming (lazy reading) of +// bitcode. An example implementation of streaming from a file or stdin +// is included. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "Data-stream" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/DataStream.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/system_error.h" +#include <string> +#include <cerrno> +#include <cstdio> +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include <unistd.h> +#else +#include <io.h> +#endif +#include <fcntl.h> +using namespace llvm; + +// Interface goals: +// * StreamableMemoryObject doesn't care about complexities like using +// threads/async callbacks to actually overlap download+compile +// * Don't want to duplicate Data in memory +// * Don't need to know total Data len in advance +// Non-goals: +// StreamableMemoryObject already has random access so this interface only does +// in-order streaming (no arbitrary seeking, else we'd have to buffer all the +// Data here in addition to MemoryObject). This also means that if we want +// to be able to to free Data, BitstreamBytes/BitcodeReader will implement it + +STATISTIC(NumStreamFetches, "Number of calls to Data stream fetch"); + +namespace llvm { +DataStreamer::~DataStreamer() {} +} + +namespace { + +// Very simple stream backed by a file. Mostly useful for stdin and debugging; +// actual file access is probably still best done with mmap. +class DataFileStreamer : public DataStreamer { + int Fd; +public: + DataFileStreamer() : Fd(0) {} + virtual ~DataFileStreamer() { + close(Fd); + } + virtual size_t GetBytes(unsigned char *buf, size_t len) { + NumStreamFetches++; + return read(Fd, buf, len); + } + + error_code OpenFile(const std::string &Filename) { + if (Filename == "-") { + Fd = 0; + sys::Program::ChangeStdinToBinary(); + return error_code::success(); + } + + int OpenFlags = O_RDONLY; +#ifdef O_BINARY + OpenFlags |= O_BINARY; // Open input file in binary mode on win32. +#endif + Fd = ::open(Filename.c_str(), OpenFlags); + if (Fd == -1) + return error_code(errno, posix_category()); + return error_code::success(); + } +}; + +} + +namespace llvm { +DataStreamer *getDataFileStreamer(const std::string &Filename, + std::string *StrError) { + DataFileStreamer *s = new DataFileStreamer(); + if (error_code e = s->OpenFile(Filename)) { + *StrError = std::string("Could not open ") + Filename + ": " + + e.message() + "\n"; + return NULL; + } + return s; +} + +} diff --git a/lib/Support/Dwarf.cpp b/lib/Support/Dwarf.cpp index 95a9550f9663..5c59a3ef8ef3 100644 --- a/lib/Support/Dwarf.cpp +++ b/lib/Support/Dwarf.cpp @@ -95,6 +95,7 @@ const char *llvm::dwarf::TagString(unsigned Tag) { return "DW_TAG_GNU_template_parameter_pack"; case DW_TAG_GNU_formal_parameter_pack: return "DW_TAG_GNU_formal_parameter_pack"; + case DW_TAG_APPLE_property: return "DW_TAG_APPLE_property"; } return 0; } @@ -245,6 +246,7 @@ const char *llvm::dwarf::AttributeString(unsigned Attribute) { case DW_AT_APPLE_property_getter: return "DW_AT_APPLE_property_getter"; case DW_AT_APPLE_property_setter: return "DW_AT_APPLE_property_setter"; case DW_AT_APPLE_property_attribute: return "DW_AT_APPLE_property_attribute"; + case DW_AT_APPLE_property: return "DW_AT_APPLE_property"; case DW_AT_APPLE_objc_complete_type: return "DW_AT_APPLE_objc_complete_type"; } return 0; diff --git a/lib/Support/FileUtilities.cpp b/lib/Support/FileUtilities.cpp index 4c8c0c63ffc4..f9e9cf036608 100644 --- a/lib/Support/FileUtilities.cpp +++ b/lib/Support/FileUtilities.cpp @@ -200,7 +200,6 @@ int llvm::DiffFilesWithTolerance(const sys::PathWithStatus &FileA, // Now its safe to mmap the files into memory because both files // have a non-zero size. - error_code ec; OwningPtr<MemoryBuffer> F1; if (error_code ec = MemoryBuffer::getFile(FileA.c_str(), F1)) { if (Error) diff --git a/lib/Support/FoldingSet.cpp b/lib/Support/FoldingSet.cpp index 17b827132f57..c6282c6ab2ab 100644 --- a/lib/Support/FoldingSet.cpp +++ b/lib/Support/FoldingSet.cpp @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/Hashing.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -29,24 +30,7 @@ using namespace llvm; /// ComputeHash - Compute a strong hash value for this FoldingSetNodeIDRef, /// used to lookup the node in the FoldingSetImpl. unsigned FoldingSetNodeIDRef::ComputeHash() const { - // This is adapted from SuperFastHash by Paul Hsieh. - unsigned Hash = static_cast<unsigned>(Size); - for (const unsigned *BP = Data, *E = BP+Size; BP != E; ++BP) { - unsigned Data = *BP; - Hash += Data & 0xFFFF; - unsigned Tmp = ((Data >> 16) << 11) ^ Hash; - Hash = (Hash << 16) ^ Tmp; - Hash += Hash >> 11; - } - - // Force "avalanching" of final 127 bits. - Hash ^= Hash << 3; - Hash += Hash >> 5; - Hash ^= Hash << 4; - Hash += Hash >> 17; - Hash ^= Hash << 25; - Hash += Hash >> 6; - return Hash; + return static_cast<unsigned>(hash_combine_range(Data, Data+Size)); } bool FoldingSetNodeIDRef::operator==(FoldingSetNodeIDRef RHS) const { @@ -281,15 +265,15 @@ void FoldingSetImpl::GrowHashTable() { FoldingSetImpl::Node *FoldingSetImpl::FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) { - - void **Bucket = GetBucketFor(ID.ComputeHash(), Buckets, NumBuckets); + unsigned IDHash = ID.ComputeHash(); + void **Bucket = GetBucketFor(IDHash, Buckets, NumBuckets); void *Probe = *Bucket; InsertPos = 0; FoldingSetNodeID TempID; while (Node *NodeInBucket = GetNextPtr(Probe)) { - if (NodeEquals(NodeInBucket, ID, TempID)) + if (NodeEquals(NodeInBucket, ID, IDHash, TempID)) return NodeInBucket; TempID.clear(); diff --git a/lib/Support/GraphWriter.cpp b/lib/Support/GraphWriter.cpp index 0dba28a2530c..32126ec39eba 100644 --- a/lib/Support/GraphWriter.cpp +++ b/lib/Support/GraphWriter.cpp @@ -11,12 +11,16 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Support/CommandLine.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" #include "llvm/Config/config.h" using namespace llvm; +static cl::opt<bool> ViewBackground("view-background", cl::Hidden, + cl::desc("Execute graph viewer in the background. Creates tmp file litter.")); + std::string llvm::DOT::EscapeString(const std::string &Label) { std::string Str(Label); for (unsigned i = 0; i != Str.length(); ++i) @@ -49,10 +53,28 @@ std::string llvm::DOT::EscapeString(const std::string &Label) { return Str; } - +// Execute the graph viewer. Return true if successful. +static bool LLVM_ATTRIBUTE_UNUSED +ExecGraphViewer(const sys::Path &ExecPath, std::vector<const char*> &args, + const sys::Path &Filename, bool wait, std::string &ErrMsg) { + if (wait) { + if (sys::Program::ExecuteAndWait(ExecPath, &args[0],0,0,0,0,&ErrMsg)) { + errs() << "Error: " << ErrMsg << "\n"; + return false; + } + Filename.eraseFromDisk(); + errs() << " done. \n"; + } + else { + sys::Program::ExecuteNoWait(ExecPath, &args[0],0,0,0,&ErrMsg); + errs() << "Remember to erase graph file: " << Filename.str() << "\n"; + } + return true; +} void llvm::DisplayGraph(const sys::Path &Filename, bool wait, GraphProgram::Name program) { + wait &= !ViewBackground; std::string ErrMsg; #if HAVE_GRAPHVIZ sys::Path Graphviz(LLVM_PATH_GRAPHVIZ); @@ -61,14 +83,10 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait, args.push_back(Graphviz.c_str()); args.push_back(Filename.c_str()); args.push_back(0); - + errs() << "Running 'Graphviz' program... "; - if (sys::Program::ExecuteAndWait(Graphviz, &args[0],0,0,0,0,&ErrMsg)) { - errs() << "Error: " << ErrMsg << "\n"; + if (!ExecGraphViewer(Graphviz, args, Filename, wait, ErrMsg)) return; - } - Filename.eraseFromDisk(); - errs() << " done. \n"; #elif HAVE_XDOT_PY std::vector<const char*> args; @@ -83,17 +101,12 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait, case GraphProgram::CIRCO: args.push_back("-f"); args.push_back("circo");break; default: errs() << "Unknown graph layout name; using default.\n"; } - + args.push_back(0); errs() << "Running 'xdot.py' program... "; - if (sys::Program::ExecuteAndWait(sys::Path(LLVM_PATH_XDOT_PY), - &args[0],0,0,0,0,&ErrMsg)) { - errs() << "Error: " << ErrMsg << "\n"; + if (!ExecGraphViewer(sys::Path(LLVM_PATH_XDOT_PY), args, Filename, wait, ErrMsg)) return; - } - Filename.eraseFromDisk(); - errs() << " done. \n"; #elif (HAVE_GV && (HAVE_DOT || HAVE_FDP || HAVE_NEATO || \ HAVE_TWOPI || HAVE_CIRCO)) @@ -150,14 +163,11 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait, args.push_back("-o"); args.push_back(PSFilename.c_str()); args.push_back(0); - + errs() << "Running '" << prog.str() << "' program... "; - if (sys::Program::ExecuteAndWait(prog, &args[0], 0, 0, 0, 0, &ErrMsg)) { - errs() << "Error: " << ErrMsg << "\n"; + if (!ExecGraphViewer(prog, args, Filename, wait, ErrMsg)) return; - } - errs() << " done. \n"; sys::Path gv(LLVM_PATH_GV); args.clear(); @@ -165,19 +175,11 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait, args.push_back(PSFilename.c_str()); args.push_back("--spartan"); args.push_back(0); - + ErrMsg.clear(); - if (wait) { - if (sys::Program::ExecuteAndWait(gv, &args[0],0,0,0,0,&ErrMsg)) - errs() << "Error: " << ErrMsg << "\n"; - Filename.eraseFromDisk(); - PSFilename.eraseFromDisk(); - } - else { - sys::Program::ExecuteNoWait(gv, &args[0],0,0,0,&ErrMsg); - errs() << "Remember to erase graph files: " << Filename.str() << " " - << PSFilename.str() << "\n"; - } + if (!ExecGraphViewer(gv, args, PSFilename, wait, ErrMsg)) + return; + #elif HAVE_DOTTY sys::Path dotty(LLVM_PATH_DOTTY); @@ -185,16 +187,13 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait, args.push_back(dotty.c_str()); args.push_back(Filename.c_str()); args.push_back(0); - - errs() << "Running 'dotty' program... "; - if (sys::Program::ExecuteAndWait(dotty, &args[0],0,0,0,0,&ErrMsg)) { - errs() << "Error: " << ErrMsg << "\n"; - } else { + // Dotty spawns another app and doesn't wait until it returns #if defined (__MINGW32__) || defined (_WINDOWS) - return; + wait = false; #endif - Filename.eraseFromDisk(); - } + errs() << "Running 'dotty' program... "; + if (!ExecGraphViewer(dotty, args, Filename, wait, ErrMsg)) + return; #endif } diff --git a/lib/Support/Hashing.cpp b/lib/Support/Hashing.cpp new file mode 100644 index 000000000000..c69efb7c3cc9 --- /dev/null +++ b/lib/Support/Hashing.cpp @@ -0,0 +1,29 @@ +//===-------------- lib/Support/Hashing.cpp -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides implementation bits for the LLVM common hashing +// infrastructure. Documentation and most of the other information is in the +// header file. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Hashing.h" + +using namespace llvm; + +// Provide a definition and static initializer for the fixed seed. This +// initializer should always be zero to ensure its value can never appear to be +// non-zero, even during dynamic initialization. +size_t llvm::hashing::detail::fixed_seed_override = 0; + +// Implement the function for forced setting of the fixed seed. +// FIXME: Use atomic operations here so that there is no data race. +void llvm::set_fixed_execution_hash_seed(size_t fixed_value) { + hashing::detail::fixed_seed_override = fixed_value; +} diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp index a19e4b41189b..0f0696438ca6 100644 --- a/lib/Support/Host.cpp +++ b/lib/Support/Host.cpp @@ -61,6 +61,8 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, *rECX = registers[2]; *rEDX = registers[3]; return false; + #else + return true; #endif #elif defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86) #if defined(__GNUC__) @@ -87,9 +89,14 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, mov dword ptr [esi],edx } return false; +// pedantic #else returns to appease -Wunreachable-code (so we don't generate +// postprocessed code that looks like "return true; return false;") + #else + return true; #endif -#endif +#else return true; +#endif } static void DetectX86FamilyModel(unsigned EAX, unsigned &Family, @@ -298,6 +305,10 @@ std::string sys::getHostCPUName() { } case 16: return "amdfam10"; + case 20: + return "btver1"; + case 21: + return "bdver1"; default: return "generic"; } diff --git a/lib/Support/IntrusiveRefCntPtr.cpp b/lib/Support/IntrusiveRefCntPtr.cpp new file mode 100644 index 000000000000..a8b45593ae70 --- /dev/null +++ b/lib/Support/IntrusiveRefCntPtr.cpp @@ -0,0 +1,14 @@ +//== IntrusiveRefCntPtr.cpp - Smart Refcounting Pointer ----------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/IntrusiveRefCntPtr.h" + +using namespace llvm; + +void RefCountedBaseVPTR::anchor() { } diff --git a/lib/Support/JSONParser.cpp b/lib/Support/JSONParser.cpp new file mode 100644 index 000000000000..5dfcf297a7ea --- /dev/null +++ b/lib/Support/JSONParser.cpp @@ -0,0 +1,302 @@ +//===--- JSONParser.cpp - Simple JSON parser ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a JSON parser. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/JSONParser.h" + +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace llvm; + +JSONParser::JSONParser(StringRef Input, SourceMgr *SM) + : SM(SM), Failed(false) { + InputBuffer = MemoryBuffer::getMemBuffer(Input, "JSON"); + SM->AddNewSourceBuffer(InputBuffer, SMLoc()); + End = InputBuffer->getBuffer().end(); + Position = InputBuffer->getBuffer().begin(); +} + +JSONValue *JSONParser::parseRoot() { + if (Position != InputBuffer->getBuffer().begin()) + report_fatal_error("Cannot reuse JSONParser."); + if (isWhitespace()) + nextNonWhitespace(); + if (errorIfAtEndOfFile("'[' or '{' at start of JSON text")) + return 0; + switch (*Position) { + case '[': + return new (ValueAllocator.Allocate<JSONArray>(1)) JSONArray(this); + case '{': + return new (ValueAllocator.Allocate<JSONObject>(1)) JSONObject(this); + default: + setExpectedError("'[' or '{' at start of JSON text", *Position); + return 0; + } +} + +bool JSONParser::validate() { + JSONValue *Root = parseRoot(); + if (Root == NULL) { + return false; + } + return skip(*Root); +} + +bool JSONParser::skip(const JSONAtom &Atom) { + switch(Atom.getKind()) { + case JSONAtom::JK_Array: + case JSONAtom::JK_Object: + return skipContainer(*cast<JSONContainer>(&Atom)); + case JSONAtom::JK_String: + return true; + case JSONAtom::JK_KeyValuePair: + return skip(*cast<JSONKeyValuePair>(&Atom)->Value); + } + llvm_unreachable("Impossible enum value."); +} + +// Sets the current error to: +// "expected <Expected>, but found <Found>". +void JSONParser::setExpectedError(StringRef Expected, StringRef Found) { + SM->PrintMessage(SMLoc::getFromPointer(Position), SourceMgr::DK_Error, + "expected " + Expected + ", but found " + Found + ".", ArrayRef<SMRange>()); + Failed = true; +} + +// Sets the current error to: +// "expected <Expected>, but found <Found>". +void JSONParser::setExpectedError(StringRef Expected, char Found) { + setExpectedError(Expected, ("'" + StringRef(&Found, 1) + "'").str()); +} + +// If there is no character available, returns true and sets the current error +// to: "expected <Expected>, but found EOF.". +bool JSONParser::errorIfAtEndOfFile(StringRef Expected) { + if (Position == End) { + setExpectedError(Expected, "EOF"); + return true; + } + return false; +} + +// Sets the current error if the current character is not C to: +// "expected 'C', but got <current character>". +bool JSONParser::errorIfNotAt(char C, StringRef Message) { + if (*Position != C) { + std::string Expected = + ("'" + StringRef(&C, 1) + "' " + Message).str(); + if (Position == End) + setExpectedError(Expected, "EOF"); + else + setExpectedError(Expected, *Position); + return true; + } + return false; +} + +// Forbidding inlining improves performance by roughly 20%. +// FIXME: Remove once llvm optimizes this to the faster version without hints. +LLVM_ATTRIBUTE_NOINLINE static bool +wasEscaped(StringRef::iterator First, StringRef::iterator Position); + +// Returns whether a character at 'Position' was escaped with a leading '\'. +// 'First' specifies the position of the first character in the string. +static bool wasEscaped(StringRef::iterator First, + StringRef::iterator Position) { + assert(Position - 1 >= First); + StringRef::iterator I = Position - 1; + // We calulate the number of consecutive '\'s before the current position + // by iterating backwards through our string. + while (I >= First && *I == '\\') --I; + // (Position - 1 - I) now contains the number of '\'s before the current + // position. If it is odd, the character at 'Positon' was escaped. + return (Position - 1 - I) % 2 == 1; +} + +// Parses a JSONString, assuming that the current position is on a quote. +JSONString *JSONParser::parseString() { + assert(Position != End); + assert(!isWhitespace()); + if (errorIfNotAt('"', "at start of string")) + return 0; + StringRef::iterator First = Position + 1; + + // Benchmarking shows that this loop is the hot path of the application with + // about 2/3rd of the runtime cycles. Since escaped quotes are not the common + // case, and multiple escaped backslashes before escaped quotes are very rare, + // we pessimize this case to achieve a smaller inner loop in the common case. + // We're doing that by having a quick inner loop that just scans for the next + // quote. Once we find the quote we check the last character to see whether + // the quote might have been escaped. If the last character is not a '\', we + // know the quote was not escaped and have thus found the end of the string. + // If the immediately preceding character was a '\', we have to scan backwards + // to see whether the previous character was actually an escaped backslash, or + // an escape character for the quote. If we find that the current quote was + // escaped, we continue parsing for the next quote and repeat. + // This optimization brings around 30% performance improvements. + do { + // Step over the current quote. + ++Position; + // Find the next quote. + while (Position != End && *Position != '"') + ++Position; + if (errorIfAtEndOfFile("'\"' at end of string")) + return 0; + // Repeat until the previous character was not a '\' or was an escaped + // backslash. + } while (*(Position - 1) == '\\' && wasEscaped(First, Position)); + + return new (ValueAllocator.Allocate<JSONString>()) + JSONString(StringRef(First, Position - First)); +} + + +// Advances the position to the next non-whitespace position. +void JSONParser::nextNonWhitespace() { + do { + ++Position; + } while (isWhitespace()); +} + +// Checks if there is a whitespace character at the current position. +bool JSONParser::isWhitespace() { + return *Position == ' ' || *Position == '\t' || + *Position == '\n' || *Position == '\r'; +} + +bool JSONParser::failed() const { + return Failed; +} + +// Parses a JSONValue, assuming that the current position is at the first +// character of the value. +JSONValue *JSONParser::parseValue() { + assert(Position != End); + assert(!isWhitespace()); + switch (*Position) { + case '[': + return new (ValueAllocator.Allocate<JSONArray>(1)) JSONArray(this); + case '{': + return new (ValueAllocator.Allocate<JSONObject>(1)) JSONObject(this); + case '"': + return parseString(); + default: + setExpectedError("'[', '{' or '\"' at start of value", *Position); + return 0; + } +} + +// Parses a JSONKeyValuePair, assuming that the current position is at the first +// character of the key, value pair. +JSONKeyValuePair *JSONParser::parseKeyValuePair() { + assert(Position != End); + assert(!isWhitespace()); + + JSONString *Key = parseString(); + if (Key == 0) + return 0; + + nextNonWhitespace(); + if (errorIfNotAt(':', "between key and value")) + return 0; + + nextNonWhitespace(); + const JSONValue *Value = parseValue(); + if (Value == 0) + return 0; + + return new (ValueAllocator.Allocate<JSONKeyValuePair>(1)) + JSONKeyValuePair(Key, Value); +} + +/// \brief Parses the first element of a JSON array or object, or closes the +/// array. +/// +/// The method assumes that the current position is before the first character +/// of the element, with possible white space in between. When successful, it +/// returns the new position after parsing the element. Otherwise, if there is +/// no next value, it returns a default constructed StringRef::iterator. +StringRef::iterator JSONParser::parseFirstElement(JSONAtom::Kind ContainerKind, + char StartChar, char EndChar, + const JSONAtom *&Element) { + assert(*Position == StartChar); + Element = 0; + nextNonWhitespace(); + if (errorIfAtEndOfFile("value or end of container at start of container")) + return StringRef::iterator(); + + if (*Position == EndChar) + return StringRef::iterator(); + + Element = parseElement(ContainerKind); + if (Element == 0) + return StringRef::iterator(); + + return Position; +} + +/// \brief Parses the next element of a JSON array or object, or closes the +/// array. +/// +/// The method assumes that the current position is before the ',' which +/// separates the next element from the current element. When successful, it +/// returns the new position after parsing the element. Otherwise, if there is +/// no next value, it returns a default constructed StringRef::iterator. +StringRef::iterator JSONParser::parseNextElement(JSONAtom::Kind ContainerKind, + char EndChar, + const JSONAtom *&Element) { + Element = 0; + nextNonWhitespace(); + if (errorIfAtEndOfFile("',' or end of container for next element")) + return 0; + + if (*Position == ',') { + nextNonWhitespace(); + if (errorIfAtEndOfFile("element in container")) + return StringRef::iterator(); + + Element = parseElement(ContainerKind); + if (Element == 0) + return StringRef::iterator(); + + return Position; + } else if (*Position == EndChar) { + return StringRef::iterator(); + } else { + setExpectedError("',' or end of container for next element", *Position); + return StringRef::iterator(); + } +} + +const JSONAtom *JSONParser::parseElement(JSONAtom::Kind ContainerKind) { + switch (ContainerKind) { + case JSONAtom::JK_Array: + return parseValue(); + case JSONAtom::JK_Object: + return parseKeyValuePair(); + default: + llvm_unreachable("Impossible code path"); + } +} + +bool JSONParser::skipContainer(const JSONContainer &Container) { + for (JSONContainer::AtomIterator I = Container.atom_current(), + E = Container.atom_end(); + I != E; ++I) { + assert(*I != 0); + if (!skip(**I)) + return false; + } + return !failed(); +} diff --git a/lib/Support/LLVMBuild.txt b/lib/Support/LLVMBuild.txt new file mode 100644 index 000000000000..5b88be0203e5 --- /dev/null +++ b/lib/Support/LLVMBuild.txt @@ -0,0 +1,21 @@ +;===- ./lib/Support/LLVMBuild.txt ------------------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = Support +parent = Libraries diff --git a/lib/Support/LockFileManager.cpp b/lib/Support/LockFileManager.cpp new file mode 100644 index 000000000000..64404a1a8e77 --- /dev/null +++ b/lib/Support/LockFileManager.cpp @@ -0,0 +1,216 @@ +//===--- LockFileManager.cpp - File-level Locking Utility------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "llvm/Support/LockFileManager.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" +#include <fstream> +#include <sys/types.h> +#include <sys/stat.h> +#if LLVM_ON_WIN32 +#include <windows.h> +#endif +#if LLVM_ON_UNIX +#include <unistd.h> +#endif +using namespace llvm; + +/// \brief Attempt to read the lock file with the given name, if it exists. +/// +/// \param LockFileName The name of the lock file to read. +/// +/// \returns The process ID of the process that owns this lock file +Optional<std::pair<std::string, int> > +LockFileManager::readLockFile(StringRef LockFileName) { + // Check whether the lock file exists. If not, clearly there's nothing + // to read, so we just return. + bool Exists = false; + if (sys::fs::exists(LockFileName, Exists) || !Exists) + return Optional<std::pair<std::string, int> >(); + + // Read the owning host and PID out of the lock file. If it appears that the + // owning process is dead, the lock file is invalid. + int PID = 0; + std::string Hostname; + std::ifstream Input(LockFileName.str().c_str()); + if (Input >> Hostname >> PID && PID > 0 && + processStillExecuting(Hostname, PID)) + return std::make_pair(Hostname, PID); + + // Delete the lock file. It's invalid anyway. + bool Existed; + sys::fs::remove(LockFileName, Existed); + return Optional<std::pair<std::string, int> >(); +} + +bool LockFileManager::processStillExecuting(StringRef Hostname, int PID) { +#if LLVM_ON_UNIX + char MyHostname[256]; + MyHostname[255] = 0; + MyHostname[0] = 0; + gethostname(MyHostname, 255); + // Check whether the process is dead. If so, we're done. + if (MyHostname == Hostname && getsid(PID) == -1 && errno == ESRCH) + return false; +#endif + + return true; +} + +LockFileManager::LockFileManager(StringRef FileName) +{ + LockFileName = FileName; + LockFileName += ".lock"; + + // If the lock file already exists, don't bother to try to create our own + // lock file; it won't work anyway. Just figure out who owns this lock file. + if ((Owner = readLockFile(LockFileName))) + return; + + // Create a lock file that is unique to this instance. + UniqueLockFileName = LockFileName; + UniqueLockFileName += "-%%%%%%%%"; + int UniqueLockFileID; + if (error_code EC + = sys::fs::unique_file(UniqueLockFileName.str(), + UniqueLockFileID, + UniqueLockFileName, + /*makeAbsolute=*/false)) { + Error = EC; + return; + } + + // Write our process ID to our unique lock file. + { + raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true); + +#if LLVM_ON_UNIX + // FIXME: move getpid() call into LLVM + char hostname[256]; + hostname[255] = 0; + hostname[0] = 0; + gethostname(hostname, 255); + Out << hostname << ' ' << getpid(); +#else + Out << "localhost 1"; +#endif + Out.close(); + + if (Out.has_error()) { + // We failed to write out PID, so make up an excuse, remove the + // unique lock file, and fail. + Error = make_error_code(errc::no_space_on_device); + bool Existed; + sys::fs::remove(UniqueLockFileName.c_str(), Existed); + return; + } + } + + // Create a hard link from the lock file name. If this succeeds, we're done. + error_code EC + = sys::fs::create_hard_link(UniqueLockFileName.str(), + LockFileName.str()); + if (EC == errc::success) + return; + + // Creating the hard link failed. + +#ifdef LLVM_ON_UNIX + // The creation of the hard link may appear to fail, but if stat'ing the + // unique file returns a link count of 2, then we can still declare success. + struct stat StatBuf; + if (stat(UniqueLockFileName.c_str(), &StatBuf) == 0 && + StatBuf.st_nlink == 2) + return; +#endif + + // Someone else managed to create the lock file first. Wipe out our unique + // lock file (it's useless now) and read the process ID from the lock file. + bool Existed; + sys::fs::remove(UniqueLockFileName.str(), Existed); + if ((Owner = readLockFile(LockFileName))) + return; + + // There is a lock file that nobody owns; try to clean it up and report + // an error. + sys::fs::remove(LockFileName.str(), Existed); + Error = EC; +} + +LockFileManager::LockFileState LockFileManager::getState() const { + if (Owner) + return LFS_Shared; + + if (Error) + return LFS_Error; + + return LFS_Owned; +} + +LockFileManager::~LockFileManager() { + if (getState() != LFS_Owned) + return; + + // Since we own the lock, remove the lock file and our own unique lock file. + bool Existed; + sys::fs::remove(LockFileName.str(), Existed); + sys::fs::remove(UniqueLockFileName.str(), Existed); +} + +void LockFileManager::waitForUnlock() { + if (getState() != LFS_Shared) + return; + +#if LLVM_ON_WIN32 + unsigned long Interval = 1; +#else + struct timespec Interval; + Interval.tv_sec = 0; + Interval.tv_nsec = 1000000; +#endif + // Don't wait more than an hour for the file to appear. + const unsigned MaxSeconds = 3600; + do { + // Sleep for the designated interval, to allow the owning process time to + // 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 + Sleep(Interval); +#else + nanosleep(&Interval, NULL); +#endif + // If the file no longer exists, we're done. + bool Exists = false; + if (!sys::fs::exists(LockFileName.str(), Exists) && !Exists) + return; + + if (!processStillExecuting((*Owner).first, (*Owner).second)) + return; + + // Exponentially increase the time we wait for the lock to be removed. +#if LLVM_ON_WIN32 + Interval *= 2; +#else + Interval.tv_sec *= 2; + Interval.tv_nsec *= 2; + if (Interval.tv_nsec >= 1000000000) { + ++Interval.tv_sec; + Interval.tv_nsec -= 1000000000; + } +#endif + } while ( +#if LLVM_ON_WIN32 + Interval < MaxSeconds * 1000 +#else + Interval.tv_sec < (time_t)MaxSeconds +#endif + ); + + // Give up. +} diff --git a/lib/Support/ManagedStatic.cpp b/lib/Support/ManagedStatic.cpp index c767c15e71c9..098cccb68df5 100644 --- a/lib/Support/ManagedStatic.cpp +++ b/lib/Support/ManagedStatic.cpp @@ -27,8 +27,15 @@ void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(), if (Ptr == 0) { void* tmp = Creator ? Creator() : 0; + TsanHappensBefore(this); sys::MemoryFence(); + + // This write is racy against the first read in the ManagedStatic + // accessors. The race is benign because it does a second read after a + // memory fence, at which point it isn't possible to get a partial value. + TsanIgnoreWritesBegin(); Ptr = tmp; + TsanIgnoreWritesEnd(); DeleterFn = Deleter; // Add to list of managed statics. @@ -72,4 +79,3 @@ void llvm::llvm_shutdown() { if (llvm_is_multithreaded()) llvm_stop_multithreaded(); } - diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp index 0771af5fee07..16e5c7a9f72b 100644 --- a/lib/Support/MemoryBuffer.cpp +++ b/lib/Support/MemoryBuffer.cpp @@ -14,6 +14,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Config/config.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Errno.h" #include "llvm/Support/Path.h" @@ -29,15 +30,12 @@ #include <sys/stat.h> #if !defined(_MSC_VER) && !defined(__MINGW32__) #include <unistd.h> -#include <sys/uio.h> #else #include <io.h> #endif #include <fcntl.h> using namespace llvm; -namespace { const llvm::error_code success; } - //===----------------------------------------------------------------------===// // MemoryBuffer implementation itself. //===----------------------------------------------------------------------===// @@ -306,7 +304,17 @@ error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, RealMapOffset)) { result.reset(GetNamedBuffer<MemoryBufferMMapFile>( StringRef(Pages + Delta, MapSize), Filename, RequiresNullTerminator)); - return success; + + if (RequiresNullTerminator && result->getBufferEnd()[0] != '\0') { + // There could be a racing issue that resulted in the file being larger + // than the FileSize passed by the caller. We already have an assertion + // for this in MemoryBuffer::init() but have a runtime guarantee that + // the buffer will be null-terminated here, so do a copy that adds a + // null-terminator. + result.reset(MemoryBuffer::getMemBufferCopy(result->getBuffer(), + Filename)); + } + return error_code::success(); } } @@ -321,29 +329,35 @@ error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, char *BufPtr = const_cast<char*>(SB->getBufferStart()); size_t BytesLeft = MapSize; +#ifndef HAVE_PREAD if (lseek(FD, Offset, SEEK_SET) == -1) return error_code(errno, posix_category()); +#endif while (BytesLeft) { +#ifdef HAVE_PREAD + ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset); +#else ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); +#endif if (NumRead == -1) { if (errno == EINTR) continue; // Error while reading. return error_code(errno, posix_category()); - } else if (NumRead == 0) { - // We hit EOF early, truncate and terminate buffer. - Buf->BufferEnd = BufPtr; - *BufPtr = 0; - result.swap(SB); - return success; + } + if (NumRead == 0) { + assert(0 && "We got inaccurate FileSize value or fstat reported an " + "invalid file size."); + *BufPtr = '\0'; // null-terminate at the actual size. + break; } BytesLeft -= NumRead; BufPtr += NumRead; } result.swap(SB); - return success; + return error_code::success(); } //===----------------------------------------------------------------------===// @@ -372,5 +386,5 @@ error_code MemoryBuffer::getSTDIN(OwningPtr<MemoryBuffer> &result) { } while (ReadBytes != 0); result.reset(getMemBufferCopy(Buffer, "<stdin>")); - return success; + return error_code::success(); } diff --git a/lib/Support/Mutex.cpp b/lib/Support/Mutex.cpp index 8874e943f4c2..da5baab4be46 100644 --- a/lib/Support/Mutex.cpp +++ b/lib/Support/Mutex.cpp @@ -19,7 +19,7 @@ //=== independent code. //===----------------------------------------------------------------------===// -#if !defined(ENABLE_THREADS) || ENABLE_THREADS == 0 +#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0 // Define all methods as no-ops if threading is explicitly disabled namespace llvm { using namespace sys; @@ -40,109 +40,80 @@ bool MutexImpl::tryacquire() { return true; } namespace llvm { using namespace sys; - -// This variable is useful for situations where the pthread library has been -// compiled with weak linkage for its interface symbols. This allows the -// threading support to be turned off by simply not linking against -lpthread. -// In that situation, the value of pthread_mutex_init will be 0 and -// consequently pthread_enabled will be false. In such situations, all the -// pthread operations become no-ops and the functions all return false. If -// pthread_mutex_init does have an address, then mutex support is enabled. -// Note: all LLVM tools will link against -lpthread if its available since it -// is configured into the LIBS variable. -// Note: this line of code generates a warning if pthread_mutex_init is not -// declared with weak linkage. It's safe to ignore the warning. -static const bool pthread_enabled = true; - // Construct a Mutex using pthread calls MutexImpl::MutexImpl( bool recursive) : data_(0) { - if (pthread_enabled) - { - // Declare the pthread_mutex data structures - pthread_mutex_t* mutex = - static_cast<pthread_mutex_t*>(malloc(sizeof(pthread_mutex_t))); - pthread_mutexattr_t attr; - - // Initialize the mutex attributes - int errorcode = pthread_mutexattr_init(&attr); - assert(errorcode == 0); - - // Initialize the mutex as a recursive mutex, if requested, or normal - // otherwise. - int kind = ( recursive ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL ); - errorcode = pthread_mutexattr_settype(&attr, kind); - assert(errorcode == 0); + // Declare the pthread_mutex data structures + pthread_mutex_t* mutex = + static_cast<pthread_mutex_t*>(malloc(sizeof(pthread_mutex_t))); + pthread_mutexattr_t attr; + + // Initialize the mutex attributes + int errorcode = pthread_mutexattr_init(&attr); + assert(errorcode == 0); (void)errorcode; + + // Initialize the mutex as a recursive mutex, if requested, or normal + // otherwise. + int kind = ( recursive ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL ); + errorcode = pthread_mutexattr_settype(&attr, kind); + assert(errorcode == 0); #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) - // Make it a process local mutex - errorcode = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); - assert(errorcode == 0); + // Make it a process local mutex + errorcode = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); + assert(errorcode == 0); #endif - // Initialize the mutex - errorcode = pthread_mutex_init(mutex, &attr); - assert(errorcode == 0); + // Initialize the mutex + errorcode = pthread_mutex_init(mutex, &attr); + assert(errorcode == 0); - // Destroy the attributes - errorcode = pthread_mutexattr_destroy(&attr); - assert(errorcode == 0); + // Destroy the attributes + errorcode = pthread_mutexattr_destroy(&attr); + assert(errorcode == 0); - // Assign the data member - data_ = mutex; - } + // Assign the data member + data_ = mutex; } // Destruct a Mutex MutexImpl::~MutexImpl() { - if (pthread_enabled) - { - pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_); - assert(mutex != 0); - pthread_mutex_destroy(mutex); - free(mutex); - } + pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_); + assert(mutex != 0); + pthread_mutex_destroy(mutex); + free(mutex); } bool MutexImpl::acquire() { - if (pthread_enabled) - { - pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_); - assert(mutex != 0); - - int errorcode = pthread_mutex_lock(mutex); - return errorcode == 0; - } else return false; + pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_); + assert(mutex != 0); + + int errorcode = pthread_mutex_lock(mutex); + return errorcode == 0; } bool MutexImpl::release() { - if (pthread_enabled) - { - pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_); - assert(mutex != 0); - - int errorcode = pthread_mutex_unlock(mutex); - return errorcode == 0; - } else return false; + pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_); + assert(mutex != 0); + + int errorcode = pthread_mutex_unlock(mutex); + return errorcode == 0; } bool MutexImpl::tryacquire() { - if (pthread_enabled) - { - pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_); - assert(mutex != 0); - - int errorcode = pthread_mutex_trylock(mutex); - return errorcode == 0; - } else return false; + pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_); + assert(mutex != 0); + + int errorcode = pthread_mutex_trylock(mutex); + return errorcode == 0; } } diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp index e5b7cd3bfbc2..dcddeda977d1 100644 --- a/lib/Support/Path.cpp +++ b/lib/Support/Path.cpp @@ -38,16 +38,6 @@ bool Path::operator<(const Path& that) const { return path < that.path; } -Path -Path::GetLLVMConfigDir() { - Path result; -#ifdef LLVM_ETCDIR - if (result.set(LLVM_ETCDIR)) - return result; -#endif - return GetLLVMDefaultConfigDir(); -} - LLVMFileType sys::IdentifyFileType(const char *magic, unsigned length) { assert(magic && "Invalid magic number string"); @@ -100,7 +90,7 @@ sys::IdentifyFileType(const char *magic, unsigned length) { case 0xCF: { uint16_t type = 0; if (magic[0] == char(0xFE) && magic[1] == char(0xED) && - magic[2] == char(0xFA) && + magic[2] == char(0xFA) && (magic[3] == char(0xCE) || magic[3] == char(0xCF))) { /* Native endian */ if (length >= 16) type = magic[14] << 8 | magic[15]; @@ -162,31 +152,31 @@ sys::IdentifyFileType(const char *magic, unsigned length) { bool Path::isArchive() const { - LLVMFileType type; + fs::file_magic type; if (fs::identify_magic(str(), type)) return false; - return type == Archive_FileType; + return type == fs::file_magic::archive; } bool Path::isDynamicLibrary() const { - LLVMFileType type; + fs::file_magic type; if (fs::identify_magic(str(), type)) return false; switch (type) { default: return false; - case Mach_O_FixedVirtualMemorySharedLib_FileType: - case Mach_O_DynamicallyLinkedSharedLib_FileType: - case Mach_O_DynamicallyLinkedSharedLibStub_FileType: - case ELF_SharedObject_FileType: - case COFF_FileType: return true; + case fs::file_magic::macho_fixed_virtual_memory_shared_lib: + case fs::file_magic::macho_dynamically_linked_shared_lib: + case fs::file_magic::macho_dynamically_linked_shared_lib_stub: + case fs::file_magic::elf_shared_object: + case fs::file_magic::pecoff_executable: return true; } } bool Path::isObjectFile() const { - LLVMFileType type; - if (fs::identify_magic(str(), type) || type == Unknown_FileType) + fs::file_magic type; + if (fs::identify_magic(str(), type) || type == fs::file_magic::unknown) return false; return true; } @@ -222,10 +212,10 @@ Path::appendSuffix(StringRef suffix) { bool Path::isBitcodeFile() const { - LLVMFileType type; + fs::file_magic type; if (fs::identify_magic(str(), type)) return false; - return type == Bitcode_FileType; + return type == fs::file_magic::bitcode; } bool Path::hasMagicNumber(StringRef Magic) const { diff --git a/lib/Support/PathV2.cpp b/lib/Support/PathV2.cpp index bebe442e2478..e2a69a650db8 100644 --- a/lib/Support/PathV2.cpp +++ b/lib/Support/PathV2.cpp @@ -13,6 +13,7 @@ #include "llvm/Support/PathV2.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include <cctype> #include <cstdio> @@ -23,15 +24,13 @@ namespace { using llvm::sys::path::is_separator; #ifdef LLVM_ON_WIN32 - const StringRef separators = "\\/"; - const char prefered_separator = '\\'; + const char *separators = "\\/"; + const char prefered_separator = '\\'; #else - const StringRef separators = "/"; - const char prefered_separator = '/'; + const char separators = '/'; + const char prefered_separator = '/'; #endif - const llvm::error_code success; - StringRef find_first_component(StringRef path) { // Look for this first component in the following order. // * empty (in this case we return an empty string) @@ -347,7 +346,7 @@ const StringRef root_directory(StringRef path) { const StringRef relative_path(StringRef path) { StringRef root = root_path(path); - return root.substr(root.size()); + return path.substr(root.size()); } void append(SmallVectorImpl<char> &path, const Twine &a, @@ -492,7 +491,7 @@ bool is_separator(char value) { void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result) { result.clear(); - + // Check whether the temporary directory is specified by an environment // variable. const char *EnvironmentVariable; @@ -505,7 +504,7 @@ void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result) { result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); return; } - + // Fall back to a system default. const char *DefaultResult; #ifdef LLVM_ON_WIN32 @@ -519,7 +518,7 @@ void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result) { #endif result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); } - + bool has_root_name(const Twine &path) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); @@ -601,12 +600,16 @@ namespace fs { error_code make_absolute(SmallVectorImpl<char> &path) { StringRef p(path.data(), path.size()); - bool rootName = path::has_root_name(p), - rootDirectory = path::has_root_directory(p); + bool rootDirectory = path::has_root_directory(p), +#ifdef LLVM_ON_WIN32 + rootName = path::has_root_name(p); +#else + rootName = true; +#endif // Already absolute. if (rootName && rootDirectory) - return success; + return error_code::success(); // All of the following conditions will need the current directory. SmallString<128> current_dir; @@ -618,7 +621,7 @@ error_code make_absolute(SmallVectorImpl<char> &path) { path::append(current_dir, p); // Set path to the result. path.swap(current_dir); - return success; + return error_code::success(); } if (!rootName && rootDirectory) { @@ -627,7 +630,7 @@ error_code make_absolute(SmallVectorImpl<char> &path) { path::append(curDirRootName, p); // Set path to the result. path.swap(curDirRootName); - return success; + return error_code::success(); } if (rootName && !rootDirectory) { @@ -639,7 +642,7 @@ error_code make_absolute(SmallVectorImpl<char> &path) { SmallString<128> res; path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath); path.swap(res); - return success; + return error_code::success(); } llvm_unreachable("All rootName and rootDirectory combinations should have " @@ -651,12 +654,13 @@ error_code create_directories(const Twine &path, bool &existed) { StringRef p = path.toStringRef(path_storage); StringRef parent = path::parent_path(p); - bool parent_exists; + if (!parent.empty()) { + bool parent_exists; + if (error_code ec = fs::exists(parent, parent_exists)) return ec; - if (error_code ec = fs::exists(parent, parent_exists)) return ec; - - if (!parent_exists) - if (error_code ec = create_directories(parent, existed)) return ec; + if (!parent_exists) + if (error_code ec = create_directories(parent, existed)) return ec; + } return create_directory(p, existed); } @@ -678,7 +682,7 @@ error_code is_directory(const Twine &path, bool &result) { if (error_code ec = status(path, st)) return ec; result = is_directory(st); - return success; + return error_code::success(); } bool is_regular_file(file_status status) { @@ -690,7 +694,7 @@ error_code is_regular_file(const Twine &path, bool &result) { if (error_code ec = status(path, st)) return ec; result = is_regular_file(st); - return success; + return error_code::success(); } bool is_symlink(file_status status) { @@ -702,7 +706,7 @@ error_code is_symlink(const Twine &path, bool &result) { if (error_code ec = status(path, st)) return ec; result = is_symlink(st); - return success; + return error_code::success(); } bool is_other(file_status status) { @@ -729,23 +733,134 @@ error_code has_magic(const Twine &path, const Twine &magic, bool &result) { if (ec == errc::value_too_large) { // Magic.size() > file_size(Path). result = false; - return success; + return error_code::success(); } return ec; } result = Magic == Buffer; - return success; + return error_code::success(); +} + +/// @brief Identify the magic in magic. +file_magic identify_magic(StringRef magic) { + switch ((unsigned char)magic[0]) { + case 0xDE: // 0x0B17C0DE = BC wraper + if (magic[1] == (char)0xC0 && magic[2] == (char)0x17 && + magic[3] == (char)0x0B) + return file_magic::bitcode; + break; + case 'B': + if (magic[1] == 'C' && magic[2] == (char)0xC0 && magic[3] == (char)0xDE) + return file_magic::bitcode; + break; + case '!': + if (magic.size() >= 8) + if (memcmp(magic.data(),"!<arch>\n",8) == 0) + return file_magic::archive; + break; + + case '\177': + if (magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') { + if (magic.size() >= 18 && magic[17] == 0) + switch (magic[16]) { + default: break; + case 1: return file_magic::elf_relocatable; + case 2: return file_magic::elf_executable; + case 3: return file_magic::elf_shared_object; + case 4: return file_magic::elf_core; + } + } + break; + + case 0xCA: + if (magic[1] == char(0xFE) && magic[2] == char(0xBA) && + magic[3] == char(0xBE)) { + // This is complicated by an overlap with Java class files. + // See the Mach-O section in /usr/share/file/magic for details. + if (magic.size() >= 8 && magic[7] < 43) + // FIXME: Universal Binary of any type. + return file_magic::macho_dynamically_linked_shared_lib; + } + break; + + // The two magic numbers for mach-o are: + // 0xfeedface - 32-bit mach-o + // 0xfeedfacf - 64-bit mach-o + case 0xFE: + case 0xCE: + case 0xCF: { + uint16_t type = 0; + if (magic[0] == char(0xFE) && magic[1] == char(0xED) && + magic[2] == char(0xFA) && + (magic[3] == char(0xCE) || magic[3] == char(0xCF))) { + /* Native endian */ + if (magic.size() >= 16) type = magic[14] << 8 | magic[15]; + } else if ((magic[0] == char(0xCE) || magic[0] == char(0xCF)) && + magic[1] == char(0xFA) && magic[2] == char(0xED) && + magic[3] == char(0xFE)) { + /* Reverse endian */ + if (magic.size() >= 14) type = magic[13] << 8 | magic[12]; + } + switch (type) { + default: break; + case 1: return file_magic::macho_object; + case 2: return file_magic::macho_executable; + case 3: return file_magic::macho_fixed_virtual_memory_shared_lib; + case 4: return file_magic::macho_core; + case 5: return file_magic::macho_preload_executabl; + case 6: return file_magic::macho_dynamically_linked_shared_lib; + case 7: return file_magic::macho_dynamic_linker; + case 8: return file_magic::macho_bundle; + case 9: return file_magic::macho_dynamic_linker; + case 10: return file_magic::macho_dsym_companion; + } + break; + } + case 0xF0: // PowerPC Windows + case 0x83: // Alpha 32-bit + case 0x84: // Alpha 64-bit + case 0x66: // MPS R4000 Windows + case 0x50: // mc68K + case 0x4c: // 80386 Windows + if (magic[1] == 0x01) + return file_magic::coff_object; + + case 0x90: // PA-RISC Windows + case 0x68: // mc68K Windows + if (magic[1] == 0x02) + return file_magic::coff_object; + break; + + case 0x4d: // Possible MS-DOS stub on Windows PE file + if (magic[1] == 0x5a) { + uint32_t off = + *reinterpret_cast<const support::ulittle32_t*>(magic.data() + 0x3c); + // PE/COFF file, either EXE or DLL. + if (off < magic.size() && memcmp(magic.data() + off, "PE\0\0",4) == 0) + return file_magic::pecoff_executable; + } + break; + + case 0x64: // x86-64 Windows. + if (magic[1] == char(0x86)) + return file_magic::coff_object; + break; + + default: + break; + } + return file_magic::unknown; } -error_code identify_magic(const Twine &path, LLVMFileType &result) { +error_code identify_magic(const Twine &path, file_magic &result) { SmallString<32> Magic; error_code ec = get_magic(path, Magic.capacity(), Magic); if (ec && ec != errc::value_too_large) return ec; - result = IdentifyFileType(Magic.data(), Magic.size()); - return success; + result = identify_magic(Magic); + return error_code::success(); } namespace { @@ -753,7 +868,9 @@ error_code remove_all_r(StringRef path, file_type ft, uint32_t &count) { if (ft == file_type::directory_file) { // This code would be a lot better with exceptions ;/. error_code ec; - for (directory_iterator i(path, ec), e; i != e; i.increment(ec)) { + directory_iterator i(path, ec); + if (ec) return ec; + for (directory_iterator e; i != e; i.increment(ec)) { if (ec) return ec; file_status st; if (error_code ec = i->status(st)) return ec; @@ -770,7 +887,7 @@ error_code remove_all_r(StringRef path, file_type ft, uint32_t &count) { ++count; } - return success; + return error_code::success(); } } // end unnamed namespace diff --git a/lib/Support/Program.cpp b/lib/Support/Program.cpp index 01860b082d62..75bc282d9bd4 100644 --- a/lib/Support/Program.cpp +++ b/lib/Support/Program.cpp @@ -13,6 +13,7 @@ #include "llvm/Support/Program.h" #include "llvm/Config/config.h" +#include "llvm/Support/system_error.h" using namespace llvm; using namespace sys; diff --git a/lib/Support/RWMutex.cpp b/lib/Support/RWMutex.cpp index d0b1e10b56fb..6a34f2d08524 100644 --- a/lib/Support/RWMutex.cpp +++ b/lib/Support/RWMutex.cpp @@ -20,7 +20,7 @@ //=== independent code. //===----------------------------------------------------------------------===// -#if !defined(ENABLE_THREADS) || ENABLE_THREADS == 0 +#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0 // Define all methods as no-ops if threading is explicitly disabled namespace llvm { using namespace sys; @@ -42,107 +42,75 @@ bool RWMutexImpl::writer_release() { return true; } namespace llvm { using namespace sys; - -// This variable is useful for situations where the pthread library has been -// compiled with weak linkage for its interface symbols. This allows the -// threading support to be turned off by simply not linking against -lpthread. -// In that situation, the value of pthread_mutex_init will be 0 and -// consequently pthread_enabled will be false. In such situations, all the -// pthread operations become no-ops and the functions all return false. If -// pthread_rwlock_init does have an address, then rwlock support is enabled. -// Note: all LLVM tools will link against -lpthread if its available since it -// is configured into the LIBS variable. -// Note: this line of code generates a warning if pthread_rwlock_init is not -// declared with weak linkage. It's safe to ignore the warning. -static const bool pthread_enabled = true; - // Construct a RWMutex using pthread calls RWMutexImpl::RWMutexImpl() : data_(0) { - if (pthread_enabled) - { - // Declare the pthread_rwlock data structures - pthread_rwlock_t* rwlock = - static_cast<pthread_rwlock_t*>(malloc(sizeof(pthread_rwlock_t))); + // Declare the pthread_rwlock data structures + pthread_rwlock_t* rwlock = + static_cast<pthread_rwlock_t*>(malloc(sizeof(pthread_rwlock_t))); #ifdef __APPLE__ - // Workaround a bug/mis-feature in Darwin's pthread_rwlock_init. - bzero(rwlock, sizeof(pthread_rwlock_t)); + // Workaround a bug/mis-feature in Darwin's pthread_rwlock_init. + bzero(rwlock, sizeof(pthread_rwlock_t)); #endif - // Initialize the rwlock - int errorcode = pthread_rwlock_init(rwlock, NULL); - (void)errorcode; - assert(errorcode == 0); + // Initialize the rwlock + int errorcode = pthread_rwlock_init(rwlock, NULL); + (void)errorcode; + assert(errorcode == 0); - // Assign the data member - data_ = rwlock; - } + // Assign the data member + data_ = rwlock; } // Destruct a RWMutex RWMutexImpl::~RWMutexImpl() { - if (pthread_enabled) - { - pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); - assert(rwlock != 0); - pthread_rwlock_destroy(rwlock); - free(rwlock); - } + pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); + assert(rwlock != 0); + pthread_rwlock_destroy(rwlock); + free(rwlock); } bool RWMutexImpl::reader_acquire() { - if (pthread_enabled) - { - pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); - assert(rwlock != 0); - - int errorcode = pthread_rwlock_rdlock(rwlock); - return errorcode == 0; - } else return false; + pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); + assert(rwlock != 0); + + int errorcode = pthread_rwlock_rdlock(rwlock); + return errorcode == 0; } bool RWMutexImpl::reader_release() { - if (pthread_enabled) - { - pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); - assert(rwlock != 0); - - int errorcode = pthread_rwlock_unlock(rwlock); - return errorcode == 0; - } else return false; + pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); + assert(rwlock != 0); + + int errorcode = pthread_rwlock_unlock(rwlock); + return errorcode == 0; } bool RWMutexImpl::writer_acquire() { - if (pthread_enabled) - { - pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); - assert(rwlock != 0); - - int errorcode = pthread_rwlock_wrlock(rwlock); - return errorcode == 0; - } else return false; + pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); + assert(rwlock != 0); + + int errorcode = pthread_rwlock_wrlock(rwlock); + return errorcode == 0; } bool RWMutexImpl::writer_release() { - if (pthread_enabled) - { - pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); - assert(rwlock != 0); - - int errorcode = pthread_rwlock_unlock(rwlock); - return errorcode == 0; - } else return false; + pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); + assert(rwlock != 0); + + int errorcode = pthread_rwlock_unlock(rwlock); + return errorcode == 0; } } diff --git a/lib/Support/SmallPtrSet.cpp b/lib/Support/SmallPtrSet.cpp index 997ce0b74cd2..68d9c29411f0 100644 --- a/lib/Support/SmallPtrSet.cpp +++ b/lib/Support/SmallPtrSet.cpp @@ -14,6 +14,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/MathExtras.h" +#include <algorithm> #include <cstdlib> using namespace llvm; @@ -223,6 +224,56 @@ void SmallPtrSetImpl::CopyFrom(const SmallPtrSetImpl &RHS) { NumTombstones = RHS.NumTombstones; } +void SmallPtrSetImpl::swap(SmallPtrSetImpl &RHS) { + if (this == &RHS) return; + + // We can only avoid copying elements if neither set is small. + if (!this->isSmall() && !RHS.isSmall()) { + std::swap(this->CurArray, RHS.CurArray); + std::swap(this->CurArraySize, RHS.CurArraySize); + std::swap(this->NumElements, RHS.NumElements); + std::swap(this->NumTombstones, RHS.NumTombstones); + return; + } + + // FIXME: From here on we assume that both sets have the same small size. + + // If only RHS is small, copy the small elements into LHS and move the pointer + // from LHS to RHS. + if (!this->isSmall() && RHS.isSmall()) { + std::copy(RHS.SmallArray, RHS.SmallArray+RHS.CurArraySize, + this->SmallArray); + std::swap(this->NumElements, RHS.NumElements); + std::swap(this->CurArraySize, RHS.CurArraySize); + RHS.CurArray = this->CurArray; + RHS.NumTombstones = this->NumTombstones; + this->CurArray = this->SmallArray; + this->NumTombstones = 0; + return; + } + + // If only LHS is small, copy the small elements into RHS and move the pointer + // from RHS to LHS. + if (this->isSmall() && !RHS.isSmall()) { + std::copy(this->SmallArray, this->SmallArray+this->CurArraySize, + RHS.SmallArray); + std::swap(RHS.NumElements, this->NumElements); + std::swap(RHS.CurArraySize, this->CurArraySize); + this->CurArray = RHS.CurArray; + this->NumTombstones = RHS.NumTombstones; + RHS.CurArray = RHS.SmallArray; + RHS.NumTombstones = 0; + return; + } + + // Both a small, just swap the small elements. + assert(this->isSmall() && RHS.isSmall()); + assert(this->CurArraySize == RHS.CurArraySize); + std::swap_ranges(this->SmallArray, this->SmallArray+this->CurArraySize, + RHS.SmallArray); + std::swap(this->NumElements, RHS.NumElements); +} + SmallPtrSetImpl::~SmallPtrSetImpl() { if (!isSmall()) free(CurArray); diff --git a/lib/Support/SourceMgr.cpp b/lib/Support/SourceMgr.cpp index de042a9f53c8..bbe36b260b9d 100644 --- a/lib/Support/SourceMgr.cpp +++ b/lib/Support/SourceMgr.cpp @@ -140,8 +140,9 @@ void SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const { /// /// @param Type - If non-null, the kind of message (e.g., "error") which is /// prefixed to the message. -SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, const Twine &Msg, - const char *Type, bool ShowLine) const { +SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind, + const Twine &Msg, + ArrayRef<SMRange> Ranges) const { // First thing to do: find the current buffer containing the specified // location. @@ -156,33 +157,48 @@ SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, const Twine &Msg, LineStart[-1] != '\n' && LineStart[-1] != '\r') --LineStart; - std::string LineStr; - if (ShowLine) { - // Get the end of the line. - const char *LineEnd = Loc.getPointer(); - while (LineEnd != CurMB->getBufferEnd() && - LineEnd[0] != '\n' && LineEnd[0] != '\r') - ++LineEnd; - LineStr = std::string(LineStart, LineEnd); - } - - std::string PrintedMsg; - raw_string_ostream OS(PrintedMsg); - if (Type) - OS << Type << ": "; - OS << Msg; + // Get the end of the line. + const char *LineEnd = Loc.getPointer(); + while (LineEnd != CurMB->getBufferEnd() && + LineEnd[0] != '\n' && LineEnd[0] != '\r') + ++LineEnd; + std::string LineStr(LineStart, LineEnd); + // Convert any ranges to column ranges that only intersect the line of the + // location. + SmallVector<std::pair<unsigned, unsigned>, 4> ColRanges; + for (unsigned i = 0, e = Ranges.size(); i != e; ++i) { + SMRange R = Ranges[i]; + if (!R.isValid()) continue; + + // If the line doesn't contain any part of the range, then ignore it. + if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart) + continue; + + // Ignore pieces of the range that go onto other lines. + if (R.Start.getPointer() < LineStart) + R.Start = SMLoc::getFromPointer(LineStart); + if (R.End.getPointer() > LineEnd) + R.End = SMLoc::getFromPointer(LineEnd); + + // Translate from SMLoc ranges to column ranges. + ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart, + R.End.getPointer()-LineStart)); + } + return SMDiagnostic(*this, Loc, CurMB->getBufferIdentifier(), FindLineNumber(Loc, CurBuf), - Loc.getPointer()-LineStart, OS.str(), - LineStr, ShowLine); + Loc.getPointer()-LineStart, Kind, Msg.str(), + LineStr, ColRanges); } -void SourceMgr::PrintMessage(SMLoc Loc, const Twine &Msg, - const char *Type, bool ShowLine) const { +void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind, + const Twine &Msg, ArrayRef<SMRange> Ranges) const { + SMDiagnostic Diagnostic = GetMessage(Loc, Kind, Msg, Ranges); + // Report the message with the diagnostic handler if present. if (DiagHandler) { - DiagHandler(GetMessage(Loc, Msg, Type, ShowLine), DiagContext); + DiagHandler(Diagnostic, DiagContext); return; } @@ -192,14 +208,24 @@ void SourceMgr::PrintMessage(SMLoc Loc, const Twine &Msg, assert(CurBuf != -1 && "Invalid or unspecified location!"); PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS); - GetMessage(Loc, Msg, Type, ShowLine).Print(0, OS); + Diagnostic.print(0, OS); } //===----------------------------------------------------------------------===// // SMDiagnostic Implementation //===----------------------------------------------------------------------===// -void SMDiagnostic::Print(const char *ProgName, raw_ostream &S) const { +SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, const std::string &FN, + int Line, int Col, SourceMgr::DiagKind Kind, + const std::string &Msg, + const std::string &LineStr, + ArrayRef<std::pair<unsigned,unsigned> > Ranges) + : SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Kind(Kind), + Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()) { +} + + +void SMDiagnostic::print(const char *ProgName, raw_ostream &S) const { if (ProgName && ProgName[0]) S << ProgName << ": "; @@ -217,16 +243,71 @@ void SMDiagnostic::Print(const char *ProgName, raw_ostream &S) const { S << ": "; } + switch (Kind) { + case SourceMgr::DK_Error: S << "error: "; break; + case SourceMgr::DK_Warning: S << "warning: "; break; + case SourceMgr::DK_Note: S << "note: "; break; + } + S << Message << '\n'; - if (LineNo != -1 && ColumnNo != -1 && ShowLine) { - S << LineContents << '\n'; + if (LineNo == -1 || ColumnNo == -1) + return; - // Print out spaces/tabs before the caret. - for (unsigned i = 0; i != unsigned(ColumnNo); ++i) - S << (LineContents[i] == '\t' ? '\t' : ' '); - S << "^\n"; + // Build the line with the caret and ranges. + std::string CaretLine(LineContents.size()+1, ' '); + + // Expand any ranges. + for (unsigned r = 0, e = Ranges.size(); r != e; ++r) { + std::pair<unsigned, unsigned> R = Ranges[r]; + for (unsigned i = R.first, + e = std::min(R.second, (unsigned)LineContents.size())+1; i != e; ++i) + CaretLine[i] = '~'; + } + + // Finally, plop on the caret. + if (unsigned(ColumnNo) <= LineContents.size()) + CaretLine[ColumnNo] = '^'; + else + CaretLine[LineContents.size()] = '^'; + + // ... and remove trailing whitespace so the output doesn't wrap for it. We + // know that the line isn't completely empty because it has the caret in it at + // least. + CaretLine.erase(CaretLine.find_last_not_of(' ')+1); + + // Print out the source line one character at a time, so we can expand tabs. + for (unsigned i = 0, e = LineContents.size(), OutCol = 0; i != e; ++i) { + if (LineContents[i] != '\t') { + S << LineContents[i]; + ++OutCol; + continue; + } + + // If we have a tab, emit at least one space, then round up to 8 columns. + do { + S << ' '; + ++OutCol; + } while (OutCol & 7); + } + S << '\n'; + + // Print out the caret line, matching tabs in the source line. + for (unsigned i = 0, e = CaretLine.size(), OutCol = 0; i != e; ++i) { + if (i >= LineContents.size() || LineContents[i] != '\t') { + S << CaretLine[i]; + ++OutCol; + continue; + } + + // Okay, we have a tab. Insert the appropriate number of characters. + do { + S << CaretLine[i]; + ++OutCol; + } while (OutCol & 7); } + + S << '\n'; } diff --git a/lib/Support/Statistic.cpp b/lib/Support/Statistic.cpp index 1e733d92e610..d8a6ad35ba9c 100644 --- a/lib/Support/Statistic.cpp +++ b/lib/Support/Statistic.cpp @@ -24,6 +24,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Mutex.h" @@ -72,9 +73,12 @@ void Statistic::RegisterStatistic() { if (Enabled) StatInfo->addStatistic(this); + TsanHappensBefore(this); sys::MemoryFence(); // Remember we have been registered. + TsanIgnoreWritesBegin(); Initialized = true; + TsanIgnoreWritesEnd(); } } @@ -126,13 +130,11 @@ void llvm::PrintStatistics(raw_ostream &OS) { << "===" << std::string(73, '-') << "===\n\n"; // Print all of the statistics. - for (size_t i = 0, e = Stats.Stats.size(); i != e; ++i) { - std::string CountStr = utostr(Stats.Stats[i]->getValue()); - OS << std::string(MaxValLen-CountStr.size(), ' ') - << CountStr << " " << Stats.Stats[i]->getName() - << std::string(MaxNameLen-std::strlen(Stats.Stats[i]->getName()), ' ') - << " - " << Stats.Stats[i]->getDesc() << "\n"; - } + for (size_t i = 0, e = Stats.Stats.size(); i != e; ++i) + OS << format("%*u %-*s - %s\n", + MaxValLen, Stats.Stats[i]->getValue(), + MaxNameLen, Stats.Stats[i]->getName(), + Stats.Stats[i]->getDesc()); OS << '\n'; // Flush the output stream. OS.flush(); diff --git a/lib/Support/StreamableMemoryObject.cpp b/lib/Support/StreamableMemoryObject.cpp new file mode 100644 index 000000000000..c23f07b8fc3c --- /dev/null +++ b/lib/Support/StreamableMemoryObject.cpp @@ -0,0 +1,140 @@ +//===- StreamableMemoryObject.cpp - Streamable data interface -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/StreamableMemoryObject.h" +#include <cassert> +#include <cstring> + + +using namespace llvm; + +namespace { + +class RawMemoryObject : public StreamableMemoryObject { +public: + RawMemoryObject(const unsigned char *Start, const unsigned char *End) : + FirstChar(Start), LastChar(End) { + assert(LastChar > FirstChar && "Invalid start/end range"); + } + + virtual uint64_t getBase() const { return 0; } + virtual uint64_t getExtent() const { return LastChar - FirstChar; } + virtual int readByte(uint64_t address, uint8_t* ptr) const; + virtual int readBytes(uint64_t address, + uint64_t size, + uint8_t* buf, + uint64_t* copied) const; + virtual const uint8_t *getPointer(uint64_t address, uint64_t size) const; + virtual bool isValidAddress(uint64_t address) const { + return validAddress(address); + } + virtual bool isObjectEnd(uint64_t address) const {return objectEnd(address);} + +private: + const uint8_t* const FirstChar; + const uint8_t* const LastChar; + + // These are implemented as inline functions here to avoid multiple virtual + // calls per public function + bool validAddress(uint64_t address) const { + return static_cast<ptrdiff_t>(address) < LastChar - FirstChar; + } + bool objectEnd(uint64_t address) const { + return static_cast<ptrdiff_t>(address) == LastChar - FirstChar; + } + + RawMemoryObject(const RawMemoryObject&); // DO NOT IMPLEMENT + void operator=(const RawMemoryObject&); // DO NOT IMPLEMENT +}; + +int RawMemoryObject::readByte(uint64_t address, uint8_t* ptr) const { + if (!validAddress(address)) return -1; + *ptr = *((uint8_t *)(uintptr_t)(address + FirstChar)); + return 0; +} + +int RawMemoryObject::readBytes(uint64_t address, + uint64_t size, + uint8_t* buf, + uint64_t* copied) const { + if (!validAddress(address) || !validAddress(address + size - 1)) return -1; + memcpy(buf, (uint8_t *)(uintptr_t)(address + FirstChar), size); + if (copied) *copied = size; + return size; +} + +const uint8_t *RawMemoryObject::getPointer(uint64_t address, + uint64_t size) const { + return FirstChar + address; +} +} // anonymous namespace + +namespace llvm { +// If the bitcode has a header, then its size is known, and we don't have to +// block until we actually want to read it. +bool StreamingMemoryObject::isValidAddress(uint64_t address) const { + if (ObjectSize && address < ObjectSize) return true; + return fetchToPos(address); +} + +bool StreamingMemoryObject::isObjectEnd(uint64_t address) const { + if (ObjectSize) return address == ObjectSize; + fetchToPos(address); + return address == ObjectSize && address != 0; +} + +uint64_t StreamingMemoryObject::getExtent() const { + if (ObjectSize) return ObjectSize; + size_t pos = BytesRead + kChunkSize; + // keep fetching until we run out of bytes + while (fetchToPos(pos)) pos += kChunkSize; + return ObjectSize; +} + +int StreamingMemoryObject::readByte(uint64_t address, uint8_t* ptr) const { + if (!fetchToPos(address)) return -1; + *ptr = Bytes[address + BytesSkipped]; + return 0; +} + +int StreamingMemoryObject::readBytes(uint64_t address, + uint64_t size, + uint8_t* buf, + uint64_t* copied) const { + if (!fetchToPos(address + size - 1)) return -1; + memcpy(buf, &Bytes[address + BytesSkipped], size); + if (copied) *copied = size; + return 0; +} + +bool StreamingMemoryObject::dropLeadingBytes(size_t s) { + if (BytesRead < s) return true; + BytesSkipped = s; + BytesRead -= s; + return false; +} + +void StreamingMemoryObject::setKnownObjectSize(size_t size) { + ObjectSize = size; + Bytes.reserve(size); +} + +StreamableMemoryObject *getNonStreamedMemoryObject( + const unsigned char *Start, const unsigned char *End) { + return new RawMemoryObject(Start, End); +} + +StreamableMemoryObject::~StreamableMemoryObject() { } + +StreamingMemoryObject::StreamingMemoryObject(DataStreamer *streamer) : + Bytes(kChunkSize), Streamer(streamer), BytesRead(0), BytesSkipped(0), + ObjectSize(0), EOFReached(false) { + BytesRead = streamer->GetBytes(&Bytes[0], kChunkSize); +} +} diff --git a/lib/Support/StringExtras.cpp b/lib/Support/StringExtras.cpp index 49c5ac4252c8..d77ad7f55a18 100644 --- a/lib/Support/StringExtras.cpp +++ b/lib/Support/StringExtras.cpp @@ -57,24 +57,3 @@ void llvm::SplitString(StringRef Source, S = getToken(S.second, Delimiters); } } - -void llvm::StringRef::split(SmallVectorImpl<StringRef> &A, - StringRef Separators, int MaxSplit, - bool KeepEmpty) const { - StringRef rest = *this; - - // rest.data() is used to distinguish cases like "a," that splits into - // "a" + "" and "a" that splits into "a" + 0. - for (int splits = 0; - rest.data() != NULL && (MaxSplit < 0 || splits < MaxSplit); - ++splits) { - std::pair<llvm::StringRef, llvm::StringRef> p = rest.split(Separators); - - if (p.first.size() != 0 || KeepEmpty) - A.push_back(p.first); - rest = p.second; - } - // If we have a tail left, add it. - if (rest.data() != NULL && (rest.size() != 0 || KeepEmpty)) - A.push_back(rest); -} diff --git a/lib/Support/StringMap.cpp b/lib/Support/StringMap.cpp index a1ac512fa244..c131fe07f48d 100644 --- a/lib/Support/StringMap.cpp +++ b/lib/Support/StringMap.cpp @@ -39,11 +39,13 @@ void StringMapImpl::init(unsigned InitSize) { NumItems = 0; NumTombstones = 0; - TheTable = (ItemBucket*)calloc(NumBuckets+1, sizeof(ItemBucket)); - + TheTable = (StringMapEntryBase **)calloc(NumBuckets+1, + sizeof(StringMapEntryBase **) + + sizeof(unsigned)); + // Allocate one extra bucket, set it to look filled so the iterators stop at // end. - TheTable[NumBuckets].Item = (StringMapEntryBase*)2; + TheTable[NumBuckets] = (StringMapEntryBase*)2; } @@ -60,29 +62,29 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) { } unsigned FullHashValue = HashString(Name); unsigned BucketNo = FullHashValue & (HTSize-1); - + unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1); + unsigned ProbeAmt = 1; int FirstTombstone = -1; while (1) { - ItemBucket &Bucket = TheTable[BucketNo]; - StringMapEntryBase *BucketItem = Bucket.Item; + StringMapEntryBase *BucketItem = TheTable[BucketNo]; // If we found an empty bucket, this key isn't in the table yet, return it. if (BucketItem == 0) { // If we found a tombstone, we want to reuse the tombstone instead of an // empty bucket. This reduces probing. if (FirstTombstone != -1) { - TheTable[FirstTombstone].FullHashValue = FullHashValue; + HashTable[FirstTombstone] = FullHashValue; return FirstTombstone; } - Bucket.FullHashValue = FullHashValue; + HashTable[BucketNo] = FullHashValue; return BucketNo; } if (BucketItem == getTombstoneVal()) { // Skip over tombstones. However, remember the first one we see. if (FirstTombstone == -1) FirstTombstone = BucketNo; - } else if (Bucket.FullHashValue == FullHashValue) { + } else if (HashTable[BucketNo] == FullHashValue) { // If the full hash value matches, check deeply for a match. The common // 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 @@ -115,18 +117,18 @@ int StringMapImpl::FindKey(StringRef Key) const { if (HTSize == 0) return -1; // Really empty table? unsigned FullHashValue = HashString(Key); unsigned BucketNo = FullHashValue & (HTSize-1); - + unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1); + unsigned ProbeAmt = 1; while (1) { - ItemBucket &Bucket = TheTable[BucketNo]; - StringMapEntryBase *BucketItem = Bucket.Item; + StringMapEntryBase *BucketItem = TheTable[BucketNo]; // If we found an empty bucket, this key isn't in the table yet, return. if (BucketItem == 0) return -1; if (BucketItem == getTombstoneVal()) { // Ignore tombstones. - } else if (Bucket.FullHashValue == FullHashValue) { + } else if (HashTable[BucketNo] == FullHashValue) { // If the full hash value matches, check deeply for a match. The common // 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 @@ -165,8 +167,8 @@ StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) { int Bucket = FindKey(Key); if (Bucket == -1) return 0; - StringMapEntryBase *Result = TheTable[Bucket].Item; - TheTable[Bucket].Item = getTombstoneVal(); + StringMapEntryBase *Result = TheTable[Bucket]; + TheTable[Bucket] = getTombstoneVal(); --NumItems; ++NumTombstones; assert(NumItems + NumTombstones <= NumBuckets); @@ -180,6 +182,7 @@ StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) { /// the appropriate mod-of-hashtable-size. void StringMapImpl::RehashTable() { unsigned NewSize; + unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1); // If the hash table is now more than 3/4 full, or if fewer than 1/8 of // the buckets are empty (meaning that many are filled with tombstones), @@ -194,19 +197,23 @@ void StringMapImpl::RehashTable() { // Allocate one extra bucket which will always be non-empty. This allows the // iterators to stop at end. - ItemBucket *NewTableArray =(ItemBucket*)calloc(NewSize+1, sizeof(ItemBucket)); - NewTableArray[NewSize].Item = (StringMapEntryBase*)2; - + StringMapEntryBase **NewTableArray = + (StringMapEntryBase **)calloc(NewSize+1, sizeof(StringMapEntryBase *) + + sizeof(unsigned)); + unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1); + NewTableArray[NewSize] = (StringMapEntryBase*)2; + // Rehash all the items into their new buckets. Luckily :) we already have // the hash values available, so we don't have to rehash any strings. - for (ItemBucket *IB = TheTable, *E = TheTable+NumBuckets; IB != E; ++IB) { - if (IB->Item && IB->Item != getTombstoneVal()) { + for (unsigned I = 0, E = NumBuckets; I != E; ++I) { + StringMapEntryBase *Bucket = TheTable[I]; + if (Bucket && Bucket != getTombstoneVal()) { // Fast case, bucket available. - unsigned FullHash = IB->FullHashValue; + unsigned FullHash = HashTable[I]; unsigned NewBucket = FullHash & (NewSize-1); - if (NewTableArray[NewBucket].Item == 0) { - NewTableArray[FullHash & (NewSize-1)].Item = IB->Item; - NewTableArray[FullHash & (NewSize-1)].FullHashValue = FullHash; + if (NewTableArray[NewBucket] == 0) { + NewTableArray[FullHash & (NewSize-1)] = Bucket; + NewHashArray[FullHash & (NewSize-1)] = FullHash; continue; } @@ -214,11 +221,11 @@ void StringMapImpl::RehashTable() { unsigned ProbeSize = 1; do { NewBucket = (NewBucket + ProbeSize++) & (NewSize-1); - } while (NewTableArray[NewBucket].Item); + } while (NewTableArray[NewBucket]); // Finally found a slot. Fill it in. - NewTableArray[NewBucket].Item = IB->Item; - NewTableArray[NewBucket].FullHashValue = FullHash; + NewTableArray[NewBucket] = Bucket; + NewHashArray[NewBucket] = FullHash; } } diff --git a/lib/Support/StringRef.cpp b/lib/Support/StringRef.cpp index b5b4f9476026..abe570f6df4b 100644 --- a/lib/Support/StringRef.cpp +++ b/lib/Support/StringRef.cpp @@ -10,6 +10,8 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/edit_distance.h" #include <bitset> using namespace llvm; @@ -25,6 +27,12 @@ static char ascii_tolower(char x) { return x; } +static char ascii_toupper(char x) { + if (x >= 'a' && x <= 'z') + return x - 'a' + 'A'; + return x; +} + static bool ascii_isdigit(char x) { return x >= '0' && x <= '9'; } @@ -78,56 +86,29 @@ int StringRef::compare_numeric(StringRef RHS) const { unsigned StringRef::edit_distance(llvm::StringRef Other, bool AllowReplacements, unsigned MaxEditDistance) { - // The algorithm implemented below is the "classic" - // dynamic-programming algorithm for computing the Levenshtein - // distance, which is described here: - // - // http://en.wikipedia.org/wiki/Levenshtein_distance - // - // Although the algorithm is typically described using an m x n - // array, only two rows are used at a time, so this implemenation - // just keeps two separate vectors for those two rows. - size_type m = size(); - size_type n = Other.size(); - - const unsigned SmallBufferSize = 64; - unsigned SmallBuffer[SmallBufferSize]; - llvm::OwningArrayPtr<unsigned> Allocated; - unsigned *previous = SmallBuffer; - if (2*(n + 1) > SmallBufferSize) { - previous = new unsigned [2*(n+1)]; - Allocated.reset(previous); - } - unsigned *current = previous + (n + 1); - - for (unsigned i = 0; i <= n; ++i) - previous[i] = i; - - for (size_type y = 1; y <= m; ++y) { - current[0] = y; - unsigned BestThisRow = current[0]; - - for (size_type x = 1; x <= n; ++x) { - if (AllowReplacements) { - current[x] = min(previous[x-1] + ((*this)[y-1] == Other[x-1]? 0u:1u), - min(current[x-1], previous[x])+1); - } - else { - if ((*this)[y-1] == Other[x-1]) current[x] = previous[x-1]; - else current[x] = min(current[x-1], previous[x]) + 1; - } - BestThisRow = min(BestThisRow, current[x]); - } + return llvm::ComputeEditDistance( + llvm::ArrayRef<char>(data(), size()), + llvm::ArrayRef<char>(Other.data(), Other.size()), + AllowReplacements, MaxEditDistance); +} - if (MaxEditDistance && BestThisRow > MaxEditDistance) - return MaxEditDistance + 1; +//===----------------------------------------------------------------------===// +// String Operations +//===----------------------------------------------------------------------===// - unsigned *tmp = current; - current = previous; - previous = tmp; +std::string StringRef::lower() const { + std::string Result(size(), char()); + for (size_type i = 0, e = size(); i != e; ++i) { + Result[i] = ascii_tolower(Data[i]); } + return Result; +} - unsigned Result = previous[n]; +std::string StringRef::upper() const { + std::string Result(size(), char()); + for (size_type i = 0, e = size(); i != e; ++i) { + Result[i] = ascii_toupper(Data[i]); + } return Result; } @@ -144,9 +125,35 @@ size_t StringRef::find(StringRef Str, size_t From) const { size_t N = Str.size(); if (N > Length) return npos; - for (size_t e = Length - N + 1, i = min(From, e); i != e; ++i) - if (substr(i, N).equals(Str)) - return i; + + // For short haystacks or unsupported needles fall back to the naive algorithm + if (Length < 16 || N > 255 || N == 0) { + for (size_t e = Length - N + 1, i = min(From, e); i != e; ++i) + if (substr(i, N).equals(Str)) + return i; + return npos; + } + + if (From >= Length) + return npos; + + // Build the bad char heuristic table, with uint8_t to reduce cache thrashing. + uint8_t BadCharSkip[256]; + std::memset(BadCharSkip, N, 256); + for (unsigned i = 0; i != N-1; ++i) + BadCharSkip[(uint8_t)Str[i]] = N-1-i; + + unsigned Len = Length-From, Pos = From; + while (Len >= N) { + if (substr(Pos, N).equals(Str)) // See if this is the correct substring. + return Pos; + + // Otherwise skip the appropriate number of bytes. + uint8_t Skip = BadCharSkip[(uint8_t)(*this)[Pos+N-1]]; + Len -= Skip; + Pos += Skip; + } + return npos; } @@ -223,6 +230,27 @@ StringRef::size_type StringRef::find_last_of(StringRef Chars, return npos; } +void StringRef::split(SmallVectorImpl<StringRef> &A, + StringRef Separators, int MaxSplit, + bool KeepEmpty) const { + StringRef rest = *this; + + // rest.data() is used to distinguish cases like "a," that splits into + // "a" + "" and "a" that splits into "a" + 0. + for (int splits = 0; + rest.data() != NULL && (MaxSplit < 0 || splits < MaxSplit); + ++splits) { + std::pair<StringRef, StringRef> p = rest.split(Separators); + + if (KeepEmpty || p.first.size() != 0) + A.push_back(p.first); + rest = p.second; + } + // If we have a tail left, add it. + if (rest.data() != NULL && (rest.size() != 0 || KeepEmpty)) + A.push_back(rest); +} + //===----------------------------------------------------------------------===// // Helpful Algorithms //===----------------------------------------------------------------------===// @@ -257,8 +285,8 @@ static unsigned GetAutoSenseRadix(StringRef &Str) { /// GetAsUnsignedInteger - Workhorse method that converts a integer character /// sequence of radix up to 36 to an unsigned long long value. -static bool GetAsUnsignedInteger(StringRef Str, unsigned Radix, - unsigned long long &Result) { +bool llvm::getAsUnsignedInteger(StringRef Str, unsigned Radix, + unsigned long long &Result) { // Autosense radix if not specified. if (Radix == 0) Radix = GetAutoSenseRadix(Str); @@ -298,17 +326,13 @@ static bool GetAsUnsignedInteger(StringRef Str, unsigned Radix, return false; } -bool StringRef::getAsInteger(unsigned Radix, unsigned long long &Result) const { - return GetAsUnsignedInteger(*this, Radix, Result); -} - - -bool StringRef::getAsInteger(unsigned Radix, long long &Result) const { +bool llvm::getAsSignedInteger(StringRef Str, unsigned Radix, + long long &Result) { unsigned long long ULLVal; // Handle positive strings first. - if (empty() || front() != '-') { - if (GetAsUnsignedInteger(*this, Radix, ULLVal) || + if (Str.empty() || Str.front() != '-') { + if (getAsUnsignedInteger(Str, Radix, ULLVal) || // Check for value so large it overflows a signed value. (long long)ULLVal < 0) return true; @@ -317,7 +341,7 @@ bool StringRef::getAsInteger(unsigned Radix, long long &Result) const { } // Get the positive part of the value. - if (GetAsUnsignedInteger(substr(1), Radix, ULLVal) || + if (getAsUnsignedInteger(Str.substr(1), Radix, ULLVal) || // Reject values so large they'd overflow as negative signed, but allow // "-0". This negates the unsigned so that the negative isn't undefined // on signed overflow. @@ -328,24 +352,6 @@ bool StringRef::getAsInteger(unsigned Radix, long long &Result) const { return false; } -bool StringRef::getAsInteger(unsigned Radix, int &Result) const { - long long Val; - if (getAsInteger(Radix, Val) || - (int)Val != Val) - return true; - Result = Val; - return false; -} - -bool StringRef::getAsInteger(unsigned Radix, unsigned &Result) const { - unsigned long long Val; - if (getAsInteger(Radix, Val) || - (unsigned)Val != Val) - return true; - Result = Val; - return false; -} - bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const { StringRef Str = *this; @@ -420,3 +426,9 @@ bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const { return false; } + + +// Implementation of StringRef hashing. +hash_code llvm::hash_value(StringRef S) { + return hash_combine_range(S.begin(), S.end()); +} diff --git a/lib/Support/TargetRegistry.cpp b/lib/Support/TargetRegistry.cpp index 7497bfe035c6..53c8d84e7d45 100644 --- a/lib/Support/TargetRegistry.cpp +++ b/lib/Support/TargetRegistry.cpp @@ -84,7 +84,7 @@ void TargetRegistry::RegisterTarget(Target &T, } const Target *TargetRegistry::getClosestTargetForJIT(std::string &Error) { - const Target *TheTarget = lookupTarget(sys::getHostTriple(), Error); + const Target *TheTarget = lookupTarget(sys::getDefaultTargetTriple(), Error); if (TheTarget && !TheTarget->hasJIT()) { Error = "No JIT compatible target available for this host"; diff --git a/lib/Support/ThreadLocal.cpp b/lib/Support/ThreadLocal.cpp index fdb251c0a36b..08b12b658bea 100644 --- a/lib/Support/ThreadLocal.cpp +++ b/lib/Support/ThreadLocal.cpp @@ -19,7 +19,7 @@ //=== independent code. //===----------------------------------------------------------------------===// -#if !defined(ENABLE_THREADS) || ENABLE_THREADS == 0 +#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0 // Define all methods as no-ops if threading is explicitly disabled namespace llvm { using namespace sys; diff --git a/lib/Support/Threading.cpp b/lib/Support/Threading.cpp index 8f0bb93eb4d1..7483225fdfb0 100644 --- a/lib/Support/Threading.cpp +++ b/lib/Support/Threading.cpp @@ -24,7 +24,7 @@ static bool multithreaded_mode = false; static sys::Mutex* global_lock = 0; bool llvm::llvm_start_multithreaded() { -#if ENABLE_THREADS != 0 +#if LLVM_ENABLE_THREADS != 0 assert(!multithreaded_mode && "Already multithreaded!"); multithreaded_mode = true; global_lock = new sys::Mutex(true); @@ -39,7 +39,7 @@ bool llvm::llvm_start_multithreaded() { } void llvm::llvm_stop_multithreaded() { -#if ENABLE_THREADS != 0 +#if LLVM_ENABLE_THREADS != 0 assert(multithreaded_mode && "Not currently multithreaded!"); // We fence here to insure that all threaded operations are complete BEFORE we @@ -63,7 +63,7 @@ void llvm::llvm_release_global_lock() { if (multithreaded_mode) global_lock->release(); } -#if ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H) +#if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H) #include <pthread.h> struct ThreadInfo { @@ -102,7 +102,7 @@ void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, error: ::pthread_attr_destroy(&Attr); } -#elif ENABLE_THREADS!=0 && defined(LLVM_ON_WIN32) +#elif LLVM_ENABLE_THREADS!=0 && defined(LLVM_ON_WIN32) #include "Windows/Windows.h" #include <process.h> diff --git a/lib/Support/Timer.cpp b/lib/Support/Timer.cpp index a9ed5eecfa7e..598e8ad6a1a5 100644 --- a/lib/Support/Timer.cpp +++ b/lib/Support/Timer.cpp @@ -168,10 +168,8 @@ void Timer::stopTimer() { static void printVal(double Val, double Total, raw_ostream &OS) { if (Total < 1e-7) // Avoid dividing by zero. OS << " ----- "; - else { - OS << " " << format("%7.4f", Val) << " ("; - OS << format("%5.1f", Val*100/Total) << "%)"; - } + else + OS << format(" %7.4f (%5.1f%%)", Val, Val*100/Total); } void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const { @@ -186,7 +184,7 @@ void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const { OS << " "; if (Total.getMemUsed()) - OS << format("%9lld", (long long)getMemUsed()) << " "; + OS << format("%9" PRId64 " ", (int64_t)getMemUsed()); } @@ -332,11 +330,9 @@ void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { // If this is not an collection of ungrouped times, print the total time. // Ungrouped timers don't really make sense to add up. We still print the // TOTAL line to make the percentages make sense. - if (this != DefaultTimerGroup) { - OS << " Total Execution Time: "; - OS << format("%5.4f", Total.getProcessTime()) << " seconds ("; - OS << format("%5.4f", Total.getWallTime()) << " wall clock)\n"; - } + if (this != DefaultTimerGroup) + OS << format(" Total Execution Time: %5.4f seconds (%5.4f wall clock)\n", + Total.getProcessTime(), Total.getWallTime()); OS << '\n'; if (Total.getUserTime()) diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp index c61af372d79c..44a1b38d98d1 100644 --- a/lib/Support/Triple.cpp +++ b/lib/Support/Triple.cpp @@ -9,19 +9,19 @@ #include "llvm/ADT/Triple.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/ErrorHandling.h" #include <cstring> using namespace llvm; const char *Triple::getArchTypeName(ArchType Kind) { switch (Kind) { - case InvalidArch: return "<invalid>"; case UnknownArch: return "unknown"; - case alpha: return "alpha"; case arm: return "arm"; - case bfin: return "bfin"; case cellspu: return "cellspu"; + case hexagon: return "hexagon"; case mips: return "mips"; case mipsel: return "mipsel"; case mips64: return "mips64"; @@ -29,9 +29,9 @@ const char *Triple::getArchTypeName(ArchType Kind) { case msp430: return "msp430"; case ppc64: return "powerpc64"; case ppc: return "powerpc"; + case r600: return "r600"; case sparc: return "sparc"; case sparcv9: return "sparcv9"; - case systemz: return "s390x"; case tce: return "tce"; case thumb: return "thumb"; case x86: return "i386"; @@ -44,7 +44,7 @@ const char *Triple::getArchTypeName(ArchType Kind) { case amdil: return "amdil"; } - return "<invalid>"; + llvm_unreachable("Invalid ArchType!"); } const char *Triple::getArchTypePrefix(ArchType Kind) { @@ -52,13 +52,9 @@ const char *Triple::getArchTypePrefix(ArchType Kind) { default: return 0; - case alpha: return "alpha"; - case arm: case thumb: return "arm"; - case bfin: return "bfin"; - case cellspu: return "spu"; case ppc64: @@ -66,6 +62,10 @@ const char *Triple::getArchTypePrefix(ArchType Kind) { case mblaze: return "mblaze"; + case hexagon: return "hexagon"; + + case r600: return "r600"; + case sparcv9: case sparc: return "sparc"; @@ -88,9 +88,11 @@ const char *Triple::getVendorTypeName(VendorType Kind) { case Apple: return "apple"; case PC: return "pc"; case SCEI: return "scei"; + case BGP: return "bgp"; + case BGQ: return "bgq"; } - return "<invalid>"; + llvm_unreachable("Invalid VendorType!"); } const char *Triple::getOSTypeName(OSType Kind) { @@ -110,83 +112,59 @@ const char *Triple::getOSTypeName(OSType Kind) { case MinGW32: return "mingw32"; case NetBSD: return "netbsd"; case OpenBSD: return "openbsd"; - case Psp: return "psp"; case Solaris: return "solaris"; case Win32: return "win32"; case Haiku: return "haiku"; case Minix: return "minix"; case RTEMS: return "rtems"; case NativeClient: return "nacl"; + case CNK: return "cnk"; } - return "<invalid>"; + llvm_unreachable("Invalid OSType"); } const char *Triple::getEnvironmentTypeName(EnvironmentType Kind) { switch (Kind) { case UnknownEnvironment: return "unknown"; case GNU: return "gnu"; + case GNUEABIHF: return "gnueabihf"; case GNUEABI: return "gnueabi"; case EABI: return "eabi"; case MachO: return "macho"; + case ANDROIDEABI: return "androideabi"; } - return "<invalid>"; + llvm_unreachable("Invalid EnvironmentType!"); } Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { - if (Name == "alpha") - return alpha; - if (Name == "arm") - return arm; - if (Name == "bfin") - return bfin; - if (Name == "cellspu") - return cellspu; - if (Name == "mips") - return mips; - if (Name == "mipsel") - return mipsel; - if (Name == "mips64") - return mips64; - if (Name == "mips64el") - return mips64el; - if (Name == "msp430") - return msp430; - if (Name == "ppc64") - return ppc64; - if (Name == "ppc32") - return ppc; - if (Name == "ppc") - return ppc; - if (Name == "mblaze") - return mblaze; - if (Name == "sparc") - return sparc; - if (Name == "sparcv9") - return sparcv9; - if (Name == "systemz") - return systemz; - if (Name == "tce") - return tce; - if (Name == "thumb") - return thumb; - if (Name == "x86") - return x86; - if (Name == "x86-64") - return x86_64; - if (Name == "xcore") - return xcore; - if (Name == "ptx32") - return ptx32; - if (Name == "ptx64") - return ptx64; - if (Name == "le32") - return le32; - if (Name == "amdil") - return amdil; - - return UnknownArch; + return StringSwitch<Triple::ArchType>(Name) + .Case("arm", arm) + .Case("cellspu", cellspu) + .Case("mips", mips) + .Case("mipsel", mipsel) + .Case("mips64", mips64) + .Case("mips64el", mips64el) + .Case("msp430", msp430) + .Case("ppc64", ppc64) + .Case("ppc32", ppc) + .Case("ppc", ppc) + .Case("mblaze", mblaze) + .Case("r600", r600) + .Case("hexagon", hexagon) + .Case("sparc", sparc) + .Case("sparcv9", sparcv9) + .Case("tce", tce) + .Case("thumb", thumb) + .Case("x86", x86) + .Case("x86-64", x86_64) + .Case("xcore", xcore) + .Case("ptx32", ptx32) + .Case("ptx64", ptx64) + .Case("le32", le32) + .Case("amdil", amdil) + .Default(UnknownArch); } Triple::ArchType Triple::getArchTypeForDarwinArchName(StringRef Str) { @@ -202,36 +180,22 @@ Triple::ArchType Triple::getArchTypeForDarwinArchName(StringRef Str) { // This code must be kept in sync with Clang's Darwin specific argument // translation. - if (Str == "ppc" || Str == "ppc601" || Str == "ppc603" || Str == "ppc604" || - Str == "ppc604e" || Str == "ppc750" || Str == "ppc7400" || - Str == "ppc7450" || Str == "ppc970") - return Triple::ppc; - - if (Str == "ppc64") - return Triple::ppc64; - - if (Str == "i386" || Str == "i486" || Str == "i486SX" || Str == "pentium" || - Str == "i586" || Str == "pentpro" || Str == "i686" || Str == "pentIIm3" || - Str == "pentIIm5" || Str == "pentium4") - return Triple::x86; - - if (Str == "x86_64") - return Triple::x86_64; - - // This is derived from the driver driver. - if (Str == "arm" || Str == "armv4t" || Str == "armv5" || Str == "xscale" || - Str == "armv6" || Str == "armv7" || Str == "armv7f" || Str == "armv7k" || - Str == "armv7s") - return Triple::arm; - - if (Str == "ptx32") - return Triple::ptx32; - if (Str == "ptx64") - return Triple::ptx64; - if (Str == "amdil") - return Triple::amdil; - - return Triple::UnknownArch; + return StringSwitch<ArchType>(Str) + .Cases("ppc", "ppc601", "ppc603", "ppc604", "ppc604e", Triple::ppc) + .Cases("ppc750", "ppc7400", "ppc7450", "ppc970", Triple::ppc) + .Case("ppc64", Triple::ppc64) + .Cases("i386", "i486", "i486SX", "i586", "i686", Triple::x86) + .Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4", + Triple::x86) + .Case("x86_64", Triple::x86_64) + // This is derived from the driver driver. + .Cases("arm", "armv4t", "armv5", "armv6", Triple::arm) + .Cases("armv7", "armv7f", "armv7k", "armv7s", "xscale", Triple::arm) + .Case("r600", Triple::r600) + .Case("ptx32", Triple::ptx32) + .Case("ptx64", Triple::ptx64) + .Case("amdil", Triple::amdil) + .Default(Triple::UnknownArch); } // Returns architecture name that is understood by the target assembler. @@ -239,188 +203,150 @@ const char *Triple::getArchNameForAssembler() { if (!isOSDarwin() && getVendor() != Triple::Apple) return NULL; - StringRef Str = getArchName(); - if (Str == "i386") - return "i386"; - if (Str == "x86_64") - return "x86_64"; - if (Str == "powerpc") - return "ppc"; - if (Str == "powerpc64") - return "ppc64"; - if (Str == "mblaze" || Str == "microblaze") - return "mblaze"; - if (Str == "arm") - return "arm"; - if (Str == "armv4t" || Str == "thumbv4t") - return "armv4t"; - if (Str == "armv5" || Str == "armv5e" || Str == "thumbv5" - || Str == "thumbv5e") - return "armv5"; - if (Str == "armv6" || Str == "thumbv6") - return "armv6"; - if (Str == "armv7" || Str == "thumbv7") - return "armv7"; - if (Str == "ptx32") - return "ptx32"; - if (Str == "ptx64") - return "ptx64"; - if (Str == "le32") - return "le32"; - if (Str == "amdil") - return "amdil"; - return NULL; + return StringSwitch<const char*>(getArchName()) + .Case("i386", "i386") + .Case("x86_64", "x86_64") + .Case("powerpc", "ppc") + .Case("powerpc64", "ppc64") + .Cases("mblaze", "microblaze", "mblaze") + .Case("arm", "arm") + .Cases("armv4t", "thumbv4t", "armv4t") + .Cases("armv5", "armv5e", "thumbv5", "thumbv5e", "armv5") + .Cases("armv6", "thumbv6", "armv6") + .Cases("armv7", "thumbv7", "armv7") + .Case("r600", "r600") + .Case("ptx32", "ptx32") + .Case("ptx64", "ptx64") + .Case("le32", "le32") + .Case("amdil", "amdil") + .Default(NULL); } -// +static Triple::ArchType parseArch(StringRef ArchName) { + return StringSwitch<Triple::ArchType>(ArchName) + .Cases("i386", "i486", "i586", "i686", Triple::x86) + // FIXME: Do we need to support these? + .Cases("i786", "i886", "i986", Triple::x86) + .Cases("amd64", "x86_64", Triple::x86_64) + .Case("powerpc", Triple::ppc) + .Cases("powerpc64", "ppu", Triple::ppc64) + .Case("mblaze", Triple::mblaze) + .Cases("arm", "xscale", Triple::arm) + // FIXME: It would be good to replace these with explicit names for all the + // various suffixes supported. + .StartsWith("armv", Triple::arm) + .Case("thumb", Triple::thumb) + .StartsWith("thumbv", Triple::thumb) + .Cases("spu", "cellspu", Triple::cellspu) + .Case("msp430", Triple::msp430) + .Cases("mips", "mipseb", "mipsallegrex", Triple::mips) + .Cases("mipsel", "mipsallegrexel", Triple::mipsel) + .Cases("mips64", "mips64eb", Triple::mips64) + .Case("mips64el", Triple::mips64el) + .Case("r600", Triple::r600) + .Case("hexagon", Triple::hexagon) + .Case("sparc", Triple::sparc) + .Case("sparcv9", Triple::sparcv9) + .Case("tce", Triple::tce) + .Case("xcore", Triple::xcore) + .Case("ptx32", Triple::ptx32) + .Case("ptx64", Triple::ptx64) + .Case("le32", Triple::le32) + .Case("amdil", Triple::amdil) + .Default(Triple::UnknownArch); +} -Triple::ArchType Triple::ParseArch(StringRef ArchName) { - if (ArchName.size() == 4 && ArchName[0] == 'i' && - ArchName[2] == '8' && ArchName[3] == '6' && - ArchName[1] - '3' < 6) // i[3-9]86 - return x86; - else if (ArchName == "amd64" || ArchName == "x86_64") - return x86_64; - else if (ArchName == "bfin") - return bfin; - else if (ArchName == "powerpc") - return ppc; - else if ((ArchName == "powerpc64") || (ArchName == "ppu")) - return ppc64; - else if (ArchName == "mblaze") - return mblaze; - else if (ArchName == "arm" || - ArchName.startswith("armv") || - ArchName == "xscale") - return arm; - else if (ArchName == "thumb" || - ArchName.startswith("thumbv")) - return thumb; - else if (ArchName.startswith("alpha")) - return alpha; - else if (ArchName == "spu" || ArchName == "cellspu") - return cellspu; - else if (ArchName == "msp430") - return msp430; - else if (ArchName == "mips" || ArchName == "mipseb" || - ArchName == "mipsallegrex") - return mips; - else if (ArchName == "mipsel" || ArchName == "mipsallegrexel" || - ArchName == "psp") - return mipsel; - else if (ArchName == "mips64" || ArchName == "mips64eb") - return mips64; - else if (ArchName == "mips64el") - return mips64el; - else if (ArchName == "sparc") - return sparc; - else if (ArchName == "sparcv9") - return sparcv9; - else if (ArchName == "s390x") - return systemz; - else if (ArchName == "tce") - return tce; - else if (ArchName == "xcore") - return xcore; - else if (ArchName == "ptx32") - return ptx32; - else if (ArchName == "ptx64") - return ptx64; - else if (ArchName == "le32") - return le32; - else if (ArchName == "amdil") - return amdil; - else - return UnknownArch; +static Triple::VendorType parseVendor(StringRef VendorName) { + return StringSwitch<Triple::VendorType>(VendorName) + .Case("apple", Triple::Apple) + .Case("pc", Triple::PC) + .Case("scei", Triple::SCEI) + .Case("bgp", Triple::BGP) + .Case("bgq", Triple::BGQ) + .Default(Triple::UnknownVendor); } -Triple::VendorType Triple::ParseVendor(StringRef VendorName) { - if (VendorName == "apple") - return Apple; - else if (VendorName == "pc") - return PC; - else if (VendorName == "scei") - return SCEI; - else - return UnknownVendor; -} - -Triple::OSType Triple::ParseOS(StringRef OSName) { - if (OSName.startswith("auroraux")) - return AuroraUX; - else if (OSName.startswith("cygwin")) - return Cygwin; - else if (OSName.startswith("darwin")) - return Darwin; - else if (OSName.startswith("dragonfly")) - return DragonFly; - else if (OSName.startswith("freebsd")) - return FreeBSD; - else if (OSName.startswith("ios")) - return IOS; - else if (OSName.startswith("kfreebsd")) - return KFreeBSD; - else if (OSName.startswith("linux")) - return Linux; - else if (OSName.startswith("lv2")) - return Lv2; - else if (OSName.startswith("macosx")) - return MacOSX; - else if (OSName.startswith("mingw32")) - return MinGW32; - else if (OSName.startswith("netbsd")) - return NetBSD; - else if (OSName.startswith("openbsd")) - return OpenBSD; - else if (OSName.startswith("psp")) - return Psp; - else if (OSName.startswith("solaris")) - return Solaris; - else if (OSName.startswith("win32")) - return Win32; - else if (OSName.startswith("haiku")) - return Haiku; - else if (OSName.startswith("minix")) - return Minix; - else if (OSName.startswith("rtems")) - return RTEMS; - else if (OSName.startswith("nacl")) - return NativeClient; - else - return UnknownOS; -} - -Triple::EnvironmentType Triple::ParseEnvironment(StringRef EnvironmentName) { - if (EnvironmentName.startswith("eabi")) - return EABI; - else if (EnvironmentName.startswith("gnueabi")) - return GNUEABI; - else if (EnvironmentName.startswith("gnu")) - return GNU; - else if (EnvironmentName.startswith("macho")) - return MachO; - else - return UnknownEnvironment; +static Triple::OSType parseOS(StringRef OSName) { + return StringSwitch<Triple::OSType>(OSName) + .StartsWith("auroraux", Triple::AuroraUX) + .StartsWith("cygwin", Triple::Cygwin) + .StartsWith("darwin", Triple::Darwin) + .StartsWith("dragonfly", Triple::DragonFly) + .StartsWith("freebsd", Triple::FreeBSD) + .StartsWith("ios", Triple::IOS) + .StartsWith("kfreebsd", Triple::KFreeBSD) + .StartsWith("linux", Triple::Linux) + .StartsWith("lv2", Triple::Lv2) + .StartsWith("macosx", Triple::MacOSX) + .StartsWith("mingw32", Triple::MinGW32) + .StartsWith("netbsd", Triple::NetBSD) + .StartsWith("openbsd", Triple::OpenBSD) + .StartsWith("solaris", Triple::Solaris) + .StartsWith("win32", Triple::Win32) + .StartsWith("haiku", Triple::Haiku) + .StartsWith("minix", Triple::Minix) + .StartsWith("rtems", Triple::RTEMS) + .StartsWith("nacl", Triple::NativeClient) + .StartsWith("cnk", Triple::CNK) + .Default(Triple::UnknownOS); } -void Triple::Parse() const { - assert(!isInitialized() && "Invalid parse call."); +static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { + return StringSwitch<Triple::EnvironmentType>(EnvironmentName) + .StartsWith("eabi", Triple::EABI) + .StartsWith("gnueabihf", Triple::GNUEABIHF) + .StartsWith("gnueabi", Triple::GNUEABI) + .StartsWith("gnu", Triple::GNU) + .StartsWith("macho", Triple::MachO) + .StartsWith("androideabi", Triple::ANDROIDEABI) + .Default(Triple::UnknownEnvironment); +} - Arch = ParseArch(getArchName()); - Vendor = ParseVendor(getVendorName()); - OS = ParseOS(getOSName()); - Environment = ParseEnvironment(getEnvironmentName()); +/// \brief Construct a triple from the string representation provided. +/// +/// This stores the string representation and parses the various pieces into +/// enum members. +Triple::Triple(const Twine &Str) + : Data(Str.str()), + Arch(parseArch(getArchName())), + Vendor(parseVendor(getVendorName())), + OS(parseOS(getOSName())), + Environment(parseEnvironment(getEnvironmentName())) { +} - assert(isInitialized() && "Failed to initialize!"); +/// \brief Construct a triple from string representations of the architecture, +/// vendor, and OS. +/// +/// This joins each argument into a canonical string representation and parses +/// them into enum members. It leaves the environment unknown and omits it from +/// the string representation. +Triple::Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr) + : Data((ArchStr + Twine('-') + VendorStr + Twine('-') + OSStr).str()), + Arch(parseArch(ArchStr.str())), + Vendor(parseVendor(VendorStr.str())), + OS(parseOS(OSStr.str())), + Environment() { +} + +/// \brief Construct a triple from string representations of the architecture, +/// vendor, OS, and environment. +/// +/// This joins each argument into a canonical string representation and parses +/// them into enum members. +Triple::Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr, + const Twine &EnvironmentStr) + : Data((ArchStr + Twine('-') + VendorStr + Twine('-') + OSStr + Twine('-') + + EnvironmentStr).str()), + Arch(parseArch(ArchStr.str())), + Vendor(parseVendor(VendorStr.str())), + OS(parseOS(OSStr.str())), + Environment(parseEnvironment(EnvironmentStr.str())) { } std::string Triple::normalize(StringRef Str) { // Parse into components. SmallVector<StringRef, 4> Components; - for (size_t First = 0, Last = 0; Last != StringRef::npos; First = Last + 1) { - Last = Str.find('-', First); - Components.push_back(Str.slice(First, Last)); - } + Str.split(Components, "-"); // If the first component corresponds to a known architecture, preferentially // use it for the architecture. If the second component corresponds to a @@ -429,16 +355,16 @@ std::string Triple::normalize(StringRef Str) { // valid os. ArchType Arch = UnknownArch; if (Components.size() > 0) - Arch = ParseArch(Components[0]); + Arch = parseArch(Components[0]); VendorType Vendor = UnknownVendor; if (Components.size() > 1) - Vendor = ParseVendor(Components[1]); + Vendor = parseVendor(Components[1]); OSType OS = UnknownOS; if (Components.size() > 2) - OS = ParseOS(Components[2]); + OS = parseOS(Components[2]); EnvironmentType Environment = UnknownEnvironment; if (Components.size() > 3) - Environment = ParseEnvironment(Components[3]); + Environment = parseEnvironment(Components[3]); // Note which components are already in their final position. These will not // be moved. @@ -464,22 +390,21 @@ std::string Triple::normalize(StringRef Str) { bool Valid = false; StringRef Comp = Components[Idx]; switch (Pos) { - default: - assert(false && "unexpected component type!"); + default: llvm_unreachable("unexpected component type!"); case 0: - Arch = ParseArch(Comp); + Arch = parseArch(Comp); Valid = Arch != UnknownArch; break; case 1: - Vendor = ParseVendor(Comp); + Vendor = parseVendor(Comp); Valid = Vendor != UnknownVendor; break; case 2: - OS = ParseOS(Comp); + OS = parseOS(Comp); Valid = OS != UnknownOS; break; case 3: - Environment = ParseEnvironment(Comp); + Environment = parseEnvironment(Comp); Valid = Environment != UnknownEnvironment; break; } @@ -500,7 +425,8 @@ std::string Triple::normalize(StringRef Str) { // components to the right. for (unsigned i = Pos; !CurrentComponent.empty(); ++i) { // Skip over any fixed components. - while (i < array_lengthof(Found) && Found[i]) ++i; + while (i < array_lengthof(Found) && Found[i]) + ++i; // Place the component at the new position, getting the component // that was at this position - it will be moved right. std::swap(CurrentComponent, Components[i]); @@ -528,7 +454,8 @@ std::string Triple::normalize(StringRef Str) { Components.push_back(CurrentComponent); // Advance Idx to the component's new position. - while (++Idx < array_lengthof(Found) && Found[Idx]) {} + while (++Idx < array_lengthof(Found) && Found[Idx]) + ; } while (Idx < Pos); // Add more until the final position is reached. } assert(Pos < Components.size() && Components[Pos] == Comp && @@ -618,9 +545,47 @@ void Triple::getOSVersion(unsigned &Major, unsigned &Minor, } } +bool Triple::getMacOSXVersion(unsigned &Major, unsigned &Minor, + unsigned &Micro) const { + getOSVersion(Major, Minor, Micro); + + switch (getOS()) { + default: llvm_unreachable("unexpected OS for Darwin triple"); + case Darwin: + // Default to darwin8, i.e., MacOSX 10.4. + if (Major == 0) + Major = 8; + // Darwin version numbers are skewed from OS X versions. + if (Major < 4) + return false; + Micro = 0; + Minor = Major - 4; + Major = 10; + break; + case MacOSX: + // Default to 10.4. + if (Major == 0) { + Major = 10; + Minor = 4; + } + if (Major != 10) + return false; + break; + case IOS: + // Ignore the version from the triple. This is only handled because the + // the clang driver combines OS X and IOS support into a common Darwin + // toolchain that wants to know the OS X version number even when targeting + // IOS. + Major = 10; + Minor = 4; + Micro = 0; + break; + } + return true; +} + void Triple::setTriple(const Twine &Str) { - Data = Str.str(); - Arch = InvalidArch; + *this = Triple(Str); } void Triple::setArch(ArchType Kind) { @@ -670,3 +635,126 @@ void Triple::setEnvironmentName(StringRef Str) { void Triple::setOSAndEnvironmentName(StringRef Str) { setTriple(getArchName() + "-" + getVendorName() + "-" + Str); } + +static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { + switch (Arch) { + case llvm::Triple::UnknownArch: + return 0; + + case llvm::Triple::msp430: + return 16; + + case llvm::Triple::amdil: + case llvm::Triple::arm: + case llvm::Triple::cellspu: + case llvm::Triple::hexagon: + case llvm::Triple::le32: + case llvm::Triple::mblaze: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::ppc: + case llvm::Triple::ptx32: + case llvm::Triple::r600: + case llvm::Triple::sparc: + case llvm::Triple::tce: + case llvm::Triple::thumb: + case llvm::Triple::x86: + case llvm::Triple::xcore: + return 32; + + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::ppc64: + case llvm::Triple::ptx64: + case llvm::Triple::sparcv9: + case llvm::Triple::x86_64: + return 64; + } + llvm_unreachable("Invalid architecture value"); +} + +bool Triple::isArch64Bit() const { + return getArchPointerBitWidth(getArch()) == 64; +} + +bool Triple::isArch32Bit() const { + return getArchPointerBitWidth(getArch()) == 32; +} + +bool Triple::isArch16Bit() const { + return getArchPointerBitWidth(getArch()) == 16; +} + +Triple Triple::get32BitArchVariant() const { + Triple T(*this); + switch (getArch()) { + case Triple::UnknownArch: + case Triple::msp430: + T.setArch(UnknownArch); + break; + + case Triple::amdil: + case Triple::arm: + case Triple::cellspu: + case Triple::hexagon: + case Triple::le32: + case Triple::mblaze: + case Triple::mips: + case Triple::mipsel: + case Triple::ppc: + case Triple::ptx32: + case Triple::r600: + case Triple::sparc: + case Triple::tce: + case Triple::thumb: + case Triple::x86: + case Triple::xcore: + // Already 32-bit. + break; + + case Triple::mips64: T.setArch(Triple::mips); break; + case Triple::mips64el: T.setArch(Triple::mipsel); break; + case Triple::ppc64: T.setArch(Triple::ppc); break; + case Triple::ptx64: T.setArch(Triple::ptx32); break; + case Triple::sparcv9: T.setArch(Triple::sparc); break; + case Triple::x86_64: T.setArch(Triple::x86); break; + } + return T; +} + +Triple Triple::get64BitArchVariant() const { + Triple T(*this); + switch (getArch()) { + case Triple::UnknownArch: + case Triple::amdil: + case Triple::arm: + case Triple::cellspu: + case Triple::hexagon: + case Triple::le32: + case Triple::mblaze: + case Triple::msp430: + case Triple::r600: + case Triple::tce: + case Triple::thumb: + case Triple::xcore: + T.setArch(UnknownArch); + break; + + case Triple::mips64: + case Triple::mips64el: + case Triple::ppc64: + case Triple::ptx64: + case Triple::sparcv9: + case Triple::x86_64: + // Already 64-bit. + break; + + case Triple::mips: T.setArch(Triple::mips64); break; + case Triple::mipsel: T.setArch(Triple::mips64el); break; + case Triple::ppc: T.setArch(Triple::ppc64); break; + case Triple::ptx32: T.setArch(Triple::ptx64); break; + case Triple::sparc: T.setArch(Triple::sparcv9); break; + case Triple::x86: T.setArch(Triple::x86_64); break; + } + return T; +} diff --git a/lib/Support/Unix/Host.inc b/lib/Support/Unix/Host.inc index dda3ce2c6f97..726e2fbcf056 100644 --- a/lib/Support/Unix/Host.inc +++ b/lib/Support/Unix/Host.inc @@ -35,14 +35,11 @@ static std::string getOSVersion() { return info.release; } -std::string sys::getHostTriple() { - // FIXME: Derive directly instead of relying on the autoconf generated - // variable. +std::string sys::getDefaultTargetTriple() { + StringRef TargetTripleString(LLVM_DEFAULT_TARGET_TRIPLE); + std::pair<StringRef, StringRef> ArchSplit = TargetTripleString.split('-'); - StringRef HostTripleString(LLVM_HOSTTRIPLE); - std::pair<StringRef, StringRef> ArchSplit = HostTripleString.split('-'); - - // Normalize the arch, since the host triple may not actually match the host. + // Normalize the arch, since the target triple may not actually match the target. std::string Arch = ArchSplit.first; std::string Triple(Arch); @@ -55,7 +52,7 @@ std::string sys::getHostTriple() { Triple[1] = '3'; // On darwin, we want to update the version to match that of the - // host. + // target. std::string::size_type DarwinDashIdx = Triple.find("-darwin"); if (DarwinDashIdx != std::string::npos) { Triple.resize(DarwinDashIdx + strlen("-darwin")); diff --git a/lib/Support/Unix/Path.inc b/lib/Support/Unix/Path.inc index 85c7c4022f48..ddc1e0f9cec8 100644 --- a/lib/Support/Unix/Path.inc +++ b/lib/Support/Unix/Path.inc @@ -60,6 +60,11 @@ #include <mach-o/dyld.h> #endif +// For GNU Hurd +#if defined(__GNU__) && !defined(MAXPATHLEN) +# define MAXPATHLEN 4096 +#endif + // Put in a hack for Cygwin which falsely reports that the mkdtemp function // is available when it is not. #ifdef __CYGWIN__ @@ -235,11 +240,6 @@ Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) { } Path -Path::GetLLVMDefaultConfigDir() { - return Path("/etc/llvm/"); -} - -Path Path::GetUserHomeDirectory() { const char* home = getenv("HOME"); Path result; @@ -261,7 +261,7 @@ Path::GetCurrentDirectory() { } #if defined(__FreeBSD__) || defined (__NetBSD__) || \ - defined(__OpenBSD__) || defined(__minix) + defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) static int test_dir(char buf[PATH_MAX], char ret[PATH_MAX], const char *dir, const char *bin) @@ -313,7 +313,7 @@ getprogpath(char ret[PATH_MAX], const char *bin) free(pv); return (NULL); } -#endif // __FreeBSD__ || __NetBSD__ +#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__ /// GetMainExecutable - Return the path to the main executable, given the /// value of argv[0] from program startup. @@ -330,7 +330,7 @@ Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { return Path(link_path); } #elif defined(__FreeBSD__) || defined (__NetBSD__) || \ - defined(__OpenBSD__) || defined(__minix) + defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) char exe_path[PATH_MAX]; if (getprogpath(exe_path, argv0) != NULL) diff --git a/lib/Support/Unix/PathV2.inc b/lib/Support/Unix/PathV2.inc index bbbc344661be..edb101efb0f6 100644 --- a/lib/Support/Unix/PathV2.inc +++ b/lib/Support/Unix/PathV2.inc @@ -46,6 +46,11 @@ #include <limits.h> #endif +// For GNU Hurd +#if defined(__GNU__) && !defined(PATH_MAX) +# define PATH_MAX 4096 +#endif + using namespace llvm; namespace { @@ -87,7 +92,7 @@ namespace { result.clear(); StringRef d(dir); result.append(d.begin(), d.end()); - return success; + return error_code::success(); } } @@ -96,7 +101,12 @@ namespace sys { namespace fs { error_code current_path(SmallVectorImpl<char> &result) { +#ifdef MAXPATHLEN result.reserve(MAXPATHLEN); +#else +// For GNU Hurd + result.reserve(1024); +#endif while (true) { if (::getcwd(result.data(), result.capacity()) == 0) { @@ -110,7 +120,7 @@ error_code current_path(SmallVectorImpl<char> &result) { } result.set_size(strlen(result.data())); - return success; + return error_code::success(); } error_code copy_file(const Twine &from, const Twine &to, copy_option copt) { @@ -169,7 +179,7 @@ error_code copy_file(const Twine &from, const Twine &to, copy_option copt) { if (sz_read < 0) return error_code(errno, system_category()); - return success; + return error_code::success(); } error_code create_directory(const Twine &path, bool &existed) { @@ -183,7 +193,7 @@ error_code create_directory(const Twine &path, bool &existed) { } else existed = false; - return success; + return error_code::success(); } error_code create_hard_link(const Twine &to, const Twine &from) { @@ -196,7 +206,7 @@ error_code create_hard_link(const Twine &to, const Twine &from) { if (::link(t.begin(), f.begin()) == -1) return error_code(errno, system_category()); - return success; + return error_code::success(); } error_code create_symlink(const Twine &to, const Twine &from) { @@ -209,7 +219,7 @@ error_code create_symlink(const Twine &to, const Twine &from) { if (::symlink(t.begin(), f.begin()) == -1) return error_code(errno, system_category()); - return success; + return error_code::success(); } error_code remove(const Twine &path, bool &existed) { @@ -223,7 +233,7 @@ error_code remove(const Twine &path, bool &existed) { } else existed = true; - return success; + return error_code::success(); } error_code rename(const Twine &from, const Twine &to) { @@ -245,7 +255,7 @@ error_code rename(const Twine &from, const Twine &to) { return error_code(errno, system_category()); } - return success; + return error_code::success(); } error_code resize_file(const Twine &path, uint64_t size) { @@ -255,7 +265,7 @@ error_code resize_file(const Twine &path, uint64_t size) { if (::truncate(p.begin(), size) == -1) return error_code(errno, system_category()); - return success; + return error_code::success(); } error_code exists(const Twine &path, bool &result) { @@ -270,32 +280,21 @@ error_code exists(const Twine &path, bool &result) { } else result = true; - return success; + return error_code::success(); } -error_code equivalent(const Twine &A, const Twine &B, bool &result) { - // Get arguments. - SmallString<128> a_storage; - SmallString<128> b_storage; - StringRef a = A.toNullTerminatedStringRef(a_storage); - StringRef b = B.toNullTerminatedStringRef(b_storage); - - struct stat stat_a, stat_b; - int error_b = ::stat(b.begin(), &stat_b); - int error_a = ::stat(a.begin(), &stat_a); - - // If both are invalid, it's an error. If only one is, the result is false. - if (error_a != 0 || error_b != 0) { - if (error_a == error_b) - return error_code(errno, system_category()); - result = false; - } else { - result = - stat_a.st_dev == stat_b.st_dev && - stat_a.st_ino == stat_b.st_ino; - } +bool equivalent(file_status A, file_status B) { + assert(status_known(A) && status_known(B)); + return A.st_dev == B.st_dev && + A.st_ino == B.st_ino; +} - return success; +error_code equivalent(const Twine &A, const Twine &B, bool &result) { + file_status fsA, fsB; + if (error_code ec = status(A, fsA)) return ec; + if (error_code ec = status(B, fsB)) return ec; + result = equivalent(fsA, fsB); + return error_code::success(); } error_code file_size(const Twine &path, uint64_t &result) { @@ -309,7 +308,7 @@ error_code file_size(const Twine &path, uint64_t &result) { return make_error_code(errc::operation_not_permitted); result = status.st_size; - return success; + return error_code::success(); } error_code status(const Twine &path, file_status &result) { @@ -341,7 +340,10 @@ error_code status(const Twine &path, file_status &result) { else result = file_status(file_type::type_unknown); - return success; + result.st_dev = status.st_dev; + result.st_ino = status.st_ino; + + return error_code::success(); } error_code unique_file(const Twine &model, int &result_fd, @@ -436,10 +438,11 @@ rety_open_create: result_path.append(d.begin(), d.end()); result_fd = RandomFD; - return success; + return error_code::success(); } -error_code directory_iterator_construct(directory_iterator &it, StringRef path){ +error_code detail::directory_iterator_construct(detail::DirIterState &it, + StringRef path){ SmallString<128> path_null(path); DIR *directory = ::opendir(path_null.c_str()); if (directory == 0) @@ -452,15 +455,15 @@ error_code directory_iterator_construct(directory_iterator &it, StringRef path){ return directory_iterator_increment(it); } -error_code directory_iterator_destruct(directory_iterator& it) { +error_code detail::directory_iterator_destruct(detail::DirIterState &it) { if (it.IterationHandle) ::closedir(reinterpret_cast<DIR *>(it.IterationHandle)); it.IterationHandle = 0; it.CurrentEntry = directory_entry(); - return success; + return error_code::success(); } -error_code directory_iterator_increment(directory_iterator& it) { +error_code detail::directory_iterator_increment(detail::DirIterState &it) { errno = 0; dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle)); if (cur_dir == 0 && errno != 0) { @@ -474,7 +477,7 @@ error_code directory_iterator_increment(directory_iterator& it) { } else return directory_iterator_destruct(it); - return success; + return error_code::success(); } error_code get_magic(const Twine &path, uint32_t len, @@ -505,7 +508,7 @@ error_code get_magic(const Twine &path, uint32_t len, } std::fclose(file); result.set_size(len); - return success; + return error_code::success(); } } // end namespace fs diff --git a/lib/Support/Unix/Process.inc b/lib/Support/Unix/Process.inc index da440fd48f3d..2d7fd384e8bb 100644 --- a/lib/Support/Unix/Process.inc +++ b/lib/Support/Unix/Process.inc @@ -136,7 +136,7 @@ int Process::GetCurrentGroupId() { return getgid(); } -#ifdef HAVE_MACH_MACH_H +#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) #include <mach/mach.h> #endif @@ -150,7 +150,7 @@ void Process::PreventCoreFiles() { setrlimit(RLIMIT_CORE, &rlim); #endif -#ifdef HAVE_MACH_MACH_H +#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) // Disable crash reporting on Mac OS X 10.0-10.4 // get information about the original set of exception ports for the task @@ -293,7 +293,3 @@ const char *Process::OutputBold(bool bg) { const char *Process::ResetColor() { return "\033[0m"; } - -void Process::SetWorkingDirectory(std::string Path) { - ::chdir(Path.c_str()); -} diff --git a/lib/Support/Unix/Program.inc b/lib/Support/Unix/Program.inc index 346baf1744dc..e5990d06ecc2 100644 --- a/lib/Support/Unix/Program.inc +++ b/lib/Support/Unix/Program.inc @@ -412,19 +412,19 @@ Program::Kill(std::string* ErrMsg) { return false; } -bool Program::ChangeStdinToBinary(){ +error_code Program::ChangeStdinToBinary(){ // Do nothing, as Unix doesn't differentiate between text and binary. - return false; + return make_error_code(errc::success); } -bool Program::ChangeStdoutToBinary(){ +error_code Program::ChangeStdoutToBinary(){ // Do nothing, as Unix doesn't differentiate between text and binary. - return false; + return make_error_code(errc::success); } -bool Program::ChangeStderrToBinary(){ +error_code Program::ChangeStderrToBinary(){ // Do nothing, as Unix doesn't differentiate between text and binary. - return false; + return make_error_code(errc::success); } } diff --git a/lib/Support/Unix/Signals.inc b/lib/Support/Unix/Signals.inc index e286869e775d..c9ec9fce9aa1 100644 --- a/lib/Support/Unix/Signals.inc +++ b/lib/Support/Unix/Signals.inc @@ -30,6 +30,10 @@ #include <dlfcn.h> #include <cxxabi.h> #endif +#if HAVE_MACH_MACH_H +#include <mach/mach.h> +#endif + using namespace llvm; static RETSIGTYPE SignalHandler(int Sig); // defined below. @@ -261,6 +265,22 @@ static void PrintStackTrace(void *) { /// SIGSEGV) is delivered to the process, print a stack trace and then exit. void llvm::sys::PrintStackTraceOnErrorSignal() { AddSignalHandler(PrintStackTrace, 0); + +#if defined(__APPLE__) + // Environment variable to disable any kind of crash dialog. + if (getenv("LLVM_DISABLE_CRASH_REPORT")) { + mach_port_t self = mach_task_self(); + + exception_mask_t mask = EXC_MASK_CRASH; + + kern_return_t ret = task_set_exception_ports(self, + mask, + MACH_PORT_NULL, + EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, + THREAD_STATE_NONE); + (void)ret; + } +#endif } diff --git a/lib/Support/Valgrind.cpp b/lib/Support/Valgrind.cpp index 703448524ed9..2b250a357758 100644 --- a/lib/Support/Valgrind.cpp +++ b/lib/Support/Valgrind.cpp @@ -52,3 +52,16 @@ void llvm::sys::ValgrindDiscardTranslations(const void *Addr, size_t Len) { } #endif // !HAVE_VALGRIND_VALGRIND_H + +#if LLVM_ENABLE_THREADS != 0 && !defined(NDEBUG) +// These functions require no implementation, tsan just looks at the arguments +// they're called with. +extern "C" { +void AnnotateHappensBefore(const char *file, int line, + const volatile void *cv) {} +void AnnotateHappensAfter(const char *file, int line, + const volatile void *cv) {} +void AnnotateIgnoreWritesBegin(const char *file, int line) {} +void AnnotateIgnoreWritesEnd(const char *file, int line) {} +} +#endif diff --git a/lib/Support/Windows/Host.inc b/lib/Support/Windows/Host.inc index 733830e82f08..2e6d6f190370 100644 --- a/lib/Support/Windows/Host.inc +++ b/lib/Support/Windows/Host.inc @@ -17,7 +17,6 @@ using namespace llvm; -std::string sys::getHostTriple() { - // FIXME: Adapt to running version. - return LLVM_HOSTTRIPLE; +std::string sys::getDefaultTargetTriple() { + return LLVM_DEFAULT_TARGET_TRIPLE; } diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc index 42a92f9c6dfe..d8dc5226ccee 100644 --- a/lib/Support/Windows/Path.inc +++ b/lib/Support/Windows/Path.inc @@ -66,29 +66,20 @@ Path::operator=(StringRef that) { return *this; } -// push_back 0 on create, and pop_back on delete. -struct ScopedNullTerminator { - std::string &str; - ScopedNullTerminator(std::string &s) : str(s) { str.push_back(0); } - ~ScopedNullTerminator() { - // str.pop_back(); But wait, C++03 doesn't have this... - assert(!str.empty() && str[str.size() - 1] == 0 - && "Null char not present!"); - str.resize(str.size() - 1); - } -}; - bool Path::isValid() const { if (path.empty()) return false; + size_t len = path.size(); + // If there is a null character, it and all its successors are ignored. + size_t pos = path.find_first_of('\0'); + if (pos != std::string::npos) + len = pos; + // If there is a colon, it must be the second character, preceded by a letter // and followed by something. - size_t len = path.size(); - // This code assumes that path is null terminated, so make sure it is. - ScopedNullTerminator snt(path); - size_t pos = path.rfind(':',len); + pos = path.rfind(':',len); size_t rootslash = 0; if (pos != std::string::npos) { if (pos != 1 || !isalpha(path[0]) || len < 3) @@ -118,13 +109,13 @@ Path::isValid() const { for (pos = 0; pos < len; ++pos) { // A component may not end in a space. if (path[pos] == ' ') { - if (path[pos+1] == '/' || path[pos+1] == '\0') + if (pos+1 == len || path[pos+1] == '/' || path[pos+1] == '\0') return false; } // A component may not end in a period. if (path[pos] == '.') { - if (path[pos+1] == '/' || path[pos+1] == '\0') { + if (pos+1 == len || path[pos+1] == '/') { // Unless it is the pseudo-directory "."... if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':') return true; @@ -286,14 +277,6 @@ Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) { } Path -Path::GetLLVMDefaultConfigDir() { - Path ret = GetUserHomeDirectory(); - if (!ret.appendComponent(".llvm")) - assert(0 && "Failed to append .llvm"); - return ret; -} - -Path Path::GetUserHomeDirectory() { char buff[MAX_PATH]; HRESULT res = SHGetFolderPathA(NULL, diff --git a/lib/Support/Windows/PathV2.inc b/lib/Support/Windows/PathV2.inc index bc597b2dcc89..e9ce5d9097a3 100644 --- a/lib/Support/Windows/PathV2.inc +++ b/lib/Support/Windows/PathV2.inc @@ -17,7 +17,6 @@ //===----------------------------------------------------------------------===// #include "Windows.h" -#include <wincrypt.h> #include <fcntl.h> #include <io.h> #include <sys/stat.h> @@ -63,7 +62,7 @@ namespace { utf16.push_back(0); utf16.pop_back(); - return success; + return error_code::success(); } error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, @@ -93,7 +92,7 @@ namespace { utf8.push_back(0); utf8.pop_back(); - return success; + return error_code::success(); } error_code TempDir(SmallVectorImpl<wchar_t> &result) { @@ -109,17 +108,9 @@ namespace { } result.set_size(len); - return success; + return error_code::success(); } - // Forwarder for ScopedHandle. - BOOL WINAPI CryptReleaseContext(HCRYPTPROV Provider) { - return ::CryptReleaseContext(Provider, 0); - } - - typedef ScopedHandle<HCRYPTPROV, uintptr_t(-1), - BOOL (WINAPI*)(HCRYPTPROV), CryptReleaseContext> - ScopedCryptContext; bool is_separator(const wchar_t value) { switch (value) { case L'\\': @@ -176,7 +167,7 @@ retry_cur_dir: if (len == 0) return windows_error(::GetLastError()); - return success; + return error_code::success(); } error_code copy_file(const Twine &from, const Twine &to, copy_option copt) { @@ -199,7 +190,7 @@ error_code copy_file(const Twine &from, const Twine &to, copy_option copt) { if (res == 0) return windows_error(::GetLastError()); - return success; + return error_code::success(); } error_code create_directory(const Twine &path, bool &existed) { @@ -219,7 +210,7 @@ error_code create_directory(const Twine &path, bool &existed) { } else existed = false; - return success; + return error_code::success(); } error_code create_hard_link(const Twine &to, const Twine &from) { @@ -238,7 +229,7 @@ error_code create_hard_link(const Twine &to, const Twine &from) { if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) return windows_error(::GetLastError()); - return success; + return error_code::success(); } error_code create_symlink(const Twine &to, const Twine &from) { @@ -261,7 +252,7 @@ error_code create_symlink(const Twine &to, const Twine &from) { if (!create_symbolic_link_api(wide_from.begin(), wide_to.begin(), 0)) return windows_error(::GetLastError()); - return success; + return error_code::success(); } error_code remove(const Twine &path, bool &existed) { @@ -294,7 +285,7 @@ error_code remove(const Twine &path, bool &existed) { existed = true; } - return success; + return error_code::success(); } error_code rename(const Twine &from, const Twine &to) { @@ -314,7 +305,7 @@ error_code rename(const Twine &from, const Twine &to) { MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) return windows_error(::GetLastError()); - return success; + return error_code::success(); } error_code resize_file(const Twine &path, uint64_t size) { @@ -356,72 +347,26 @@ error_code exists(const Twine &path, bool &result) { result = false; } else result = true; - return success; + return error_code::success(); } -error_code equivalent(const Twine &A, const Twine &B, bool &result) { - // Get arguments. - SmallString<128> a_storage; - SmallString<128> b_storage; - StringRef a = A.toStringRef(a_storage); - StringRef b = B.toStringRef(b_storage); - - // Convert to utf-16. - SmallVector<wchar_t, 128> wide_a; - SmallVector<wchar_t, 128> wide_b; - if (error_code ec = UTF8ToUTF16(a, wide_a)) return ec; - if (error_code ec = UTF8ToUTF16(b, wide_b)) return ec; - - AutoHandle HandleB( - ::CreateFileW(wide_b.begin(), - 0, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - 0)); - - AutoHandle HandleA( - ::CreateFileW(wide_a.begin(), - 0, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - 0)); - - // If both handles are invalid, it's an error. - if (HandleA == INVALID_HANDLE_VALUE && - HandleB == INVALID_HANDLE_VALUE) - return windows_error(::GetLastError()); - - // If only one is invalid, it's false. - if (HandleA == INVALID_HANDLE_VALUE && - HandleB == INVALID_HANDLE_VALUE) { - result = false; - return success; - } - - // Get file information. - BY_HANDLE_FILE_INFORMATION InfoA, InfoB; - if (!::GetFileInformationByHandle(HandleA, &InfoA)) - return windows_error(::GetLastError()); - if (!::GetFileInformationByHandle(HandleB, &InfoB)) - return windows_error(::GetLastError()); +bool equivalent(file_status A, file_status B) { + assert(status_known(A) && status_known(B)); + return A.FileIndexHigh == B.FileIndexHigh && + A.FileIndexLow == B.FileIndexLow && + A.FileSizeHigh == B.FileSizeHigh && + A.FileSizeLow == B.FileSizeLow && + A.LastWriteTimeHigh == B.LastWriteTimeHigh && + A.LastWriteTimeLow == B.LastWriteTimeLow && + A.VolumeSerialNumber == B.VolumeSerialNumber; +} - // See if it's all the same. - result = - InfoA.dwVolumeSerialNumber == InfoB.dwVolumeSerialNumber && - InfoA.nFileIndexHigh == InfoB.nFileIndexHigh && - InfoA.nFileIndexLow == InfoB.nFileIndexLow && - InfoA.nFileSizeHigh == InfoB.nFileSizeHigh && - InfoA.nFileSizeLow == InfoB.nFileSizeLow && - InfoA.ftLastWriteTime.dwLowDateTime == - InfoB.ftLastWriteTime.dwLowDateTime && - InfoA.ftLastWriteTime.dwHighDateTime == - InfoB.ftLastWriteTime.dwHighDateTime; - - return success; +error_code equivalent(const Twine &A, const Twine &B, bool &result) { + file_status fsA, fsB; + if (error_code ec = status(A, fsA)) return ec; + if (error_code ec = status(B, fsB)) return ec; + result = equivalent(fsA, fsB); + return error_code::success(); } error_code file_size(const Twine &path, uint64_t &result) { @@ -442,7 +387,7 @@ error_code file_size(const Twine &path, uint64_t &result) { (uint64_t(FileData.nFileSizeHigh) << (sizeof(FileData.nFileSizeLow) * 8)) + FileData.nFileSizeLow; - return success; + return error_code::success(); } static bool isReservedName(StringRef path) { @@ -475,11 +420,10 @@ error_code status(const Twine &path, file_status &result) { StringRef path8 = path.toStringRef(path_storage); if (isReservedName(path8)) { result = file_status(file_type::character_file); - return success; + return error_code::success(); } - if (error_code ec = UTF8ToUTF16(path8, - path_utf16)) + if (error_code ec = UTF8ToUTF16(path8, path_utf16)) return ec; DWORD attr = ::GetFileAttributesW(path_utf16.begin()); @@ -488,7 +432,7 @@ error_code status(const Twine &path, file_status &result) { // Handle reparse points. if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { - AutoHandle h( + ScopedFileHandle h( ::CreateFileW(path_utf16.begin(), 0, // Attributes only. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, @@ -496,16 +440,37 @@ error_code status(const Twine &path, file_status &result) { OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); - if (h == INVALID_HANDLE_VALUE) + if (!h) goto handle_status_error; } if (attr & FILE_ATTRIBUTE_DIRECTORY) result = file_status(file_type::directory_file); - else + else { result = file_status(file_type::regular_file); + ScopedFileHandle h( + ::CreateFileW(path_utf16.begin(), + 0, // Attributes only. + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + 0)); + if (!h) + goto handle_status_error; + BY_HANDLE_FILE_INFORMATION Info; + if (!::GetFileInformationByHandle(h, &Info)) + goto handle_status_error; + result.FileIndexHigh = Info.nFileIndexHigh; + result.FileIndexLow = Info.nFileIndexLow; + result.FileSizeHigh = Info.nFileSizeHigh; + result.FileSizeLow = Info.nFileSizeLow; + result.LastWriteTimeHigh = Info.ftLastWriteTime.dwHighDateTime; + result.LastWriteTimeLow = Info.ftLastWriteTime.dwLowDateTime; + result.VolumeSerialNumber = Info.dwVolumeSerialNumber; + } - return success; + return error_code::success(); handle_status_error: error_code ec = windows_error(::GetLastError()); @@ -519,7 +484,7 @@ handle_status_error: return ec; } - return success; + return error_code::success(); } error_code unique_file(const Twine &model, int &result_fd, @@ -535,7 +500,7 @@ error_code unique_file(const Twine &model, int &result_fd, if (makeAbsolute) { // Make model absolute by prepending a temp directory if it's not already. bool absolute = path::is_absolute(m); - + if (!absolute) { SmallVector<wchar_t, 64> temp_dir; if (error_code ec = TempDir(temp_dir)) return ec; @@ -646,7 +611,7 @@ retry_create_file: } result_fd = fd; - return success; + return error_code::success(); } error_code get_magic(const Twine &path, uint32_t len, @@ -688,10 +653,11 @@ error_code get_magic(const Twine &path, uint32_t len, } result.set_size(len); - return success; + return error_code::success(); } -error_code directory_iterator_construct(directory_iterator &it, StringRef path){ +error_code detail::directory_iterator_construct(detail::DirIterState &it, + StringRef path){ SmallVector<wchar_t, 128> path_utf16; if (error_code ec = UTF8ToUTF16(path, @@ -722,7 +688,7 @@ error_code directory_iterator_construct(directory_iterator &it, StringRef path){ error_code ec = windows_error(::GetLastError()); // Check for end. if (ec == windows_error::no_more_files) - return directory_iterator_destruct(it); + return detail::directory_iterator_destruct(it); return ec; } else FilenameLen = ::wcslen(FirstFind.cFileName); @@ -739,25 +705,25 @@ error_code directory_iterator_construct(directory_iterator &it, StringRef path){ path::append(directory_entry_path, directory_entry_name_utf8.str()); it.CurrentEntry = directory_entry(directory_entry_path.str()); - return success; + return error_code::success(); } -error_code directory_iterator_destruct(directory_iterator& it) { +error_code detail::directory_iterator_destruct(detail::DirIterState &it) { if (it.IterationHandle != 0) // Closes the handle if it's valid. ScopedFindHandle close(HANDLE(it.IterationHandle)); it.IterationHandle = 0; it.CurrentEntry = directory_entry(); - return success; + return error_code::success(); } -error_code directory_iterator_increment(directory_iterator& it) { +error_code detail::directory_iterator_increment(detail::DirIterState &it) { WIN32_FIND_DATAW FindData; if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) { error_code ec = windows_error(::GetLastError()); // Check for end. if (ec == windows_error::no_more_files) - return directory_iterator_destruct(it); + return detail::directory_iterator_destruct(it); return ec; } @@ -774,7 +740,7 @@ error_code directory_iterator_increment(directory_iterator& it) { return ec; it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); - return success; + return error_code::success(); } } // end namespace fs diff --git a/lib/Support/Windows/Process.inc b/lib/Support/Windows/Process.inc index fe54eb1a7972..913b0734ddc9 100644 --- a/lib/Support/Windows/Process.inc +++ b/lib/Support/Windows/Process.inc @@ -220,8 +220,4 @@ const char *Process::ResetColor() { return 0; } -void Process::SetWorkingDirectory(std::string Path) { - ::_chdir(Path.c_str()); -} - } diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc index e486e6ec2381..80ccaa6ea6b1 100644 --- a/lib/Support/Windows/Program.inc +++ b/lib/Support/Windows/Program.inc @@ -299,14 +299,14 @@ Program::Execute(const Path& path, Data_ = wpi; // Make sure these get closed no matter what. - AutoHandle hThread(pi.hThread); + ScopedCommonHandle hThread(pi.hThread); // Assign the process to a job if a memory limit is defined. - AutoHandle hJob(0); + ScopedJobHandle hJob; if (memoryLimit != 0) { hJob = CreateJobObject(0, 0); bool success = false; - if (hJob != 0) { + if (hJob) { JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; memset(&jeli, 0, sizeof(jeli)); jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; @@ -367,7 +367,17 @@ Program::Wait(const Path &path, return -2; } - return status; + if (!status) + return 0; + + // Pass 10(Warning) and 11(Error) to the callee as negative value. + if ((status & 0xBFFF0000U) == 0x80000000U) + return (int)status; + + if (status & 0xFF) + return status & 0x7FFFFFFF; + + return 1; } bool @@ -387,19 +397,25 @@ Program::Kill(std::string* ErrMsg) { return false; } -bool Program::ChangeStdinToBinary(){ +error_code Program::ChangeStdinToBinary(){ int result = _setmode( _fileno(stdin), _O_BINARY ); - return result == -1; + if (result == -1) + return error_code(errno, generic_category()); + return make_error_code(errc::success); } -bool Program::ChangeStdoutToBinary(){ +error_code Program::ChangeStdoutToBinary(){ int result = _setmode( _fileno(stdout), _O_BINARY ); - return result == -1; + if (result == -1) + return error_code(errno, generic_category()); + return make_error_code(errc::success); } -bool Program::ChangeStderrToBinary(){ +error_code Program::ChangeStderrToBinary(){ int result = _setmode( _fileno(stderr), _O_BINARY ); - return result == -1; + if (result == -1) + return error_code(errno, generic_category()); + return make_error_code(errc::success); } } diff --git a/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc index 0d4b8a26b023..38308f6abd85 100644 --- a/lib/Support/Windows/Signals.inc +++ b/lib/Support/Windows/Signals.inc @@ -239,7 +239,7 @@ static void RegisterHandler() { SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); // Environment variable to disable any kind of crash dialog. - if (getenv("LLVM_DISABLE_CRT_DEBUG")) { + if (getenv("LLVM_DISABLE_CRASH_REPORT")) { #ifdef _MSC_VER _CrtSetReportHook(CRTReportHook); #endif @@ -446,7 +446,7 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { } if (ExitOnUnhandledExceptions) - _exit(-3); + _exit(ep->ExceptionRecord->ExceptionCode); // Allow dialog box to pop up allowing choice to start debugger. if (OldFilter) diff --git a/lib/Support/Windows/Windows.h b/lib/Support/Windows/Windows.h index 67b6f015114f..5c1da0d617aa 100644 --- a/lib/Support/Windows/Windows.h +++ b/lib/Support/Windows/Windows.h @@ -26,6 +26,7 @@ #include "llvm/Config/config.h" // Get build system configuration settings #include <windows.h> +#include <wincrypt.h> #include <shlobj.h> #include <cassert> #include <string> @@ -41,70 +42,99 @@ inline bool MakeErrMsg(std::string* ErrMsg, const std::string& prefix) { return true; } -class AutoHandle { - HANDLE handle; +template <typename HandleTraits> +class ScopedHandle { + typedef typename HandleTraits::handle_type handle_type; + handle_type Handle; + ScopedHandle(const ScopedHandle &other); // = delete; + void operator=(const ScopedHandle &other); // = delete; public: - AutoHandle(HANDLE h) : handle(h) {} + ScopedHandle() + : Handle(HandleTraits::GetInvalid()) {} + + explicit ScopedHandle(handle_type h) + : Handle(h) {} - ~AutoHandle() { - if (handle) - CloseHandle(handle); + ~ScopedHandle() { + if (HandleTraits::IsValid(Handle)) + HandleTraits::Close(Handle); } - operator HANDLE() { - return handle; + handle_type take() { + handle_type t = Handle; + Handle = HandleTraits::GetInvalid(); + return t; } - AutoHandle &operator=(HANDLE h) { - handle = h; + ScopedHandle &operator=(handle_type h) { + if (HandleTraits::IsValid(Handle)) + HandleTraits::Close(Handle); + Handle = h; return *this; } + + // True if Handle is valid. + operator bool() const { + return HandleTraits::IsValid(Handle) ? true : false; + } + + operator handle_type() const { + return Handle; + } }; -template <class HandleType, uintptr_t InvalidHandle, - class DeleterType, DeleterType D> -class ScopedHandle { - HandleType Handle; +struct CommonHandleTraits { + typedef HANDLE handle_type; -public: - ScopedHandle() : Handle(InvalidHandle) {} - ScopedHandle(HandleType handle) : Handle(handle) {} + static handle_type GetInvalid() { + return INVALID_HANDLE_VALUE; + } - ~ScopedHandle() { - if (Handle != HandleType(InvalidHandle)) - D(Handle); + static void Close(handle_type h) { + ::CloseHandle(h); } - HandleType take() { - HandleType temp = Handle; - Handle = HandleType(InvalidHandle); - return temp; + static bool IsValid(handle_type h) { + return h != GetInvalid(); } +}; - operator HandleType() const { return Handle; } +struct JobHandleTraits : CommonHandleTraits { + static handle_type GetInvalid() { + return NULL; + } +}; - ScopedHandle &operator=(HandleType handle) { - Handle = handle; - return *this; +struct CryptContextTraits : CommonHandleTraits { + typedef HCRYPTPROV handle_type; + + static handle_type GetInvalid() { + return 0; } - typedef void (*unspecified_bool_type)(); - static void unspecified_bool_true() {} + static void Close(handle_type h) { + ::CryptReleaseContext(h, 0); + } - // True if Handle is valid. - operator unspecified_bool_type() const { - return Handle == HandleType(InvalidHandle) ? 0 : unspecified_bool_true; + static bool IsValid(handle_type h) { + return h != GetInvalid(); } +}; - bool operator!() const { - return Handle == HandleType(InvalidHandle); +struct FindHandleTraits : CommonHandleTraits { + static void Close(handle_type h) { + ::FindClose(h); } }; -typedef ScopedHandle<HANDLE, uintptr_t(-1), - BOOL (WINAPI*)(HANDLE), ::FindClose> - ScopedFindHandle; +struct FileHandleTraits : CommonHandleTraits {}; + +typedef ScopedHandle<CommonHandleTraits> ScopedCommonHandle; +typedef ScopedHandle<FileHandleTraits> ScopedFileHandle; +typedef ScopedHandle<CryptContextTraits> ScopedCryptContext; +typedef ScopedHandle<FindHandleTraits> ScopedFindHandle; +typedef ScopedHandle<JobHandleTraits> ScopedJobHandle; namespace llvm { template <class T> diff --git a/lib/Support/YAMLParser.cpp b/lib/Support/YAMLParser.cpp new file mode 100644 index 000000000000..330519f3019d --- /dev/null +++ b/lib/Support/YAMLParser.cpp @@ -0,0 +1,2117 @@ +//===--- YAMLParser.cpp - Simple YAML parser ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a YAML parser. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/YAMLParser.h" + +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/SourceMgr.h" + +using namespace llvm; +using namespace yaml; + +enum UnicodeEncodingForm { + UEF_UTF32_LE, //< UTF-32 Little Endian + UEF_UTF32_BE, //< UTF-32 Big Endian + UEF_UTF16_LE, //< UTF-16 Little Endian + UEF_UTF16_BE, //< UTF-16 Big Endian + UEF_UTF8, //< UTF-8 or ascii. + UEF_Unknown //< Not a valid Unicode encoding. +}; + +/// EncodingInfo - Holds the encoding type and length of the byte order mark if +/// it exists. Length is in {0, 2, 3, 4}. +typedef std::pair<UnicodeEncodingForm, unsigned> EncodingInfo; + +/// getUnicodeEncoding - Reads up to the first 4 bytes to determine the Unicode +/// encoding form of \a Input. +/// +/// @param Input A string of length 0 or more. +/// @returns An EncodingInfo indicating the Unicode encoding form of the input +/// and how long the byte order mark is if one exists. +static EncodingInfo getUnicodeEncoding(StringRef Input) { + if (Input.size() == 0) + return std::make_pair(UEF_Unknown, 0); + + switch (uint8_t(Input[0])) { + case 0x00: + if (Input.size() >= 4) { + if ( Input[1] == 0 + && uint8_t(Input[2]) == 0xFE + && uint8_t(Input[3]) == 0xFF) + return std::make_pair(UEF_UTF32_BE, 4); + if (Input[1] == 0 && Input[2] == 0 && Input[3] != 0) + return std::make_pair(UEF_UTF32_BE, 0); + } + + if (Input.size() >= 2 && Input[1] != 0) + return std::make_pair(UEF_UTF16_BE, 0); + return std::make_pair(UEF_Unknown, 0); + case 0xFF: + if ( Input.size() >= 4 + && uint8_t(Input[1]) == 0xFE + && Input[2] == 0 + && Input[3] == 0) + return std::make_pair(UEF_UTF32_LE, 4); + + if (Input.size() >= 2 && uint8_t(Input[1]) == 0xFE) + return std::make_pair(UEF_UTF16_LE, 2); + return std::make_pair(UEF_Unknown, 0); + case 0xFE: + if (Input.size() >= 2 && uint8_t(Input[1]) == 0xFF) + return std::make_pair(UEF_UTF16_BE, 2); + return std::make_pair(UEF_Unknown, 0); + case 0xEF: + if ( Input.size() >= 3 + && uint8_t(Input[1]) == 0xBB + && uint8_t(Input[2]) == 0xBF) + return std::make_pair(UEF_UTF8, 3); + return std::make_pair(UEF_Unknown, 0); + } + + // It could still be utf-32 or utf-16. + if (Input.size() >= 4 && Input[1] == 0 && Input[2] == 0 && Input[3] == 0) + return std::make_pair(UEF_UTF32_LE, 0); + + if (Input.size() >= 2 && Input[1] == 0) + return std::make_pair(UEF_UTF16_LE, 0); + + return std::make_pair(UEF_UTF8, 0); +} + +namespace llvm { +namespace yaml { +/// Token - A single YAML token. +struct Token : ilist_node<Token> { + enum TokenKind { + TK_Error, // Uninitialized token. + TK_StreamStart, + TK_StreamEnd, + TK_VersionDirective, + TK_TagDirective, + TK_DocumentStart, + TK_DocumentEnd, + TK_BlockEntry, + TK_BlockEnd, + TK_BlockSequenceStart, + TK_BlockMappingStart, + TK_FlowEntry, + TK_FlowSequenceStart, + TK_FlowSequenceEnd, + TK_FlowMappingStart, + TK_FlowMappingEnd, + TK_Key, + TK_Value, + TK_Scalar, + TK_Alias, + TK_Anchor, + TK_Tag + } Kind; + + /// A string of length 0 or more whose begin() points to the logical location + /// of the token in the input. + StringRef Range; + + Token() : Kind(TK_Error) {} +}; +} +} + +namespace llvm { +template<> +struct ilist_sentinel_traits<Token> { + Token *createSentinel() const { + return &Sentinel; + } + static void destroySentinel(Token*) {} + + Token *provideInitialHead() const { return createSentinel(); } + Token *ensureHead(Token*) const { return createSentinel(); } + static void noteHead(Token*, Token*) {} + +private: + mutable Token Sentinel; +}; + +template<> +struct ilist_node_traits<Token> { + Token *createNode(const Token &V) { + return new (Alloc.Allocate<Token>()) Token(V); + } + static void deleteNode(Token *V) {} + + void addNodeToList(Token *) {} + void removeNodeFromList(Token *) {} + void transferNodesFromList(ilist_node_traits & /*SrcTraits*/, + ilist_iterator<Token> /*first*/, + ilist_iterator<Token> /*last*/) {} + + BumpPtrAllocator Alloc; +}; +} + +typedef ilist<Token> TokenQueueT; + +namespace { +/// @brief 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, +/// if the Token To be returned is referenced by a SimpleKey, we continue +/// tokenizing until that potential simple key has either been found to not be +/// a simple key (we moved on to the next line or went further than 1024 chars). +/// Or when we run into a Value, and then insert a Key token (and possibly +/// others) before the SimpleKey's Tok. +struct SimpleKey { + TokenQueueT::iterator Tok; + unsigned Column; + unsigned Line; + unsigned FlowLevel; + bool IsRequired; + + bool operator ==(const SimpleKey &Other) { + return Tok == Other.Tok; + } +}; +} + +/// @brief 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. +typedef std::pair<uint32_t, unsigned> UTF8Decoded; + +static UTF8Decoded decodeUTF8(StringRef Range) { + StringRef::iterator Position= Range.begin(); + StringRef::iterator End = Range.end(); + // 1 byte: [0x00, 0x7f] + // Bit pattern: 0xxxxxxx + if ((*Position & 0x80) == 0) { + return std::make_pair(*Position, 1); + } + // 2 bytes: [0x80, 0x7ff] + // Bit pattern: 110xxxxx 10xxxxxx + if (Position + 1 != End && + ((*Position & 0xE0) == 0xC0) && + ((*(Position + 1) & 0xC0) == 0x80)) { + uint32_t codepoint = ((*Position & 0x1F) << 6) | + (*(Position + 1) & 0x3F); + if (codepoint >= 0x80) + return std::make_pair(codepoint, 2); + } + // 3 bytes: [0x8000, 0xffff] + // Bit pattern: 1110xxxx 10xxxxxx 10xxxxxx + if (Position + 2 != End && + ((*Position & 0xF0) == 0xE0) && + ((*(Position + 1) & 0xC0) == 0x80) && + ((*(Position + 2) & 0xC0) == 0x80)) { + uint32_t codepoint = ((*Position & 0x0F) << 12) | + ((*(Position + 1) & 0x3F) << 6) | + (*(Position + 2) & 0x3F); + // Codepoints between 0xD800 and 0xDFFF are invalid, as + // they are high / low surrogate halves used by UTF-16. + if (codepoint >= 0x800 && + (codepoint < 0xD800 || codepoint > 0xDFFF)) + return std::make_pair(codepoint, 3); + } + // 4 bytes: [0x10000, 0x10FFFF] + // Bit pattern: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + if (Position + 3 != End && + ((*Position & 0xF8) == 0xF0) && + ((*(Position + 1) & 0xC0) == 0x80) && + ((*(Position + 2) & 0xC0) == 0x80) && + ((*(Position + 3) & 0xC0) == 0x80)) { + uint32_t codepoint = ((*Position & 0x07) << 18) | + ((*(Position + 1) & 0x3F) << 12) | + ((*(Position + 2) & 0x3F) << 6) | + (*(Position + 3) & 0x3F); + if (codepoint >= 0x10000 && codepoint <= 0x10FFFF) + return std::make_pair(codepoint, 4); + } + return std::make_pair(0, 0); +} + +namespace llvm { +namespace yaml { +/// @brief Scans YAML tokens from a MemoryBuffer. +class Scanner { +public: + Scanner(const StringRef Input, SourceMgr &SM); + + /// @brief Parse the next token and return it without popping it. + Token &peekNext(); + + /// @brief Parse the next token and pop it from the queue. + Token getNext(); + + void printError(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Message, + ArrayRef<SMRange> Ranges = ArrayRef<SMRange>()) { + SM.PrintMessage(Loc, Kind, Message, Ranges); + } + + void setError(const Twine &Message, StringRef::iterator Position) { + if (Current >= End) + Current = End - 1; + + // Don't print out more errors after the first one we encounter. The rest + // are just the result of the first, and have no meaning. + if (!Failed) + printError(SMLoc::getFromPointer(Current), SourceMgr::DK_Error, Message); + Failed = true; + } + + void setError(const Twine &Message) { + setError(Message, Current); + } + + /// @brief Returns true if an error occurred while parsing. + bool failed() { + return Failed; + } + +private: + StringRef currentInput() { + return StringRef(Current, End - Current); + } + + /// @brief 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 + /// code unit subsequence, then the Unicode scalar value is 0, and the length + /// is 0. + UTF8Decoded decodeUTF8(StringRef::iterator Position) { + return ::decodeUTF8(StringRef(Position, End - Position)); + } + + // The following functions are based on the gramar rules in the YAML spec. The + // style of the function names it meant to closely match how they are written + // in the spec. The number within the [] is the number of the grammar rule in + // the spec. + // + // See 4.2 [Production Naming Conventions] for the meaning of the prefixes. + // + // c- + // A production starting and ending with a special character. + // b- + // A production matching a single line break. + // nb- + // A production starting and ending with a non-break character. + // s- + // A production starting and ending with a white space character. + // ns- + // A production starting and ending with a non-space character. + // l- + // A production matching complete line(s). + + /// @brief 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] + /// + /// @returns The code unit after the nb-char, or Position if it's not an + /// nb-char. + StringRef::iterator skip_nb_char(StringRef::iterator Position); + + /// @brief Skip a single b-break[28] starting at Position. + /// + /// A b-break is 0xD 0xA | 0xD | 0xA + /// + /// @returns The code unit after the b-break, or Position if it's not a + /// b-break. + StringRef::iterator skip_b_break(StringRef::iterator Position); + + /// @brief Skip a single s-white[33] starting at Position. + /// + /// A s-white is 0x20 | 0x9 + /// + /// @returns The code unit after the s-white, or Position if it's not a + /// s-white. + StringRef::iterator skip_s_white(StringRef::iterator Position); + + /// @brief Skip a single ns-char[34] starting at Position. + /// + /// A ns-char is nb-char - s-white + /// + /// @returns The code unit after the ns-char, or Position if it's not a + /// ns-char. + StringRef::iterator skip_ns_char(StringRef::iterator Position); + + typedef StringRef::iterator (Scanner::*SkipWhileFunc)(StringRef::iterator); + /// @brief Skip minimal well-formed code unit subsequences until Func + /// returns its input. + /// + /// @returns The code unit after the last minimal well-formed code unit + /// subsequence that Func accepted. + StringRef::iterator skip_while( SkipWhileFunc Func + , StringRef::iterator Position); + + /// @brief Scan ns-uri-char[39]s starting at Cur. + /// + /// This updates Cur and Column while scanning. + /// + /// @returns A StringRef starting at Cur which covers the longest contiguous + /// sequence of ns-uri-char. + StringRef scan_ns_uri_char(); + + /// @brief Scan ns-plain-one-line[133] starting at \a Cur. + StringRef scan_ns_plain_one_line(); + + /// @brief 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. + void skip(uint32_t Distance); + + /// @brief Return true if the minimal well-formed code unit subsequence at + /// Pos is whitespace or a new line + bool isBlankOrBreak(StringRef::iterator Position); + + /// @brief 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. + /// + /// 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. + void removeSimpleKeyCandidatesOnFlowLevel(unsigned Level); + + /// @brief 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 + /// if needed. + bool rollIndent( int ToColumn + , Token::TokenKind Kind + , TokenQueueT::iterator InsertPoint); + + /// @brief Skip whitespace and comments until the start of the next token. + void scanToNextToken(); + + /// @brief Must be the first token generated. + bool scanStreamStart(); + + /// @brief Generate tokens needed to close out the stream. + bool scanStreamEnd(); + + /// @brief Scan a %BLAH directive. + bool scanDirective(); + + /// @brief Scan a ... or ---. + bool scanDocumentIndicator(bool IsStart); + + /// @brief 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. + bool scanFlowCollectionEnd(bool IsSequence); + + /// @brief Scan the , that separates entries in a flow collection. + bool scanFlowEntry(); + + /// @brief Scan the - that starts block sequence entries. + bool scanBlockEntry(); + + /// @brief Scan an explicit ? indicating a key. + bool scanKey(); + + /// @brief Scan an explicit : indicating a value. + bool scanValue(); + + /// @brief Scan a quoted scalar. + bool scanFlowScalar(bool IsDoubleQuoted); + + /// @brief Scan an unquoted scalar. + bool scanPlainScalar(); + + /// @brief Scan an Alias or Anchor starting with * or &. + bool scanAliasOrAnchor(bool IsAlias); + + /// @brief Scan a block scalar starting with | or >. + bool scanBlockScalar(bool IsLiteral); + + /// @brief Scan a tag of the form !stuff. + bool scanTag(); + + /// @brief Dispatch to the next scanning function based on \a *Cur. + bool fetchMoreTokens(); + + /// @brief The SourceMgr used for diagnostics and buffer management. + SourceMgr &SM; + + /// @brief The original input. + MemoryBuffer *InputBuffer; + + /// @brief The current position of the scanner. + StringRef::iterator Current; + + /// @brief The end of the input (one past the last character). + StringRef::iterator End; + + /// @brief Current YAML indentation level in spaces. + int Indent; + + /// @brief Current column number in Unicode code points. + unsigned Column; + + /// @brief Current line number. + unsigned Line; + + /// @brief How deep we are in flow style containers. 0 Means at block level. + unsigned FlowLevel; + + /// @brief Are we at the start of the stream? + bool IsStartOfStream; + + /// @brief Can the next token be the start of a simple key? + bool IsSimpleKeyAllowed; + + /// @brief Is the next token required to start a simple key? + bool IsSimpleKeyRequired; + + /// @brief True if an error has occurred. + bool Failed; + + /// @brief 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. + SmallVector<int, 4> Indents; + + /// @brief Potential simple keys. + SmallVector<SimpleKey, 4> SimpleKeys; +}; + +} // end namespace yaml +} // end namespace llvm + +/// encodeUTF8 - Encode \a UnicodeScalarValue in UTF-8 and append it to result. +static void encodeUTF8( uint32_t UnicodeScalarValue + , SmallVectorImpl<char> &Result) { + if (UnicodeScalarValue <= 0x7F) { + Result.push_back(UnicodeScalarValue & 0x7F); + } else if (UnicodeScalarValue <= 0x7FF) { + uint8_t FirstByte = 0xC0 | ((UnicodeScalarValue & 0x7C0) >> 6); + uint8_t SecondByte = 0x80 | (UnicodeScalarValue & 0x3F); + Result.push_back(FirstByte); + Result.push_back(SecondByte); + } else if (UnicodeScalarValue <= 0xFFFF) { + uint8_t FirstByte = 0xE0 | ((UnicodeScalarValue & 0xF000) >> 12); + uint8_t SecondByte = 0x80 | ((UnicodeScalarValue & 0xFC0) >> 6); + uint8_t ThirdByte = 0x80 | (UnicodeScalarValue & 0x3F); + Result.push_back(FirstByte); + Result.push_back(SecondByte); + Result.push_back(ThirdByte); + } else if (UnicodeScalarValue <= 0x10FFFF) { + uint8_t FirstByte = 0xF0 | ((UnicodeScalarValue & 0x1F0000) >> 18); + uint8_t SecondByte = 0x80 | ((UnicodeScalarValue & 0x3F000) >> 12); + uint8_t ThirdByte = 0x80 | ((UnicodeScalarValue & 0xFC0) >> 6); + uint8_t FourthByte = 0x80 | (UnicodeScalarValue & 0x3F); + Result.push_back(FirstByte); + Result.push_back(SecondByte); + Result.push_back(ThirdByte); + Result.push_back(FourthByte); + } +} + +bool yaml::dumpTokens(StringRef Input, raw_ostream &OS) { + SourceMgr SM; + Scanner scanner(Input, SM); + while (true) { + Token T = scanner.getNext(); + switch (T.Kind) { + case Token::TK_StreamStart: + OS << "Stream-Start: "; + break; + case Token::TK_StreamEnd: + OS << "Stream-End: "; + break; + case Token::TK_VersionDirective: + OS << "Version-Directive: "; + break; + case Token::TK_TagDirective: + OS << "Tag-Directive: "; + break; + case Token::TK_DocumentStart: + OS << "Document-Start: "; + break; + case Token::TK_DocumentEnd: + OS << "Document-End: "; + break; + case Token::TK_BlockEntry: + OS << "Block-Entry: "; + break; + case Token::TK_BlockEnd: + OS << "Block-End: "; + break; + case Token::TK_BlockSequenceStart: + OS << "Block-Sequence-Start: "; + break; + case Token::TK_BlockMappingStart: + OS << "Block-Mapping-Start: "; + break; + case Token::TK_FlowEntry: + OS << "Flow-Entry: "; + break; + case Token::TK_FlowSequenceStart: + OS << "Flow-Sequence-Start: "; + break; + case Token::TK_FlowSequenceEnd: + OS << "Flow-Sequence-End: "; + break; + case Token::TK_FlowMappingStart: + OS << "Flow-Mapping-Start: "; + break; + case Token::TK_FlowMappingEnd: + OS << "Flow-Mapping-End: "; + break; + case Token::TK_Key: + OS << "Key: "; + break; + case Token::TK_Value: + OS << "Value: "; + break; + case Token::TK_Scalar: + OS << "Scalar: "; + break; + case Token::TK_Alias: + OS << "Alias: "; + break; + case Token::TK_Anchor: + OS << "Anchor: "; + break; + case Token::TK_Tag: + OS << "Tag: "; + break; + case Token::TK_Error: + break; + } + OS << T.Range << "\n"; + if (T.Kind == Token::TK_StreamEnd) + break; + else if (T.Kind == Token::TK_Error) + return false; + } + return true; +} + +bool yaml::scanTokens(StringRef Input) { + llvm::SourceMgr SM; + llvm::yaml::Scanner scanner(Input, SM); + for (;;) { + llvm::yaml::Token T = scanner.getNext(); + if (T.Kind == Token::TK_StreamEnd) + break; + else if (T.Kind == Token::TK_Error) + return false; + } + return true; +} + +std::string yaml::escape(StringRef Input) { + std::string EscapedInput; + for (StringRef::iterator i = Input.begin(), e = Input.end(); i != e; ++i) { + if (*i == '\\') + EscapedInput += "\\\\"; + else if (*i == '"') + EscapedInput += "\\\""; + else if (*i == 0) + EscapedInput += "\\0"; + else if (*i == 0x07) + EscapedInput += "\\a"; + else if (*i == 0x08) + EscapedInput += "\\b"; + else if (*i == 0x09) + EscapedInput += "\\t"; + else if (*i == 0x0A) + EscapedInput += "\\n"; + else if (*i == 0x0B) + EscapedInput += "\\v"; + else if (*i == 0x0C) + EscapedInput += "\\f"; + else if (*i == 0x0D) + EscapedInput += "\\r"; + else if (*i == 0x1B) + EscapedInput += "\\e"; + else if (*i >= 0 && *i < 0x20) { // Control characters not handled above. + std::string HexStr = utohexstr(*i); + EscapedInput += "\\x" + std::string(2 - HexStr.size(), '0') + HexStr; + } else if (*i & 0x80) { // UTF-8 multiple code unit subsequence. + UTF8Decoded UnicodeScalarValue + = decodeUTF8(StringRef(i, Input.end() - i)); + if (UnicodeScalarValue.second == 0) { + // Found invalid char. + SmallString<4> Val; + encodeUTF8(0xFFFD, Val); + EscapedInput.insert(EscapedInput.end(), Val.begin(), Val.end()); + // FIXME: Error reporting. + return EscapedInput; + } + if (UnicodeScalarValue.first == 0x85) + EscapedInput += "\\N"; + else if (UnicodeScalarValue.first == 0xA0) + EscapedInput += "\\_"; + else if (UnicodeScalarValue.first == 0x2028) + EscapedInput += "\\L"; + else if (UnicodeScalarValue.first == 0x2029) + EscapedInput += "\\P"; + else { + std::string HexStr = utohexstr(UnicodeScalarValue.first); + if (HexStr.size() <= 2) + EscapedInput += "\\x" + std::string(2 - HexStr.size(), '0') + HexStr; + else if (HexStr.size() <= 4) + EscapedInput += "\\u" + std::string(4 - HexStr.size(), '0') + HexStr; + else if (HexStr.size() <= 8) + EscapedInput += "\\U" + std::string(8 - HexStr.size(), '0') + HexStr; + } + i += UnicodeScalarValue.second - 1; + } else + EscapedInput.push_back(*i); + } + return EscapedInput; +} + +Scanner::Scanner(StringRef Input, SourceMgr &sm) + : SM(sm) + , Indent(-1) + , Column(0) + , Line(0) + , FlowLevel(0) + , IsStartOfStream(true) + , IsSimpleKeyAllowed(true) + , IsSimpleKeyRequired(false) + , Failed(false) { + InputBuffer = MemoryBuffer::getMemBuffer(Input, "YAML"); + SM.AddNewSourceBuffer(InputBuffer, SMLoc()); + Current = InputBuffer->getBufferStart(); + End = InputBuffer->getBufferEnd(); +} + +Token &Scanner::peekNext() { + // If the current token is a possible simple key, keep parsing until we + // can confirm. + bool NeedMore = false; + while (true) { + if (TokenQueue.empty() || NeedMore) { + if (!fetchMoreTokens()) { + TokenQueue.clear(); + TokenQueue.push_back(Token()); + return TokenQueue.front(); + } + } + assert(!TokenQueue.empty() && + "fetchMoreTokens lied about getting tokens!"); + + removeStaleSimpleKeyCandidates(); + SimpleKey SK; + SK.Tok = TokenQueue.front(); + if (std::find(SimpleKeys.begin(), SimpleKeys.end(), SK) + == SimpleKeys.end()) + break; + else + NeedMore = true; + } + return TokenQueue.front(); +} + +Token Scanner::getNext() { + Token Ret = peekNext(); + // TokenQueue can be empty if there was an error getting the next token. + if (!TokenQueue.empty()) + TokenQueue.pop_front(); + + // There cannot be any referenced Token's if the TokenQueue is empty. So do a + // quick deallocation of them all. + if (TokenQueue.empty()) { + TokenQueue.Alloc.Reset(); + } + + return Ret; +} + +StringRef::iterator Scanner::skip_nb_char(StringRef::iterator Position) { + // Check 7 bit c-printable - b-char. + if ( *Position == 0x09 + || (*Position >= 0x20 && *Position <= 0x7E)) + return Position + 1; + + // Check for valid UTF-8. + if (uint8_t(*Position) & 0x80) { + UTF8Decoded u8d = decodeUTF8(Position); + if ( u8d.second != 0 + && u8d.first != 0xFEFF + && ( u8d.first == 0x85 + || ( u8d.first >= 0xA0 + && u8d.first <= 0xD7FF) + || ( u8d.first >= 0xE000 + && u8d.first <= 0xFFFD) + || ( u8d.first >= 0x10000 + && u8d.first <= 0x10FFFF))) + return Position + u8d.second; + } + return Position; +} + +StringRef::iterator Scanner::skip_b_break(StringRef::iterator Position) { + if (*Position == 0x0D) { + if (Position + 1 != End && *(Position + 1) == 0x0A) + return Position + 2; + return Position + 1; + } + + if (*Position == 0x0A) + return Position + 1; + return Position; +} + + +StringRef::iterator Scanner::skip_s_white(StringRef::iterator Position) { + if (Position == End) + return Position; + if (*Position == ' ' || *Position == '\t') + return Position + 1; + return Position; +} + +StringRef::iterator Scanner::skip_ns_char(StringRef::iterator Position) { + if (Position == End) + return Position; + if (*Position == ' ' || *Position == '\t') + return Position; + return skip_nb_char(Position); +} + +StringRef::iterator Scanner::skip_while( SkipWhileFunc Func + , StringRef::iterator Position) { + while (true) { + StringRef::iterator i = (this->*Func)(Position); + if (i == Position) + break; + Position = i; + } + return Position; +} + +static bool is_ns_hex_digit(const char C) { + return (C >= '0' && C <= '9') + || (C >= 'a' && C <= 'z') + || (C >= 'A' && C <= 'Z'); +} + +static bool is_ns_word_char(const char C) { + return C == '-' + || (C >= 'a' && C <= 'z') + || (C >= 'A' && C <= 'Z'); +} + +StringRef Scanner::scan_ns_uri_char() { + StringRef::iterator Start = Current; + while (true) { + if (Current == End) + break; + if (( *Current == '%' + && Current + 2 < End + && is_ns_hex_digit(*(Current + 1)) + && is_ns_hex_digit(*(Current + 2))) + || is_ns_word_char(*Current) + || StringRef(Current, 1).find_first_of("#;/?:@&=+$,_.!~*'()[]") + != StringRef::npos) { + ++Current; + ++Column; + } else + break; + } + return StringRef(Start, Current - Start); +} + +StringRef Scanner::scan_ns_plain_one_line() { + StringRef::iterator start = Current; + // The first character must already be verified. + ++Current; + while (true) { + if (Current == End) { + break; + } else if (*Current == ':') { + // Check if the next character is a ns-char. + if (Current + 1 == End) + break; + StringRef::iterator i = skip_ns_char(Current + 1); + if (Current + 1 != i) { + Current = i; + Column += 2; // Consume both the ':' and ns-char. + } else + break; + } else if (*Current == '#') { + // Check if the previous character was a ns-char. + // The & 0x80 check is to check for the trailing byte of a utf-8 + if (*(Current - 1) & 0x80 || skip_ns_char(Current - 1) == Current) { + ++Current; + ++Column; + } else + break; + } else { + StringRef::iterator i = skip_nb_char(Current); + if (i == Current) + break; + Current = i; + ++Column; + } + } + return StringRef(start, Current - start); +} + +bool Scanner::consume(uint32_t Expected) { + if (Expected >= 0x80) + report_fatal_error("Not dealing with this yet"); + if (Current == End) + return false; + if (uint8_t(*Current) >= 0x80) + report_fatal_error("Not dealing with this yet"); + if (uint8_t(*Current) == Expected) { + ++Current; + ++Column; + return true; + } + return false; +} + +void Scanner::skip(uint32_t Distance) { + Current += Distance; + Column += Distance; +} + +bool Scanner::isBlankOrBreak(StringRef::iterator Position) { + if (Position == End) + return false; + if ( *Position == ' ' || *Position == '\t' + || *Position == '\r' || *Position == '\n') + return true; + return false; +} + +void Scanner::saveSimpleKeyCandidate( TokenQueueT::iterator Tok + , unsigned AtColumn + , bool IsRequired) { + if (IsSimpleKeyAllowed) { + SimpleKey SK; + SK.Tok = Tok; + SK.Line = Line; + SK.Column = AtColumn; + SK.IsRequired = IsRequired; + SK.FlowLevel = FlowLevel; + SimpleKeys.push_back(SK); + } +} + +void Scanner::removeStaleSimpleKeyCandidates() { + for (SmallVectorImpl<SimpleKey>::iterator i = SimpleKeys.begin(); + i != SimpleKeys.end();) { + if (i->Line != Line || i->Column + 1024 < Column) { + if (i->IsRequired) + setError( "Could not find expected : for simple key" + , i->Tok->Range.begin()); + i = SimpleKeys.erase(i); + } else + ++i; + } +} + +void Scanner::removeSimpleKeyCandidatesOnFlowLevel(unsigned Level) { + if (!SimpleKeys.empty() && (SimpleKeys.end() - 1)->FlowLevel == Level) + SimpleKeys.pop_back(); +} + +bool Scanner::unrollIndent(int ToColumn) { + Token T; + // Indentation is ignored in flow. + if (FlowLevel != 0) + return true; + + while (Indent > ToColumn) { + T.Kind = Token::TK_BlockEnd; + T.Range = StringRef(Current, 1); + TokenQueue.push_back(T); + Indent = Indents.pop_back_val(); + } + + return true; +} + +bool Scanner::rollIndent( int ToColumn + , Token::TokenKind Kind + , TokenQueueT::iterator InsertPoint) { + if (FlowLevel) + return true; + if (Indent < ToColumn) { + Indents.push_back(Indent); + Indent = ToColumn; + + Token T; + T.Kind = Kind; + T.Range = StringRef(Current, 0); + TokenQueue.insert(InsertPoint, T); + } + return true; +} + +void Scanner::scanToNextToken() { + while (true) { + while (*Current == ' ' || *Current == '\t') { + skip(1); + } + + // Skip comment. + if (*Current == '#') { + while (true) { + // This may skip more than one byte, thus Column is only incremented + // for code points. + StringRef::iterator i = skip_nb_char(Current); + if (i == Current) + break; + Current = i; + ++Column; + } + } + + // Skip EOL. + StringRef::iterator i = skip_b_break(Current); + if (i == Current) + break; + Current = i; + ++Line; + Column = 0; + // New lines may start a simple key. + if (!FlowLevel) + IsSimpleKeyAllowed = true; + } +} + +bool Scanner::scanStreamStart() { + IsStartOfStream = false; + + EncodingInfo EI = getUnicodeEncoding(currentInput()); + + Token T; + T.Kind = Token::TK_StreamStart; + T.Range = StringRef(Current, EI.second); + TokenQueue.push_back(T); + Current += EI.second; + return true; +} + +bool Scanner::scanStreamEnd() { + // Force an ending new line if one isn't present. + if (Column != 0) { + Column = 0; + ++Line; + } + + unrollIndent(-1); + SimpleKeys.clear(); + IsSimpleKeyAllowed = false; + + Token T; + T.Kind = Token::TK_StreamEnd; + T.Range = StringRef(Current, 0); + TokenQueue.push_back(T); + return true; +} + +bool Scanner::scanDirective() { + // Reset the indentation level. + unrollIndent(-1); + SimpleKeys.clear(); + IsSimpleKeyAllowed = false; + + StringRef::iterator Start = Current; + consume('%'); + StringRef::iterator NameStart = Current; + Current = skip_while(&Scanner::skip_ns_char, Current); + StringRef Name(NameStart, Current - NameStart); + Current = skip_while(&Scanner::skip_s_white, Current); + + if (Name == "YAML") { + Current = skip_while(&Scanner::skip_ns_char, Current); + Token T; + T.Kind = Token::TK_VersionDirective; + T.Range = StringRef(Start, Current - Start); + TokenQueue.push_back(T); + return true; + } + return false; +} + +bool Scanner::scanDocumentIndicator(bool IsStart) { + unrollIndent(-1); + SimpleKeys.clear(); + IsSimpleKeyAllowed = false; + + Token T; + T.Kind = IsStart ? Token::TK_DocumentStart : Token::TK_DocumentEnd; + T.Range = StringRef(Current, 3); + skip(3); + TokenQueue.push_back(T); + return true; +} + +bool Scanner::scanFlowCollectionStart(bool IsSequence) { + Token T; + T.Kind = IsSequence ? Token::TK_FlowSequenceStart + : Token::TK_FlowMappingStart; + T.Range = StringRef(Current, 1); + skip(1); + TokenQueue.push_back(T); + + // [ and { may begin a simple key. + saveSimpleKeyCandidate(TokenQueue.back(), Column - 1, false); + + // And may also be followed by a simple key. + IsSimpleKeyAllowed = true; + ++FlowLevel; + return true; +} + +bool Scanner::scanFlowCollectionEnd(bool IsSequence) { + removeSimpleKeyCandidatesOnFlowLevel(FlowLevel); + IsSimpleKeyAllowed = false; + Token T; + T.Kind = IsSequence ? Token::TK_FlowSequenceEnd + : Token::TK_FlowMappingEnd; + T.Range = StringRef(Current, 1); + skip(1); + TokenQueue.push_back(T); + if (FlowLevel) + --FlowLevel; + return true; +} + +bool Scanner::scanFlowEntry() { + removeSimpleKeyCandidatesOnFlowLevel(FlowLevel); + IsSimpleKeyAllowed = true; + Token T; + T.Kind = Token::TK_FlowEntry; + T.Range = StringRef(Current, 1); + skip(1); + TokenQueue.push_back(T); + return true; +} + +bool Scanner::scanBlockEntry() { + rollIndent(Column, Token::TK_BlockSequenceStart, TokenQueue.end()); + removeSimpleKeyCandidatesOnFlowLevel(FlowLevel); + IsSimpleKeyAllowed = true; + Token T; + T.Kind = Token::TK_BlockEntry; + T.Range = StringRef(Current, 1); + skip(1); + TokenQueue.push_back(T); + return true; +} + +bool Scanner::scanKey() { + if (!FlowLevel) + rollIndent(Column, Token::TK_BlockMappingStart, TokenQueue.end()); + + removeSimpleKeyCandidatesOnFlowLevel(FlowLevel); + IsSimpleKeyAllowed = !FlowLevel; + + Token T; + T.Kind = Token::TK_Key; + T.Range = StringRef(Current, 1); + skip(1); + TokenQueue.push_back(T); + return true; +} + +bool Scanner::scanValue() { + // If the previous token could have been a simple key, insert the key token + // into the token queue. + if (!SimpleKeys.empty()) { + SimpleKey SK = SimpleKeys.pop_back_val(); + Token T; + T.Kind = Token::TK_Key; + T.Range = SK.Tok->Range; + TokenQueueT::iterator i, e; + for (i = TokenQueue.begin(), e = TokenQueue.end(); i != e; ++i) { + if (i == SK.Tok) + break; + } + assert(i != e && "SimpleKey not in token queue!"); + i = TokenQueue.insert(i, T); + + // We may also need to add a Block-Mapping-Start token. + rollIndent(SK.Column, Token::TK_BlockMappingStart, i); + + IsSimpleKeyAllowed = false; + } else { + if (!FlowLevel) + rollIndent(Column, Token::TK_BlockMappingStart, TokenQueue.end()); + IsSimpleKeyAllowed = !FlowLevel; + } + + Token T; + T.Kind = Token::TK_Value; + T.Range = StringRef(Current, 1); + skip(1); + TokenQueue.push_back(T); + return true; +} + +// Forbidding inlining improves performance by roughly 20%. +// FIXME: Remove once llvm optimizes this to the faster version without hints. +LLVM_ATTRIBUTE_NOINLINE static bool +wasEscaped(StringRef::iterator First, StringRef::iterator Position); + +// Returns whether a character at 'Position' was escaped with a leading '\'. +// 'First' specifies the position of the first character in the string. +static bool wasEscaped(StringRef::iterator First, + StringRef::iterator Position) { + assert(Position - 1 >= First); + StringRef::iterator I = Position - 1; + // We calculate the number of consecutive '\'s before the current position + // by iterating backwards through our string. + while (I >= First && *I == '\\') --I; + // (Position - 1 - I) now contains the number of '\'s before the current + // position. If it is odd, the character at 'Position' was escaped. + return (Position - 1 - I) % 2 == 1; +} + +bool Scanner::scanFlowScalar(bool IsDoubleQuoted) { + StringRef::iterator Start = Current; + unsigned ColStart = Column; + if (IsDoubleQuoted) { + do { + ++Current; + while (Current != End && *Current != '"') + ++Current; + // Repeat until the previous character was not a '\' or was an escaped + // backslash. + } while (*(Current - 1) == '\\' && wasEscaped(Start + 1, Current)); + } else { + skip(1); + while (true) { + // Skip a ' followed by another '. + if (Current + 1 < End && *Current == '\'' && *(Current + 1) == '\'') { + skip(2); + continue; + } else if (*Current == '\'') + break; + StringRef::iterator i = skip_nb_char(Current); + if (i == Current) { + i = skip_b_break(Current); + if (i == Current) + break; + Current = i; + Column = 0; + ++Line; + } else { + if (i == End) + break; + Current = i; + ++Column; + } + } + } + skip(1); // Skip ending quote. + Token T; + T.Kind = Token::TK_Scalar; + T.Range = StringRef(Start, Current - Start); + TokenQueue.push_back(T); + + saveSimpleKeyCandidate(TokenQueue.back(), ColStart, false); + + IsSimpleKeyAllowed = false; + + return true; +} + +bool Scanner::scanPlainScalar() { + StringRef::iterator Start = Current; + unsigned ColStart = Column; + unsigned LeadingBlanks = 0; + assert(Indent >= -1 && "Indent must be >= -1 !"); + unsigned indent = static_cast<unsigned>(Indent + 1); + while (true) { + if (*Current == '#') + break; + + while (!isBlankOrBreak(Current)) { + if ( FlowLevel && *Current == ':' + && !(isBlankOrBreak(Current + 1) || *(Current + 1) == ',')) { + setError("Found unexpected ':' while scanning a plain scalar", Current); + return false; + } + + // Check for the end of the plain scalar. + if ( (*Current == ':' && isBlankOrBreak(Current + 1)) + || ( FlowLevel + && (StringRef(Current, 1).find_first_of(",:?[]{}") + != StringRef::npos))) + break; + + StringRef::iterator i = skip_nb_char(Current); + if (i == Current) + break; + Current = i; + ++Column; + } + + // Are we at the end? + if (!isBlankOrBreak(Current)) + break; + + // Eat blanks. + StringRef::iterator Tmp = Current; + while (isBlankOrBreak(Tmp)) { + StringRef::iterator i = skip_s_white(Tmp); + if (i != Tmp) { + if (LeadingBlanks && (Column < indent) && *Tmp == '\t') { + setError("Found invalid tab character in indentation", Tmp); + return false; + } + Tmp = i; + ++Column; + } else { + i = skip_b_break(Tmp); + if (!LeadingBlanks) + LeadingBlanks = 1; + Tmp = i; + Column = 0; + ++Line; + } + } + + if (!FlowLevel && Column < indent) + break; + + Current = Tmp; + } + if (Start == Current) { + setError("Got empty plain scalar", Start); + return false; + } + Token T; + T.Kind = Token::TK_Scalar; + T.Range = StringRef(Start, Current - Start); + TokenQueue.push_back(T); + + // Plain scalars can be simple keys. + saveSimpleKeyCandidate(TokenQueue.back(), ColStart, false); + + IsSimpleKeyAllowed = false; + + return true; +} + +bool Scanner::scanAliasOrAnchor(bool IsAlias) { + StringRef::iterator Start = Current; + unsigned ColStart = Column; + skip(1); + while(true) { + if ( *Current == '[' || *Current == ']' + || *Current == '{' || *Current == '}' + || *Current == ',' + || *Current == ':') + break; + StringRef::iterator i = skip_ns_char(Current); + if (i == Current) + break; + Current = i; + ++Column; + } + + if (Start == Current) { + setError("Got empty alias or anchor", Start); + return false; + } + + Token T; + T.Kind = IsAlias ? Token::TK_Alias : Token::TK_Anchor; + T.Range = StringRef(Start, Current - Start); + TokenQueue.push_back(T); + + // Alias and anchors can be simple keys. + saveSimpleKeyCandidate(TokenQueue.back(), ColStart, false); + + IsSimpleKeyAllowed = false; + + return true; +} + +bool Scanner::scanBlockScalar(bool IsLiteral) { + StringRef::iterator Start = Current; + skip(1); // Eat | or > + while(true) { + StringRef::iterator i = skip_nb_char(Current); + if (i == Current) { + if (Column == 0) + break; + i = skip_b_break(Current); + if (i != Current) { + // We got a line break. + Column = 0; + ++Line; + Current = i; + continue; + } else { + // There was an error, which should already have been printed out. + return false; + } + } + Current = i; + ++Column; + } + + if (Start == Current) { + setError("Got empty block scalar", Start); + return false; + } + + Token T; + T.Kind = Token::TK_Scalar; + T.Range = StringRef(Start, Current - Start); + TokenQueue.push_back(T); + return true; +} + +bool Scanner::scanTag() { + StringRef::iterator Start = Current; + unsigned ColStart = Column; + skip(1); // Eat !. + if (Current == End || isBlankOrBreak(Current)); // An empty tag. + else if (*Current == '<') { + skip(1); + scan_ns_uri_char(); + if (!consume('>')) + return false; + } else { + // FIXME: Actually parse the c-ns-shorthand-tag rule. + Current = skip_while(&Scanner::skip_ns_char, Current); + } + + Token T; + T.Kind = Token::TK_Tag; + T.Range = StringRef(Start, Current - Start); + TokenQueue.push_back(T); + + // Tags can be simple keys. + saveSimpleKeyCandidate(TokenQueue.back(), ColStart, false); + + IsSimpleKeyAllowed = false; + + return true; +} + +bool Scanner::fetchMoreTokens() { + if (IsStartOfStream) + return scanStreamStart(); + + scanToNextToken(); + + if (Current == End) + return scanStreamEnd(); + + removeStaleSimpleKeyCandidates(); + + unrollIndent(Column); + + if (Column == 0 && *Current == '%') + return scanDirective(); + + if (Column == 0 && Current + 4 <= End + && *Current == '-' + && *(Current + 1) == '-' + && *(Current + 2) == '-' + && (Current + 3 == End || isBlankOrBreak(Current + 3))) + return scanDocumentIndicator(true); + + if (Column == 0 && Current + 4 <= End + && *Current == '.' + && *(Current + 1) == '.' + && *(Current + 2) == '.' + && (Current + 3 == End || isBlankOrBreak(Current + 3))) + return scanDocumentIndicator(false); + + if (*Current == '[') + return scanFlowCollectionStart(true); + + if (*Current == '{') + return scanFlowCollectionStart(false); + + if (*Current == ']') + return scanFlowCollectionEnd(true); + + if (*Current == '}') + return scanFlowCollectionEnd(false); + + if (*Current == ',') + return scanFlowEntry(); + + if (*Current == '-' && isBlankOrBreak(Current + 1)) + return scanBlockEntry(); + + if (*Current == '?' && (FlowLevel || isBlankOrBreak(Current + 1))) + return scanKey(); + + if (*Current == ':' && (FlowLevel || isBlankOrBreak(Current + 1))) + return scanValue(); + + if (*Current == '*') + return scanAliasOrAnchor(true); + + if (*Current == '&') + return scanAliasOrAnchor(false); + + if (*Current == '!') + return scanTag(); + + if (*Current == '|' && !FlowLevel) + return scanBlockScalar(true); + + if (*Current == '>' && !FlowLevel) + return scanBlockScalar(false); + + if (*Current == '\'') + return scanFlowScalar(false); + + if (*Current == '"') + return scanFlowScalar(true); + + // Get a plain scalar. + StringRef FirstChar(Current, 1); + if (!(isBlankOrBreak(Current) + || FirstChar.find_first_of("-?:,[]{}#&*!|>'\"%@`") != StringRef::npos) + || (*Current == '-' && !isBlankOrBreak(Current + 1)) + || (!FlowLevel && (*Current == '?' || *Current == ':') + && isBlankOrBreak(Current + 1)) + || (!FlowLevel && *Current == ':' + && Current + 2 < End + && *(Current + 1) == ':' + && !isBlankOrBreak(Current + 2))) + return scanPlainScalar(); + + setError("Unrecognized character while tokenizing."); + return false; +} + +Stream::Stream(StringRef Input, SourceMgr &SM) + : scanner(new Scanner(Input, SM)) + , CurrentDoc(0) {} + +Stream::~Stream() {} + +bool Stream::failed() { return scanner->failed(); } + +void Stream::printError(Node *N, const Twine &Msg) { + SmallVector<SMRange, 1> Ranges; + Ranges.push_back(N->getSourceRange()); + scanner->printError( N->getSourceRange().Start + , SourceMgr::DK_Error + , Msg + , Ranges); +} + +void Stream::handleYAMLDirective(const Token &t) { + // TODO: Ensure version is 1.x. +} + +document_iterator Stream::begin() { + if (CurrentDoc) + report_fatal_error("Can only iterate over the stream once"); + + // Skip Stream-Start. + scanner->getNext(); + + CurrentDoc.reset(new Document(*this)); + return document_iterator(CurrentDoc); +} + +document_iterator Stream::end() { + return document_iterator(); +} + +void Stream::skip() { + for (document_iterator i = begin(), e = end(); i != e; ++i) + i->skip(); +} + +Node::Node(unsigned int Type, OwningPtr<Document> &D, StringRef A) + : Doc(D) + , TypeID(Type) + , Anchor(A) { + SMLoc Start = SMLoc::getFromPointer(peekNext().Range.begin()); + SourceRange = SMRange(Start, Start); +} + +Token &Node::peekNext() { + return Doc->peekNext(); +} + +Token Node::getNext() { + return Doc->getNext(); +} + +Node *Node::parseBlockNode() { + return Doc->parseBlockNode(); +} + +BumpPtrAllocator &Node::getAllocator() { + return Doc->NodeAllocator; +} + +void Node::setError(const Twine &Msg, Token &Tok) const { + Doc->setError(Msg, Tok); +} + +bool Node::failed() const { + return Doc->failed(); +} + + + +StringRef ScalarNode::getValue(SmallVectorImpl<char> &Storage) const { + // TODO: Handle newlines properly. We need to remove leading whitespace. + if (Value[0] == '"') { // Double quoted. + // Pull off the leading and trailing "s. + StringRef UnquotedValue = Value.substr(1, Value.size() - 2); + // Search for characters that would require unescaping the value. + StringRef::size_type i = UnquotedValue.find_first_of("\\\r\n"); + if (i != StringRef::npos) + return unescapeDoubleQuoted(UnquotedValue, i, Storage); + return UnquotedValue; + } else if (Value[0] == '\'') { // Single quoted. + // Pull off the leading and trailing 's. + StringRef UnquotedValue = Value.substr(1, Value.size() - 2); + StringRef::size_type i = UnquotedValue.find('\''); + if (i != StringRef::npos) { + // We're going to need Storage. + Storage.clear(); + Storage.reserve(UnquotedValue.size()); + for (; i != StringRef::npos; i = UnquotedValue.find('\'')) { + StringRef Valid(UnquotedValue.begin(), i); + Storage.insert(Storage.end(), Valid.begin(), Valid.end()); + Storage.push_back('\''); + UnquotedValue = UnquotedValue.substr(i + 2); + } + Storage.insert(Storage.end(), UnquotedValue.begin(), UnquotedValue.end()); + return StringRef(Storage.begin(), Storage.size()); + } + return UnquotedValue; + } + // Plain or block. + size_t trimtrail = Value.rfind(' '); + return Value.drop_back( + trimtrail == StringRef::npos ? 0 : Value.size() - trimtrail); +} + +StringRef ScalarNode::unescapeDoubleQuoted( StringRef UnquotedValue + , StringRef::size_type i + , SmallVectorImpl<char> &Storage) + const { + // Use Storage to build proper value. + Storage.clear(); + Storage.reserve(UnquotedValue.size()); + for (; i != StringRef::npos; i = UnquotedValue.find_first_of("\\\r\n")) { + // Insert all previous chars into Storage. + StringRef Valid(UnquotedValue.begin(), i); + Storage.insert(Storage.end(), Valid.begin(), Valid.end()); + // Chop off inserted chars. + UnquotedValue = UnquotedValue.substr(i); + + assert(!UnquotedValue.empty() && "Can't be empty!"); + + // Parse escape or line break. + switch (UnquotedValue[0]) { + case '\r': + case '\n': + Storage.push_back('\n'); + if ( UnquotedValue.size() > 1 + && (UnquotedValue[1] == '\r' || UnquotedValue[1] == '\n')) + UnquotedValue = UnquotedValue.substr(1); + UnquotedValue = UnquotedValue.substr(1); + break; + default: + if (UnquotedValue.size() == 1) + // TODO: Report error. + break; + UnquotedValue = UnquotedValue.substr(1); + switch (UnquotedValue[0]) { + default: { + Token T; + T.Range = StringRef(UnquotedValue.begin(), 1); + setError("Unrecognized escape code!", T); + return ""; + } + case '\r': + case '\n': + // Remove the new line. + if ( UnquotedValue.size() > 1 + && (UnquotedValue[1] == '\r' || UnquotedValue[1] == '\n')) + UnquotedValue = UnquotedValue.substr(1); + // If this was just a single byte newline, it will get skipped + // below. + break; + case '0': + Storage.push_back(0x00); + break; + case 'a': + Storage.push_back(0x07); + break; + case 'b': + Storage.push_back(0x08); + break; + case 't': + case 0x09: + Storage.push_back(0x09); + break; + case 'n': + Storage.push_back(0x0A); + break; + case 'v': + Storage.push_back(0x0B); + break; + case 'f': + Storage.push_back(0x0C); + break; + case 'r': + Storage.push_back(0x0D); + break; + case 'e': + Storage.push_back(0x1B); + break; + case ' ': + Storage.push_back(0x20); + break; + case '"': + Storage.push_back(0x22); + break; + case '/': + Storage.push_back(0x2F); + break; + case '\\': + Storage.push_back(0x5C); + break; + case 'N': + encodeUTF8(0x85, Storage); + break; + case '_': + encodeUTF8(0xA0, Storage); + break; + case 'L': + encodeUTF8(0x2028, Storage); + break; + case 'P': + encodeUTF8(0x2029, Storage); + break; + case 'x': { + if (UnquotedValue.size() < 3) + // TODO: Report error. + break; + unsigned int UnicodeScalarValue; + UnquotedValue.substr(1, 2).getAsInteger(16, UnicodeScalarValue); + encodeUTF8(UnicodeScalarValue, Storage); + UnquotedValue = UnquotedValue.substr(2); + break; + } + case 'u': { + if (UnquotedValue.size() < 5) + // TODO: Report error. + break; + unsigned int UnicodeScalarValue; + UnquotedValue.substr(1, 4).getAsInteger(16, UnicodeScalarValue); + encodeUTF8(UnicodeScalarValue, Storage); + UnquotedValue = UnquotedValue.substr(4); + break; + } + case 'U': { + if (UnquotedValue.size() < 9) + // TODO: Report error. + break; + unsigned int UnicodeScalarValue; + UnquotedValue.substr(1, 8).getAsInteger(16, UnicodeScalarValue); + encodeUTF8(UnicodeScalarValue, Storage); + UnquotedValue = UnquotedValue.substr(8); + break; + } + } + UnquotedValue = UnquotedValue.substr(1); + } + } + Storage.insert(Storage.end(), UnquotedValue.begin(), UnquotedValue.end()); + return StringRef(Storage.begin(), Storage.size()); +} + +Node *KeyValueNode::getKey() { + if (Key) + return Key; + // Handle implicit null keys. + { + Token &t = peekNext(); + if ( t.Kind == Token::TK_BlockEnd + || t.Kind == Token::TK_Value + || t.Kind == Token::TK_Error) { + return Key = new (getAllocator()) NullNode(Doc); + } + if (t.Kind == Token::TK_Key) + getNext(); // skip TK_Key. + } + + // Handle explicit null keys. + Token &t = peekNext(); + if (t.Kind == Token::TK_BlockEnd || t.Kind == Token::TK_Value) { + return Key = new (getAllocator()) NullNode(Doc); + } + + // We've got a normal key. + return Key = parseBlockNode(); +} + +Node *KeyValueNode::getValue() { + if (Value) + return Value; + getKey()->skip(); + if (failed()) + return Value = new (getAllocator()) NullNode(Doc); + + // Handle implicit null values. + { + Token &t = peekNext(); + if ( t.Kind == Token::TK_BlockEnd + || t.Kind == Token::TK_FlowMappingEnd + || t.Kind == Token::TK_Key + || t.Kind == Token::TK_FlowEntry + || t.Kind == Token::TK_Error) { + return Value = new (getAllocator()) NullNode(Doc); + } + + if (t.Kind != Token::TK_Value) { + setError("Unexpected token in Key Value.", t); + return Value = new (getAllocator()) NullNode(Doc); + } + getNext(); // skip TK_Value. + } + + // Handle explicit null values. + Token &t = peekNext(); + if (t.Kind == Token::TK_BlockEnd || t.Kind == Token::TK_Key) { + return Value = new (getAllocator()) NullNode(Doc); + } + + // We got a normal value. + return Value = parseBlockNode(); +} + +void MappingNode::increment() { + if (failed()) { + IsAtEnd = true; + CurrentEntry = 0; + return; + } + if (CurrentEntry) { + CurrentEntry->skip(); + if (Type == MT_Inline) { + IsAtEnd = true; + CurrentEntry = 0; + return; + } + } + Token T = peekNext(); + if (T.Kind == Token::TK_Key || T.Kind == Token::TK_Scalar) { + // KeyValueNode eats the TK_Key. That way it can detect null keys. + CurrentEntry = new (getAllocator()) KeyValueNode(Doc); + } else if (Type == MT_Block) { + switch (T.Kind) { + case Token::TK_BlockEnd: + getNext(); + IsAtEnd = true; + CurrentEntry = 0; + break; + default: + setError("Unexpected token. Expected Key or Block End", T); + case Token::TK_Error: + IsAtEnd = true; + CurrentEntry = 0; + } + } else { + switch (T.Kind) { + case Token::TK_FlowEntry: + // Eat the flow entry and recurse. + getNext(); + return increment(); + case Token::TK_FlowMappingEnd: + getNext(); + case Token::TK_Error: + // Set this to end iterator. + IsAtEnd = true; + CurrentEntry = 0; + break; + default: + setError( "Unexpected token. Expected Key, Flow Entry, or Flow " + "Mapping End." + , T); + IsAtEnd = true; + CurrentEntry = 0; + } + } +} + +void SequenceNode::increment() { + if (failed()) { + IsAtEnd = true; + CurrentEntry = 0; + return; + } + if (CurrentEntry) + CurrentEntry->skip(); + Token T = peekNext(); + if (SeqType == ST_Block) { + switch (T.Kind) { + case Token::TK_BlockEntry: + getNext(); + CurrentEntry = parseBlockNode(); + if (CurrentEntry == 0) { // An error occurred. + IsAtEnd = true; + CurrentEntry = 0; + } + break; + case Token::TK_BlockEnd: + getNext(); + IsAtEnd = true; + CurrentEntry = 0; + break; + default: + setError( "Unexpected token. Expected Block Entry or Block End." + , T); + case Token::TK_Error: + IsAtEnd = true; + CurrentEntry = 0; + } + } else if (SeqType == ST_Indentless) { + switch (T.Kind) { + case Token::TK_BlockEntry: + getNext(); + CurrentEntry = parseBlockNode(); + if (CurrentEntry == 0) { // An error occurred. + IsAtEnd = true; + CurrentEntry = 0; + } + break; + default: + case Token::TK_Error: + IsAtEnd = true; + CurrentEntry = 0; + } + } else if (SeqType == ST_Flow) { + switch (T.Kind) { + case Token::TK_FlowEntry: + // Eat the flow entry and recurse. + getNext(); + WasPreviousTokenFlowEntry = true; + return increment(); + case Token::TK_FlowSequenceEnd: + getNext(); + case Token::TK_Error: + // Set this to end iterator. + IsAtEnd = true; + CurrentEntry = 0; + break; + case Token::TK_StreamEnd: + case Token::TK_DocumentEnd: + case Token::TK_DocumentStart: + setError("Could not find closing ]!", T); + // Set this to end iterator. + IsAtEnd = true; + CurrentEntry = 0; + break; + default: + if (!WasPreviousTokenFlowEntry) { + setError("Expected , between entries!", T); + IsAtEnd = true; + CurrentEntry = 0; + break; + } + // Otherwise it must be a flow entry. + CurrentEntry = parseBlockNode(); + if (!CurrentEntry) { + IsAtEnd = true; + } + WasPreviousTokenFlowEntry = false; + break; + } + } +} + +Document::Document(Stream &S) : stream(S), Root(0) { + if (parseDirectives()) + expectToken(Token::TK_DocumentStart); + Token &T = peekNext(); + if (T.Kind == Token::TK_DocumentStart) + getNext(); +} + +bool Document::skip() { + if (stream.scanner->failed()) + return false; + if (!Root) + getRoot(); + Root->skip(); + Token &T = peekNext(); + if (T.Kind == Token::TK_StreamEnd) + return false; + if (T.Kind == Token::TK_DocumentEnd) { + getNext(); + return skip(); + } + return true; +} + +Token &Document::peekNext() { + return stream.scanner->peekNext(); +} + +Token Document::getNext() { + return stream.scanner->getNext(); +} + +void Document::setError(const Twine &Message, Token &Location) const { + stream.scanner->setError(Message, Location.Range.begin()); +} + +bool Document::failed() const { + return stream.scanner->failed(); +} + +Node *Document::parseBlockNode() { + Token T = peekNext(); + // Handle properties. + Token AnchorInfo; +parse_property: + switch (T.Kind) { + case Token::TK_Alias: + getNext(); + return new (NodeAllocator) AliasNode(stream.CurrentDoc, T.Range.substr(1)); + case Token::TK_Anchor: + if (AnchorInfo.Kind == Token::TK_Anchor) { + setError("Already encountered an anchor for this node!", T); + return 0; + } + AnchorInfo = getNext(); // Consume TK_Anchor. + T = peekNext(); + goto parse_property; + case Token::TK_Tag: + getNext(); // Skip TK_Tag. + T = peekNext(); + goto parse_property; + default: + break; + } + + switch (T.Kind) { + case Token::TK_BlockEntry: + // We got an unindented BlockEntry sequence. This is not terminated with + // a BlockEnd. + // Don't eat the TK_BlockEntry, SequenceNode needs it. + return new (NodeAllocator) SequenceNode( stream.CurrentDoc + , AnchorInfo.Range.substr(1) + , SequenceNode::ST_Indentless); + case Token::TK_BlockSequenceStart: + getNext(); + return new (NodeAllocator) + SequenceNode( stream.CurrentDoc + , AnchorInfo.Range.substr(1) + , SequenceNode::ST_Block); + case Token::TK_BlockMappingStart: + getNext(); + return new (NodeAllocator) + MappingNode( stream.CurrentDoc + , AnchorInfo.Range.substr(1) + , MappingNode::MT_Block); + case Token::TK_FlowSequenceStart: + getNext(); + return new (NodeAllocator) + SequenceNode( stream.CurrentDoc + , AnchorInfo.Range.substr(1) + , SequenceNode::ST_Flow); + case Token::TK_FlowMappingStart: + getNext(); + return new (NodeAllocator) + MappingNode( stream.CurrentDoc + , AnchorInfo.Range.substr(1) + , MappingNode::MT_Flow); + case Token::TK_Scalar: + getNext(); + return new (NodeAllocator) + ScalarNode( stream.CurrentDoc + , AnchorInfo.Range.substr(1) + , T.Range); + case Token::TK_Key: + // Don't eat the TK_Key, KeyValueNode expects it. + return new (NodeAllocator) + MappingNode( stream.CurrentDoc + , AnchorInfo.Range.substr(1) + , MappingNode::MT_Inline); + case Token::TK_DocumentStart: + case Token::TK_DocumentEnd: + case Token::TK_StreamEnd: + default: + // TODO: Properly handle tags. "[!!str ]" should resolve to !!str "", not + // !!null null. + return new (NodeAllocator) NullNode(stream.CurrentDoc); + case Token::TK_Error: + return 0; + } + llvm_unreachable("Control flow shouldn't reach here."); + return 0; +} + +bool Document::parseDirectives() { + bool isDirective = false; + while (true) { + Token T = peekNext(); + if (T.Kind == Token::TK_TagDirective) { + handleTagDirective(getNext()); + isDirective = true; + } else if (T.Kind == Token::TK_VersionDirective) { + stream.handleYAMLDirective(getNext()); + isDirective = true; + } else + break; + } + return isDirective; +} + +bool Document::expectToken(int TK) { + Token T = getNext(); + if (T.Kind != TK) { + setError("Unexpected token", T); + return false; + } + return true; +} + +OwningPtr<Document> document_iterator::NullDoc; diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp index 4927e9a7b9d4..72d3986f41dd 100644 --- a/lib/Support/raw_ostream.cpp +++ b/lib/Support/raw_ostream.cpp @@ -20,6 +20,7 @@ #include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/system_error.h" #include "llvm/ADT/STLExtras.h" #include <cctype> #include <cerrno> |