diff options
Diffstat (limited to 'contrib/llvm/lib/Support')
114 files changed, 33204 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Support/APFloat.cpp b/contrib/llvm/lib/Support/APFloat.cpp new file mode 100644 index 0000000..409d4fb --- /dev/null +++ b/contrib/llvm/lib/Support/APFloat.cpp @@ -0,0 +1,3606 @@ +//===-- APFloat.cpp - Implement APFloat class -----------------------------===// +// +// 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 class to represent arbitrary precision floating +// point values and provide a variety of arithmetic operations on them. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APSInt.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> +#include <cstring> + +using namespace llvm; + +#define convolve(lhs, rhs) ((lhs) * 4 + (rhs)) + +/* Assumed in hexadecimal significand parsing, and conversion to + hexadecimal strings. */ +#define COMPILE_TIME_ASSERT(cond) extern int CTAssert[(cond) ? 1 : -1] +COMPILE_TIME_ASSERT(integerPartWidth % 4 == 0); + +namespace llvm { + + /* Represents floating point arithmetic semantics. */ + struct fltSemantics { + /* The largest E such that 2^E is representable; this matches the + definition of IEEE 754. */ + exponent_t maxExponent; + + /* The smallest E such that 2^E is a normalized number; this + matches the definition of IEEE 754. */ + exponent_t minExponent; + + /* Number of bits in the significand. This includes the integer + bit. */ + unsigned int precision; + + /* True if arithmetic is supported. */ + unsigned int arithmeticOK; + }; + + const fltSemantics APFloat::IEEEhalf = { 15, -14, 11, true }; + const fltSemantics APFloat::IEEEsingle = { 127, -126, 24, true }; + const fltSemantics APFloat::IEEEdouble = { 1023, -1022, 53, true }; + const fltSemantics APFloat::IEEEquad = { 16383, -16382, 113, true }; + const fltSemantics APFloat::x87DoubleExtended = { 16383, -16382, 64, true }; + const fltSemantics APFloat::Bogus = { 0, 0, 0, true }; + + // The PowerPC format consists of two doubles. It does not map cleanly + // onto the usual format above. For now only storage of constants of + // this type is supported, no arithmetic. + const fltSemantics APFloat::PPCDoubleDouble = { 1023, -1022, 106, false }; + + /* A tight upper bound on number of parts required to hold the value + pow(5, power) is + + power * 815 / (351 * integerPartWidth) + 1 + + However, whilst the result may require only this many parts, + because we are multiplying two values to get it, the + multiplication may require an extra part with the excess part + being zero (consider the trivial case of 1 * 1, tcFullMultiply + requires two parts to hold the single-part result). So we add an + extra one to guarantee enough space whilst multiplying. */ + const unsigned int maxExponent = 16383; + const unsigned int maxPrecision = 113; + const unsigned int maxPowerOfFiveExponent = maxExponent + maxPrecision - 1; + const unsigned int maxPowerOfFiveParts = 2 + ((maxPowerOfFiveExponent * 815) + / (351 * integerPartWidth)); +} + +/* A bunch of private, handy routines. */ + +static inline unsigned int +partCountForBits(unsigned int bits) +{ + return ((bits) + integerPartWidth - 1) / integerPartWidth; +} + +/* Returns 0U-9U. Return values >= 10U are not digits. */ +static inline unsigned int +decDigitValue(unsigned int c) +{ + return c - '0'; +} + +static unsigned int +hexDigitValue(unsigned int c) +{ + unsigned int r; + + r = c - '0'; + if (r <= 9) + return r; + + r = c - 'A'; + if (r <= 5) + return r + 10; + + r = c - 'a'; + if (r <= 5) + return r + 10; + + return -1U; +} + +static inline void +assertArithmeticOK(const llvm::fltSemantics &semantics) { + assert(semantics.arithmeticOK && + "Compile-time arithmetic does not support these semantics"); +} + +/* Return the value of a decimal exponent of the form + [+-]ddddddd. + + If the exponent overflows, returns a large exponent with the + appropriate sign. */ +static int +readExponent(StringRef::iterator begin, StringRef::iterator end) +{ + bool isNegative; + unsigned int absExponent; + const unsigned int overlargeExponent = 24000; /* FIXME. */ + StringRef::iterator p = begin; + + assert(p != end && "Exponent has no digits"); + + isNegative = (*p == '-'); + if (*p == '-' || *p == '+') { + p++; + assert(p != end && "Exponent has no digits"); + } + + absExponent = decDigitValue(*p++); + assert(absExponent < 10U && "Invalid character in exponent"); + + for (; p != end; ++p) { + unsigned int value; + + value = decDigitValue(*p); + assert(value < 10U && "Invalid character in exponent"); + + value += absExponent * 10; + if (absExponent >= overlargeExponent) { + absExponent = overlargeExponent; + p = end; /* outwit assert below */ + break; + } + absExponent = value; + } + + assert(p == end && "Invalid exponent in exponent"); + + if (isNegative) + return -(int) absExponent; + else + return (int) absExponent; +} + +/* This is ugly and needs cleaning up, but I don't immediately see + how whilst remaining safe. */ +static int +totalExponent(StringRef::iterator p, StringRef::iterator end, + int exponentAdjustment) +{ + int unsignedExponent; + bool negative, overflow; + int exponent = 0; + + assert(p != end && "Exponent has no digits"); + + negative = *p == '-'; + if (*p == '-' || *p == '+') { + p++; + assert(p != end && "Exponent has no digits"); + } + + unsignedExponent = 0; + overflow = false; + for (; p != end; ++p) { + unsigned int value; + + value = decDigitValue(*p); + assert(value < 10U && "Invalid character in exponent"); + + unsignedExponent = unsignedExponent * 10 + value; + if (unsignedExponent > 32767) + overflow = true; + } + + if (exponentAdjustment > 32767 || exponentAdjustment < -32768) + overflow = true; + + if (!overflow) { + exponent = unsignedExponent; + if (negative) + exponent = -exponent; + exponent += exponentAdjustment; + if (exponent > 32767 || exponent < -32768) + overflow = true; + } + + if (overflow) + exponent = negative ? -32768: 32767; + + return exponent; +} + +static StringRef::iterator +skipLeadingZeroesAndAnyDot(StringRef::iterator begin, StringRef::iterator end, + StringRef::iterator *dot) +{ + StringRef::iterator p = begin; + *dot = end; + while (*p == '0' && p != end) + p++; + + if (*p == '.') { + *dot = p++; + + assert(end - begin != 1 && "Significand has no digits"); + + while (*p == '0' && p != end) + p++; + } + + return p; +} + +/* Given a normal decimal floating point number of the form + + dddd.dddd[eE][+-]ddd + + where the decimal point and exponent are optional, fill out the + structure D. Exponent is appropriate if the significand is + treated as an integer, and normalizedExponent if the significand + is taken to have the decimal point after a single leading + non-zero digit. + + If the value is zero, V->firstSigDigit points to a non-digit, and + the return exponent is zero. +*/ +struct decimalInfo { + const char *firstSigDigit; + const char *lastSigDigit; + int exponent; + int normalizedExponent; +}; + +static void +interpretDecimal(StringRef::iterator begin, StringRef::iterator end, + decimalInfo *D) +{ + StringRef::iterator dot = end; + StringRef::iterator p = skipLeadingZeroesAndAnyDot (begin, end, &dot); + + D->firstSigDigit = p; + D->exponent = 0; + D->normalizedExponent = 0; + + for (; p != end; ++p) { + if (*p == '.') { + assert(dot == end && "String contains multiple dots"); + dot = p++; + if (p == end) + break; + } + if (decDigitValue(*p) >= 10U) + break; + } + + if (p != end) { + assert((*p == 'e' || *p == 'E') && "Invalid character in significand"); + assert(p != begin && "Significand has no digits"); + assert((dot == end || p - begin != 1) && "Significand has no digits"); + + /* p points to the first non-digit in the string */ + D->exponent = readExponent(p + 1, end); + + /* Implied decimal point? */ + if (dot == end) + dot = p; + } + + /* If number is all zeroes accept any exponent. */ + if (p != D->firstSigDigit) { + /* Drop insignificant trailing zeroes. */ + if (p != begin) { + do + do + p--; + while (p != begin && *p == '0'); + while (p != begin && *p == '.'); + } + + /* Adjust the exponents for any decimal point. */ + D->exponent += static_cast<exponent_t>((dot - p) - (dot > p)); + D->normalizedExponent = (D->exponent + + static_cast<exponent_t>((p - D->firstSigDigit) + - (dot > D->firstSigDigit && dot < p))); + } + + D->lastSigDigit = p; +} + +/* Return the trailing fraction of a hexadecimal number. + DIGITVALUE is the first hex digit of the fraction, P points to + the next digit. */ +static lostFraction +trailingHexadecimalFraction(StringRef::iterator p, StringRef::iterator end, + unsigned int digitValue) +{ + unsigned int hexDigit; + + /* If the first trailing digit isn't 0 or 8 we can work out the + fraction immediately. */ + if (digitValue > 8) + return lfMoreThanHalf; + else if (digitValue < 8 && digitValue > 0) + return lfLessThanHalf; + + /* Otherwise we need to find the first non-zero digit. */ + while (*p == '0') + p++; + + assert(p != end && "Invalid trailing hexadecimal fraction!"); + + hexDigit = hexDigitValue(*p); + + /* If we ran off the end it is exactly zero or one-half, otherwise + a little more. */ + if (hexDigit == -1U) + return digitValue == 0 ? lfExactlyZero: lfExactlyHalf; + else + return digitValue == 0 ? lfLessThanHalf: lfMoreThanHalf; +} + +/* Return the fraction lost were a bignum truncated losing the least + significant BITS bits. */ +static lostFraction +lostFractionThroughTruncation(const integerPart *parts, + unsigned int partCount, + unsigned int bits) +{ + unsigned int lsb; + + lsb = APInt::tcLSB(parts, partCount); + + /* Note this is guaranteed true if bits == 0, or LSB == -1U. */ + if (bits <= lsb) + return lfExactlyZero; + if (bits == lsb + 1) + return lfExactlyHalf; + if (bits <= partCount * integerPartWidth && + APInt::tcExtractBit(parts, bits - 1)) + return lfMoreThanHalf; + + return lfLessThanHalf; +} + +/* Shift DST right BITS bits noting lost fraction. */ +static lostFraction +shiftRight(integerPart *dst, unsigned int parts, unsigned int bits) +{ + lostFraction lost_fraction; + + lost_fraction = lostFractionThroughTruncation(dst, parts, bits); + + APInt::tcShiftRight(dst, parts, bits); + + return lost_fraction; +} + +/* Combine the effect of two lost fractions. */ +static lostFraction +combineLostFractions(lostFraction moreSignificant, + lostFraction lessSignificant) +{ + if (lessSignificant != lfExactlyZero) { + if (moreSignificant == lfExactlyZero) + moreSignificant = lfLessThanHalf; + else if (moreSignificant == lfExactlyHalf) + moreSignificant = lfMoreThanHalf; + } + + return moreSignificant; +} + +/* The error from the true value, in half-ulps, on multiplying two + floating point numbers, which differ from the value they + approximate by at most HUE1 and HUE2 half-ulps, is strictly less + than the returned value. + + See "How to Read Floating Point Numbers Accurately" by William D + Clinger. */ +static unsigned int +HUerrBound(bool inexactMultiply, unsigned int HUerr1, unsigned int HUerr2) +{ + assert(HUerr1 < 2 || HUerr2 < 2 || (HUerr1 + HUerr2 < 8)); + + if (HUerr1 + HUerr2 == 0) + return inexactMultiply * 2; /* <= inexactMultiply half-ulps. */ + else + return inexactMultiply + 2 * (HUerr1 + HUerr2); +} + +/* The number of ulps from the boundary (zero, or half if ISNEAREST) + when the least significant BITS are truncated. BITS cannot be + zero. */ +static integerPart +ulpsFromBoundary(const integerPart *parts, unsigned int bits, bool isNearest) +{ + unsigned int count, partBits; + integerPart part, boundary; + + assert(bits != 0); + + bits--; + count = bits / integerPartWidth; + partBits = bits % integerPartWidth + 1; + + part = parts[count] & (~(integerPart) 0 >> (integerPartWidth - partBits)); + + if (isNearest) + boundary = (integerPart) 1 << (partBits - 1); + else + boundary = 0; + + if (count == 0) { + if (part - boundary <= boundary - part) + return part - boundary; + else + return boundary - part; + } + + if (part == boundary) { + while (--count) + if (parts[count]) + return ~(integerPart) 0; /* A lot. */ + + return parts[0]; + } else if (part == boundary - 1) { + while (--count) + if (~parts[count]) + return ~(integerPart) 0; /* A lot. */ + + return -parts[0]; + } + + return ~(integerPart) 0; /* A lot. */ +} + +/* Place pow(5, power) in DST, and return the number of parts used. + DST must be at least one part larger than size of the answer. */ +static unsigned int +powerOf5(integerPart *dst, unsigned int power) +{ + static const integerPart firstEightPowers[] = { 1, 5, 25, 125, 625, 3125, + 15625, 78125 }; + integerPart pow5s[maxPowerOfFiveParts * 2 + 5]; + pow5s[0] = 78125 * 5; + + unsigned int partsCount[16] = { 1 }; + integerPart scratch[maxPowerOfFiveParts], *p1, *p2, *pow5; + unsigned int result; + assert(power <= maxExponent); + + p1 = dst; + p2 = scratch; + + *p1 = firstEightPowers[power & 7]; + power >>= 3; + + result = 1; + pow5 = pow5s; + + for (unsigned int n = 0; power; power >>= 1, n++) { + unsigned int pc; + + pc = partsCount[n]; + + /* Calculate pow(5,pow(2,n+3)) if we haven't yet. */ + if (pc == 0) { + pc = partsCount[n - 1]; + APInt::tcFullMultiply(pow5, pow5 - pc, pow5 - pc, pc, pc); + pc *= 2; + if (pow5[pc - 1] == 0) + pc--; + partsCount[n] = pc; + } + + if (power & 1) { + integerPart *tmp; + + APInt::tcFullMultiply(p2, p1, pow5, result, pc); + result += pc; + if (p2[result - 1] == 0) + result--; + + /* Now result is in p1 with partsCount parts and p2 is scratch + space. */ + tmp = p1, p1 = p2, p2 = tmp; + } + + pow5 += pc; + } + + if (p1 != dst) + APInt::tcAssign(dst, p1, result); + + return result; +} + +/* Zero at the end to avoid modular arithmetic when adding one; used + when rounding up during hexadecimal output. */ +static const char hexDigitsLower[] = "0123456789abcdef0"; +static const char hexDigitsUpper[] = "0123456789ABCDEF0"; +static const char infinityL[] = "infinity"; +static const char infinityU[] = "INFINITY"; +static const char NaNL[] = "nan"; +static const char NaNU[] = "NAN"; + +/* Write out an integerPart in hexadecimal, starting with the most + significant nibble. Write out exactly COUNT hexdigits, return + COUNT. */ +static unsigned int +partAsHex (char *dst, integerPart part, unsigned int count, + const char *hexDigitChars) +{ + unsigned int result = count; + + assert(count != 0 && count <= integerPartWidth / 4); + + part >>= (integerPartWidth - 4 * count); + while (count--) { + dst[count] = hexDigitChars[part & 0xf]; + part >>= 4; + } + + return result; +} + +/* Write out an unsigned decimal integer. */ +static char * +writeUnsignedDecimal (char *dst, unsigned int n) +{ + char buff[40], *p; + + p = buff; + do + *p++ = '0' + n % 10; + while (n /= 10); + + do + *dst++ = *--p; + while (p != buff); + + return dst; +} + +/* Write out a signed decimal integer. */ +static char * +writeSignedDecimal (char *dst, int value) +{ + if (value < 0) { + *dst++ = '-'; + dst = writeUnsignedDecimal(dst, -(unsigned) value); + } else + dst = writeUnsignedDecimal(dst, value); + + return dst; +} + +/* Constructors. */ +void +APFloat::initialize(const fltSemantics *ourSemantics) +{ + unsigned int count; + + semantics = ourSemantics; + count = partCount(); + if (count > 1) + significand.parts = new integerPart[count]; +} + +void +APFloat::freeSignificand() +{ + if (partCount() > 1) + delete [] significand.parts; +} + +void +APFloat::assign(const APFloat &rhs) +{ + assert(semantics == rhs.semantics); + + sign = rhs.sign; + category = rhs.category; + exponent = rhs.exponent; + sign2 = rhs.sign2; + exponent2 = rhs.exponent2; + if (category == fcNormal || category == fcNaN) + copySignificand(rhs); +} + +void +APFloat::copySignificand(const APFloat &rhs) +{ + assert(category == fcNormal || category == fcNaN); + assert(rhs.partCount() >= partCount()); + + APInt::tcAssign(significandParts(), rhs.significandParts(), + partCount()); +} + +/* Make this number a NaN, with an arbitrary but deterministic value + for the significand. If double or longer, this is a signalling NaN, + which may not be ideal. If float, this is QNaN(0). */ +void APFloat::makeNaN(bool SNaN, bool Negative, const APInt *fill) +{ + category = fcNaN; + sign = Negative; + + integerPart *significand = significandParts(); + unsigned numParts = partCount(); + + // Set the significand bits to the fill. + if (!fill || fill->getNumWords() < numParts) + APInt::tcSet(significand, 0, numParts); + if (fill) { + APInt::tcAssign(significand, fill->getRawData(), + std::min(fill->getNumWords(), numParts)); + + // Zero out the excess bits of the significand. + unsigned bitsToPreserve = semantics->precision - 1; + unsigned part = bitsToPreserve / 64; + bitsToPreserve %= 64; + significand[part] &= ((1ULL << bitsToPreserve) - 1); + for (part++; part != numParts; ++part) + significand[part] = 0; + } + + unsigned QNaNBit = semantics->precision - 2; + + if (SNaN) { + // We always have to clear the QNaN bit to make it an SNaN. + APInt::tcClearBit(significand, QNaNBit); + + // If there are no bits set in the payload, we have to set + // *something* to make it a NaN instead of an infinity; + // conventionally, this is the next bit down from the QNaN bit. + if (APInt::tcIsZero(significand, numParts)) + APInt::tcSetBit(significand, QNaNBit - 1); + } else { + // We always have to set the QNaN bit to make it a QNaN. + APInt::tcSetBit(significand, QNaNBit); + } + + // For x87 extended precision, we want to make a NaN, not a + // pseudo-NaN. Maybe we should expose the ability to make + // pseudo-NaNs? + if (semantics == &APFloat::x87DoubleExtended) + APInt::tcSetBit(significand, QNaNBit + 1); +} + +APFloat APFloat::makeNaN(const fltSemantics &Sem, bool SNaN, bool Negative, + const APInt *fill) { + APFloat value(Sem, uninitialized); + value.makeNaN(SNaN, Negative, fill); + return value; +} + +APFloat & +APFloat::operator=(const APFloat &rhs) +{ + if (this != &rhs) { + if (semantics != rhs.semantics) { + freeSignificand(); + initialize(rhs.semantics); + } + assign(rhs); + } + + return *this; +} + +bool +APFloat::bitwiseIsEqual(const APFloat &rhs) const { + if (this == &rhs) + return true; + if (semantics != rhs.semantics || + category != rhs.category || + sign != rhs.sign) + return false; + if (semantics==(const llvm::fltSemantics*)&PPCDoubleDouble && + sign2 != rhs.sign2) + return false; + if (category==fcZero || category==fcInfinity) + return true; + else if (category==fcNormal && exponent!=rhs.exponent) + return false; + else if (semantics==(const llvm::fltSemantics*)&PPCDoubleDouble && + exponent2!=rhs.exponent2) + return false; + else { + int i= partCount(); + const integerPart* p=significandParts(); + const integerPart* q=rhs.significandParts(); + for (; i>0; i--, p++, q++) { + if (*p != *q) + return false; + } + return true; + } +} + +APFloat::APFloat(const fltSemantics &ourSemantics, integerPart value) + : exponent2(0), sign2(0) { + assertArithmeticOK(ourSemantics); + initialize(&ourSemantics); + sign = 0; + zeroSignificand(); + exponent = ourSemantics.precision - 1; + significandParts()[0] = value; + normalize(rmNearestTiesToEven, lfExactlyZero); +} + +APFloat::APFloat(const fltSemantics &ourSemantics) : exponent2(0), sign2(0) { + assertArithmeticOK(ourSemantics); + initialize(&ourSemantics); + category = fcZero; + sign = false; +} + +APFloat::APFloat(const fltSemantics &ourSemantics, uninitializedTag tag) + : exponent2(0), sign2(0) { + assertArithmeticOK(ourSemantics); + // Allocates storage if necessary but does not initialize it. + initialize(&ourSemantics); +} + +APFloat::APFloat(const fltSemantics &ourSemantics, + fltCategory ourCategory, bool negative) + : exponent2(0), sign2(0) { + assertArithmeticOK(ourSemantics); + initialize(&ourSemantics); + category = ourCategory; + sign = negative; + if (category == fcNormal) + category = fcZero; + else if (ourCategory == fcNaN) + makeNaN(); +} + +APFloat::APFloat(const fltSemantics &ourSemantics, StringRef text) + : exponent2(0), sign2(0) { + assertArithmeticOK(ourSemantics); + initialize(&ourSemantics); + convertFromString(text, rmNearestTiesToEven); +} + +APFloat::APFloat(const APFloat &rhs) : exponent2(0), sign2(0) { + initialize(rhs.semantics); + assign(rhs); +} + +APFloat::~APFloat() +{ + freeSignificand(); +} + +// Profile - This method 'profiles' an APFloat for use with FoldingSet. +void APFloat::Profile(FoldingSetNodeID& ID) const { + ID.Add(bitcastToAPInt()); +} + +unsigned int +APFloat::partCount() const +{ + return partCountForBits(semantics->precision + 1); +} + +unsigned int +APFloat::semanticsPrecision(const fltSemantics &semantics) +{ + return semantics.precision; +} + +const integerPart * +APFloat::significandParts() const +{ + return const_cast<APFloat *>(this)->significandParts(); +} + +integerPart * +APFloat::significandParts() +{ + assert(category == fcNormal || category == fcNaN); + + if (partCount() > 1) + return significand.parts; + else + return &significand.part; +} + +void +APFloat::zeroSignificand() +{ + category = fcNormal; + APInt::tcSet(significandParts(), 0, partCount()); +} + +/* Increment an fcNormal floating point number's significand. */ +void +APFloat::incrementSignificand() +{ + integerPart carry; + + carry = APInt::tcIncrement(significandParts(), partCount()); + + /* Our callers should never cause us to overflow. */ + assert(carry == 0); + (void)carry; +} + +/* Add the significand of the RHS. Returns the carry flag. */ +integerPart +APFloat::addSignificand(const APFloat &rhs) +{ + integerPart *parts; + + parts = significandParts(); + + assert(semantics == rhs.semantics); + assert(exponent == rhs.exponent); + + return APInt::tcAdd(parts, rhs.significandParts(), 0, partCount()); +} + +/* Subtract the significand of the RHS with a borrow flag. Returns + the borrow flag. */ +integerPart +APFloat::subtractSignificand(const APFloat &rhs, integerPart borrow) +{ + integerPart *parts; + + parts = significandParts(); + + assert(semantics == rhs.semantics); + assert(exponent == rhs.exponent); + + return APInt::tcSubtract(parts, rhs.significandParts(), borrow, + partCount()); +} + +/* Multiply the significand of the RHS. If ADDEND is non-NULL, add it + on to the full-precision result of the multiplication. Returns the + lost fraction. */ +lostFraction +APFloat::multiplySignificand(const APFloat &rhs, const APFloat *addend) +{ + unsigned int omsb; // One, not zero, based MSB. + unsigned int partsCount, newPartsCount, precision; + integerPart *lhsSignificand; + integerPart scratch[4]; + integerPart *fullSignificand; + lostFraction lost_fraction; + bool ignored; + + assert(semantics == rhs.semantics); + + precision = semantics->precision; + newPartsCount = partCountForBits(precision * 2); + + if (newPartsCount > 4) + fullSignificand = new integerPart[newPartsCount]; + else + fullSignificand = scratch; + + lhsSignificand = significandParts(); + partsCount = partCount(); + + APInt::tcFullMultiply(fullSignificand, lhsSignificand, + rhs.significandParts(), partsCount, partsCount); + + lost_fraction = lfExactlyZero; + omsb = APInt::tcMSB(fullSignificand, newPartsCount) + 1; + exponent += rhs.exponent; + + if (addend) { + Significand savedSignificand = significand; + const fltSemantics *savedSemantics = semantics; + fltSemantics extendedSemantics; + opStatus status; + unsigned int extendedPrecision; + + /* Normalize our MSB. */ + extendedPrecision = precision + precision - 1; + if (omsb != extendedPrecision) { + APInt::tcShiftLeft(fullSignificand, newPartsCount, + extendedPrecision - omsb); + exponent -= extendedPrecision - omsb; + } + + /* Create new semantics. */ + extendedSemantics = *semantics; + extendedSemantics.precision = extendedPrecision; + + if (newPartsCount == 1) + significand.part = fullSignificand[0]; + else + significand.parts = fullSignificand; + semantics = &extendedSemantics; + + APFloat extendedAddend(*addend); + status = extendedAddend.convert(extendedSemantics, rmTowardZero, &ignored); + assert(status == opOK); + (void)status; + lost_fraction = addOrSubtractSignificand(extendedAddend, false); + + /* Restore our state. */ + if (newPartsCount == 1) + fullSignificand[0] = significand.part; + significand = savedSignificand; + semantics = savedSemantics; + + omsb = APInt::tcMSB(fullSignificand, newPartsCount) + 1; + } + + exponent -= (precision - 1); + + if (omsb > precision) { + unsigned int bits, significantParts; + lostFraction lf; + + bits = omsb - precision; + significantParts = partCountForBits(omsb); + lf = shiftRight(fullSignificand, significantParts, bits); + lost_fraction = combineLostFractions(lf, lost_fraction); + exponent += bits; + } + + APInt::tcAssign(lhsSignificand, fullSignificand, partsCount); + + if (newPartsCount > 4) + delete [] fullSignificand; + + return lost_fraction; +} + +/* Multiply the significands of LHS and RHS to DST. */ +lostFraction +APFloat::divideSignificand(const APFloat &rhs) +{ + unsigned int bit, i, partsCount; + const integerPart *rhsSignificand; + integerPart *lhsSignificand, *dividend, *divisor; + integerPart scratch[4]; + lostFraction lost_fraction; + + assert(semantics == rhs.semantics); + + lhsSignificand = significandParts(); + rhsSignificand = rhs.significandParts(); + partsCount = partCount(); + + if (partsCount > 2) + dividend = new integerPart[partsCount * 2]; + else + dividend = scratch; + + divisor = dividend + partsCount; + + /* Copy the dividend and divisor as they will be modified in-place. */ + for (i = 0; i < partsCount; i++) { + dividend[i] = lhsSignificand[i]; + divisor[i] = rhsSignificand[i]; + lhsSignificand[i] = 0; + } + + exponent -= rhs.exponent; + + unsigned int precision = semantics->precision; + + /* Normalize the divisor. */ + bit = precision - APInt::tcMSB(divisor, partsCount) - 1; + if (bit) { + exponent += bit; + APInt::tcShiftLeft(divisor, partsCount, bit); + } + + /* Normalize the dividend. */ + bit = precision - APInt::tcMSB(dividend, partsCount) - 1; + if (bit) { + exponent -= bit; + APInt::tcShiftLeft(dividend, partsCount, bit); + } + + /* Ensure the dividend >= divisor initially for the loop below. + Incidentally, this means that the division loop below is + guaranteed to set the integer bit to one. */ + if (APInt::tcCompare(dividend, divisor, partsCount) < 0) { + exponent--; + APInt::tcShiftLeft(dividend, partsCount, 1); + assert(APInt::tcCompare(dividend, divisor, partsCount) >= 0); + } + + /* Long division. */ + for (bit = precision; bit; bit -= 1) { + if (APInt::tcCompare(dividend, divisor, partsCount) >= 0) { + APInt::tcSubtract(dividend, divisor, 0, partsCount); + APInt::tcSetBit(lhsSignificand, bit - 1); + } + + APInt::tcShiftLeft(dividend, partsCount, 1); + } + + /* Figure out the lost fraction. */ + int cmp = APInt::tcCompare(dividend, divisor, partsCount); + + if (cmp > 0) + lost_fraction = lfMoreThanHalf; + else if (cmp == 0) + lost_fraction = lfExactlyHalf; + else if (APInt::tcIsZero(dividend, partsCount)) + lost_fraction = lfExactlyZero; + else + lost_fraction = lfLessThanHalf; + + if (partsCount > 2) + delete [] dividend; + + return lost_fraction; +} + +unsigned int +APFloat::significandMSB() const +{ + return APInt::tcMSB(significandParts(), partCount()); +} + +unsigned int +APFloat::significandLSB() const +{ + return APInt::tcLSB(significandParts(), partCount()); +} + +/* Note that a zero result is NOT normalized to fcZero. */ +lostFraction +APFloat::shiftSignificandRight(unsigned int bits) +{ + /* Our exponent should not overflow. */ + assert((exponent_t) (exponent + bits) >= exponent); + + exponent += bits; + + return shiftRight(significandParts(), partCount(), bits); +} + +/* Shift the significand left BITS bits, subtract BITS from its exponent. */ +void +APFloat::shiftSignificandLeft(unsigned int bits) +{ + assert(bits < semantics->precision); + + if (bits) { + unsigned int partsCount = partCount(); + + APInt::tcShiftLeft(significandParts(), partsCount, bits); + exponent -= bits; + + assert(!APInt::tcIsZero(significandParts(), partsCount)); + } +} + +APFloat::cmpResult +APFloat::compareAbsoluteValue(const APFloat &rhs) const +{ + int compare; + + assert(semantics == rhs.semantics); + assert(category == fcNormal); + assert(rhs.category == fcNormal); + + compare = exponent - rhs.exponent; + + /* If exponents are equal, do an unsigned bignum comparison of the + significands. */ + if (compare == 0) + compare = APInt::tcCompare(significandParts(), rhs.significandParts(), + partCount()); + + if (compare > 0) + return cmpGreaterThan; + else if (compare < 0) + return cmpLessThan; + else + return cmpEqual; +} + +/* Handle overflow. Sign is preserved. We either become infinity or + the largest finite number. */ +APFloat::opStatus +APFloat::handleOverflow(roundingMode rounding_mode) +{ + /* Infinity? */ + if (rounding_mode == rmNearestTiesToEven || + rounding_mode == rmNearestTiesToAway || + (rounding_mode == rmTowardPositive && !sign) || + (rounding_mode == rmTowardNegative && sign)) { + category = fcInfinity; + return (opStatus) (opOverflow | opInexact); + } + + /* Otherwise we become the largest finite number. */ + category = fcNormal; + exponent = semantics->maxExponent; + APInt::tcSetLeastSignificantBits(significandParts(), partCount(), + semantics->precision); + + return opInexact; +} + +/* Returns TRUE if, when truncating the current number, with BIT the + new LSB, with the given lost fraction and rounding mode, the result + would need to be rounded away from zero (i.e., by increasing the + signficand). This routine must work for fcZero of both signs, and + fcNormal numbers. */ +bool +APFloat::roundAwayFromZero(roundingMode rounding_mode, + lostFraction lost_fraction, + unsigned int bit) const +{ + /* NaNs and infinities should not have lost fractions. */ + assert(category == fcNormal || category == fcZero); + + /* Current callers never pass this so we don't handle it. */ + assert(lost_fraction != lfExactlyZero); + + switch (rounding_mode) { + case rmNearestTiesToAway: + return lost_fraction == lfExactlyHalf || lost_fraction == lfMoreThanHalf; + + case rmNearestTiesToEven: + if (lost_fraction == lfMoreThanHalf) + return true; + + /* Our zeroes don't have a significand to test. */ + if (lost_fraction == lfExactlyHalf && category != fcZero) + return APInt::tcExtractBit(significandParts(), bit); + + return false; + + case rmTowardZero: + return false; + + case rmTowardPositive: + return sign == false; + + case rmTowardNegative: + return sign == true; + } + llvm_unreachable("Invalid rounding mode found"); +} + +APFloat::opStatus +APFloat::normalize(roundingMode rounding_mode, + lostFraction lost_fraction) +{ + unsigned int omsb; /* One, not zero, based MSB. */ + int exponentChange; + + if (category != fcNormal) + return opOK; + + /* Before rounding normalize the exponent of fcNormal numbers. */ + omsb = significandMSB() + 1; + + if (omsb) { + /* OMSB is numbered from 1. We want to place it in the integer + bit numbered PRECISION if possible, with a compensating change in + the exponent. */ + exponentChange = omsb - semantics->precision; + + /* If the resulting exponent is too high, overflow according to + the rounding mode. */ + if (exponent + exponentChange > semantics->maxExponent) + return handleOverflow(rounding_mode); + + /* Subnormal numbers have exponent minExponent, and their MSB + is forced based on that. */ + if (exponent + exponentChange < semantics->minExponent) + exponentChange = semantics->minExponent - exponent; + + /* Shifting left is easy as we don't lose precision. */ + if (exponentChange < 0) { + assert(lost_fraction == lfExactlyZero); + + shiftSignificandLeft(-exponentChange); + + return opOK; + } + + if (exponentChange > 0) { + lostFraction lf; + + /* Shift right and capture any new lost fraction. */ + lf = shiftSignificandRight(exponentChange); + + lost_fraction = combineLostFractions(lf, lost_fraction); + + /* Keep OMSB up-to-date. */ + if (omsb > (unsigned) exponentChange) + omsb -= exponentChange; + else + omsb = 0; + } + } + + /* Now round the number according to rounding_mode given the lost + fraction. */ + + /* As specified in IEEE 754, since we do not trap we do not report + underflow for exact results. */ + if (lost_fraction == lfExactlyZero) { + /* Canonicalize zeroes. */ + if (omsb == 0) + category = fcZero; + + return opOK; + } + + /* Increment the significand if we're rounding away from zero. */ + if (roundAwayFromZero(rounding_mode, lost_fraction, 0)) { + if (omsb == 0) + exponent = semantics->minExponent; + + incrementSignificand(); + omsb = significandMSB() + 1; + + /* Did the significand increment overflow? */ + if (omsb == (unsigned) semantics->precision + 1) { + /* Renormalize by incrementing the exponent and shifting our + significand right one. However if we already have the + maximum exponent we overflow to infinity. */ + if (exponent == semantics->maxExponent) { + category = fcInfinity; + + return (opStatus) (opOverflow | opInexact); + } + + shiftSignificandRight(1); + + return opInexact; + } + } + + /* The normal case - we were and are not denormal, and any + significand increment above didn't overflow. */ + if (omsb == semantics->precision) + return opInexact; + + /* We have a non-zero denormal. */ + assert(omsb < semantics->precision); + + /* Canonicalize zeroes. */ + if (omsb == 0) + category = fcZero; + + /* The fcZero case is a denormal that underflowed to zero. */ + return (opStatus) (opUnderflow | opInexact); +} + +APFloat::opStatus +APFloat::addOrSubtractSpecials(const APFloat &rhs, bool subtract) +{ + switch (convolve(category, rhs.category)) { + default: + llvm_unreachable(0); + + case convolve(fcNaN, fcZero): + case convolve(fcNaN, fcNormal): + case convolve(fcNaN, fcInfinity): + case convolve(fcNaN, fcNaN): + case convolve(fcNormal, fcZero): + case convolve(fcInfinity, fcNormal): + case convolve(fcInfinity, fcZero): + return opOK; + + case convolve(fcZero, fcNaN): + case convolve(fcNormal, fcNaN): + case convolve(fcInfinity, fcNaN): + category = fcNaN; + copySignificand(rhs); + return opOK; + + case convolve(fcNormal, fcInfinity): + case convolve(fcZero, fcInfinity): + category = fcInfinity; + sign = rhs.sign ^ subtract; + return opOK; + + case convolve(fcZero, fcNormal): + assign(rhs); + sign = rhs.sign ^ subtract; + return opOK; + + case convolve(fcZero, fcZero): + /* Sign depends on rounding mode; handled by caller. */ + return opOK; + + case convolve(fcInfinity, fcInfinity): + /* Differently signed infinities can only be validly + subtracted. */ + if (((sign ^ rhs.sign)!=0) != subtract) { + makeNaN(); + return opInvalidOp; + } + + return opOK; + + case convolve(fcNormal, fcNormal): + return opDivByZero; + } +} + +/* Add or subtract two normal numbers. */ +lostFraction +APFloat::addOrSubtractSignificand(const APFloat &rhs, bool subtract) +{ + integerPart carry; + lostFraction lost_fraction; + int bits; + + /* Determine if the operation on the absolute values is effectively + an addition or subtraction. */ + subtract ^= (sign ^ rhs.sign) ? true : false; + + /* Are we bigger exponent-wise than the RHS? */ + bits = exponent - rhs.exponent; + + /* Subtraction is more subtle than one might naively expect. */ + if (subtract) { + APFloat temp_rhs(rhs); + bool reverse; + + if (bits == 0) { + reverse = compareAbsoluteValue(temp_rhs) == cmpLessThan; + lost_fraction = lfExactlyZero; + } else if (bits > 0) { + lost_fraction = temp_rhs.shiftSignificandRight(bits - 1); + shiftSignificandLeft(1); + reverse = false; + } else { + lost_fraction = shiftSignificandRight(-bits - 1); + temp_rhs.shiftSignificandLeft(1); + reverse = true; + } + + if (reverse) { + carry = temp_rhs.subtractSignificand + (*this, lost_fraction != lfExactlyZero); + copySignificand(temp_rhs); + sign = !sign; + } else { + carry = subtractSignificand + (temp_rhs, lost_fraction != lfExactlyZero); + } + + /* Invert the lost fraction - it was on the RHS and + subtracted. */ + if (lost_fraction == lfLessThanHalf) + lost_fraction = lfMoreThanHalf; + else if (lost_fraction == lfMoreThanHalf) + lost_fraction = lfLessThanHalf; + + /* The code above is intended to ensure that no borrow is + necessary. */ + assert(!carry); + (void)carry; + } else { + if (bits > 0) { + APFloat temp_rhs(rhs); + + lost_fraction = temp_rhs.shiftSignificandRight(bits); + carry = addSignificand(temp_rhs); + } else { + lost_fraction = shiftSignificandRight(-bits); + carry = addSignificand(rhs); + } + + /* We have a guard bit; generating a carry cannot happen. */ + assert(!carry); + (void)carry; + } + + return lost_fraction; +} + +APFloat::opStatus +APFloat::multiplySpecials(const APFloat &rhs) +{ + switch (convolve(category, rhs.category)) { + default: + llvm_unreachable(0); + + case convolve(fcNaN, fcZero): + case convolve(fcNaN, fcNormal): + case convolve(fcNaN, fcInfinity): + case convolve(fcNaN, fcNaN): + return opOK; + + case convolve(fcZero, fcNaN): + case convolve(fcNormal, fcNaN): + case convolve(fcInfinity, fcNaN): + category = fcNaN; + copySignificand(rhs); + return opOK; + + case convolve(fcNormal, fcInfinity): + case convolve(fcInfinity, fcNormal): + case convolve(fcInfinity, fcInfinity): + category = fcInfinity; + return opOK; + + case convolve(fcZero, fcNormal): + case convolve(fcNormal, fcZero): + case convolve(fcZero, fcZero): + category = fcZero; + return opOK; + + case convolve(fcZero, fcInfinity): + case convolve(fcInfinity, fcZero): + makeNaN(); + return opInvalidOp; + + case convolve(fcNormal, fcNormal): + return opOK; + } +} + +APFloat::opStatus +APFloat::divideSpecials(const APFloat &rhs) +{ + switch (convolve(category, rhs.category)) { + default: + llvm_unreachable(0); + + case convolve(fcNaN, fcZero): + case convolve(fcNaN, fcNormal): + case convolve(fcNaN, fcInfinity): + case convolve(fcNaN, fcNaN): + case convolve(fcInfinity, fcZero): + case convolve(fcInfinity, fcNormal): + case convolve(fcZero, fcInfinity): + case convolve(fcZero, fcNormal): + return opOK; + + case convolve(fcZero, fcNaN): + case convolve(fcNormal, fcNaN): + case convolve(fcInfinity, fcNaN): + category = fcNaN; + copySignificand(rhs); + return opOK; + + case convolve(fcNormal, fcInfinity): + category = fcZero; + return opOK; + + case convolve(fcNormal, fcZero): + category = fcInfinity; + return opDivByZero; + + case convolve(fcInfinity, fcInfinity): + case convolve(fcZero, fcZero): + makeNaN(); + return opInvalidOp; + + case convolve(fcNormal, fcNormal): + return opOK; + } +} + +APFloat::opStatus +APFloat::modSpecials(const APFloat &rhs) +{ + switch (convolve(category, rhs.category)) { + default: + llvm_unreachable(0); + + case convolve(fcNaN, fcZero): + case convolve(fcNaN, fcNormal): + case convolve(fcNaN, fcInfinity): + case convolve(fcNaN, fcNaN): + case convolve(fcZero, fcInfinity): + case convolve(fcZero, fcNormal): + case convolve(fcNormal, fcInfinity): + return opOK; + + case convolve(fcZero, fcNaN): + case convolve(fcNormal, fcNaN): + case convolve(fcInfinity, fcNaN): + category = fcNaN; + copySignificand(rhs); + return opOK; + + case convolve(fcNormal, fcZero): + case convolve(fcInfinity, fcZero): + case convolve(fcInfinity, fcNormal): + case convolve(fcInfinity, fcInfinity): + case convolve(fcZero, fcZero): + makeNaN(); + return opInvalidOp; + + case convolve(fcNormal, fcNormal): + return opOK; + } +} + +/* Change sign. */ +void +APFloat::changeSign() +{ + /* Look mummy, this one's easy. */ + sign = !sign; +} + +void +APFloat::clearSign() +{ + /* So is this one. */ + sign = 0; +} + +void +APFloat::copySign(const APFloat &rhs) +{ + /* And this one. */ + sign = rhs.sign; +} + +/* Normalized addition or subtraction. */ +APFloat::opStatus +APFloat::addOrSubtract(const APFloat &rhs, roundingMode rounding_mode, + bool subtract) +{ + opStatus fs; + + assertArithmeticOK(*semantics); + + fs = addOrSubtractSpecials(rhs, subtract); + + /* This return code means it was not a simple case. */ + if (fs == opDivByZero) { + lostFraction lost_fraction; + + lost_fraction = addOrSubtractSignificand(rhs, subtract); + fs = normalize(rounding_mode, lost_fraction); + + /* Can only be zero if we lost no fraction. */ + assert(category != fcZero || lost_fraction == lfExactlyZero); + } + + /* If two numbers add (exactly) to zero, IEEE 754 decrees it is a + positive zero unless rounding to minus infinity, except that + adding two like-signed zeroes gives that zero. */ + if (category == fcZero) { + if (rhs.category != fcZero || (sign == rhs.sign) == subtract) + sign = (rounding_mode == rmTowardNegative); + } + + return fs; +} + +/* Normalized addition. */ +APFloat::opStatus +APFloat::add(const APFloat &rhs, roundingMode rounding_mode) +{ + return addOrSubtract(rhs, rounding_mode, false); +} + +/* Normalized subtraction. */ +APFloat::opStatus +APFloat::subtract(const APFloat &rhs, roundingMode rounding_mode) +{ + return addOrSubtract(rhs, rounding_mode, true); +} + +/* Normalized multiply. */ +APFloat::opStatus +APFloat::multiply(const APFloat &rhs, roundingMode rounding_mode) +{ + opStatus fs; + + assertArithmeticOK(*semantics); + sign ^= rhs.sign; + fs = multiplySpecials(rhs); + + if (category == fcNormal) { + lostFraction lost_fraction = multiplySignificand(rhs, 0); + fs = normalize(rounding_mode, lost_fraction); + if (lost_fraction != lfExactlyZero) + fs = (opStatus) (fs | opInexact); + } + + return fs; +} + +/* Normalized divide. */ +APFloat::opStatus +APFloat::divide(const APFloat &rhs, roundingMode rounding_mode) +{ + opStatus fs; + + assertArithmeticOK(*semantics); + sign ^= rhs.sign; + fs = divideSpecials(rhs); + + if (category == fcNormal) { + lostFraction lost_fraction = divideSignificand(rhs); + fs = normalize(rounding_mode, lost_fraction); + if (lost_fraction != lfExactlyZero) + fs = (opStatus) (fs | opInexact); + } + + return fs; +} + +/* Normalized remainder. This is not currently correct in all cases. */ +APFloat::opStatus +APFloat::remainder(const APFloat &rhs) +{ + opStatus fs; + APFloat V = *this; + unsigned int origSign = sign; + + assertArithmeticOK(*semantics); + fs = V.divide(rhs, rmNearestTiesToEven); + if (fs == opDivByZero) + return fs; + + int parts = partCount(); + integerPart *x = new integerPart[parts]; + bool ignored; + fs = V.convertToInteger(x, parts * integerPartWidth, true, + rmNearestTiesToEven, &ignored); + if (fs==opInvalidOp) + return fs; + + fs = V.convertFromZeroExtendedInteger(x, parts * integerPartWidth, true, + rmNearestTiesToEven); + assert(fs==opOK); // should always work + + fs = V.multiply(rhs, rmNearestTiesToEven); + assert(fs==opOK || fs==opInexact); // should not overflow or underflow + + fs = subtract(V, rmNearestTiesToEven); + assert(fs==opOK || fs==opInexact); // likewise + + if (isZero()) + sign = origSign; // IEEE754 requires this + delete[] x; + return fs; +} + +/* Normalized llvm frem (C fmod). + This is not currently correct in all cases. */ +APFloat::opStatus +APFloat::mod(const APFloat &rhs, roundingMode rounding_mode) +{ + opStatus fs; + assertArithmeticOK(*semantics); + fs = modSpecials(rhs); + + if (category == fcNormal && rhs.category == fcNormal) { + APFloat V = *this; + unsigned int origSign = sign; + + fs = V.divide(rhs, rmNearestTiesToEven); + if (fs == opDivByZero) + return fs; + + int parts = partCount(); + integerPart *x = new integerPart[parts]; + bool ignored; + fs = V.convertToInteger(x, parts * integerPartWidth, true, + rmTowardZero, &ignored); + if (fs==opInvalidOp) + return fs; + + fs = V.convertFromZeroExtendedInteger(x, parts * integerPartWidth, true, + rmNearestTiesToEven); + assert(fs==opOK); // should always work + + fs = V.multiply(rhs, rounding_mode); + assert(fs==opOK || fs==opInexact); // should not overflow or underflow + + fs = subtract(V, rounding_mode); + assert(fs==opOK || fs==opInexact); // likewise + + if (isZero()) + sign = origSign; // IEEE754 requires this + delete[] x; + } + return fs; +} + +/* Normalized fused-multiply-add. */ +APFloat::opStatus +APFloat::fusedMultiplyAdd(const APFloat &multiplicand, + const APFloat &addend, + roundingMode rounding_mode) +{ + opStatus fs; + + assertArithmeticOK(*semantics); + + /* Post-multiplication sign, before addition. */ + sign ^= multiplicand.sign; + + /* If and only if all arguments are normal do we need to do an + extended-precision calculation. */ + if (category == fcNormal && + multiplicand.category == fcNormal && + addend.category == fcNormal) { + lostFraction lost_fraction; + + lost_fraction = multiplySignificand(multiplicand, &addend); + fs = normalize(rounding_mode, lost_fraction); + if (lost_fraction != lfExactlyZero) + fs = (opStatus) (fs | opInexact); + + /* If two numbers add (exactly) to zero, IEEE 754 decrees it is a + positive zero unless rounding to minus infinity, except that + adding two like-signed zeroes gives that zero. */ + if (category == fcZero && sign != addend.sign) + sign = (rounding_mode == rmTowardNegative); + } else { + fs = multiplySpecials(multiplicand); + + /* FS can only be opOK or opInvalidOp. There is no more work + to do in the latter case. The IEEE-754R standard says it is + implementation-defined in this case whether, if ADDEND is a + quiet NaN, we raise invalid op; this implementation does so. + + If we need to do the addition we can do so with normal + precision. */ + if (fs == opOK) + fs = addOrSubtract(addend, rounding_mode, false); + } + + return fs; +} + +/* Comparison requires normalized numbers. */ +APFloat::cmpResult +APFloat::compare(const APFloat &rhs) const +{ + cmpResult result; + + assertArithmeticOK(*semantics); + assert(semantics == rhs.semantics); + + switch (convolve(category, rhs.category)) { + default: + llvm_unreachable(0); + + case convolve(fcNaN, fcZero): + case convolve(fcNaN, fcNormal): + case convolve(fcNaN, fcInfinity): + case convolve(fcNaN, fcNaN): + case convolve(fcZero, fcNaN): + case convolve(fcNormal, fcNaN): + case convolve(fcInfinity, fcNaN): + return cmpUnordered; + + case convolve(fcInfinity, fcNormal): + case convolve(fcInfinity, fcZero): + case convolve(fcNormal, fcZero): + if (sign) + return cmpLessThan; + else + return cmpGreaterThan; + + case convolve(fcNormal, fcInfinity): + case convolve(fcZero, fcInfinity): + case convolve(fcZero, fcNormal): + if (rhs.sign) + return cmpGreaterThan; + else + return cmpLessThan; + + case convolve(fcInfinity, fcInfinity): + if (sign == rhs.sign) + return cmpEqual; + else if (sign) + return cmpLessThan; + else + return cmpGreaterThan; + + case convolve(fcZero, fcZero): + return cmpEqual; + + case convolve(fcNormal, fcNormal): + break; + } + + /* Two normal numbers. Do they have the same sign? */ + if (sign != rhs.sign) { + if (sign) + result = cmpLessThan; + else + result = cmpGreaterThan; + } else { + /* Compare absolute values; invert result if negative. */ + result = compareAbsoluteValue(rhs); + + if (sign) { + if (result == cmpLessThan) + result = cmpGreaterThan; + else if (result == cmpGreaterThan) + result = cmpLessThan; + } + } + + return result; +} + +/// APFloat::convert - convert a value of one floating point type to another. +/// The return value corresponds to the IEEE754 exceptions. *losesInfo +/// records whether the transformation lost information, i.e. whether +/// converting the result back to the original type will produce the +/// original value (this is almost the same as return value==fsOK, but there +/// are edge cases where this is not so). + +APFloat::opStatus +APFloat::convert(const fltSemantics &toSemantics, + roundingMode rounding_mode, bool *losesInfo) +{ + lostFraction lostFraction; + unsigned int newPartCount, oldPartCount; + opStatus fs; + int shift; + const fltSemantics &fromSemantics = *semantics; + + assertArithmeticOK(fromSemantics); + assertArithmeticOK(toSemantics); + lostFraction = lfExactlyZero; + newPartCount = partCountForBits(toSemantics.precision + 1); + oldPartCount = partCount(); + shift = toSemantics.precision - fromSemantics.precision; + + 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); + if (category==fcNormal || category==fcNaN) + APInt::tcAssign(newParts, significandParts(), oldPartCount); + freeSignificand(); + significand.parts = newParts; + } 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) { + fs = normalize(rounding_mode, lostFraction); + *losesInfo = (fs != opOK); + } else if (category == fcNaN) { + *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 { + *losesInfo = false; + fs = opOK; + } + + return fs; +} + +/* Convert a floating point number to an integer according to the + rounding mode. If the rounded integer value is out of range this + returns an invalid operation exception and the contents of the + destination parts are unspecified. If the rounded value is in + range but the floating point number is not the exact integer, the C + standard doesn't require an inexact exception to be raised. IEEE + 854 does require it so we do that. + + Note that for conversions to integer type the C standard requires + round-to-zero to always be used. */ +APFloat::opStatus +APFloat::convertToSignExtendedInteger(integerPart *parts, unsigned int width, + bool isSigned, + roundingMode rounding_mode, + bool *isExact) const +{ + lostFraction lost_fraction; + const integerPart *src; + unsigned int dstPartsCount, truncatedBits; + + assertArithmeticOK(*semantics); + + *isExact = false; + + /* Handle the three special cases first. */ + if (category == fcInfinity || category == fcNaN) + return opInvalidOp; + + dstPartsCount = partCountForBits(width); + + if (category == fcZero) { + APInt::tcSet(parts, 0, dstPartsCount); + // Negative zero can't be represented as an int. + *isExact = !sign; + return opOK; + } + + src = significandParts(); + + /* Step 1: place our absolute value, with any fraction truncated, in + the destination. */ + if (exponent < 0) { + /* Our absolute value is less than one; truncate everything. */ + APInt::tcSet(parts, 0, dstPartsCount); + /* For exponent -1 the integer bit represents .5, look at that. + For smaller exponents leftmost truncated bit is 0. */ + truncatedBits = semantics->precision -1U - exponent; + } else { + /* We want the most significant (exponent + 1) bits; the rest are + truncated. */ + unsigned int bits = exponent + 1U; + + /* Hopelessly large in magnitude? */ + if (bits > width) + return opInvalidOp; + + if (bits < semantics->precision) { + /* We truncate (semantics->precision - bits) bits. */ + truncatedBits = semantics->precision - bits; + APInt::tcExtract(parts, dstPartsCount, src, bits, truncatedBits); + } else { + /* We want at least as many bits as are available. */ + APInt::tcExtract(parts, dstPartsCount, src, semantics->precision, 0); + APInt::tcShiftLeft(parts, dstPartsCount, bits - semantics->precision); + truncatedBits = 0; + } + } + + /* Step 2: work out any lost fraction, and increment the absolute + value if we would round away from zero. */ + if (truncatedBits) { + lost_fraction = lostFractionThroughTruncation(src, partCount(), + truncatedBits); + if (lost_fraction != lfExactlyZero && + roundAwayFromZero(rounding_mode, lost_fraction, truncatedBits)) { + if (APInt::tcIncrement(parts, dstPartsCount)) + return opInvalidOp; /* Overflow. */ + } + } else { + lost_fraction = lfExactlyZero; + } + + /* Step 3: check if we fit in the destination. */ + unsigned int omsb = APInt::tcMSB(parts, dstPartsCount) + 1; + + if (sign) { + if (!isSigned) { + /* Negative numbers cannot be represented as unsigned. */ + if (omsb != 0) + return opInvalidOp; + } else { + /* It takes omsb bits to represent the unsigned integer value. + We lose a bit for the sign, but care is needed as the + maximally negative integer is a special case. */ + if (omsb == width && APInt::tcLSB(parts, dstPartsCount) + 1 != omsb) + return opInvalidOp; + + /* This case can happen because of rounding. */ + if (omsb > width) + return opInvalidOp; + } + + APInt::tcNegate (parts, dstPartsCount); + } else { + if (omsb >= width + !isSigned) + return opInvalidOp; + } + + if (lost_fraction == lfExactlyZero) { + *isExact = true; + return opOK; + } else + return opInexact; +} + +/* Same as convertToSignExtendedInteger, except we provide + deterministic values in case of an invalid operation exception, + namely zero for NaNs and the minimal or maximal value respectively + for underflow or overflow. + The *isExact output tells whether the result is exact, in the sense + that converting it back to the original floating point type produces + the original value. This is almost equivalent to result==opOK, + except for negative zeroes. +*/ +APFloat::opStatus +APFloat::convertToInteger(integerPart *parts, unsigned int width, + bool isSigned, + roundingMode rounding_mode, bool *isExact) const +{ + opStatus fs; + + fs = convertToSignExtendedInteger(parts, width, isSigned, rounding_mode, + isExact); + + if (fs == opInvalidOp) { + unsigned int bits, dstPartsCount; + + dstPartsCount = partCountForBits(width); + + if (category == fcNaN) + bits = 0; + else if (sign) + bits = isSigned; + else + bits = width - isSigned; + + APInt::tcSetLeastSignificantBits(parts, dstPartsCount, bits); + if (sign && isSigned) + APInt::tcShiftLeft(parts, dstPartsCount, width - 1); + } + + return fs; +} + +/* Same as convertToInteger(integerPart*, ...), except the result is returned in + an APSInt, whose initial bit-width and signed-ness are used to determine the + precision of the conversion. + */ +APFloat::opStatus +APFloat::convertToInteger(APSInt &result, + roundingMode rounding_mode, bool *isExact) const +{ + unsigned bitWidth = result.getBitWidth(); + SmallVector<uint64_t, 4> parts(result.getNumWords()); + opStatus status = convertToInteger( + parts.data(), bitWidth, result.isSigned(), rounding_mode, isExact); + // Keeps the original signed-ness. + result = APInt(bitWidth, parts); + return status; +} + +/* Convert an unsigned integer SRC to a floating point number, + rounding according to ROUNDING_MODE. The sign of the floating + point number is not modified. */ +APFloat::opStatus +APFloat::convertFromUnsignedParts(const integerPart *src, + unsigned int srcCount, + roundingMode rounding_mode) +{ + unsigned int omsb, precision, dstCount; + integerPart *dst; + lostFraction lost_fraction; + + assertArithmeticOK(*semantics); + category = fcNormal; + omsb = APInt::tcMSB(src, srcCount) + 1; + dst = significandParts(); + dstCount = partCount(); + precision = semantics->precision; + + /* We want the most significant PRECISION bits of SRC. There may not + be that many; extract what we can. */ + if (precision <= omsb) { + exponent = omsb - 1; + lost_fraction = lostFractionThroughTruncation(src, srcCount, + omsb - precision); + APInt::tcExtract(dst, dstCount, src, precision, omsb - precision); + } else { + exponent = precision - 1; + lost_fraction = lfExactlyZero; + APInt::tcExtract(dst, dstCount, src, omsb, 0); + } + + return normalize(rounding_mode, lost_fraction); +} + +APFloat::opStatus +APFloat::convertFromAPInt(const APInt &Val, + bool isSigned, + roundingMode rounding_mode) +{ + unsigned int partCount = Val.getNumWords(); + APInt api = Val; + + sign = false; + if (isSigned && api.isNegative()) { + sign = true; + api = -api; + } + + return convertFromUnsignedParts(api.getRawData(), partCount, rounding_mode); +} + +/* Convert a two's complement integer SRC to a floating point number, + rounding according to ROUNDING_MODE. ISSIGNED is true if the + integer is signed, in which case it must be sign-extended. */ +APFloat::opStatus +APFloat::convertFromSignExtendedInteger(const integerPart *src, + unsigned int srcCount, + bool isSigned, + roundingMode rounding_mode) +{ + opStatus status; + + assertArithmeticOK(*semantics); + if (isSigned && + APInt::tcExtractBit(src, srcCount * integerPartWidth - 1)) { + integerPart *copy; + + /* If we're signed and negative negate a copy. */ + sign = true; + copy = new integerPart[srcCount]; + APInt::tcAssign(copy, src, srcCount); + APInt::tcNegate(copy, srcCount); + status = convertFromUnsignedParts(copy, srcCount, rounding_mode); + delete [] copy; + } else { + sign = false; + status = convertFromUnsignedParts(src, srcCount, rounding_mode); + } + + return status; +} + +/* FIXME: should this just take a const APInt reference? */ +APFloat::opStatus +APFloat::convertFromZeroExtendedInteger(const integerPart *parts, + unsigned int width, bool isSigned, + roundingMode rounding_mode) +{ + unsigned int partCount = partCountForBits(width); + APInt api = APInt(width, makeArrayRef(parts, partCount)); + + sign = false; + if (isSigned && APInt::tcExtractBit(parts, width - 1)) { + sign = true; + api = -api; + } + + return convertFromUnsignedParts(api.getRawData(), partCount, rounding_mode); +} + +APFloat::opStatus +APFloat::convertFromHexadecimalString(StringRef s, roundingMode rounding_mode) +{ + lostFraction lost_fraction = lfExactlyZero; + integerPart *significand; + unsigned int bitPos, partsCount; + StringRef::iterator dot, firstSignificantDigit; + + zeroSignificand(); + exponent = 0; + category = fcNormal; + + significand = significandParts(); + partsCount = partCount(); + bitPos = partsCount * integerPartWidth; + + /* Skip leading zeroes and any (hexa)decimal point. */ + StringRef::iterator begin = s.begin(); + StringRef::iterator end = s.end(); + StringRef::iterator p = skipLeadingZeroesAndAnyDot(begin, end, &dot); + firstSignificantDigit = p; + + for (; p != end;) { + integerPart hex_value; + + if (*p == '.') { + assert(dot == end && "String contains multiple dots"); + dot = p++; + if (p == end) { + break; + } + } + + hex_value = hexDigitValue(*p); + if (hex_value == -1U) { + break; + } + + p++; + + if (p == end) { + break; + } else { + /* Store the number whilst 4-bit nibbles remain. */ + if (bitPos) { + bitPos -= 4; + hex_value <<= bitPos % integerPartWidth; + significand[bitPos / integerPartWidth] |= hex_value; + } else { + lost_fraction = trailingHexadecimalFraction(p, end, hex_value); + while (p != end && hexDigitValue(*p) != -1U) + p++; + break; + } + } + } + + /* Hex floats require an exponent but not a hexadecimal point. */ + assert(p != end && "Hex strings require an exponent"); + assert((*p == 'p' || *p == 'P') && "Invalid character in significand"); + assert(p != begin && "Significand has no digits"); + assert((dot == end || p - begin != 1) && "Significand has no digits"); + + /* Ignore the exponent if we are zero. */ + if (p != firstSignificantDigit) { + int expAdjustment; + + /* Implicit hexadecimal point? */ + if (dot == end) + dot = p; + + /* Calculate the exponent adjustment implicit in the number of + significant digits. */ + expAdjustment = static_cast<int>(dot - firstSignificantDigit); + if (expAdjustment < 0) + expAdjustment++; + expAdjustment = expAdjustment * 4 - 1; + + /* Adjust for writing the significand starting at the most + significant nibble. */ + expAdjustment += semantics->precision; + expAdjustment -= partsCount * integerPartWidth; + + /* Adjust for the given exponent. */ + exponent = totalExponent(p + 1, end, expAdjustment); + } + + return normalize(rounding_mode, lost_fraction); +} + +APFloat::opStatus +APFloat::roundSignificandWithExponent(const integerPart *decSigParts, + unsigned sigPartCount, int exp, + roundingMode rounding_mode) +{ + unsigned int parts, pow5PartCount; + fltSemantics calcSemantics = { 32767, -32767, 0, true }; + integerPart pow5Parts[maxPowerOfFiveParts]; + bool isNearest; + + isNearest = (rounding_mode == rmNearestTiesToEven || + rounding_mode == rmNearestTiesToAway); + + parts = partCountForBits(semantics->precision + 11); + + /* Calculate pow(5, abs(exp)). */ + pow5PartCount = powerOf5(pow5Parts, exp >= 0 ? exp: -exp); + + for (;; parts *= 2) { + opStatus sigStatus, powStatus; + unsigned int excessPrecision, truncatedBits; + + calcSemantics.precision = parts * integerPartWidth - 1; + excessPrecision = calcSemantics.precision - semantics->precision; + truncatedBits = excessPrecision; + + APFloat decSig(calcSemantics, fcZero, sign); + APFloat pow5(calcSemantics, fcZero, false); + + sigStatus = decSig.convertFromUnsignedParts(decSigParts, sigPartCount, + rmNearestTiesToEven); + powStatus = pow5.convertFromUnsignedParts(pow5Parts, pow5PartCount, + rmNearestTiesToEven); + /* Add exp, as 10^n = 5^n * 2^n. */ + decSig.exponent += exp; + + lostFraction calcLostFraction; + integerPart HUerr, HUdistance; + unsigned int powHUerr; + + if (exp >= 0) { + /* multiplySignificand leaves the precision-th bit set to 1. */ + calcLostFraction = decSig.multiplySignificand(pow5, NULL); + powHUerr = powStatus != opOK; + } else { + calcLostFraction = decSig.divideSignificand(pow5); + /* Denormal numbers have less precision. */ + if (decSig.exponent < semantics->minExponent) { + excessPrecision += (semantics->minExponent - decSig.exponent); + truncatedBits = excessPrecision; + if (excessPrecision > calcSemantics.precision) + excessPrecision = calcSemantics.precision; + } + /* Extra half-ulp lost in reciprocal of exponent. */ + powHUerr = (powStatus == opOK && calcLostFraction == lfExactlyZero) ? 0:2; + } + + /* Both multiplySignificand and divideSignificand return the + result with the integer bit set. */ + assert(APInt::tcExtractBit + (decSig.significandParts(), calcSemantics.precision - 1) == 1); + + HUerr = HUerrBound(calcLostFraction != lfExactlyZero, sigStatus != opOK, + powHUerr); + HUdistance = 2 * ulpsFromBoundary(decSig.significandParts(), + excessPrecision, isNearest); + + /* Are we guaranteed to round correctly if we truncate? */ + if (HUdistance >= HUerr) { + APInt::tcExtract(significandParts(), partCount(), decSig.significandParts(), + calcSemantics.precision - excessPrecision, + excessPrecision); + /* Take the exponent of decSig. If we tcExtract-ed less bits + above we must adjust our exponent to compensate for the + implicit right shift. */ + exponent = (decSig.exponent + semantics->precision + - (calcSemantics.precision - excessPrecision)); + calcLostFraction = lostFractionThroughTruncation(decSig.significandParts(), + decSig.partCount(), + truncatedBits); + return normalize(rounding_mode, calcLostFraction); + } + } +} + +APFloat::opStatus +APFloat::convertFromDecimalString(StringRef str, roundingMode rounding_mode) +{ + decimalInfo D; + opStatus fs; + + /* Scan the text. */ + StringRef::iterator p = str.begin(); + interpretDecimal(p, str.end(), &D); + + /* Handle the quick cases. First the case of no significant digits, + i.e. zero, and then exponents that are obviously too large or too + small. Writing L for log 10 / log 2, a number d.ddddd*10^exp + definitely overflows if + + (exp - 1) * L >= maxExponent + + and definitely underflows to zero where + + (exp + 1) * L <= minExponent - precision + + With integer arithmetic the tightest bounds for L are + + 93/28 < L < 196/59 [ numerator <= 256 ] + 42039/12655 < L < 28738/8651 [ numerator <= 65536 ] + */ + + if (decDigitValue(*D.firstSigDigit) >= 10U) { + category = fcZero; + fs = opOK; + + /* Check whether the normalized exponent is high enough to overflow + max during the log-rebasing in the max-exponent check below. */ + } else if (D.normalizedExponent - 1 > INT_MAX / 42039) { + fs = handleOverflow(rounding_mode); + + /* If it wasn't, then it also wasn't high enough to overflow max + during the log-rebasing in the min-exponent check. Check that it + won't overflow min in either check, then perform the min-exponent + check. */ + } else if (D.normalizedExponent - 1 < INT_MIN / 42039 || + (D.normalizedExponent + 1) * 28738 <= + 8651 * (semantics->minExponent - (int) semantics->precision)) { + /* Underflow to zero and round. */ + zeroSignificand(); + fs = normalize(rounding_mode, lfLessThanHalf); + + /* We can finally safely perform the max-exponent check. */ + } else if ((D.normalizedExponent - 1) * 42039 + >= 12655 * semantics->maxExponent) { + /* Overflow and round. */ + fs = handleOverflow(rounding_mode); + } else { + integerPart *decSignificand; + unsigned int partCount; + + /* A tight upper bound on number of bits required to hold an + N-digit decimal integer is N * 196 / 59. Allocate enough space + to hold the full significand, and an extra part required by + tcMultiplyPart. */ + partCount = static_cast<unsigned int>(D.lastSigDigit - D.firstSigDigit) + 1; + partCount = partCountForBits(1 + 196 * partCount / 59); + decSignificand = new integerPart[partCount + 1]; + partCount = 0; + + /* Convert to binary efficiently - we do almost all multiplication + in an integerPart. When this would overflow do we do a single + bignum multiplication, and then revert again to multiplication + in an integerPart. */ + do { + integerPart decValue, val, multiplier; + + val = 0; + multiplier = 1; + + do { + if (*p == '.') { + p++; + if (p == str.end()) { + break; + } + } + decValue = decDigitValue(*p++); + assert(decValue < 10U && "Invalid character in significand"); + multiplier *= 10; + val = val * 10 + decValue; + /* The maximum number that can be multiplied by ten with any + digit added without overflowing an integerPart. */ + } while (p <= D.lastSigDigit && multiplier <= (~ (integerPart) 0 - 9) / 10); + + /* Multiply out the current part. */ + APInt::tcMultiplyPart(decSignificand, decSignificand, multiplier, val, + partCount, partCount + 1, false); + + /* If we used another part (likely but not guaranteed), increase + the count. */ + if (decSignificand[partCount]) + partCount++; + } while (p <= D.lastSigDigit); + + category = fcNormal; + fs = roundSignificandWithExponent(decSignificand, partCount, + D.exponent, rounding_mode); + + delete [] decSignificand; + } + + return fs; +} + +APFloat::opStatus +APFloat::convertFromString(StringRef str, roundingMode rounding_mode) +{ + assertArithmeticOK(*semantics); + assert(!str.empty() && "Invalid string length"); + + /* Handle a leading minus sign. */ + StringRef::iterator p = str.begin(); + size_t slen = str.size(); + sign = *p == '-' ? 1 : 0; + if (*p == '-' || *p == '+') { + p++; + slen--; + assert(slen && "String has no digits"); + } + + if (slen >= 2 && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + assert(slen - 2 && "Invalid string"); + return convertFromHexadecimalString(StringRef(p + 2, slen - 2), + rounding_mode); + } + + return convertFromDecimalString(StringRef(p, slen), rounding_mode); +} + +/* Write out a hexadecimal representation of the floating point value + to DST, which must be of sufficient size, in the C99 form + [-]0xh.hhhhp[+-]d. Return the number of characters written, + excluding the terminating NUL. + + If UPPERCASE, the output is in upper case, otherwise in lower case. + + HEXDIGITS digits appear altogether, rounding the value if + necessary. If HEXDIGITS is 0, the minimal precision to display the + number precisely is used instead. If nothing would appear after + the decimal point it is suppressed. + + The decimal exponent is always printed and has at least one digit. + Zero values display an exponent of zero. Infinities and NaNs + appear as "infinity" or "nan" respectively. + + The above rules are as specified by C99. There is ambiguity about + what the leading hexadecimal digit should be. This implementation + uses whatever is necessary so that the exponent is displayed as + stored. This implies the exponent will fall within the IEEE format + range, and the leading hexadecimal digit will be 0 (for denormals), + 1 (normal numbers) or 2 (normal numbers rounded-away-from-zero with + any other digits zero). +*/ +unsigned int +APFloat::convertToHexString(char *dst, unsigned int hexDigits, + bool upperCase, roundingMode rounding_mode) const +{ + char *p; + + assertArithmeticOK(*semantics); + + p = dst; + if (sign) + *dst++ = '-'; + + switch (category) { + case fcInfinity: + memcpy (dst, upperCase ? infinityU: infinityL, sizeof infinityU - 1); + dst += sizeof infinityL - 1; + break; + + case fcNaN: + memcpy (dst, upperCase ? NaNU: NaNL, sizeof NaNU - 1); + dst += sizeof NaNU - 1; + break; + + case fcZero: + *dst++ = '0'; + *dst++ = upperCase ? 'X': 'x'; + *dst++ = '0'; + if (hexDigits > 1) { + *dst++ = '.'; + memset (dst, '0', hexDigits - 1); + dst += hexDigits - 1; + } + *dst++ = upperCase ? 'P': 'p'; + *dst++ = '0'; + break; + + case fcNormal: + dst = convertNormalToHexString (dst, hexDigits, upperCase, rounding_mode); + break; + } + + *dst = 0; + + return static_cast<unsigned int>(dst - p); +} + +/* Does the hard work of outputting the correctly rounded hexadecimal + form of a normal floating point number with the specified number of + hexadecimal digits. If HEXDIGITS is zero the minimum number of + digits necessary to print the value precisely is output. */ +char * +APFloat::convertNormalToHexString(char *dst, unsigned int hexDigits, + bool upperCase, + roundingMode rounding_mode) const +{ + unsigned int count, valueBits, shift, partsCount, outputDigits; + const char *hexDigitChars; + const integerPart *significand; + char *p; + bool roundUp; + + *dst++ = '0'; + *dst++ = upperCase ? 'X': 'x'; + + roundUp = false; + hexDigitChars = upperCase ? hexDigitsUpper: hexDigitsLower; + + significand = significandParts(); + partsCount = partCount(); + + /* +3 because the first digit only uses the single integer bit, so + we have 3 virtual zero most-significant-bits. */ + valueBits = semantics->precision + 3; + shift = integerPartWidth - valueBits % integerPartWidth; + + /* The natural number of digits required ignoring trailing + insignificant zeroes. */ + outputDigits = (valueBits - significandLSB () + 3) / 4; + + /* hexDigits of zero means use the required number for the + precision. Otherwise, see if we are truncating. If we are, + find out if we need to round away from zero. */ + if (hexDigits) { + if (hexDigits < outputDigits) { + /* We are dropping non-zero bits, so need to check how to round. + "bits" is the number of dropped bits. */ + unsigned int bits; + lostFraction fraction; + + bits = valueBits - hexDigits * 4; + fraction = lostFractionThroughTruncation (significand, partsCount, bits); + roundUp = roundAwayFromZero(rounding_mode, fraction, bits); + } + outputDigits = hexDigits; + } + + /* Write the digits consecutively, and start writing in the location + of the hexadecimal point. We move the most significant digit + left and add the hexadecimal point later. */ + p = ++dst; + + count = (valueBits + integerPartWidth - 1) / integerPartWidth; + + while (outputDigits && count) { + integerPart part; + + /* Put the most significant integerPartWidth bits in "part". */ + if (--count == partsCount) + part = 0; /* An imaginary higher zero part. */ + else + part = significand[count] << shift; + + if (count && shift) + part |= significand[count - 1] >> (integerPartWidth - shift); + + /* Convert as much of "part" to hexdigits as we can. */ + unsigned int curDigits = integerPartWidth / 4; + + if (curDigits > outputDigits) + curDigits = outputDigits; + dst += partAsHex (dst, part, curDigits, hexDigitChars); + outputDigits -= curDigits; + } + + if (roundUp) { + char *q = dst; + + /* Note that hexDigitChars has a trailing '0'. */ + do { + q--; + *q = hexDigitChars[hexDigitValue (*q) + 1]; + } while (*q == '0'); + assert(q >= p); + } else { + /* Add trailing zeroes. */ + memset (dst, '0', outputDigits); + dst += outputDigits; + } + + /* Move the most significant digit to before the point, and if there + is something after the decimal point add it. This must come + after rounding above. */ + p[-1] = p[0]; + if (dst -1 == p) + dst--; + else + p[0] = '.'; + + /* Finally output the exponent. */ + *dst++ = upperCase ? 'P': 'p'; + + return writeSignedDecimal (dst, exponent); +} + +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 +// possible to eliminate these and have everybody deal with APFloats, but that +// will take a while. This approach will not easily extend to long double. +// Current implementation requires integerPartWidth==64, which is correct at +// the moment but could be made more general. + +// Denormals have exponent minExponent in APFloat, but minExponent-1 in +// the actual IEEE respresentations. We compensate for that here. + +APInt +APFloat::convertF80LongDoubleAPFloatToAPInt() const +{ + assert(semantics == (const llvm::fltSemantics*)&x87DoubleExtended); + assert(partCount()==2); + + uint64_t myexponent, mysignificand; + + if (category==fcNormal) { + myexponent = exponent+16383; //bias + mysignificand = significandParts()[0]; + if (myexponent==1 && !(mysignificand & 0x8000000000000000ULL)) + myexponent = 0; // denormal + } else if (category==fcZero) { + myexponent = 0; + mysignificand = 0; + } else if (category==fcInfinity) { + myexponent = 0x7fff; + mysignificand = 0x8000000000000000ULL; + } else { + assert(category == fcNaN && "Unknown category"); + myexponent = 0x7fff; + mysignificand = significandParts()[0]; + } + + uint64_t words[2]; + words[0] = mysignificand; + words[1] = ((uint64_t)(sign & 1) << 15) | + (myexponent & 0x7fffLL); + return APInt(80, words); +} + +APInt +APFloat::convertPPCDoubleDoubleAPFloatToAPInt() const +{ + assert(semantics == (const llvm::fltSemantics*)&PPCDoubleDouble); + assert(partCount()==2); + + uint64_t myexponent, mysignificand, myexponent2, mysignificand2; + + if (category==fcNormal) { + myexponent = exponent + 1023; //bias + myexponent2 = exponent2 + 1023; + mysignificand = significandParts()[0]; + mysignificand2 = significandParts()[1]; + if (myexponent==1 && !(mysignificand & 0x10000000000000LL)) + myexponent = 0; // denormal + if (myexponent2==1 && !(mysignificand2 & 0x10000000000000LL)) + myexponent2 = 0; // denormal + } else if (category==fcZero) { + myexponent = 0; + mysignificand = 0; + myexponent2 = 0; + mysignificand2 = 0; + } else if (category==fcInfinity) { + myexponent = 0x7ff; + myexponent2 = 0; + mysignificand = 0; + mysignificand2 = 0; + } else { + assert(category == fcNaN && "Unknown category"); + myexponent = 0x7ff; + mysignificand = significandParts()[0]; + myexponent2 = exponent2; + mysignificand2 = significandParts()[1]; + } + + uint64_t words[2]; + words[0] = ((uint64_t)(sign & 1) << 63) | + ((myexponent & 0x7ff) << 52) | + (mysignificand & 0xfffffffffffffLL); + words[1] = ((uint64_t)(sign2 & 1) << 63) | + ((myexponent2 & 0x7ff) << 52) | + (mysignificand2 & 0xfffffffffffffLL); + return APInt(128, words); +} + +APInt +APFloat::convertQuadrupleAPFloatToAPInt() const +{ + assert(semantics == (const llvm::fltSemantics*)&IEEEquad); + assert(partCount()==2); + + uint64_t myexponent, mysignificand, mysignificand2; + + if (category==fcNormal) { + myexponent = exponent+16383; //bias + mysignificand = significandParts()[0]; + mysignificand2 = significandParts()[1]; + if (myexponent==1 && !(mysignificand2 & 0x1000000000000LL)) + myexponent = 0; // denormal + } else if (category==fcZero) { + myexponent = 0; + mysignificand = mysignificand2 = 0; + } else if (category==fcInfinity) { + myexponent = 0x7fff; + mysignificand = mysignificand2 = 0; + } else { + assert(category == fcNaN && "Unknown category!"); + myexponent = 0x7fff; + mysignificand = significandParts()[0]; + mysignificand2 = significandParts()[1]; + } + + uint64_t words[2]; + words[0] = mysignificand; + words[1] = ((uint64_t)(sign & 1) << 63) | + ((myexponent & 0x7fff) << 48) | + (mysignificand2 & 0xffffffffffffLL); + + return APInt(128, words); +} + +APInt +APFloat::convertDoubleAPFloatToAPInt() const +{ + assert(semantics == (const llvm::fltSemantics*)&IEEEdouble); + assert(partCount()==1); + + uint64_t myexponent, mysignificand; + + if (category==fcNormal) { + myexponent = exponent+1023; //bias + mysignificand = *significandParts(); + if (myexponent==1 && !(mysignificand & 0x10000000000000LL)) + myexponent = 0; // denormal + } else if (category==fcZero) { + myexponent = 0; + mysignificand = 0; + } else if (category==fcInfinity) { + myexponent = 0x7ff; + mysignificand = 0; + } else { + assert(category == fcNaN && "Unknown category!"); + myexponent = 0x7ff; + mysignificand = *significandParts(); + } + + return APInt(64, ((((uint64_t)(sign & 1) << 63) | + ((myexponent & 0x7ff) << 52) | + (mysignificand & 0xfffffffffffffLL)))); +} + +APInt +APFloat::convertFloatAPFloatToAPInt() const +{ + assert(semantics == (const llvm::fltSemantics*)&IEEEsingle); + assert(partCount()==1); + + uint32_t myexponent, mysignificand; + + if (category==fcNormal) { + myexponent = exponent+127; //bias + mysignificand = (uint32_t)*significandParts(); + if (myexponent == 1 && !(mysignificand & 0x800000)) + myexponent = 0; // denormal + } else if (category==fcZero) { + myexponent = 0; + mysignificand = 0; + } else if (category==fcInfinity) { + myexponent = 0xff; + mysignificand = 0; + } else { + assert(category == fcNaN && "Unknown category!"); + myexponent = 0xff; + mysignificand = (uint32_t)*significandParts(); + } + + return APInt(32, (((sign&1) << 31) | ((myexponent&0xff) << 23) | + (mysignificand & 0x7fffff))); +} + +APInt +APFloat::convertHalfAPFloatToAPInt() const +{ + assert(semantics == (const llvm::fltSemantics*)&IEEEhalf); + assert(partCount()==1); + + uint32_t myexponent, mysignificand; + + if (category==fcNormal) { + myexponent = exponent+15; //bias + mysignificand = (uint32_t)*significandParts(); + if (myexponent == 1 && !(mysignificand & 0x400)) + myexponent = 0; // denormal + } else if (category==fcZero) { + myexponent = 0; + mysignificand = 0; + } else if (category==fcInfinity) { + myexponent = 0x1f; + mysignificand = 0; + } else { + assert(category == fcNaN && "Unknown category!"); + myexponent = 0x1f; + mysignificand = (uint32_t)*significandParts(); + } + + return APInt(16, (((sign&1) << 15) | ((myexponent&0x1f) << 10) | + (mysignificand & 0x3ff))); +} + +// This function creates an APInt that is just a bit map of the floating +// point constant as it would appear in memory. It is not a conversion, +// and treating the result as a normal integer is unlikely to be useful. + +APInt +APFloat::bitcastToAPInt() const +{ + if (semantics == (const llvm::fltSemantics*)&IEEEhalf) + return convertHalfAPFloatToAPInt(); + + if (semantics == (const llvm::fltSemantics*)&IEEEsingle) + return convertFloatAPFloatToAPInt(); + + if (semantics == (const llvm::fltSemantics*)&IEEEdouble) + return convertDoubleAPFloatToAPInt(); + + if (semantics == (const llvm::fltSemantics*)&IEEEquad) + return convertQuadrupleAPFloatToAPInt(); + + if (semantics == (const llvm::fltSemantics*)&PPCDoubleDouble) + return convertPPCDoubleDoubleAPFloatToAPInt(); + + assert(semantics == (const llvm::fltSemantics*)&x87DoubleExtended && + "unknown format!"); + return convertF80LongDoubleAPFloatToAPInt(); +} + +float +APFloat::convertToFloat() const +{ + assert(semantics == (const llvm::fltSemantics*)&IEEEsingle && + "Float semantics are not IEEEsingle"); + APInt api = bitcastToAPInt(); + return api.bitsToFloat(); +} + +double +APFloat::convertToDouble() const +{ + assert(semantics == (const llvm::fltSemantics*)&IEEEdouble && + "Float semantics are not IEEEdouble"); + APInt api = bitcastToAPInt(); + return api.bitsToDouble(); +} + +/// Integer bit is explicit in this format. Intel hardware (387 and later) +/// does not support these bit patterns: +/// exponent = all 1's, integer bit 0, significand 0 ("pseudoinfinity") +/// exponent = all 1's, integer bit 0, significand nonzero ("pseudoNaN") +/// exponent = 0, integer bit 1 ("pseudodenormal") +/// exponent!=0 nor all 1's, integer bit 0 ("unnormal") +/// At the moment, the first two are treated as NaNs, the second two as Normal. +void +APFloat::initFromF80LongDoubleAPInt(const APInt &api) +{ + assert(api.getBitWidth()==80); + uint64_t i1 = api.getRawData()[0]; + uint64_t i2 = api.getRawData()[1]; + uint64_t myexponent = (i2 & 0x7fff); + uint64_t mysignificand = i1; + + initialize(&APFloat::x87DoubleExtended); + assert(partCount()==2); + + sign = static_cast<unsigned int>(i2>>15); + if (myexponent==0 && mysignificand==0) { + // exponent, significand meaningless + category = fcZero; + } else if (myexponent==0x7fff && mysignificand==0x8000000000000000ULL) { + // exponent, significand meaningless + category = fcInfinity; + } else if (myexponent==0x7fff && mysignificand!=0x8000000000000000ULL) { + // exponent meaningless + category = fcNaN; + significandParts()[0] = mysignificand; + significandParts()[1] = 0; + } else { + category = fcNormal; + exponent = myexponent - 16383; + significandParts()[0] = mysignificand; + significandParts()[1] = 0; + if (myexponent==0) // denormal + exponent = -16382; + } +} + +void +APFloat::initFromPPCDoubleDoubleAPInt(const APInt &api) +{ + assert(api.getBitWidth()==128); + uint64_t i1 = api.getRawData()[0]; + uint64_t i2 = api.getRawData()[1]; + uint64_t myexponent = (i1 >> 52) & 0x7ff; + uint64_t mysignificand = i1 & 0xfffffffffffffLL; + uint64_t myexponent2 = (i2 >> 52) & 0x7ff; + uint64_t mysignificand2 = i2 & 0xfffffffffffffLL; + + initialize(&APFloat::PPCDoubleDouble); + assert(partCount()==2); + + sign = static_cast<unsigned int>(i1>>63); + sign2 = static_cast<unsigned int>(i2>>63); + if (myexponent==0 && mysignificand==0) { + // exponent, significand meaningless + // exponent2 and significand2 are required to be 0; we don't check + category = fcZero; + } else if (myexponent==0x7ff && mysignificand==0) { + // exponent, significand meaningless + // exponent2 and significand2 are required to be 0; we don't check + category = fcInfinity; + } else if (myexponent==0x7ff && mysignificand!=0) { + // exponent meaningless. So is the whole second word, but keep it + // for determinism. + category = fcNaN; + exponent2 = myexponent2; + significandParts()[0] = mysignificand; + significandParts()[1] = mysignificand2; + } else { + category = fcNormal; + // Note there is no category2; the second word is treated as if it is + // fcNormal, although it might be something else considered by itself. + exponent = myexponent - 1023; + exponent2 = myexponent2 - 1023; + significandParts()[0] = mysignificand; + significandParts()[1] = mysignificand2; + if (myexponent==0) // denormal + exponent = -1022; + else + significandParts()[0] |= 0x10000000000000LL; // integer bit + if (myexponent2==0) + exponent2 = -1022; + else + significandParts()[1] |= 0x10000000000000LL; // integer bit + } +} + +void +APFloat::initFromQuadrupleAPInt(const APInt &api) +{ + assert(api.getBitWidth()==128); + uint64_t i1 = api.getRawData()[0]; + uint64_t i2 = api.getRawData()[1]; + uint64_t myexponent = (i2 >> 48) & 0x7fff; + uint64_t mysignificand = i1; + uint64_t mysignificand2 = i2 & 0xffffffffffffLL; + + initialize(&APFloat::IEEEquad); + assert(partCount()==2); + + sign = static_cast<unsigned int>(i2>>63); + if (myexponent==0 && + (mysignificand==0 && mysignificand2==0)) { + // exponent, significand meaningless + category = fcZero; + } else if (myexponent==0x7fff && + (mysignificand==0 && mysignificand2==0)) { + // exponent, significand meaningless + category = fcInfinity; + } else if (myexponent==0x7fff && + (mysignificand!=0 || mysignificand2 !=0)) { + // exponent meaningless + category = fcNaN; + significandParts()[0] = mysignificand; + significandParts()[1] = mysignificand2; + } else { + category = fcNormal; + exponent = myexponent - 16383; + significandParts()[0] = mysignificand; + significandParts()[1] = mysignificand2; + if (myexponent==0) // denormal + exponent = -16382; + else + significandParts()[1] |= 0x1000000000000LL; // integer bit + } +} + +void +APFloat::initFromDoubleAPInt(const APInt &api) +{ + assert(api.getBitWidth()==64); + uint64_t i = *api.getRawData(); + uint64_t myexponent = (i >> 52) & 0x7ff; + uint64_t mysignificand = i & 0xfffffffffffffLL; + + initialize(&APFloat::IEEEdouble); + assert(partCount()==1); + + sign = static_cast<unsigned int>(i>>63); + if (myexponent==0 && mysignificand==0) { + // exponent, significand meaningless + category = fcZero; + } else if (myexponent==0x7ff && mysignificand==0) { + // exponent, significand meaningless + category = fcInfinity; + } else if (myexponent==0x7ff && mysignificand!=0) { + // exponent meaningless + category = fcNaN; + *significandParts() = mysignificand; + } else { + category = fcNormal; + exponent = myexponent - 1023; + *significandParts() = mysignificand; + if (myexponent==0) // denormal + exponent = -1022; + else + *significandParts() |= 0x10000000000000LL; // integer bit + } +} + +void +APFloat::initFromFloatAPInt(const APInt & api) +{ + assert(api.getBitWidth()==32); + uint32_t i = (uint32_t)*api.getRawData(); + uint32_t myexponent = (i >> 23) & 0xff; + uint32_t mysignificand = i & 0x7fffff; + + initialize(&APFloat::IEEEsingle); + assert(partCount()==1); + + sign = i >> 31; + if (myexponent==0 && mysignificand==0) { + // exponent, significand meaningless + category = fcZero; + } else if (myexponent==0xff && mysignificand==0) { + // exponent, significand meaningless + category = fcInfinity; + } else if (myexponent==0xff && mysignificand!=0) { + // sign, exponent, significand meaningless + category = fcNaN; + *significandParts() = mysignificand; + } else { + category = fcNormal; + exponent = myexponent - 127; //bias + *significandParts() = mysignificand; + if (myexponent==0) // denormal + exponent = -126; + else + *significandParts() |= 0x800000; // integer bit + } +} + +void +APFloat::initFromHalfAPInt(const APInt & api) +{ + assert(api.getBitWidth()==16); + uint32_t i = (uint32_t)*api.getRawData(); + uint32_t myexponent = (i >> 10) & 0x1f; + uint32_t mysignificand = i & 0x3ff; + + initialize(&APFloat::IEEEhalf); + assert(partCount()==1); + + sign = i >> 15; + if (myexponent==0 && mysignificand==0) { + // exponent, significand meaningless + category = fcZero; + } else if (myexponent==0x1f && mysignificand==0) { + // exponent, significand meaningless + category = fcInfinity; + } else if (myexponent==0x1f && mysignificand!=0) { + // sign, exponent, significand meaningless + category = fcNaN; + *significandParts() = mysignificand; + } else { + category = fcNormal; + exponent = myexponent - 15; //bias + *significandParts() = mysignificand; + if (myexponent==0) // denormal + exponent = -14; + else + *significandParts() |= 0x400; // integer bit + } +} + +/// Treat api as containing the bits of a floating point number. Currently +/// we infer the floating point type from the size of the APInt. The +/// isIEEE argument distinguishes between PPC128 and IEEE128 (not meaningful +/// when the size is anything else). +void +APFloat::initFromAPInt(const APInt& api, bool isIEEE) +{ + if (api.getBitWidth() == 16) + return initFromHalfAPInt(api); + else if (api.getBitWidth() == 32) + return initFromFloatAPInt(api); + else if (api.getBitWidth()==64) + return initFromDoubleAPInt(api); + else if (api.getBitWidth()==80) + return initFromF80LongDoubleAPInt(api); + else if (api.getBitWidth()==128) + return (isIEEE ? + initFromQuadrupleAPInt(api) : initFromPPCDoubleDoubleAPInt(api)); + else + llvm_unreachable(0); +} + +APFloat +APFloat::getAllOnesValue(unsigned BitWidth, bool isIEEE) +{ + return APFloat(APInt::getAllOnesValue(BitWidth), isIEEE); +} + +APFloat APFloat::getLargest(const fltSemantics &Sem, bool Negative) { + APFloat Val(Sem, fcNormal, Negative); + + // We want (in interchange format): + // sign = {Negative} + // exponent = 1..10 + // significand = 1..1 + + Val.exponent = Sem.maxExponent; // unbiased + + // 1-initialize all bits.... + Val.zeroSignificand(); + integerPart *significand = Val.significandParts(); + unsigned N = partCountForBits(Sem.precision); + for (unsigned i = 0; i != N; ++i) + significand[i] = ~((integerPart) 0); + + // ...and then clear the top bits for internal consistency. + if (Sem.precision % integerPartWidth != 0) + significand[N-1] &= + (((integerPart) 1) << (Sem.precision % integerPartWidth)) - 1; + + return Val; +} + +APFloat APFloat::getSmallest(const fltSemantics &Sem, bool Negative) { + APFloat Val(Sem, fcNormal, Negative); + + // We want (in interchange format): + // sign = {Negative} + // exponent = 0..0 + // significand = 0..01 + + Val.exponent = Sem.minExponent; // unbiased + Val.zeroSignificand(); + Val.significandParts()[0] = 1; + return Val; +} + +APFloat APFloat::getSmallestNormalized(const fltSemantics &Sem, bool Negative) { + APFloat Val(Sem, fcNormal, Negative); + + // We want (in interchange format): + // sign = {Negative} + // exponent = 0..0 + // significand = 10..0 + + Val.exponent = Sem.minExponent; + Val.zeroSignificand(); + Val.significandParts()[partCountForBits(Sem.precision)-1] |= + (((integerPart) 1) << ((Sem.precision - 1) % integerPartWidth)); + + return Val; +} + +APFloat::APFloat(const APInt& api, bool isIEEE) : exponent2(0), sign2(0) { + initFromAPInt(api, isIEEE); +} + +APFloat::APFloat(float f) : exponent2(0), sign2(0) { + initFromAPInt(APInt::floatToBits(f)); +} + +APFloat::APFloat(double d) : exponent2(0), sign2(0) { + initFromAPInt(APInt::doubleToBits(d)); +} + +namespace { + static void append(SmallVectorImpl<char> &Buffer, + unsigned N, const char *Str) { + unsigned Start = Buffer.size(); + Buffer.set_size(Start + N); + memcpy(&Buffer[Start], Str, N); + } + + template <unsigned N> + void append(SmallVectorImpl<char> &Buffer, const char (&Str)[N]) { + append(Buffer, N, Str); + } + + /// Removes data from the given significand until it is no more + /// precise than is required for the desired precision. + void AdjustToPrecision(APInt &significand, + int &exp, unsigned FormatPrecision) { + unsigned bits = significand.getActiveBits(); + + // 196/59 is a very slight overestimate of lg_2(10). + unsigned bitsRequired = (FormatPrecision * 196 + 58) / 59; + + if (bits <= bitsRequired) return; + + unsigned tensRemovable = (bits - bitsRequired) * 59 / 196; + if (!tensRemovable) return; + + exp += tensRemovable; + + APInt divisor(significand.getBitWidth(), 1); + APInt powten(significand.getBitWidth(), 10); + while (true) { + if (tensRemovable & 1) + divisor *= powten; + tensRemovable >>= 1; + if (!tensRemovable) break; + powten *= powten; + } + + significand = significand.udiv(divisor); + + // Truncate the significand down to its active bit count, but + // don't try to drop below 32. + unsigned newPrecision = std::max(32U, significand.getActiveBits()); + significand = significand.trunc(newPrecision); + } + + + void AdjustToPrecision(SmallVectorImpl<char> &buffer, + int &exp, unsigned FormatPrecision) { + unsigned N = buffer.size(); + if (N <= FormatPrecision) return; + + // The most significant figures are the last ones in the buffer. + unsigned FirstSignificant = N - FormatPrecision; + + // Round. + // FIXME: this probably shouldn't use 'round half up'. + + // Rounding down is just a truncation, except we also want to drop + // trailing zeros from the new result. + if (buffer[FirstSignificant - 1] < '5') { + while (FirstSignificant < N && buffer[FirstSignificant] == '0') + FirstSignificant++; + + exp += FirstSignificant; + buffer.erase(&buffer[0], &buffer[FirstSignificant]); + return; + } + + // Rounding up requires a decimal add-with-carry. If we continue + // the carry, the newly-introduced zeros will just be truncated. + for (unsigned I = FirstSignificant; I != N; ++I) { + if (buffer[I] == '9') { + FirstSignificant++; + } else { + buffer[I]++; + break; + } + } + + // If we carried through, we have exactly one digit of precision. + if (FirstSignificant == N) { + exp += FirstSignificant; + buffer.clear(); + buffer.push_back('1'); + return; + } + + exp += FirstSignificant; + buffer.erase(&buffer[0], &buffer[FirstSignificant]); + } +} + +void APFloat::toString(SmallVectorImpl<char> &Str, + unsigned FormatPrecision, + unsigned FormatMaxPadding) const { + switch (category) { + case fcInfinity: + if (isNegative()) + return append(Str, "-Inf"); + else + return append(Str, "+Inf"); + + case fcNaN: return append(Str, "NaN"); + + case fcZero: + if (isNegative()) + Str.push_back('-'); + + if (!FormatMaxPadding) + append(Str, "0.0E+0"); + else + Str.push_back('0'); + return; + + case fcNormal: + break; + } + + if (isNegative()) + Str.push_back('-'); + + // Decompose the number into an APInt and an exponent. + int exp = exponent - ((int) semantics->precision - 1); + APInt significand(semantics->precision, + makeArrayRef(significandParts(), + partCountForBits(semantics->precision))); + + // Set FormatPrecision if zero. We want to do this before we + // truncate trailing zeros, as those are part of the precision. + if (!FormatPrecision) { + // It's an interesting question whether to use the nominal + // precision or the active precision here for denormals. + + // FormatPrecision = ceil(significandBits / lg_2(10)) + FormatPrecision = (semantics->precision * 59 + 195) / 196; + } + + // Ignore trailing binary zeros. + int trailingZeros = significand.countTrailingZeros(); + exp += trailingZeros; + significand = significand.lshr(trailingZeros); + + // Change the exponent from 2^e to 10^e. + if (exp == 0) { + // Nothing to do. + } else if (exp > 0) { + // Just shift left. + significand = significand.zext(semantics->precision + exp); + significand <<= exp; + exp = 0; + } else { /* exp < 0 */ + int texp = -exp; + + // We transform this using the identity: + // (N)(2^-e) == (N)(5^e)(10^-e) + // This means we have to multiply N (the significand) by 5^e. + // To avoid overflow, we have to operate on numbers large + // enough to store N * 5^e: + // log2(N * 5^e) == log2(N) + e * log2(5) + // <= semantics->precision + e * 137 / 59 + // (log_2(5) ~ 2.321928 < 2.322034 ~ 137/59) + + unsigned precision = semantics->precision + (137 * texp + 136) / 59; + + // Multiply significand by 5^e. + // N * 5^0101 == N * 5^(1*1) * 5^(0*2) * 5^(1*4) * 5^(0*8) + significand = significand.zext(precision); + APInt five_to_the_i(precision, 5); + while (true) { + if (texp & 1) significand *= five_to_the_i; + + texp >>= 1; + if (!texp) break; + five_to_the_i *= five_to_the_i; + } + } + + AdjustToPrecision(significand, exp, FormatPrecision); + + llvm::SmallVector<char, 256> buffer; + + // Fill the buffer. + unsigned precision = significand.getBitWidth(); + APInt ten(precision, 10); + APInt digit(precision, 0); + + bool inTrail = true; + while (significand != 0) { + // digit <- significand % 10 + // significand <- significand / 10 + APInt::udivrem(significand, ten, significand, digit); + + unsigned d = digit.getZExtValue(); + + // Drop trailing zeros. + if (inTrail && !d) exp++; + else { + buffer.push_back((char) ('0' + d)); + inTrail = false; + } + } + + assert(!buffer.empty() && "no characters in buffer!"); + + // Drop down to FormatPrecision. + // TODO: don't do more precise calculations above than are required. + AdjustToPrecision(buffer, exp, FormatPrecision); + + unsigned NDigits = buffer.size(); + + // Check whether we should use scientific notation. + bool FormatScientific; + if (!FormatMaxPadding) + FormatScientific = true; + else { + if (exp >= 0) { + // 765e3 --> 765000 + // ^^^ + // But we shouldn't make the number look more precise than it is. + FormatScientific = ((unsigned) exp > FormatMaxPadding || + NDigits + (unsigned) exp > FormatPrecision); + } else { + // Power of the most significant digit. + int MSD = exp + (int) (NDigits - 1); + if (MSD >= 0) { + // 765e-2 == 7.65 + FormatScientific = false; + } else { + // 765e-5 == 0.00765 + // ^ ^^ + FormatScientific = ((unsigned) -MSD) > FormatMaxPadding; + } + } + } + + // Scientific formatting is pretty straightforward. + if (FormatScientific) { + exp += (NDigits - 1); + + Str.push_back(buffer[NDigits-1]); + Str.push_back('.'); + if (NDigits == 1) + Str.push_back('0'); + else + for (unsigned I = 1; I != NDigits; ++I) + Str.push_back(buffer[NDigits-1-I]); + Str.push_back('E'); + + Str.push_back(exp >= 0 ? '+' : '-'); + if (exp < 0) exp = -exp; + SmallVector<char, 6> expbuf; + do { + expbuf.push_back((char) ('0' + (exp % 10))); + exp /= 10; + } while (exp); + for (unsigned I = 0, E = expbuf.size(); I != E; ++I) + Str.push_back(expbuf[E-1-I]); + return; + } + + // Non-scientific, positive exponents. + if (exp >= 0) { + for (unsigned I = 0; I != NDigits; ++I) + Str.push_back(buffer[NDigits-1-I]); + for (unsigned I = 0; I != (unsigned) exp; ++I) + Str.push_back('0'); + return; + } + + // Non-scientific, negative exponents. + + // The number of digits to the left of the decimal point. + int NWholeDigits = exp + (int) NDigits; + + unsigned I = 0; + if (NWholeDigits > 0) { + for (; I != (unsigned) NWholeDigits; ++I) + Str.push_back(buffer[NDigits-I-1]); + Str.push_back('.'); + } else { + unsigned NZeros = 1 + (unsigned) -NWholeDigits; + + Str.push_back('0'); + Str.push_back('.'); + for (unsigned Z = 1; Z != NZeros; ++Z) + Str.push_back('0'); + } + + for (; I != NDigits; ++I) + Str.push_back(buffer[NDigits-I-1]); +} + +bool APFloat::getExactInverse(APFloat *inv) const { + // We can only guarantee the existence of an exact inverse for IEEE floats. + if (semantics != &IEEEhalf && semantics != &IEEEsingle && + semantics != &IEEEdouble && semantics != &IEEEquad) + return false; + + // Special floats and denormals have no exact inverse. + if (category != fcNormal) + return false; + + // Check that the number is a power of two by making sure that only the + // integer bit is set in the significand. + if (significandLSB() != semantics->precision - 1) + return false; + + // Get the inverse. + APFloat reciprocal(*semantics, 1ULL); + if (reciprocal.divide(*this, rmNearestTiesToEven) != opOK) + return false; + + // Avoid multiplication with a denormal, it is not safe on all platforms and + // may be slower than a normal division. + if (reciprocal.significandMSB() + 1 < reciprocal.semantics->precision) + return false; + + assert(reciprocal.category == fcNormal && + reciprocal.significandLSB() == reciprocal.semantics->precision - 1); + + if (inv) + *inv = reciprocal; + + return true; +} diff --git a/contrib/llvm/lib/Support/APInt.cpp b/contrib/llvm/lib/Support/APInt.cpp new file mode 100644 index 0000000..9b81fe7 --- /dev/null +++ b/contrib/llvm/lib/Support/APInt.cpp @@ -0,0 +1,2870 @@ +//===-- APInt.cpp - Implement APInt class ---------------------------------===// +// +// 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 class to represent arbitrary precision integer +// constant values and provide a variety of arithmetic operations on them. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "apint" +#include "llvm/ADT/APInt.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" +#include "llvm/Support/raw_ostream.h" +#include <cmath> +#include <limits> +#include <cstring> +#include <cstdlib> +using namespace llvm; + +/// A utility function for allocating memory, checking for allocation failures, +/// and ensuring the contents are zeroed. +inline static uint64_t* getClearedMemory(unsigned numWords) { + uint64_t * result = new uint64_t[numWords]; + assert(result && "APInt memory allocation fails!"); + memset(result, 0, numWords * sizeof(uint64_t)); + return result; +} + +/// A utility function for allocating memory and checking for allocation +/// failure. The content is not zeroed. +inline static uint64_t* getMemory(unsigned numWords) { + uint64_t * result = new uint64_t[numWords]; + assert(result && "APInt memory allocation fails!"); + return result; +} + +/// A utility function that converts a character to a digit. +inline static unsigned getDigit(char cdigit, uint8_t radix) { + unsigned r; + + if (radix == 16 || radix == 36) { + r = cdigit - '0'; + if (r <= 9) + return r; + + r = cdigit - 'A'; + if (r <= radix - 11U) + return r + 10; + + r = cdigit - 'a'; + if (r <= radix - 11U) + return r + 10; + + radix = 10; + } + + r = cdigit - '0'; + if (r < radix) + return r; + + return -1U; +} + + +void APInt::initSlowCase(unsigned numBits, uint64_t val, bool isSigned) { + pVal = getClearedMemory(getNumWords()); + pVal[0] = val; + if (isSigned && int64_t(val) < 0) + for (unsigned i = 1; i < getNumWords(); ++i) + pVal[i] = -1ULL; +} + +void APInt::initSlowCase(const APInt& that) { + pVal = getMemory(getNumWords()); + memcpy(pVal, that.pVal, getNumWords() * APINT_WORD_SIZE); +} + +void APInt::initFromArray(ArrayRef<uint64_t> bigVal) { + assert(BitWidth && "Bitwidth too small"); + assert(bigVal.data() && "Null pointer detected!"); + if (isSingleWord()) + VAL = bigVal[0]; + else { + // Get memory, cleared to 0 + pVal = getClearedMemory(getNumWords()); + // Calculate the number of words to copy + unsigned words = std::min<unsigned>(bigVal.size(), getNumWords()); + // Copy the words from bigVal to pVal + memcpy(pVal, bigVal.data(), words * APINT_WORD_SIZE); + } + // Make sure unused high bits are cleared + clearUnusedBits(); +} + +APInt::APInt(unsigned numBits, ArrayRef<uint64_t> bigVal) + : BitWidth(numBits), VAL(0) { + initFromArray(bigVal); +} + +APInt::APInt(unsigned numBits, unsigned numWords, const uint64_t bigVal[]) + : BitWidth(numBits), VAL(0) { + initFromArray(makeArrayRef(bigVal, numWords)); +} + +APInt::APInt(unsigned numbits, StringRef Str, uint8_t radix) + : BitWidth(numbits), VAL(0) { + assert(BitWidth && "Bitwidth too small"); + fromString(numbits, Str, radix); +} + +APInt& APInt::AssignSlowCase(const APInt& RHS) { + // Don't do anything for X = X + if (this == &RHS) + return *this; + + if (BitWidth == RHS.getBitWidth()) { + // assume same bit-width single-word case is already handled + assert(!isSingleWord()); + memcpy(pVal, RHS.pVal, getNumWords() * APINT_WORD_SIZE); + return *this; + } + + if (isSingleWord()) { + // assume case where both are single words is already handled + assert(!RHS.isSingleWord()); + VAL = 0; + pVal = getMemory(RHS.getNumWords()); + memcpy(pVal, RHS.pVal, RHS.getNumWords() * APINT_WORD_SIZE); + } else if (getNumWords() == RHS.getNumWords()) + memcpy(pVal, RHS.pVal, RHS.getNumWords() * APINT_WORD_SIZE); + else if (RHS.isSingleWord()) { + delete [] pVal; + VAL = RHS.VAL; + } else { + delete [] pVal; + pVal = getMemory(RHS.getNumWords()); + memcpy(pVal, RHS.pVal, RHS.getNumWords() * APINT_WORD_SIZE); + } + BitWidth = RHS.BitWidth; + return clearUnusedBits(); +} + +APInt& APInt::operator=(uint64_t RHS) { + if (isSingleWord()) + VAL = RHS; + else { + pVal[0] = RHS; + memset(pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE); + } + return clearUnusedBits(); +} + +/// Profile - This method 'profiles' an APInt for use with FoldingSet. +void APInt::Profile(FoldingSetNodeID& ID) const { + ID.AddInteger(BitWidth); + + if (isSingleWord()) { + ID.AddInteger(VAL); + return; + } + + unsigned NumWords = getNumWords(); + for (unsigned i = 0; i < NumWords; ++i) + ID.AddInteger(pVal[i]); +} + +/// add_1 - This function adds a single "digit" integer, y, to the multiple +/// "digit" integer array, x[]. x[] is modified to reflect the addition and +/// 1 is returned if there is a carry out, otherwise 0 is returned. +/// @returns the carry of the addition. +static bool add_1(uint64_t dest[], uint64_t x[], unsigned len, uint64_t y) { + for (unsigned i = 0; i < len; ++i) { + dest[i] = y + x[i]; + if (dest[i] < y) + y = 1; // Carry one to next digit. + else { + y = 0; // No need to carry so exit early + break; + } + } + return y; +} + +/// @brief Prefix increment operator. Increments the APInt by one. +APInt& APInt::operator++() { + if (isSingleWord()) + ++VAL; + else + add_1(pVal, pVal, getNumWords(), 1); + return clearUnusedBits(); +} + +/// sub_1 - This function subtracts a single "digit" (64-bit word), y, from +/// the multi-digit integer array, x[], propagating the borrowed 1 value until +/// no further borrowing is neeeded or it runs out of "digits" in x. The result +/// is 1 if "borrowing" exhausted the digits in x, or 0 if x was not exhausted. +/// In other words, if y > x then this function returns 1, otherwise 0. +/// @returns the borrow out of the subtraction +static bool sub_1(uint64_t x[], unsigned len, uint64_t y) { + for (unsigned i = 0; i < len; ++i) { + uint64_t X = x[i]; + x[i] -= y; + if (y > X) + y = 1; // We have to "borrow 1" from next "digit" + else { + y = 0; // No need to borrow + break; // Remaining digits are unchanged so exit early + } + } + return bool(y); +} + +/// @brief Prefix decrement operator. Decrements the APInt by one. +APInt& APInt::operator--() { + if (isSingleWord()) + --VAL; + else + sub_1(pVal, getNumWords(), 1); + return clearUnusedBits(); +} + +/// add - This function adds the integer array x to the integer array Y and +/// places the result in dest. +/// @returns the carry out from the addition +/// @brief General addition of 64-bit integer arrays +static bool add(uint64_t *dest, const uint64_t *x, const uint64_t *y, + unsigned len) { + bool carry = false; + for (unsigned i = 0; i< len; ++i) { + uint64_t limit = std::min(x[i],y[i]); // must come first in case dest == x + dest[i] = x[i] + y[i] + carry; + carry = dest[i] < limit || (carry && dest[i] == limit); + } + return carry; +} + +/// Adds the RHS APint to this APInt. +/// @returns this, after addition of RHS. +/// @brief Addition assignment operator. +APInt& APInt::operator+=(const APInt& RHS) { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) + VAL += RHS.VAL; + else { + add(pVal, pVal, RHS.pVal, getNumWords()); + } + return clearUnusedBits(); +} + +/// Subtracts the integer array y from the integer array x +/// @returns returns the borrow out. +/// @brief Generalized subtraction of 64-bit integer arrays. +static bool sub(uint64_t *dest, const uint64_t *x, const uint64_t *y, + unsigned len) { + bool borrow = false; + for (unsigned i = 0; i < len; ++i) { + uint64_t x_tmp = borrow ? x[i] - 1 : x[i]; + borrow = y[i] > x_tmp || (borrow && x[i] == 0); + dest[i] = x_tmp - y[i]; + } + return borrow; +} + +/// Subtracts the RHS APInt from this APInt +/// @returns this, after subtraction +/// @brief Subtraction assignment operator. +APInt& APInt::operator-=(const APInt& RHS) { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) + VAL -= RHS.VAL; + else + sub(pVal, pVal, RHS.pVal, getNumWords()); + return clearUnusedBits(); +} + +/// Multiplies an integer array, x, by a uint64_t integer and places the result +/// into dest. +/// @returns the carry out of the multiplication. +/// @brief Multiply a multi-digit APInt by a single digit (64-bit) integer. +static uint64_t mul_1(uint64_t dest[], uint64_t x[], unsigned len, uint64_t y) { + // Split y into high 32-bit part (hy) and low 32-bit part (ly) + uint64_t ly = y & 0xffffffffULL, hy = y >> 32; + uint64_t carry = 0; + + // For each digit of x. + for (unsigned i = 0; i < len; ++i) { + // Split x into high and low words + uint64_t lx = x[i] & 0xffffffffULL; + uint64_t hx = x[i] >> 32; + // hasCarry - A flag to indicate if there is a carry to the next digit. + // hasCarry == 0, no carry + // hasCarry == 1, has carry + // hasCarry == 2, no carry and the calculation result == 0. + uint8_t hasCarry = 0; + dest[i] = carry + lx * ly; + // Determine if the add above introduces carry. + hasCarry = (dest[i] < carry) ? 1 : 0; + carry = hx * ly + (dest[i] >> 32) + (hasCarry ? (1ULL << 32) : 0); + // The upper limit of carry can be (2^32 - 1)(2^32 - 1) + + // (2^32 - 1) + 2^32 = 2^64. + hasCarry = (!carry && hasCarry) ? 1 : (!carry ? 2 : 0); + + carry += (lx * hy) & 0xffffffffULL; + dest[i] = (carry << 32) | (dest[i] & 0xffffffffULL); + carry = (((!carry && hasCarry != 2) || hasCarry == 1) ? (1ULL << 32) : 0) + + (carry >> 32) + ((lx * hy) >> 32) + hx * hy; + } + return carry; +} + +/// Multiplies integer array x by integer array y and stores the result into +/// the integer array dest. Note that dest's size must be >= xlen + ylen. +/// @brief Generalized multiplicate of integer arrays. +static void mul(uint64_t dest[], uint64_t x[], unsigned xlen, uint64_t y[], + unsigned ylen) { + dest[xlen] = mul_1(dest, x, xlen, y[0]); + for (unsigned i = 1; i < ylen; ++i) { + uint64_t ly = y[i] & 0xffffffffULL, hy = y[i] >> 32; + uint64_t carry = 0, lx = 0, hx = 0; + for (unsigned j = 0; j < xlen; ++j) { + lx = x[j] & 0xffffffffULL; + hx = x[j] >> 32; + // hasCarry - A flag to indicate if has carry. + // hasCarry == 0, no carry + // hasCarry == 1, has carry + // hasCarry == 2, no carry and the calculation result == 0. + uint8_t hasCarry = 0; + uint64_t resul = carry + lx * ly; + hasCarry = (resul < carry) ? 1 : 0; + carry = (hasCarry ? (1ULL << 32) : 0) + hx * ly + (resul >> 32); + hasCarry = (!carry && hasCarry) ? 1 : (!carry ? 2 : 0); + + carry += (lx * hy) & 0xffffffffULL; + resul = (carry << 32) | (resul & 0xffffffffULL); + dest[i+j] += resul; + carry = (((!carry && hasCarry != 2) || hasCarry == 1) ? (1ULL << 32) : 0)+ + (carry >> 32) + (dest[i+j] < resul ? 1 : 0) + + ((lx * hy) >> 32) + hx * hy; + } + dest[i+xlen] = carry; + } +} + +APInt& APInt::operator*=(const APInt& RHS) { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) { + VAL *= RHS.VAL; + clearUnusedBits(); + return *this; + } + + // Get some bit facts about LHS and check for zero + unsigned lhsBits = getActiveBits(); + unsigned lhsWords = !lhsBits ? 0 : whichWord(lhsBits - 1) + 1; + if (!lhsWords) + // 0 * X ===> 0 + return *this; + + // Get some bit facts about RHS and check for zero + unsigned rhsBits = RHS.getActiveBits(); + unsigned rhsWords = !rhsBits ? 0 : whichWord(rhsBits - 1) + 1; + if (!rhsWords) { + // X * 0 ===> 0 + clearAllBits(); + return *this; + } + + // Allocate space for the result + unsigned destWords = rhsWords + lhsWords; + uint64_t *dest = getMemory(destWords); + + // Perform the long multiply + mul(dest, pVal, lhsWords, RHS.pVal, rhsWords); + + // Copy result back into *this + clearAllBits(); + unsigned wordsToCopy = destWords >= getNumWords() ? getNumWords() : destWords; + memcpy(pVal, dest, wordsToCopy * APINT_WORD_SIZE); + clearUnusedBits(); + + // delete dest array and return + delete[] dest; + return *this; +} + +APInt& APInt::operator&=(const APInt& RHS) { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) { + VAL &= RHS.VAL; + return *this; + } + unsigned numWords = getNumWords(); + for (unsigned i = 0; i < numWords; ++i) + pVal[i] &= RHS.pVal[i]; + return *this; +} + +APInt& APInt::operator|=(const APInt& RHS) { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) { + VAL |= RHS.VAL; + return *this; + } + unsigned numWords = getNumWords(); + for (unsigned i = 0; i < numWords; ++i) + pVal[i] |= RHS.pVal[i]; + return *this; +} + +APInt& APInt::operator^=(const APInt& RHS) { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) { + VAL ^= RHS.VAL; + this->clearUnusedBits(); + return *this; + } + unsigned numWords = getNumWords(); + for (unsigned i = 0; i < numWords; ++i) + pVal[i] ^= RHS.pVal[i]; + return clearUnusedBits(); +} + +APInt APInt::AndSlowCase(const APInt& RHS) const { + unsigned numWords = getNumWords(); + uint64_t* val = getMemory(numWords); + for (unsigned i = 0; i < numWords; ++i) + val[i] = pVal[i] & RHS.pVal[i]; + return APInt(val, getBitWidth()); +} + +APInt APInt::OrSlowCase(const APInt& RHS) const { + unsigned numWords = getNumWords(); + uint64_t *val = getMemory(numWords); + for (unsigned i = 0; i < numWords; ++i) + val[i] = pVal[i] | RHS.pVal[i]; + return APInt(val, getBitWidth()); +} + +APInt APInt::XorSlowCase(const APInt& RHS) const { + unsigned numWords = getNumWords(); + uint64_t *val = getMemory(numWords); + for (unsigned i = 0; i < numWords; ++i) + val[i] = pVal[i] ^ RHS.pVal[i]; + + // 0^0==1 so clear the high bits in case they got set. + return APInt(val, getBitWidth()).clearUnusedBits(); +} + +APInt APInt::operator*(const APInt& RHS) const { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) + return APInt(BitWidth, VAL * RHS.VAL); + APInt Result(*this); + Result *= RHS; + return Result; +} + +APInt APInt::operator+(const APInt& RHS) const { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) + return APInt(BitWidth, VAL + RHS.VAL); + APInt Result(BitWidth, 0); + add(Result.pVal, this->pVal, RHS.pVal, getNumWords()); + return Result.clearUnusedBits(); +} + +APInt APInt::operator-(const APInt& RHS) const { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) + return APInt(BitWidth, VAL - RHS.VAL); + APInt Result(BitWidth, 0); + sub(Result.pVal, this->pVal, RHS.pVal, getNumWords()); + return Result.clearUnusedBits(); +} + +bool APInt::EqualSlowCase(const APInt& RHS) const { + // Get some facts about the number of bits used in the two operands. + unsigned n1 = getActiveBits(); + unsigned n2 = RHS.getActiveBits(); + + // If the number of bits isn't the same, they aren't equal + if (n1 != n2) + return false; + + // If the number of bits fits in a word, we only need to compare the low word. + if (n1 <= APINT_BITS_PER_WORD) + return pVal[0] == RHS.pVal[0]; + + // Otherwise, compare everything + for (int i = whichWord(n1 - 1); i >= 0; --i) + if (pVal[i] != RHS.pVal[i]) + return false; + return true; +} + +bool APInt::EqualSlowCase(uint64_t Val) const { + unsigned n = getActiveBits(); + if (n <= APINT_BITS_PER_WORD) + return pVal[0] == Val; + else + return false; +} + +bool APInt::ult(const APInt& RHS) const { + assert(BitWidth == RHS.BitWidth && "Bit widths must be same for comparison"); + if (isSingleWord()) + return VAL < RHS.VAL; + + // Get active bit length of both operands + unsigned n1 = getActiveBits(); + unsigned n2 = RHS.getActiveBits(); + + // If magnitude of LHS is less than RHS, return true. + if (n1 < n2) + return true; + + // If magnitude of RHS is greather than LHS, return false. + if (n2 < n1) + return false; + + // If they bot fit in a word, just compare the low order word + if (n1 <= APINT_BITS_PER_WORD && n2 <= APINT_BITS_PER_WORD) + return pVal[0] < RHS.pVal[0]; + + // Otherwise, compare all words + unsigned topWord = whichWord(std::max(n1,n2)-1); + for (int i = topWord; i >= 0; --i) { + if (pVal[i] > RHS.pVal[i]) + return false; + if (pVal[i] < RHS.pVal[i]) + return true; + } + return false; +} + +bool APInt::slt(const APInt& RHS) const { + assert(BitWidth == RHS.BitWidth && "Bit widths must be same for comparison"); + if (isSingleWord()) { + int64_t lhsSext = (int64_t(VAL) << (64-BitWidth)) >> (64-BitWidth); + int64_t rhsSext = (int64_t(RHS.VAL) << (64-BitWidth)) >> (64-BitWidth); + return lhsSext < rhsSext; + } + + APInt lhs(*this); + APInt rhs(RHS); + bool lhsNeg = isNegative(); + bool rhsNeg = rhs.isNegative(); + if (lhsNeg) { + // Sign bit is set so perform two's complement to make it positive + lhs.flipAllBits(); + lhs++; + } + if (rhsNeg) { + // Sign bit is set so perform two's complement to make it positive + rhs.flipAllBits(); + rhs++; + } + + // Now we have unsigned values to compare so do the comparison if necessary + // based on the negativeness of the values. + if (lhsNeg) + if (rhsNeg) + return lhs.ugt(rhs); + else + return true; + else if (rhsNeg) + return false; + else + return lhs.ult(rhs); +} + +void APInt::setBit(unsigned bitPosition) { + if (isSingleWord()) + VAL |= maskBit(bitPosition); + else + pVal[whichWord(bitPosition)] |= maskBit(bitPosition); +} + +/// Set the given bit to 0 whose position is given as "bitPosition". +/// @brief Set a given bit to 0. +void APInt::clearBit(unsigned bitPosition) { + if (isSingleWord()) + VAL &= ~maskBit(bitPosition); + else + pVal[whichWord(bitPosition)] &= ~maskBit(bitPosition); +} + +/// @brief Toggle every bit to its opposite value. + +/// Toggle a given bit to its opposite value whose position is given +/// as "bitPosition". +/// @brief Toggles a given bit to its opposite value. +void APInt::flipBit(unsigned bitPosition) { + assert(bitPosition < BitWidth && "Out of the bit-width range!"); + if ((*this)[bitPosition]) clearBit(bitPosition); + else setBit(bitPosition); +} + +unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) { + assert(!str.empty() && "Invalid string length"); + assert((radix == 10 || radix == 8 || radix == 16 || radix == 2 || + radix == 36) && + "Radix should be 2, 8, 10, 16, or 36!"); + + size_t slen = str.size(); + + // Each computation below needs to know if it's negative. + StringRef::iterator p = str.begin(); + unsigned isNegative = *p == '-'; + if (*p == '-' || *p == '+') { + p++; + slen--; + assert(slen && "String is only a sign, needs a value."); + } + + // For radixes of power-of-two values, the bits required is accurately and + // easily computed + if (radix == 2) + return slen + isNegative; + if (radix == 8) + return slen * 3 + isNegative; + if (radix == 16) + return slen * 4 + isNegative; + + // FIXME: base 36 + + // This is grossly inefficient but accurate. We could probably do something + // with a computation of roughly slen*64/20 and then adjust by the value of + // the first few digits. But, I'm not sure how accurate that could be. + + // Compute a sufficient number of bits that is always large enough but might + // be too large. This avoids the assertion in the constructor. This + // calculation doesn't work appropriately for the numbers 0-9, so just use 4 + // bits in that case. + unsigned sufficient + = radix == 10? (slen == 1 ? 4 : slen * 64/18) + : (slen == 1 ? 7 : slen * 16/3); + + // Convert to the actual binary value. + APInt tmp(sufficient, StringRef(p, slen), radix); + + // Compute how many bits are required. If the log is infinite, assume we need + // just bit. + unsigned log = tmp.logBase2(); + if (log == (unsigned)-1) { + return isNegative + 1; + } else { + return isNegative + log + 1; + } +} + +hash_code llvm::hash_value(const APInt &Arg) { + if (Arg.isSingleWord()) + return hash_combine(Arg.VAL); + + return hash_combine_range(Arg.pVal, Arg.pVal + Arg.getNumWords()); +} + +/// HiBits - This function returns the high "numBits" bits of this APInt. +APInt APInt::getHiBits(unsigned numBits) const { + return APIntOps::lshr(*this, BitWidth - numBits); +} + +/// LoBits - This function returns the low "numBits" bits of this APInt. +APInt APInt::getLoBits(unsigned numBits) const { + return APIntOps::lshr(APIntOps::shl(*this, BitWidth - numBits), + BitWidth - numBits); +} + +unsigned APInt::countLeadingZerosSlowCase() const { + // Treat the most significand word differently because it might have + // meaningless bits set beyond the precision. + unsigned BitsInMSW = BitWidth % APINT_BITS_PER_WORD; + integerPart MSWMask; + if (BitsInMSW) MSWMask = (integerPart(1) << BitsInMSW) - 1; + else { + MSWMask = ~integerPart(0); + BitsInMSW = APINT_BITS_PER_WORD; + } + + unsigned i = getNumWords(); + integerPart MSW = pVal[i-1] & MSWMask; + if (MSW) + return CountLeadingZeros_64(MSW) - (APINT_BITS_PER_WORD - BitsInMSW); + + unsigned Count = BitsInMSW; + for (--i; i > 0u; --i) { + if (pVal[i-1] == 0) + Count += APINT_BITS_PER_WORD; + else { + Count += CountLeadingZeros_64(pVal[i-1]); + break; + } + } + return Count; +} + +unsigned APInt::countLeadingOnes() const { + if (isSingleWord()) + return CountLeadingOnes_64(VAL << (APINT_BITS_PER_WORD - BitWidth)); + + unsigned highWordBits = BitWidth % APINT_BITS_PER_WORD; + unsigned shift; + if (!highWordBits) { + highWordBits = APINT_BITS_PER_WORD; + shift = 0; + } else { + shift = APINT_BITS_PER_WORD - highWordBits; + } + int i = getNumWords() - 1; + 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]); + break; + } + } + } + return Count; +} + +unsigned APInt::countTrailingZeros() const { + if (isSingleWord()) + return std::min(unsigned(CountTrailingZeros_64(VAL)), BitWidth); + unsigned Count = 0; + unsigned i = 0; + for (; i < getNumWords() && pVal[i] == 0; ++i) + Count += APINT_BITS_PER_WORD; + if (i < getNumWords()) + Count += CountTrailingZeros_64(pVal[i]); + return std::min(Count, BitWidth); +} + +unsigned APInt::countTrailingOnesSlowCase() const { + unsigned Count = 0; + unsigned i = 0; + for (; i < getNumWords() && pVal[i] == -1ULL; ++i) + Count += APINT_BITS_PER_WORD; + if (i < getNumWords()) + Count += CountTrailingOnes_64(pVal[i]); + return std::min(Count, BitWidth); +} + +unsigned APInt::countPopulationSlowCase() const { + unsigned Count = 0; + for (unsigned i = 0; i < getNumWords(); ++i) + Count += CountPopulation_64(pVal[i]); + 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))); + if (BitWidth == 32) + return APInt(BitWidth, ByteSwap_32(unsigned(VAL))); + 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); + } + if (BitWidth == 64) + return APInt(BitWidth, ByteSwap_64(VAL)); + + 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, + const APInt& API2) { + APInt A = API1, B = API2; + while (!!B) { + APInt T = B; + B = APIntOps::urem(A, B); + A = T; + } + return A; +} + +APInt llvm::APIntOps::RoundDoubleToAPInt(double Double, unsigned width) { + union { + double D; + uint64_t I; + } T; + T.D = Double; + + // Get the sign bit from the highest order bit + bool isNeg = T.I >> 63; + + // Get the 11-bit exponent and adjust for the 1023 bit bias + int64_t exp = ((T.I >> 52) & 0x7ff) - 1023; + + // If the exponent is negative, the value is < 0 so just return 0. + if (exp < 0) + return APInt(width, 0u); + + // Extract the mantissa by clearing the top 12 bits (sign + exponent). + uint64_t mantissa = (T.I & (~0ULL >> 12)) | 1ULL << 52; + + // If the exponent doesn't shift all bits out of the mantissa + if (exp < 52) + return isNeg ? -APInt(width, mantissa >> (52 - exp)) : + APInt(width, mantissa >> (52 - exp)); + + // If the client didn't provide enough bits for us to shift the mantissa into + // then the result is undefined, just return 0 + if (width <= exp - 52) + return APInt(width, 0); + + // Otherwise, we have to shift the mantissa bits up to the right location + APInt Tmp(width, mantissa); + Tmp = Tmp.shl((unsigned)exp - 52); + return isNeg ? -Tmp : Tmp; +} + +/// RoundToDouble - This function converts this APInt to a double. +/// The layout for double is as following (IEEE Standard 754): +/// -------------------------------------- +/// | Sign Exponent Fraction Bias | +/// |-------------------------------------- | +/// | 1[63] 11[62-52] 52[51-00] 1023 | +/// -------------------------------------- +double APInt::roundToDouble(bool isSigned) const { + + // Handle the simple case where the value is contained in one uint64_t. + // It is wrong to optimize getWord(0) to VAL; there might be more than one word. + if (isSingleWord() || getActiveBits() <= APINT_BITS_PER_WORD) { + if (isSigned) { + int64_t sext = (int64_t(getWord(0)) << (64-BitWidth)) >> (64-BitWidth); + return double(sext); + } else + return double(getWord(0)); + } + + // Determine if the value is negative. + bool isNeg = isSigned ? (*this)[BitWidth-1] : false; + + // Construct the absolute value if we're negative. + APInt Tmp(isNeg ? -(*this) : (*this)); + + // Figure out how many bits we're using. + unsigned n = Tmp.getActiveBits(); + + // The exponent (without bias normalization) is just the number of bits + // we are using. Note that the sign bit is gone since we constructed the + // absolute value. + uint64_t exp = n; + + // Return infinity for exponent overflow + if (exp > 1023) { + if (!isSigned || !isNeg) + return std::numeric_limits<double>::infinity(); + else + return -std::numeric_limits<double>::infinity(); + } + exp += 1023; // Increment for 1023 bias + + // Number of bits in mantissa is 52. To obtain the mantissa value, we must + // extract the high 52 bits from the correct words in pVal. + uint64_t mantissa; + unsigned hiWord = whichWord(n-1); + if (hiWord == 0) { + mantissa = Tmp.pVal[0]; + if (n > 52) + mantissa >>= n - 52; // shift down, we want the top 52 bits. + } else { + assert(hiWord > 0 && "huh?"); + uint64_t hibits = Tmp.pVal[hiWord] << (52 - n % APINT_BITS_PER_WORD); + uint64_t lobits = Tmp.pVal[hiWord-1] >> (11 + n % APINT_BITS_PER_WORD); + mantissa = hibits | lobits; + } + + // The leading bit of mantissa is implicit, so get rid of it. + uint64_t sign = isNeg ? (1ULL << (APINT_BITS_PER_WORD - 1)) : 0; + union { + double D; + uint64_t I; + } T; + T.I = sign | (exp << 52) | mantissa; + return T.D; +} + +// Truncate to new width. +APInt APInt::trunc(unsigned width) const { + assert(width < BitWidth && "Invalid APInt Truncate request"); + assert(width && "Can't truncate to 0 bits"); + + if (width <= APINT_BITS_PER_WORD) + return APInt(width, getRawData()[0]); + + APInt Result(getMemory(getNumWords(width)), width); + + // Copy full words. + unsigned i; + for (i = 0; i != width / APINT_BITS_PER_WORD; i++) + Result.pVal[i] = pVal[i]; + + // Truncate and copy any partial word. + unsigned bits = (0 - width) % APINT_BITS_PER_WORD; + if (bits != 0) + Result.pVal[i] = pVal[i] << bits >> bits; + + return Result; +} + +// Sign extend to a new width. +APInt APInt::sext(unsigned width) const { + assert(width > BitWidth && "Invalid APInt SignExtend request"); + + if (width <= APINT_BITS_PER_WORD) { + uint64_t val = VAL << (APINT_BITS_PER_WORD - BitWidth); + val = (int64_t)val >> (width - BitWidth); + return APInt(width, val >> (APINT_BITS_PER_WORD - width)); + } + + APInt Result(getMemory(getNumWords(width)), width); + + // Copy full words. + unsigned i; + uint64_t word = 0; + for (i = 0; i != BitWidth / APINT_BITS_PER_WORD; i++) { + word = getRawData()[i]; + Result.pVal[i] = word; + } + + // Read and sign-extend any partial word. + unsigned bits = (0 - BitWidth) % APINT_BITS_PER_WORD; + if (bits != 0) + word = (int64_t)getRawData()[i] << bits >> bits; + else + word = (int64_t)word >> (APINT_BITS_PER_WORD - 1); + + // Write remaining full words. + for (; i != width / APINT_BITS_PER_WORD; i++) { + Result.pVal[i] = word; + word = (int64_t)word >> (APINT_BITS_PER_WORD - 1); + } + + // Write any partial word. + bits = (0 - width) % APINT_BITS_PER_WORD; + if (bits != 0) + Result.pVal[i] = word << bits >> bits; + + return Result; +} + +// Zero extend to a new width. +APInt APInt::zext(unsigned width) const { + assert(width > BitWidth && "Invalid APInt ZeroExtend request"); + + if (width <= APINT_BITS_PER_WORD) + return APInt(width, VAL); + + APInt Result(getMemory(getNumWords(width)), width); + + // Copy words. + unsigned i; + for (i = 0; i != getNumWords(); i++) + Result.pVal[i] = getRawData()[i]; + + // Zero remaining words. + memset(&Result.pVal[i], 0, (Result.getNumWords() - i) * APINT_WORD_SIZE); + + return Result; +} + +APInt APInt::zextOrTrunc(unsigned width) const { + if (BitWidth < width) + return zext(width); + if (BitWidth > width) + return trunc(width); + return *this; +} + +APInt APInt::sextOrTrunc(unsigned width) const { + if (BitWidth < width) + return sext(width); + if (BitWidth > width) + return trunc(width); + 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 { + return ashr((unsigned)shiftAmt.getLimitedValue(BitWidth)); +} + +/// Arithmetic right-shift this APInt by shiftAmt. +/// @brief Arithmetic right-shift function. +APInt APInt::ashr(unsigned shiftAmt) const { + assert(shiftAmt <= BitWidth && "Invalid shift amount"); + // Handle a degenerate case + if (shiftAmt == 0) + return *this; + + // Handle single word shifts with built-in ashr + if (isSingleWord()) { + if (shiftAmt == BitWidth) + return APInt(BitWidth, 0); // undefined + else { + unsigned SignBit = APINT_BITS_PER_WORD - BitWidth; + return APInt(BitWidth, + (((int64_t(VAL) << SignBit) >> SignBit) >> shiftAmt)); + } + } + + // If all the bits were shifted out, the result is, technically, undefined. + // We return -1 if it was negative, 0 otherwise. We check this early to avoid + // issues in the algorithm below. + if (shiftAmt == BitWidth) { + if (isNegative()) + return APInt(BitWidth, -1ULL, true); + else + return APInt(BitWidth, 0); + } + + // Create some space for the result. + uint64_t * val = new uint64_t[getNumWords()]; + + // Compute some values needed by the following shift algorithms + unsigned wordShift = shiftAmt % APINT_BITS_PER_WORD; // bits to shift per word + unsigned offset = shiftAmt / APINT_BITS_PER_WORD; // word offset for shift + unsigned breakWord = getNumWords() - 1 - offset; // last word affected + unsigned bitsInWord = whichBit(BitWidth); // how many bits in last word? + if (bitsInWord == 0) + bitsInWord = APINT_BITS_PER_WORD; + + // If we are shifting whole words, just move whole words + if (wordShift == 0) { + // Move the words containing significant bits + for (unsigned i = 0; i <= breakWord; ++i) + val[i] = pVal[i+offset]; // move whole word + + // Adjust the top significant word for sign bit fill, if negative + if (isNegative()) + if (bitsInWord < APINT_BITS_PER_WORD) + val[breakWord] |= ~0ULL << bitsInWord; // set high bits + } else { + // Shift the low order words + for (unsigned i = 0; i < breakWord; ++i) { + // This combines the shifted corresponding word with the low bits from + // the next word (shifted into this word's high bits). + val[i] = (pVal[i+offset] >> wordShift) | + (pVal[i+offset+1] << (APINT_BITS_PER_WORD - wordShift)); + } + + // Shift the break word. In this case there are no bits from the next word + // to include in this word. + val[breakWord] = pVal[breakWord+offset] >> wordShift; + + // Deal with sign extenstion in the break word, and possibly the word before + // it. + if (isNegative()) { + if (wordShift > bitsInWord) { + if (breakWord > 0) + val[breakWord-1] |= + ~0ULL << (APINT_BITS_PER_WORD - (wordShift - bitsInWord)); + val[breakWord] |= ~0ULL; + } else + val[breakWord] |= (~0ULL << (bitsInWord - wordShift)); + } + } + + // Remaining words are 0 or -1, just assign them. + uint64_t fillValue = (isNegative() ? -1ULL : 0); + for (unsigned i = breakWord+1; i < getNumWords(); ++i) + val[i] = fillValue; + return APInt(val, BitWidth).clearUnusedBits(); +} + +/// Logical right-shift this APInt by shiftAmt. +/// @brief Logical right-shift function. +APInt APInt::lshr(const APInt &shiftAmt) const { + return lshr((unsigned)shiftAmt.getLimitedValue(BitWidth)); +} + +/// Logical right-shift this APInt by shiftAmt. +/// @brief Logical right-shift function. +APInt APInt::lshr(unsigned shiftAmt) const { + if (isSingleWord()) { + if (shiftAmt >= BitWidth) + return APInt(BitWidth, 0); + else + return APInt(BitWidth, this->VAL >> shiftAmt); + } + + // If all the bits were shifted out, the result is 0. This avoids issues + // with shifting by the size of the integer type, which produces undefined + // results. We define these "undefined results" to always be 0. + if (shiftAmt == BitWidth) + return APInt(BitWidth, 0); + + // If none of the bits are shifted out, the result is *this. This avoids + // issues with shifting by the size of the integer type, which produces + // undefined results in the code below. This is also an optimization. + if (shiftAmt == 0) + return *this; + + // Create some space for the result. + uint64_t * val = new uint64_t[getNumWords()]; + + // If we are shifting less than a word, compute the shift with a simple carry + if (shiftAmt < APINT_BITS_PER_WORD) { + lshrNear(val, pVal, getNumWords(), shiftAmt); + return APInt(val, BitWidth).clearUnusedBits(); + } + + // Compute some values needed by the remaining shift algorithms + unsigned wordShift = shiftAmt % APINT_BITS_PER_WORD; + unsigned offset = shiftAmt / APINT_BITS_PER_WORD; + + // If we are shifting whole words, just move whole words + if (wordShift == 0) { + for (unsigned i = 0; i < getNumWords() - offset; ++i) + val[i] = pVal[i+offset]; + for (unsigned i = getNumWords()-offset; i < getNumWords(); i++) + val[i] = 0; + return APInt(val,BitWidth).clearUnusedBits(); + } + + // Shift the low order words + unsigned breakWord = getNumWords() - offset -1; + for (unsigned i = 0; i < breakWord; ++i) + val[i] = (pVal[i+offset] >> wordShift) | + (pVal[i+offset+1] << (APINT_BITS_PER_WORD - wordShift)); + // Shift the break word. + val[breakWord] = pVal[breakWord+offset] >> wordShift; + + // Remaining words are 0 + for (unsigned i = breakWord+1; i < getNumWords(); ++i) + val[i] = 0; + return APInt(val, BitWidth).clearUnusedBits(); +} + +/// Left-shift this APInt by shiftAmt. +/// @brief Left-shift function. +APInt APInt::shl(const APInt &shiftAmt) const { + // It's undefined behavior in C to shift by BitWidth or greater. + return shl((unsigned)shiftAmt.getLimitedValue(BitWidth)); +} + +APInt APInt::shlSlowCase(unsigned shiftAmt) const { + // If all the bits were shifted out, the result is 0. This avoids issues + // with shifting by the size of the integer type, which produces undefined + // results. We define these "undefined results" to always be 0. + if (shiftAmt == BitWidth) + return APInt(BitWidth, 0); + + // If none of the bits are shifted out, the result is *this. This avoids a + // lshr by the words size in the loop below which can produce incorrect + // results. It also avoids the expensive computation below for a common case. + if (shiftAmt == 0) + return *this; + + // Create some space for the result. + uint64_t * val = new uint64_t[getNumWords()]; + + // If we are shifting less than a word, do it the easy way + if (shiftAmt < APINT_BITS_PER_WORD) { + uint64_t carry = 0; + for (unsigned i = 0; i < getNumWords(); i++) { + val[i] = pVal[i] << shiftAmt | carry; + carry = pVal[i] >> (APINT_BITS_PER_WORD - shiftAmt); + } + return APInt(val, BitWidth).clearUnusedBits(); + } + + // Compute some values needed by the remaining shift algorithms + unsigned wordShift = shiftAmt % APINT_BITS_PER_WORD; + unsigned offset = shiftAmt / APINT_BITS_PER_WORD; + + // If we are shifting whole words, just move whole words + if (wordShift == 0) { + for (unsigned i = 0; i < offset; i++) + val[i] = 0; + for (unsigned i = offset; i < getNumWords(); i++) + val[i] = pVal[i-offset]; + return APInt(val,BitWidth).clearUnusedBits(); + } + + // Copy whole words from this to Result. + unsigned i = getNumWords() - 1; + for (; i > offset; --i) + val[i] = pVal[i-offset] << wordShift | + pVal[i-offset-1] >> (APINT_BITS_PER_WORD - wordShift); + val[offset] = pVal[0] << wordShift; + for (i = 0; i < offset; ++i) + val[i] = 0; + return APInt(val, BitWidth).clearUnusedBits(); +} + +APInt APInt::rotl(const APInt &rotateAmt) const { + return rotl((unsigned)rotateAmt.getLimitedValue(BitWidth)); +} + +APInt APInt::rotl(unsigned rotateAmt) const { + rotateAmt %= BitWidth; + if (rotateAmt == 0) + return *this; + return shl(rotateAmt) | lshr(BitWidth - rotateAmt); +} + +APInt APInt::rotr(const APInt &rotateAmt) const { + return rotr((unsigned)rotateAmt.getLimitedValue(BitWidth)); +} + +APInt APInt::rotr(unsigned rotateAmt) const { + rotateAmt %= BitWidth; + if (rotateAmt == 0) + return *this; + return lshr(rotateAmt) | shl(BitWidth - rotateAmt); +} + +// Square Root - this method computes and returns the square root of "this". +// Three mechanisms are used for computation. For small values (<= 5 bits), +// a table lookup is done. This gets some performance for common cases. For +// values using less than 52 bits, the value is converted to double and then +// the libc sqrt function is called. The result is rounded and then converted +// back to a uint64_t which is then used to construct the result. Finally, +// the Babylonian method for computing square roots is used. +APInt APInt::sqrt() const { + + // Determine the magnitude of the value. + unsigned magnitude = getActiveBits(); + + // Use a fast table for some small values. This also gets rid of some + // rounding errors in libc sqrt for small values. + if (magnitude <= 5) { + static const uint8_t results[32] = { + /* 0 */ 0, + /* 1- 2 */ 1, 1, + /* 3- 6 */ 2, 2, 2, 2, + /* 7-12 */ 3, 3, 3, 3, 3, 3, + /* 13-20 */ 4, 4, 4, 4, 4, 4, 4, 4, + /* 21-30 */ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + /* 31 */ 6 + }; + return APInt(BitWidth, results[ (isSingleWord() ? VAL : pVal[0]) ]); + } + + // If the magnitude of the value fits in less than 52 bits (the precision of + // an IEEE double precision floating point value), then we can use the + // libc sqrt function which will probably use a hardware sqrt computation. + // This should be faster than the algorithm below. + if (magnitude < 52) { +#if HAVE_ROUND + return APInt(BitWidth, + uint64_t(::round(::sqrt(double(isSingleWord()?VAL:pVal[0]))))); +#else + return APInt(BitWidth, + uint64_t(::sqrt(double(isSingleWord()?VAL:pVal[0])) + 0.5)); +#endif + } + + // Okay, all the short cuts are exhausted. We must compute it. The following + // is a classical Babylonian method for computing the square root. This code + // was adapted to APINt from a wikipedia article on such computations. + // See http://www.wikipedia.org/ and go to the page named + // Calculate_an_integer_square_root. + unsigned nbits = BitWidth, i = 4; + APInt testy(BitWidth, 16); + APInt x_old(BitWidth, 1); + APInt x_new(BitWidth, 0); + APInt two(BitWidth, 2); + + // Select a good starting value using binary logarithms. + for (;; i += 2, testy = testy.shl(2)) + if (i >= nbits || this->ule(testy)) { + x_old = x_old.shl(i / 2); + break; + } + + // Use the Babylonian method to arrive at the integer square root: + for (;;) { + x_new = (this->udiv(x_old) + x_old).udiv(two); + if (x_old.ule(x_new)) + break; + x_old = x_new; + } + + // Make sure we return the closest approximation + // NOTE: The rounding calculation below is correct. It will produce an + // off-by-one discrepancy with results from pari/gp. That discrepancy has been + // determined to be a rounding issue with pari/gp as it begins to use a + // floating point representation after 192 bits. There are no discrepancies + // between this algorithm and pari/gp for bit widths < 192 bits. + APInt square(x_old * x_old); + APInt nextSquare((x_old + 1) * (x_old +1)); + if (this->ult(square)) + return x_old; + 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; +} + +/// Computes the multiplicative inverse of this APInt for a given modulo. The +/// iterative extended Euclidean algorithm is used to solve for this value, +/// however we simplify it to speed up calculating only the inverse, and take +/// advantage of div+rem calculations. We also use some tricks to avoid copying +/// (potentially large) APInts around. +APInt APInt::multiplicativeInverse(const APInt& modulo) const { + assert(ult(modulo) && "This APInt must be smaller than the modulo"); + + // Using the properties listed at the following web page (accessed 06/21/08): + // http://www.numbertheory.org/php/euclid.html + // (especially the properties numbered 3, 4 and 9) it can be proved that + // BitWidth bits suffice for all the computations in the algorithm implemented + // below. More precisely, this number of bits suffice if the multiplicative + // inverse exists, but may not suffice for the general extended Euclidean + // algorithm. + + APInt r[2] = { modulo, *this }; + APInt t[2] = { APInt(BitWidth, 0), APInt(BitWidth, 1) }; + APInt q(BitWidth, 0); + + unsigned i; + for (i = 0; r[i^1] != 0; i ^= 1) { + // An overview of the math without the confusing bit-flipping: + // q = r[i-2] / r[i-1] + // r[i] = r[i-2] % r[i-1] + // t[i] = t[i-2] - t[i-1] * q + udivrem(r[i], r[i^1], q, r[i]); + t[i] -= t[i^1] * q; + } + + // If this APInt and the modulo are not coprime, there is no multiplicative + // inverse, so return 0. We check this by looking at the next-to-last + // remainder, which is the gcd(*this,modulo) as calculated by the Euclidean + // algorithm. + if (r[i] != 1) + return APInt(BitWidth, 0); + + // The next-to-last t is the multiplicative inverse. However, we are + // interested in a positive inverse. Calcuate a positive one from a negative + // one if necessary. A simple addition of the modulo suffices because + // abs(t[i]) is known to be less than *this/2 (see the link above). + return t[i].isNegative() ? t[i] + modulo : t[i]; +} + +/// Calculate the magic numbers required to implement a signed integer division +/// by a constant as a sequence of multiplies, adds and shifts. Requires that +/// the divisor not be 0, 1, or -1. Taken from "Hacker's Delight", Henry S. +/// Warren, Jr., chapter 10. +APInt::ms APInt::magic() const { + const APInt& d = *this; + unsigned p; + APInt ad, anc, delta, q1, r1, q2, r2, t; + APInt signedMin = APInt::getSignedMinValue(d.getBitWidth()); + struct ms mag; + + ad = d.abs(); + t = signedMin + (d.lshr(d.getBitWidth() - 1)); + anc = t - 1 - t.urem(ad); // absolute value of nc + p = d.getBitWidth() - 1; // initialize p + q1 = signedMin.udiv(anc); // initialize q1 = 2p/abs(nc) + r1 = signedMin - q1*anc; // initialize r1 = rem(2p,abs(nc)) + q2 = signedMin.udiv(ad); // initialize q2 = 2p/abs(d) + r2 = signedMin - q2*ad; // initialize r2 = rem(2p,abs(d)) + do { + p = p + 1; + q1 = q1<<1; // update q1 = 2p/abs(nc) + r1 = r1<<1; // update r1 = rem(2p/abs(nc)) + if (r1.uge(anc)) { // must be unsigned comparison + q1 = q1 + 1; + r1 = r1 - anc; + } + q2 = q2<<1; // update q2 = 2p/abs(d) + r2 = r2<<1; // update r2 = rem(2p/abs(d)) + if (r2.uge(ad)) { // must be unsigned comparison + q2 = q2 + 1; + r2 = r2 - ad; + } + delta = ad - r2; + } while (q1.ult(delta) || (q1 == delta && r1 == 0)); + + mag.m = q2 + 1; + if (d.isNegative()) mag.m = -mag.m; // resulting magic number + mag.s = p - d.getBitWidth(); // resulting shift + return mag; +} + +/// Calculate the magic numbers required to implement an unsigned integer +/// division by a constant as a sequence of multiplies, adds and shifts. +/// Requires that the divisor not be 0. Taken from "Hacker's Delight", Henry +/// S. Warren, Jr., chapter 10. +/// LeadingZeros can be used to simplify the calculation if the upper bits +/// of the divided value are known zero. +APInt::mu APInt::magicu(unsigned LeadingZeros) const { + const APInt& d = *this; + unsigned p; + APInt nc, delta, q1, r1, q2, r2; + struct mu magu; + magu.a = 0; // initialize "add" indicator + APInt allOnes = APInt::getAllOnesValue(d.getBitWidth()).lshr(LeadingZeros); + APInt signedMin = APInt::getSignedMinValue(d.getBitWidth()); + APInt signedMax = APInt::getSignedMaxValue(d.getBitWidth()); + + nc = allOnes - (-d).urem(d); + p = d.getBitWidth() - 1; // initialize p + q1 = signedMin.udiv(nc); // initialize q1 = 2p/nc + r1 = signedMin - q1*nc; // initialize r1 = rem(2p,nc) + q2 = signedMax.udiv(d); // initialize q2 = (2p-1)/d + r2 = signedMax - q2*d; // initialize r2 = rem((2p-1),d) + do { + p = p + 1; + if (r1.uge(nc - r1)) { + q1 = q1 + q1 + 1; // update q1 + r1 = r1 + r1 - nc; // update r1 + } + else { + q1 = q1+q1; // update q1 + r1 = r1+r1; // update r1 + } + if ((r2 + 1).uge(d - r2)) { + if (q2.uge(signedMax)) magu.a = 1; + q2 = q2+q2 + 1; // update q2 + r2 = r2+r2 + 1 - d; // update r2 + } + else { + if (q2.uge(signedMin)) magu.a = 1; + q2 = q2+q2; // update q2 + r2 = r2+r2 + 1; // update r2 + } + delta = d - 1 - r2; + } while (p < d.getBitWidth()*2 && + (q1.ult(delta) || (q1 == delta && r1 == 0))); + magu.m = q2 + 1; // resulting magic number + magu.s = p - d.getBitWidth(); // resulting shift + return magu; +} + +/// Implementation of Knuth's Algorithm D (Division of nonnegative integers) +/// from "Art of Computer Programming, Volume 2", section 4.3.1, p. 272. The +/// variables here have the same names as in the algorithm. Comments explain +/// the algorithm and any deviation from it. +static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, + unsigned m, unsigned n) { + assert(u && "Must provide dividend"); + assert(v && "Must provide divisor"); + assert(q && "Must provide quotient"); + assert(u != v && u != q && v != q && "Must us different memory"); + assert(n>1 && "n must be > 1"); + + // Knuth uses the value b as the base of the number system. In our case b + // is 2^31 so we just set it to -1u. + uint64_t b = uint64_t(1) << 32; + +#if 0 + DEBUG(dbgs() << "KnuthDiv: m=" << m << " n=" << n << '\n'); + DEBUG(dbgs() << "KnuthDiv: original:"); + DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); + DEBUG(dbgs() << " by"); + DEBUG(for (int i = n; i >0; i--) dbgs() << " " << v[i-1]); + DEBUG(dbgs() << '\n'); +#endif + // D1. [Normalize.] Set d = b / (v[n-1] + 1) and multiply all the digits of + // u and v by d. Note that we have taken Knuth's advice here to use a power + // of 2 value for d such that d * v[n-1] >= b/2 (b is the base). A power of + // 2 allows us to shift instead of multiply and it is easy to determine the + // shift amount from the leading zeros. We are basically normalizing the u + // and v so that its high bits are shifted to the top of v's range without + // overflow. Note that this can require an extra word in u so that u must + // be of length m+n+1. + unsigned shift = CountLeadingZeros_32(v[n-1]); + unsigned v_carry = 0; + unsigned u_carry = 0; + if (shift) { + for (unsigned i = 0; i < m+n; ++i) { + unsigned u_tmp = u[i] >> (32 - shift); + u[i] = (u[i] << shift) | u_carry; + u_carry = u_tmp; + } + for (unsigned i = 0; i < n; ++i) { + unsigned v_tmp = v[i] >> (32 - shift); + v[i] = (v[i] << shift) | v_carry; + v_carry = v_tmp; + } + } + u[m+n] = u_carry; +#if 0 + DEBUG(dbgs() << "KnuthDiv: normal:"); + DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); + DEBUG(dbgs() << " by"); + DEBUG(for (int i = n; i >0; i--) dbgs() << " " << v[i-1]); + DEBUG(dbgs() << '\n'); +#endif + + // D2. [Initialize j.] Set j to m. This is the loop counter over the places. + int j = m; + do { + DEBUG(dbgs() << "KnuthDiv: quotient digit #" << j << '\n'); + // D3. [Calculate q'.]. + // Set qp = (u[j+n]*b + u[j+n-1]) / v[n-1]. (qp=qprime=q') + // Set rp = (u[j+n]*b + u[j+n-1]) % v[n-1]. (rp=rprime=r') + // Now test if qp == b or qp*v[n-2] > b*rp + u[j+n-2]; if so, decrease + // qp by 1, inrease rp by v[n-1], and repeat this test if rp < b. The test + // on v[n-2] determines at high speed most of the cases in which the trial + // value qp is one too large, and it eliminates all cases where qp is two + // too large. + uint64_t dividend = ((uint64_t(u[j+n]) << 32) + u[j+n-1]); + DEBUG(dbgs() << "KnuthDiv: dividend == " << dividend << '\n'); + uint64_t qp = dividend / v[n-1]; + uint64_t rp = dividend % v[n-1]; + if (qp == b || qp*v[n-2] > b*rp + u[j+n-2]) { + qp--; + rp += v[n-1]; + if (rp < b && (qp == b || qp*v[n-2] > b*rp + u[j+n-2])) + qp--; + } + DEBUG(dbgs() << "KnuthDiv: qp == " << qp << ", rp == " << rp << '\n'); + + // D4. [Multiply and subtract.] Replace (u[j+n]u[j+n-1]...u[j]) with + // (u[j+n]u[j+n-1]..u[j]) - qp * (v[n-1]...v[1]v[0]). This computation + // consists of a simple multiplication by a one-place number, combined with + // a subtraction. + bool isNeg = false; + for (unsigned i = 0; i < n; ++i) { + uint64_t u_tmp = uint64_t(u[j+i]) | (uint64_t(u[j+i+1]) << 32); + uint64_t subtrahend = uint64_t(qp) * uint64_t(v[i]); + bool borrow = subtrahend > u_tmp; + DEBUG(dbgs() << "KnuthDiv: u_tmp == " << u_tmp + << ", subtrahend == " << subtrahend + << ", borrow = " << borrow << '\n'); + + uint64_t result = u_tmp - subtrahend; + unsigned k = j + i; + u[k++] = (unsigned)(result & (b-1)); // subtract low word + u[k++] = (unsigned)(result >> 32); // subtract high word + while (borrow && k <= m+n) { // deal with borrow to the left + borrow = u[k] == 0; + u[k]--; + k++; + } + isNeg |= borrow; + DEBUG(dbgs() << "KnuthDiv: u[j+i] == " << u[j+i] << ", u[j+i+1] == " << + u[j+i+1] << '\n'); + } + DEBUG(dbgs() << "KnuthDiv: after subtraction:"); + DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); + DEBUG(dbgs() << '\n'); + // The digits (u[j+n]...u[j]) should be kept positive; if the result of + // this step is actually negative, (u[j+n]...u[j]) should be left as the + // true value plus b**(n+1), namely as the b's complement of + // the true value, and a "borrow" to the left should be remembered. + // + if (isNeg) { + bool carry = true; // true because b's complement is "complement + 1" + for (unsigned i = 0; i <= m+n; ++i) { + u[i] = ~u[i] + carry; // b's complement + carry = carry && u[i] == 0; + } + } + DEBUG(dbgs() << "KnuthDiv: after complement:"); + DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); + DEBUG(dbgs() << '\n'); + + // D5. [Test remainder.] Set q[j] = qp. If the result of step D4 was + // negative, go to step D6; otherwise go on to step D7. + q[j] = (unsigned)qp; + if (isNeg) { + // D6. [Add back]. The probability that this step is necessary is very + // small, on the order of only 2/b. Make sure that test data accounts for + // this possibility. Decrease q[j] by 1 + q[j]--; + // and add (0v[n-1]...v[1]v[0]) to (u[j+n]u[j+n-1]...u[j+1]u[j]). + // A carry will occur to the left of u[j+n], and it should be ignored + // since it cancels with the borrow that occurred in D4. + bool carry = false; + for (unsigned i = 0; i < n; i++) { + unsigned limit = std::min(u[j+i],v[i]); + u[j+i] += v[i] + carry; + carry = u[j+i] < limit || (carry && u[j+i] == limit); + } + u[j+n] += carry; + } + DEBUG(dbgs() << "KnuthDiv: after correction:"); + DEBUG(for (int i = m+n; i >=0; i--) dbgs() <<" " << u[i]); + DEBUG(dbgs() << "\nKnuthDiv: digit result = " << q[j] << '\n'); + + // D7. [Loop on j.] Decrease j by one. Now if j >= 0, go back to D3. + } while (--j >= 0); + + DEBUG(dbgs() << "KnuthDiv: quotient:"); + DEBUG(for (int i = m; i >=0; i--) dbgs() <<" " << q[i]); + DEBUG(dbgs() << '\n'); + + // D8. [Unnormalize]. Now q[...] is the desired quotient, and the desired + // remainder may be obtained by dividing u[...] by d. If r is non-null we + // compute the remainder (urem uses this). + if (r) { + // The value d is expressed by the "shift" value above since we avoided + // multiplication by d by using a shift left. So, all we have to do is + // shift right here. In order to mak + if (shift) { + unsigned carry = 0; + DEBUG(dbgs() << "KnuthDiv: remainder:"); + for (int i = n-1; i >= 0; i--) { + r[i] = (u[i] >> shift) | carry; + carry = u[i] << (32 - shift); + DEBUG(dbgs() << " " << r[i]); + } + } else { + for (int i = n-1; i >= 0; i--) { + r[i] = u[i]; + DEBUG(dbgs() << " " << r[i]); + } + } + DEBUG(dbgs() << '\n'); + } +#if 0 + DEBUG(dbgs() << '\n'); +#endif +} + +void APInt::divide(const APInt LHS, unsigned lhsWords, + const APInt &RHS, unsigned rhsWords, + APInt *Quotient, APInt *Remainder) +{ + assert(lhsWords >= rhsWords && "Fractional result"); + + // First, compose the values into an array of 32-bit words instead of + // 64-bit words. This is a necessity of both the "short division" algorithm + // and the Knuth "classical algorithm" which requires there to be native + // operations for +, -, and * on an m bit value with an m*2 bit result. We + // can't use 64-bit operands here because we don't have native results of + // 128-bits. Furthermore, casting the 64-bit values to 32-bit values won't + // work on large-endian machines. + uint64_t mask = ~0ull >> (sizeof(unsigned)*CHAR_BIT); + unsigned n = rhsWords * 2; + unsigned m = (lhsWords * 2) - n; + + // Allocate space for the temporary values we need either on the stack, if + // it will fit, or on the heap if it won't. + unsigned SPACE[128]; + unsigned *U = 0; + unsigned *V = 0; + unsigned *Q = 0; + unsigned *R = 0; + if ((Remainder?4:3)*n+2*m+1 <= 128) { + U = &SPACE[0]; + V = &SPACE[m+n+1]; + Q = &SPACE[(m+n+1) + n]; + if (Remainder) + R = &SPACE[(m+n+1) + n + (m+n)]; + } else { + U = new unsigned[m + n + 1]; + V = new unsigned[n]; + Q = new unsigned[m+n]; + if (Remainder) + R = new unsigned[n]; + } + + // Initialize the dividend + memset(U, 0, (m+n+1)*sizeof(unsigned)); + for (unsigned i = 0; i < lhsWords; ++i) { + uint64_t tmp = (LHS.getNumWords() == 1 ? LHS.VAL : LHS.pVal[i]); + U[i * 2] = (unsigned)(tmp & mask); + U[i * 2 + 1] = (unsigned)(tmp >> (sizeof(unsigned)*CHAR_BIT)); + } + U[m+n] = 0; // this extra word is for "spill" in the Knuth algorithm. + + // Initialize the divisor + memset(V, 0, (n)*sizeof(unsigned)); + for (unsigned i = 0; i < rhsWords; ++i) { + uint64_t tmp = (RHS.getNumWords() == 1 ? RHS.VAL : RHS.pVal[i]); + V[i * 2] = (unsigned)(tmp & mask); + V[i * 2 + 1] = (unsigned)(tmp >> (sizeof(unsigned)*CHAR_BIT)); + } + + // initialize the quotient and remainder + memset(Q, 0, (m+n) * sizeof(unsigned)); + if (Remainder) + memset(R, 0, n * sizeof(unsigned)); + + // Now, adjust m and n for the Knuth division. n is the number of words in + // the divisor. m is the number of words by which the dividend exceeds the + // divisor (i.e. m+n is the length of the dividend). These sizes must not + // contain any zero words or the Knuth algorithm fails. + for (unsigned i = n; i > 0 && V[i-1] == 0; i--) { + n--; + m++; + } + for (unsigned i = m+n; i > 0 && U[i-1] == 0; i--) + m--; + + // If we're left with only a single word for the divisor, Knuth doesn't work + // so we implement the short division algorithm here. This is much simpler + // and faster because we are certain that we can divide a 64-bit quantity + // by a 32-bit quantity at hardware speed and short division is simply a + // series of such operations. This is just like doing short division but we + // are using base 2^32 instead of base 10. + assert(n != 0 && "Divide by zero?"); + if (n == 1) { + unsigned divisor = V[0]; + unsigned remainder = 0; + for (int i = m+n-1; i >= 0; i--) { + uint64_t partial_dividend = uint64_t(remainder) << 32 | U[i]; + if (partial_dividend == 0) { + Q[i] = 0; + remainder = 0; + } else if (partial_dividend < divisor) { + Q[i] = 0; + remainder = (unsigned)partial_dividend; + } else if (partial_dividend == divisor) { + Q[i] = 1; + remainder = 0; + } else { + Q[i] = (unsigned)(partial_dividend / divisor); + remainder = (unsigned)(partial_dividend - (Q[i] * divisor)); + } + } + if (R) + R[0] = remainder; + } else { + // Now we're ready to invoke the Knuth classical divide algorithm. In this + // case n > 1. + KnuthDiv(U, V, Q, R, m, n); + } + + // If the caller wants the quotient + if (Quotient) { + // Set up the Quotient value's memory. + if (Quotient->BitWidth != LHS.BitWidth) { + if (Quotient->isSingleWord()) + Quotient->VAL = 0; + else + delete [] Quotient->pVal; + Quotient->BitWidth = LHS.BitWidth; + if (!Quotient->isSingleWord()) + Quotient->pVal = getClearedMemory(Quotient->getNumWords()); + } else + Quotient->clearAllBits(); + + // The quotient is in Q. Reconstitute the quotient into Quotient's low + // order words. + if (lhsWords == 1) { + uint64_t tmp = + uint64_t(Q[0]) | (uint64_t(Q[1]) << (APINT_BITS_PER_WORD / 2)); + if (Quotient->isSingleWord()) + Quotient->VAL = tmp; + else + Quotient->pVal[0] = tmp; + } else { + assert(!Quotient->isSingleWord() && "Quotient APInt not large enough"); + for (unsigned i = 0; i < lhsWords; ++i) + Quotient->pVal[i] = + uint64_t(Q[i*2]) | (uint64_t(Q[i*2+1]) << (APINT_BITS_PER_WORD / 2)); + } + } + + // If the caller wants the remainder + if (Remainder) { + // Set up the Remainder value's memory. + if (Remainder->BitWidth != RHS.BitWidth) { + if (Remainder->isSingleWord()) + Remainder->VAL = 0; + else + delete [] Remainder->pVal; + Remainder->BitWidth = RHS.BitWidth; + if (!Remainder->isSingleWord()) + Remainder->pVal = getClearedMemory(Remainder->getNumWords()); + } else + Remainder->clearAllBits(); + + // The remainder is in R. Reconstitute the remainder into Remainder's low + // order words. + if (rhsWords == 1) { + uint64_t tmp = + uint64_t(R[0]) | (uint64_t(R[1]) << (APINT_BITS_PER_WORD / 2)); + if (Remainder->isSingleWord()) + Remainder->VAL = tmp; + else + Remainder->pVal[0] = tmp; + } else { + assert(!Remainder->isSingleWord() && "Remainder APInt not large enough"); + for (unsigned i = 0; i < rhsWords; ++i) + Remainder->pVal[i] = + uint64_t(R[i*2]) | (uint64_t(R[i*2+1]) << (APINT_BITS_PER_WORD / 2)); + } + } + + // Clean up the memory we allocated. + if (U != &SPACE[0]) { + delete [] U; + delete [] V; + delete [] Q; + delete [] R; + } +} + +APInt APInt::udiv(const APInt& RHS) const { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + + // First, deal with the easy case + if (isSingleWord()) { + assert(RHS.VAL != 0 && "Divide by zero?"); + return APInt(BitWidth, VAL / RHS.VAL); + } + + // Get some facts about the LHS and RHS number of bits and words + unsigned rhsBits = RHS.getActiveBits(); + unsigned rhsWords = !rhsBits ? 0 : (APInt::whichWord(rhsBits - 1) + 1); + assert(rhsWords && "Divided by zero???"); + unsigned lhsBits = this->getActiveBits(); + unsigned lhsWords = !lhsBits ? 0 : (APInt::whichWord(lhsBits - 1) + 1); + + // Deal with some degenerate cases + if (!lhsWords) + // 0 / X ===> 0 + return APInt(BitWidth, 0); + else if (lhsWords < rhsWords || this->ult(RHS)) { + // X / Y ===> 0, iff X < Y + return APInt(BitWidth, 0); + } else if (*this == RHS) { + // X / X ===> 1 + return APInt(BitWidth, 1); + } else if (lhsWords == 1 && rhsWords == 1) { + // All high words are zero, just use native divide + return APInt(BitWidth, this->pVal[0] / RHS.pVal[0]); + } + + // We have to compute it the hard way. Invoke the Knuth divide algorithm. + APInt Quotient(1,0); // to hold result. + divide(*this, lhsWords, RHS, rhsWords, &Quotient, 0); + return Quotient; +} + +APInt APInt::urem(const APInt& RHS) const { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) { + assert(RHS.VAL != 0 && "Remainder by zero?"); + return APInt(BitWidth, VAL % RHS.VAL); + } + + // Get some facts about the LHS + unsigned lhsBits = getActiveBits(); + unsigned lhsWords = !lhsBits ? 0 : (whichWord(lhsBits - 1) + 1); + + // Get some facts about the RHS + unsigned rhsBits = RHS.getActiveBits(); + unsigned rhsWords = !rhsBits ? 0 : (APInt::whichWord(rhsBits - 1) + 1); + assert(rhsWords && "Performing remainder operation by zero ???"); + + // Check the degenerate cases + if (lhsWords == 0) { + // 0 % Y ===> 0 + return APInt(BitWidth, 0); + } else if (lhsWords < rhsWords || this->ult(RHS)) { + // X % Y ===> X, iff X < Y + return *this; + } else if (*this == RHS) { + // X % X == 0; + return APInt(BitWidth, 0); + } else if (lhsWords == 1) { + // All high words are zero, just use native remainder + return APInt(BitWidth, pVal[0] % RHS.pVal[0]); + } + + // We have to compute it the hard way. Invoke the Knuth divide algorithm. + APInt Remainder(1,0); + divide(*this, lhsWords, RHS, rhsWords, 0, &Remainder); + return Remainder; +} + +void APInt::udivrem(const APInt &LHS, const APInt &RHS, + APInt &Quotient, APInt &Remainder) { + // Get some size facts about the dividend and divisor + unsigned lhsBits = LHS.getActiveBits(); + unsigned lhsWords = !lhsBits ? 0 : (APInt::whichWord(lhsBits - 1) + 1); + unsigned rhsBits = RHS.getActiveBits(); + unsigned rhsWords = !rhsBits ? 0 : (APInt::whichWord(rhsBits - 1) + 1); + + // Check the degenerate cases + if (lhsWords == 0) { + Quotient = 0; // 0 / Y ===> 0 + Remainder = 0; // 0 % Y ===> 0 + return; + } + + if (lhsWords < rhsWords || LHS.ult(RHS)) { + Remainder = LHS; // X % Y ===> X, iff X < Y + Quotient = 0; // X / Y ===> 0, iff X < Y + return; + } + + if (LHS == RHS) { + Quotient = 1; // X / X ===> 1 + Remainder = 0; // X % X ===> 0; + return; + } + + if (lhsWords == 1 && rhsWords == 1) { + // There is only one word to consider so use the native versions. + uint64_t lhsValue = LHS.isSingleWord() ? LHS.VAL : LHS.pVal[0]; + uint64_t rhsValue = RHS.isSingleWord() ? RHS.VAL : RHS.pVal[0]; + Quotient = APInt(LHS.getBitWidth(), lhsValue / rhsValue); + Remainder = APInt(LHS.getBitWidth(), lhsValue % rhsValue); + return; + } + + // Okay, lets do it the long way + divide(LHS, lhsWords, RHS, rhsWords, &Quotient, &Remainder); +} + +APInt APInt::sadd_ov(const APInt &RHS, bool &Overflow) const { + APInt Res = *this+RHS; + Overflow = isNonNegative() == RHS.isNonNegative() && + Res.isNonNegative() != isNonNegative(); + return Res; +} + +APInt APInt::uadd_ov(const APInt &RHS, bool &Overflow) const { + APInt Res = *this+RHS; + Overflow = Res.ult(RHS); + return Res; +} + +APInt APInt::ssub_ov(const APInt &RHS, bool &Overflow) const { + APInt Res = *this - RHS; + Overflow = isNonNegative() != RHS.isNonNegative() && + Res.isNonNegative() != isNonNegative(); + return Res; +} + +APInt APInt::usub_ov(const APInt &RHS, bool &Overflow) const { + APInt Res = *this-RHS; + Overflow = Res.ugt(*this); + return Res; +} + +APInt APInt::sdiv_ov(const APInt &RHS, bool &Overflow) const { + // MININT/-1 --> overflow. + Overflow = isMinSignedValue() && RHS.isAllOnesValue(); + return sdiv(RHS); +} + +APInt APInt::smul_ov(const APInt &RHS, bool &Overflow) const { + APInt Res = *this * RHS; + + if (*this != 0 && RHS != 0) + Overflow = Res.sdiv(RHS) != *this || Res.sdiv(*this) != RHS; + else + Overflow = false; + return Res; +} + +APInt APInt::umul_ov(const APInt &RHS, bool &Overflow) const { + APInt Res = *this * RHS; + + if (*this != 0 && RHS != 0) + Overflow = Res.udiv(RHS) != *this || Res.udiv(*this) != RHS; + else + Overflow = false; + return Res; +} + +APInt APInt::sshl_ov(unsigned ShAmt, bool &Overflow) const { + Overflow = ShAmt >= getBitWidth(); + if (Overflow) + ShAmt = getBitWidth()-1; + + if (isNonNegative()) // Don't allow sign change. + Overflow = ShAmt >= countLeadingZeros(); + else + Overflow = ShAmt >= countLeadingOnes(); + + return *this << ShAmt; +} + + + + +void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) { + // Check our assumptions here + assert(!str.empty() && "Invalid string length"); + assert((radix == 10 || radix == 8 || radix == 16 || radix == 2 || + radix == 36) && + "Radix should be 2, 8, 10, 16, or 36!"); + + StringRef::iterator p = str.begin(); + size_t slen = str.size(); + bool isNeg = *p == '-'; + if (*p == '-' || *p == '+') { + p++; + slen--; + assert(slen && "String is only a sign, needs a value."); + } + assert((slen <= numbits || radix != 2) && "Insufficient bit width"); + assert(((slen-1)*3 <= numbits || radix != 8) && "Insufficient bit width"); + assert(((slen-1)*4 <= numbits || radix != 16) && "Insufficient bit width"); + assert((((slen-1)*64)/22 <= numbits || radix != 10) && + "Insufficient bit width"); + + // Allocate memory + if (!isSingleWord()) + pVal = getClearedMemory(getNumWords()); + + // Figure out if we can shift instead of multiply + unsigned shift = (radix == 16 ? 4 : radix == 8 ? 3 : radix == 2 ? 1 : 0); + + // Set up an APInt for the digit to add outside the loop so we don't + // constantly construct/destruct it. + APInt apdigit(getBitWidth(), 0); + APInt apradix(getBitWidth(), radix); + + // Enter digit traversal loop + for (StringRef::iterator e = str.end(); p != e; ++p) { + unsigned digit = getDigit(*p, radix); + assert(digit < radix && "Invalid character in digit string"); + + // Shift or multiply the value by the radix + if (slen > 1) { + if (shift) + *this <<= shift; + else + *this *= apradix; + } + + // Add in the digit we just interpreted + if (apdigit.isSingleWord()) + apdigit.VAL = digit; + else + apdigit.pVal[0] = digit; + *this += apdigit; + } + // If its negative, put it in two's complement form + if (isNeg) { + (*this)--; + this->flipAllBits(); + } +} + +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, 16, or 36!"); + + const char *Prefix = ""; + if (formatAsCLiteral) { + switch (Radix) { + case 2: + // Binary literals are a non-standard extension added in gcc 4.3: + // http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Binary-constants.html + Prefix = "0b"; + break; + case 8: + Prefix = "0"; + break; + case 10: + break; // No prefix + case 16: + Prefix = "0x"; + break; + default: + llvm_unreachable("Invalid radix!"); + } + } + + // First, check for a zero value and just short circuit the logic below. + if (*this == 0) { + while (*Prefix) { + Str.push_back(*Prefix); + ++Prefix; + }; + Str.push_back('0'); + return; + } + + static const char Digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + if (isSingleWord()) { + char Buffer[65]; + char *BufPtr = Buffer+65; + + uint64_t N; + if (!Signed) { + N = getZExtValue(); + } else { + int64_t I = getSExtValue(); + if (I >= 0) { + N = I; + } else { + Str.push_back('-'); + N = -(uint64_t)I; + } + } + + while (*Prefix) { + Str.push_back(*Prefix); + ++Prefix; + }; + + while (N) { + *--BufPtr = Digits[N % Radix]; + N /= Radix; + } + Str.append(BufPtr, Buffer+65); + return; + } + + APInt Tmp(*this); + + if (Signed && isNegative()) { + // They want to print the signed version and it is a negative value + // Flip the bits and add one to turn it into the equivalent positive + // value and put a '-' in the result. + Tmp.flipAllBits(); + Tmp++; + Str.push_back('-'); + } + + while (*Prefix) { + Str.push_back(*Prefix); + ++Prefix; + }; + + // We insert the digits backward, then reverse them to get the right order. + unsigned StartDig = Str.size(); + + // For the 2, 8 and 16 bit cases, we can just shift instead of divide + // because the number of bits per digit (1, 3 and 4 respectively) divides + // equaly. We just shift until the value is zero. + if (Radix == 2 || Radix == 8 || Radix == 16) { + // Just shift tmp right for each digit width until it becomes zero + unsigned ShiftAmt = (Radix == 16 ? 4 : (Radix == 8 ? 3 : 1)); + unsigned MaskAmt = Radix - 1; + + while (Tmp != 0) { + unsigned Digit = unsigned(Tmp.getRawData()[0]) & MaskAmt; + Str.push_back(Digits[Digit]); + Tmp = Tmp.lshr(ShiftAmt); + } + } else { + APInt divisor(Radix == 10? 4 : 8, Radix); + while (Tmp != 0) { + APInt APdigit(1, 0); + APInt tmp2(Tmp.getBitWidth(), 0); + divide(Tmp, Tmp.getNumWords(), divisor, divisor.getNumWords(), &tmp2, + &APdigit); + unsigned Digit = (unsigned)APdigit.getZExtValue(); + assert(Digit < Radix && "divide failed"); + Str.push_back(Digits[Digit]); + Tmp = tmp2; + } + } + + // Reverse the digits before returning. + std::reverse(Str.begin()+StartDig, Str.end()); +} + +/// toString - This returns the APInt as a std::string. Note that this is an +/// inefficient method. It is better to pass in a SmallVector/SmallString +/// to the methods above. +std::string APInt::toString(unsigned Radix = 10, bool Signed = true) const { + SmallString<40> S; + toString(S, Radix, Signed, /* formatAsCLiteral = */false); + return S.str(); +} + + +void APInt::dump() const { + SmallString<40> S, U; + this->toStringUnsigned(U); + this->toStringSigned(S); + dbgs() << "APInt(" << BitWidth << "b, " + << U.str() << "u " << S.str() << "s)"; +} + +void APInt::print(raw_ostream &OS, bool isSigned) const { + SmallString<40> S; + this->toString(S, 10, isSigned, /* formatAsCLiteral = */false); + OS << S.str(); +} + +// This implements a variety of operations on a representation of +// arbitrary precision, two's-complement, bignum integer values. + +// Assumed by lowHalf, highHalf, partMSB and partLSB. A fairly safe +// and unrestricting assumption. +#define COMPILE_TIME_ASSERT(cond) extern int CTAssert[(cond) ? 1 : -1] +COMPILE_TIME_ASSERT(integerPartWidth % 2 == 0); + +/* Some handy functions local to this file. */ +namespace { + + /* Returns the integer part with the least significant BITS set. + BITS cannot be zero. */ + static inline integerPart + lowBitMask(unsigned int bits) + { + assert(bits != 0 && bits <= integerPartWidth); + + return ~(integerPart) 0 >> (integerPartWidth - bits); + } + + /* Returns the value of the lower half of PART. */ + static inline integerPart + lowHalf(integerPart part) + { + return part & lowBitMask(integerPartWidth / 2); + } + + /* Returns the value of the upper half of PART. */ + static inline integerPart + highHalf(integerPart part) + { + return part >> (integerPartWidth / 2); + } + + /* Returns the bit number of the most significant set bit of a part. + If the input number has no bits set -1U is returned. */ + static unsigned int + partMSB(integerPart value) + { + unsigned int n, msb; + + if (value == 0) + return -1U; + + n = integerPartWidth / 2; + + msb = 0; + do { + if (value >> n) { + value >>= n; + msb += n; + } + + n >>= 1; + } while (n); + + return msb; + } + + /* Returns the bit number of the least significant set bit of a + part. If the input number has no bits set -1U is returned. */ + static unsigned int + partLSB(integerPart value) + { + unsigned int n, lsb; + + if (value == 0) + return -1U; + + lsb = integerPartWidth - 1; + n = integerPartWidth / 2; + + do { + if (value << n) { + value <<= n; + lsb -= n; + } + + n >>= 1; + } while (n); + + return lsb; + } +} + +/* Sets the least significant part of a bignum to the input value, and + zeroes out higher parts. */ +void +APInt::tcSet(integerPart *dst, integerPart part, unsigned int parts) +{ + unsigned int i; + + assert(parts > 0); + + dst[0] = part; + for (i = 1; i < parts; i++) + dst[i] = 0; +} + +/* Assign one bignum to another. */ +void +APInt::tcAssign(integerPart *dst, const integerPart *src, unsigned int parts) +{ + unsigned int i; + + for (i = 0; i < parts; i++) + dst[i] = src[i]; +} + +/* Returns true if a bignum is zero, false otherwise. */ +bool +APInt::tcIsZero(const integerPart *src, unsigned int parts) +{ + unsigned int i; + + for (i = 0; i < parts; i++) + if (src[i]) + return false; + + return true; +} + +/* Extract the given bit of a bignum; returns 0 or 1. */ +int +APInt::tcExtractBit(const integerPart *parts, unsigned int bit) +{ + return (parts[bit / integerPartWidth] & + ((integerPart) 1 << bit % integerPartWidth)) != 0; +} + +/* Set the given bit of a bignum. */ +void +APInt::tcSetBit(integerPart *parts, unsigned int bit) +{ + parts[bit / integerPartWidth] |= (integerPart) 1 << (bit % integerPartWidth); +} + +/* Clears the given bit of a bignum. */ +void +APInt::tcClearBit(integerPart *parts, unsigned int bit) +{ + parts[bit / integerPartWidth] &= + ~((integerPart) 1 << (bit % integerPartWidth)); +} + +/* Returns the bit number of the least significant set bit of a + number. If the input number has no bits set -1U is returned. */ +unsigned int +APInt::tcLSB(const integerPart *parts, unsigned int n) +{ + unsigned int i, lsb; + + for (i = 0; i < n; i++) { + if (parts[i] != 0) { + lsb = partLSB(parts[i]); + + return lsb + i * integerPartWidth; + } + } + + return -1U; +} + +/* Returns the bit number of the most significant set bit of a number. + If the input number has no bits set -1U is returned. */ +unsigned int +APInt::tcMSB(const integerPart *parts, unsigned int n) +{ + unsigned int msb; + + do { + --n; + + if (parts[n] != 0) { + msb = partMSB(parts[n]); + + return msb + n * integerPartWidth; + } + } while (n); + + return -1U; +} + +/* Copy the bit vector of width srcBITS from SRC, starting at bit + srcLSB, to DST, of dstCOUNT parts, such that the bit srcLSB becomes + the least significant bit of DST. All high bits above srcBITS in + DST are zero-filled. */ +void +APInt::tcExtract(integerPart *dst, unsigned int dstCount,const integerPart *src, + unsigned int srcBits, unsigned int srcLSB) +{ + unsigned int firstSrcPart, dstParts, shift, n; + + dstParts = (srcBits + integerPartWidth - 1) / integerPartWidth; + assert(dstParts <= dstCount); + + firstSrcPart = srcLSB / integerPartWidth; + tcAssign (dst, src + firstSrcPart, dstParts); + + shift = srcLSB % integerPartWidth; + tcShiftRight (dst, dstParts, shift); + + /* We now have (dstParts * integerPartWidth - shift) bits from SRC + in DST. If this is less that srcBits, append the rest, else + clear the high bits. */ + n = dstParts * integerPartWidth - shift; + if (n < srcBits) { + integerPart mask = lowBitMask (srcBits - n); + dst[dstParts - 1] |= ((src[firstSrcPart + dstParts] & mask) + << n % integerPartWidth); + } else if (n > srcBits) { + if (srcBits % integerPartWidth) + dst[dstParts - 1] &= lowBitMask (srcBits % integerPartWidth); + } + + /* Clear high parts. */ + while (dstParts < dstCount) + dst[dstParts++] = 0; +} + +/* DST += RHS + C where C is zero or one. Returns the carry flag. */ +integerPart +APInt::tcAdd(integerPart *dst, const integerPart *rhs, + integerPart c, unsigned int parts) +{ + unsigned int i; + + assert(c <= 1); + + for (i = 0; i < parts; i++) { + integerPart l; + + l = dst[i]; + if (c) { + dst[i] += rhs[i] + 1; + c = (dst[i] <= l); + } else { + dst[i] += rhs[i]; + c = (dst[i] < l); + } + } + + return c; +} + +/* DST -= RHS + C where C is zero or one. Returns the carry flag. */ +integerPart +APInt::tcSubtract(integerPart *dst, const integerPart *rhs, + integerPart c, unsigned int parts) +{ + unsigned int i; + + assert(c <= 1); + + for (i = 0; i < parts; i++) { + integerPart l; + + l = dst[i]; + if (c) { + dst[i] -= rhs[i] + 1; + c = (dst[i] >= l); + } else { + dst[i] -= rhs[i]; + c = (dst[i] > l); + } + } + + return c; +} + +/* Negate a bignum in-place. */ +void +APInt::tcNegate(integerPart *dst, unsigned int parts) +{ + tcComplement(dst, parts); + tcIncrement(dst, parts); +} + +/* DST += SRC * MULTIPLIER + CARRY if add is true + DST = SRC * MULTIPLIER + CARRY if add is false + + Requires 0 <= DSTPARTS <= SRCPARTS + 1. If DST overlaps SRC + they must start at the same point, i.e. DST == SRC. + + If DSTPARTS == SRCPARTS + 1 no overflow occurs and zero is + returned. Otherwise DST is filled with the least significant + DSTPARTS parts of the result, and if all of the omitted higher + parts were zero return zero, otherwise overflow occurred and + return one. */ +int +APInt::tcMultiplyPart(integerPart *dst, const integerPart *src, + integerPart multiplier, integerPart carry, + unsigned int srcParts, unsigned int dstParts, + bool add) +{ + unsigned int i, n; + + /* Otherwise our writes of DST kill our later reads of SRC. */ + assert(dst <= src || dst >= src + srcParts); + assert(dstParts <= srcParts + 1); + + /* N loops; minimum of dstParts and srcParts. */ + n = dstParts < srcParts ? dstParts: srcParts; + + for (i = 0; i < n; i++) { + integerPart low, mid, high, srcPart; + + /* [ LOW, HIGH ] = MULTIPLIER * SRC[i] + DST[i] + CARRY. + + This cannot overflow, because + + (n - 1) * (n - 1) + 2 (n - 1) = (n - 1) * (n + 1) + + which is less than n^2. */ + + srcPart = src[i]; + + if (multiplier == 0 || srcPart == 0) { + low = carry; + high = 0; + } else { + low = lowHalf(srcPart) * lowHalf(multiplier); + high = highHalf(srcPart) * highHalf(multiplier); + + mid = lowHalf(srcPart) * highHalf(multiplier); + high += highHalf(mid); + mid <<= integerPartWidth / 2; + if (low + mid < low) + high++; + low += mid; + + mid = highHalf(srcPart) * lowHalf(multiplier); + high += highHalf(mid); + mid <<= integerPartWidth / 2; + if (low + mid < low) + high++; + low += mid; + + /* Now add carry. */ + if (low + carry < low) + high++; + low += carry; + } + + if (add) { + /* And now DST[i], and store the new low part there. */ + if (low + dst[i] < low) + high++; + dst[i] += low; + } else + dst[i] = low; + + carry = high; + } + + if (i < dstParts) { + /* Full multiplication, there is no overflow. */ + assert(i + 1 == dstParts); + dst[i] = carry; + return 0; + } else { + /* We overflowed if there is carry. */ + if (carry) + return 1; + + /* We would overflow if any significant unwritten parts would be + non-zero. This is true if any remaining src parts are non-zero + and the multiplier is non-zero. */ + if (multiplier) + for (; i < srcParts; i++) + if (src[i]) + return 1; + + /* We fitted in the narrow destination. */ + return 0; + } +} + +/* DST = LHS * RHS, where DST has the same width as the operands and + is filled with the least significant parts of the result. Returns + one if overflow occurred, otherwise zero. DST must be disjoint + from both operands. */ +int +APInt::tcMultiply(integerPart *dst, const integerPart *lhs, + const integerPart *rhs, unsigned int parts) +{ + unsigned int i; + int overflow; + + assert(dst != lhs && dst != rhs); + + overflow = 0; + tcSet(dst, 0, parts); + + for (i = 0; i < parts; i++) + overflow |= tcMultiplyPart(&dst[i], lhs, rhs[i], 0, parts, + parts - i, true); + + return overflow; +} + +/* DST = LHS * RHS, where DST has width the sum of the widths of the + operands. No overflow occurs. DST must be disjoint from both + operands. Returns the number of parts required to hold the + result. */ +unsigned int +APInt::tcFullMultiply(integerPart *dst, const integerPart *lhs, + const integerPart *rhs, unsigned int lhsParts, + unsigned int rhsParts) +{ + /* Put the narrower number on the LHS for less loops below. */ + if (lhsParts > rhsParts) { + return tcFullMultiply (dst, rhs, lhs, rhsParts, lhsParts); + } else { + unsigned int n; + + assert(dst != lhs && dst != rhs); + + tcSet(dst, 0, rhsParts); + + for (n = 0; n < lhsParts; n++) + tcMultiplyPart(&dst[n], rhs, lhs[n], 0, rhsParts, rhsParts + 1, true); + + n = lhsParts + rhsParts; + + return n - (dst[n - 1] == 0); + } +} + +/* If RHS is zero LHS and REMAINDER are left unchanged, return one. + Otherwise set LHS to LHS / RHS with the fractional part discarded, + set REMAINDER to the remainder, return zero. i.e. + + OLD_LHS = RHS * LHS + REMAINDER + + SCRATCH is a bignum of the same size as the operands and result for + use by the routine; its contents need not be initialized and are + destroyed. LHS, REMAINDER and SCRATCH must be distinct. +*/ +int +APInt::tcDivide(integerPart *lhs, const integerPart *rhs, + integerPart *remainder, integerPart *srhs, + unsigned int parts) +{ + unsigned int n, shiftCount; + integerPart mask; + + assert(lhs != remainder && lhs != srhs && remainder != srhs); + + shiftCount = tcMSB(rhs, parts) + 1; + if (shiftCount == 0) + return true; + + shiftCount = parts * integerPartWidth - shiftCount; + n = shiftCount / integerPartWidth; + mask = (integerPart) 1 << (shiftCount % integerPartWidth); + + tcAssign(srhs, rhs, parts); + tcShiftLeft(srhs, parts, shiftCount); + tcAssign(remainder, lhs, parts); + tcSet(lhs, 0, parts); + + /* Loop, subtracting SRHS if REMAINDER is greater and adding that to + the total. */ + for (;;) { + int compare; + + compare = tcCompare(remainder, srhs, parts); + if (compare >= 0) { + tcSubtract(remainder, srhs, 0, parts); + lhs[n] |= mask; + } + + if (shiftCount == 0) + break; + shiftCount--; + tcShiftRight(srhs, parts, 1); + if ((mask >>= 1) == 0) + mask = (integerPart) 1 << (integerPartWidth - 1), n--; + } + + return false; +} + +/* Shift a bignum left COUNT bits in-place. Shifted in bits are zero. + There are no restrictions on COUNT. */ +void +APInt::tcShiftLeft(integerPart *dst, unsigned int parts, unsigned int count) +{ + if (count) { + unsigned int jump, shift; + + /* Jump is the inter-part jump; shift is is intra-part shift. */ + jump = count / integerPartWidth; + shift = count % integerPartWidth; + + while (parts > jump) { + integerPart part; + + parts--; + + /* dst[i] comes from the two parts src[i - jump] and, if we have + an intra-part shift, src[i - jump - 1]. */ + part = dst[parts - jump]; + if (shift) { + part <<= shift; + if (parts >= jump + 1) + part |= dst[parts - jump - 1] >> (integerPartWidth - shift); + } + + dst[parts] = part; + } + + while (parts > 0) + dst[--parts] = 0; + } +} + +/* Shift a bignum right COUNT bits in-place. Shifted in bits are + zero. There are no restrictions on COUNT. */ +void +APInt::tcShiftRight(integerPart *dst, unsigned int parts, unsigned int count) +{ + if (count) { + unsigned int i, jump, shift; + + /* Jump is the inter-part jump; shift is is intra-part shift. */ + jump = count / integerPartWidth; + shift = count % integerPartWidth; + + /* Perform the shift. This leaves the most significant COUNT bits + of the result at zero. */ + for (i = 0; i < parts; i++) { + integerPart part; + + if (i + jump >= parts) { + part = 0; + } else { + part = dst[i + jump]; + if (shift) { + part >>= shift; + if (i + jump + 1 < parts) + part |= dst[i + jump + 1] << (integerPartWidth - shift); + } + } + + dst[i] = part; + } + } +} + +/* Bitwise and of two bignums. */ +void +APInt::tcAnd(integerPart *dst, const integerPart *rhs, unsigned int parts) +{ + unsigned int i; + + for (i = 0; i < parts; i++) + dst[i] &= rhs[i]; +} + +/* Bitwise inclusive or of two bignums. */ +void +APInt::tcOr(integerPart *dst, const integerPart *rhs, unsigned int parts) +{ + unsigned int i; + + for (i = 0; i < parts; i++) + dst[i] |= rhs[i]; +} + +/* Bitwise exclusive or of two bignums. */ +void +APInt::tcXor(integerPart *dst, const integerPart *rhs, unsigned int parts) +{ + unsigned int i; + + for (i = 0; i < parts; i++) + dst[i] ^= rhs[i]; +} + +/* Complement a bignum in-place. */ +void +APInt::tcComplement(integerPart *dst, unsigned int parts) +{ + unsigned int i; + + for (i = 0; i < parts; i++) + dst[i] = ~dst[i]; +} + +/* Comparison (unsigned) of two bignums. */ +int +APInt::tcCompare(const integerPart *lhs, const integerPart *rhs, + unsigned int parts) +{ + while (parts) { + parts--; + if (lhs[parts] == rhs[parts]) + continue; + + if (lhs[parts] > rhs[parts]) + return 1; + else + return -1; + } + + return 0; +} + +/* Increment a bignum in-place, return the carry flag. */ +integerPart +APInt::tcIncrement(integerPart *dst, unsigned int parts) +{ + unsigned int i; + + for (i = 0; i < parts; i++) + if (++dst[i] != 0) + break; + + return i == parts; +} + +/* Set the least significant BITS bits of a bignum, clear the + rest. */ +void +APInt::tcSetLeastSignificantBits(integerPart *dst, unsigned int parts, + unsigned int bits) +{ + unsigned int i; + + i = 0; + while (bits > integerPartWidth) { + dst[i++] = ~(integerPart) 0; + bits -= integerPartWidth; + } + + if (bits) + dst[i++] = ~(integerPart) 0 >> (integerPartWidth - bits); + + while (i < parts) + dst[i++] = 0; +} diff --git a/contrib/llvm/lib/Support/APSInt.cpp b/contrib/llvm/lib/Support/APSInt.cpp new file mode 100644 index 0000000..73acafa --- /dev/null +++ b/contrib/llvm/lib/Support/APSInt.cpp @@ -0,0 +1,23 @@ +//===-- llvm/ADT/APSInt.cpp - Arbitrary Precision Signed Int ---*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the APSInt class, which is a simple class that +// represents an arbitrary sized integer that knows its signedness. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/FoldingSet.h" + +using namespace llvm; + +void APSInt::Profile(FoldingSetNodeID& ID) const { + ID.AddInteger((unsigned) (IsUnsigned ? 1 : 0)); + APInt::Profile(ID); +} diff --git a/contrib/llvm/lib/Support/Allocator.cpp b/contrib/llvm/lib/Support/Allocator.cpp new file mode 100644 index 0000000..b897830 --- /dev/null +++ b/contrib/llvm/lib/Support/Allocator.cpp @@ -0,0 +1,188 @@ +//===--- Allocator.cpp - Simple memory allocation abstraction -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the BumpPtrAllocator interface. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Allocator.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Recycler.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Memory.h" +#include <cstring> + +namespace llvm { + +BumpPtrAllocator::BumpPtrAllocator(size_t size, size_t threshold, + SlabAllocator &allocator) + : SlabSize(size), SizeThreshold(std::min(size, threshold)), + Allocator(allocator), CurSlab(0), BytesAllocated(0) { } + +BumpPtrAllocator::~BumpPtrAllocator() { + DeallocateSlabs(CurSlab); +} + +/// AlignPtr - Align Ptr to Alignment bytes, rounding up. Alignment should +/// be a power of two. This method rounds up, so AlignPtr(7, 4) == 8 and +/// AlignPtr(8, 4) == 8. +char *BumpPtrAllocator::AlignPtr(char *Ptr, size_t Alignment) { + assert(Alignment && (Alignment & (Alignment - 1)) == 0 && + "Alignment is not a power of two!"); + + // Do the alignment. + return (char*)(((uintptr_t)Ptr + Alignment - 1) & + ~(uintptr_t)(Alignment - 1)); +} + +/// StartNewSlab - Allocate a new slab and move the bump pointers over into +/// the new slab. Modifies CurPtr and End. +void BumpPtrAllocator::StartNewSlab() { + // If we allocated a big number of slabs already it's likely that we're going + // to allocate more. Increase slab size to reduce mallocs and possibly memory + // overhead. The factors are chosen conservatively to avoid overallocation. + if (BytesAllocated >= SlabSize * 128) + SlabSize *= 2; + + MemSlab *NewSlab = Allocator.Allocate(SlabSize); + NewSlab->NextPtr = CurSlab; + CurSlab = NewSlab; + CurPtr = (char*)(CurSlab + 1); + End = ((char*)CurSlab) + CurSlab->Size; +} + +/// DeallocateSlabs - Deallocate all memory slabs after and including this +/// one. +void BumpPtrAllocator::DeallocateSlabs(MemSlab *Slab) { + while (Slab) { + MemSlab *NextSlab = Slab->NextPtr; +#ifndef NDEBUG + // Poison the memory so stale pointers crash sooner. Note we must + // preserve the Size and NextPtr fields at the beginning. + sys::Memory::setRangeWritable(Slab + 1, Slab->Size - sizeof(MemSlab)); + memset(Slab + 1, 0xCD, Slab->Size - sizeof(MemSlab)); +#endif + Allocator.Deallocate(Slab); + Slab = NextSlab; + } +} + +/// Reset - Deallocate all but the current slab and reset the current pointer +/// to the beginning of it, freeing all memory allocated so far. +void BumpPtrAllocator::Reset() { + if (!CurSlab) + return; + DeallocateSlabs(CurSlab->NextPtr); + CurSlab->NextPtr = 0; + CurPtr = (char*)(CurSlab + 1); + End = ((char*)CurSlab) + CurSlab->Size; +} + +/// Allocate - Allocate space at the specified alignment. +/// +void *BumpPtrAllocator::Allocate(size_t Size, size_t Alignment) { + if (!CurSlab) // Start a new slab if we haven't allocated one already. + StartNewSlab(); + + // Keep track of how many bytes we've allocated. + BytesAllocated += Size; + + // 0-byte alignment means 1-byte alignment. + if (Alignment == 0) Alignment = 1; + + // Allocate the aligned space, going forwards from CurPtr. + char *Ptr = AlignPtr(CurPtr, Alignment); + + // Check if we can hold it. + if (Ptr + Size <= End) { + CurPtr = Ptr + Size; + return Ptr; + } + + // If Size is really big, allocate a separate slab for it. + size_t PaddedSize = Size + sizeof(MemSlab) + Alignment - 1; + if (PaddedSize > SizeThreshold) { + MemSlab *NewSlab = Allocator.Allocate(PaddedSize); + + // Put the new slab after the current slab, since we are not allocating + // into it. + NewSlab->NextPtr = CurSlab->NextPtr; + CurSlab->NextPtr = NewSlab; + + Ptr = AlignPtr((char*)(NewSlab + 1), Alignment); + assert((uintptr_t)Ptr + Size <= (uintptr_t)NewSlab + NewSlab->Size); + return Ptr; + } + + // Otherwise, start a new slab and try again. + StartNewSlab(); + Ptr = AlignPtr(CurPtr, Alignment); + CurPtr = Ptr + Size; + assert(CurPtr <= End && "Unable to allocate memory!"); + return Ptr; +} + +unsigned BumpPtrAllocator::GetNumSlabs() const { + unsigned NumSlabs = 0; + for (MemSlab *Slab = CurSlab; Slab != 0; Slab = Slab->NextPtr) { + ++NumSlabs; + } + return NumSlabs; +} + +size_t BumpPtrAllocator::getTotalMemory() const { + size_t TotalMemory = 0; + for (MemSlab *Slab = CurSlab; Slab != 0; Slab = Slab->NextPtr) { + TotalMemory += Slab->Size; + } + return TotalMemory; +} + +void BumpPtrAllocator::PrintStats() const { + unsigned NumSlabs = 0; + size_t TotalMemory = 0; + for (MemSlab *Slab = CurSlab; Slab != 0; Slab = Slab->NextPtr) { + TotalMemory += Slab->Size; + ++NumSlabs; + } + + errs() << "\nNumber of memory regions: " << NumSlabs << '\n' + << "Bytes used: " << BytesAllocated << '\n' + << "Bytes allocated: " << TotalMemory << '\n' + << "Bytes wasted: " << (TotalMemory - BytesAllocated) + << " (includes alignment, etc)\n"; +} + +MallocSlabAllocator BumpPtrAllocator::DefaultSlabAllocator = + MallocSlabAllocator(); + +SlabAllocator::~SlabAllocator() { } + +MallocSlabAllocator::~MallocSlabAllocator() { } + +MemSlab *MallocSlabAllocator::Allocate(size_t Size) { + MemSlab *Slab = (MemSlab*)Allocator.Allocate(Size, 0); + Slab->Size = Size; + Slab->NextPtr = 0; + return Slab; +} + +void MallocSlabAllocator::Deallocate(MemSlab *Slab) { + Allocator.Deallocate(Slab); +} + +void PrintRecyclerStats(size_t Size, + size_t Align, + size_t FreeListSize) { + errs() << "Recycler element size: " << Size << '\n' + << "Recycler element alignment: " << Align << '\n' + << "Number of elements free for recycling: " << FreeListSize << '\n'; +} + +} diff --git a/contrib/llvm/lib/Support/Atomic.cpp b/contrib/llvm/lib/Support/Atomic.cpp new file mode 100644 index 0000000..3001f6c --- /dev/null +++ b/contrib/llvm/lib/Support/Atomic.cpp @@ -0,0 +1,112 @@ +//===-- Atomic.cpp - Atomic Operations --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements atomic operations. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Atomic.h" +#include "llvm/Config/llvm-config.h" + +using namespace llvm; + +#if defined(_MSC_VER) +#include <windows.h> +#undef MemoryFence +#endif + +void sys::MemoryFence() { +#if LLVM_HAS_ATOMICS == 0 + return; +#else +# if defined(__GNUC__) + __sync_synchronize(); +# elif defined(_MSC_VER) + MemoryBarrier(); +# else +# error No memory fence implementation for your platform! +# endif +#endif +} + +sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr, + sys::cas_flag new_value, + sys::cas_flag old_value) { +#if LLVM_HAS_ATOMICS == 0 + sys::cas_flag result = *ptr; + if (result == old_value) + *ptr = new_value; + return result; +#elif defined(__GNUC__) + return __sync_val_compare_and_swap(ptr, old_value, new_value); +#elif defined(_MSC_VER) + return InterlockedCompareExchange(ptr, new_value, old_value); +#else +# error No compare-and-swap implementation for your platform! +#endif +} + +sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) { +#if LLVM_HAS_ATOMICS == 0 + ++(*ptr); + return *ptr; +#elif defined(__GNUC__) + return __sync_add_and_fetch(ptr, 1); +#elif defined(_MSC_VER) + return InterlockedIncrement(ptr); +#else +# error No atomic increment implementation for your platform! +#endif +} + +sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) { +#if LLVM_HAS_ATOMICS == 0 + --(*ptr); + return *ptr; +#elif defined(__GNUC__) + return __sync_sub_and_fetch(ptr, 1); +#elif defined(_MSC_VER) + return InterlockedDecrement(ptr); +#else +# error No atomic decrement implementation for your platform! +#endif +} + +sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) { +#if LLVM_HAS_ATOMICS == 0 + *ptr += val; + return *ptr; +#elif defined(__GNUC__) + return __sync_add_and_fetch(ptr, val); +#elif defined(_MSC_VER) + return InterlockedExchangeAdd(ptr, val) + val; +#else +# error No atomic add implementation for your platform! +#endif +} + +sys::cas_flag sys::AtomicMul(volatile sys::cas_flag* ptr, sys::cas_flag val) { + sys::cas_flag original, result; + do { + original = *ptr; + result = original * val; + } while (sys::CompareAndSwap(ptr, result, original) != original); + + return result; +} + +sys::cas_flag sys::AtomicDiv(volatile sys::cas_flag* ptr, sys::cas_flag val) { + sys::cas_flag original, result; + do { + original = *ptr; + result = original / val; + } while (sys::CompareAndSwap(ptr, result, original) != original); + + return result; +} diff --git a/contrib/llvm/lib/Support/BlockFrequency.cpp b/contrib/llvm/lib/Support/BlockFrequency.cpp new file mode 100644 index 0000000..84a993e --- /dev/null +++ b/contrib/llvm/lib/Support/BlockFrequency.cpp @@ -0,0 +1,130 @@ +//====--------------- lib/Support/BlockFrequency.cpp -----------*- C++ -*-====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Block Frequency class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/BranchProbability.h" +#include "llvm/Support/BlockFrequency.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> + +using namespace llvm; + +namespace { + +/// mult96bit - Multiply FREQ by N and store result in W array. +void mult96bit(uint64_t freq, uint32_t N, uint64_t W[2]) { + uint64_t u0 = freq & UINT32_MAX; + uint64_t u1 = freq >> 32; + + // Represent 96-bit value as w[2]:w[1]:w[0]; + uint32_t w[3] = { 0, 0, 0 }; + + uint64_t t = u0 * N; + uint64_t k = t >> 32; + w[0] = t; + t = u1 * N + k; + w[1] = t; + w[2] = t >> 32; + + // W[1] - higher bits. + // W[0] - lower bits. + W[0] = w[0] + ((uint64_t) w[1] << 32); + W[1] = w[2]; +} + + +/// div96bit - Divide 96-bit value stored in W array by D. Return 64-bit frequency. +uint64_t div96bit(uint64_t W[2], uint32_t D) { + uint64_t y = W[0]; + uint64_t x = W[1]; + int i; + + for (i = 1; i <= 64 && x; ++i) { + uint32_t t = (int)x >> 31; + x = (x << 1) | (y >> 63); + y = y << 1; + if ((x | t) >= D) { + x -= D; + ++y; + } + } + + return y << (64 - i + 1); +} + +} + + +BlockFrequency &BlockFrequency::operator*=(const BranchProbability &Prob) { + uint32_t n = Prob.getNumerator(); + uint32_t d = Prob.getDenominator(); + + assert(n <= d && "Probability must be less or equal to 1."); + + // 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]; + + // Probability is less or equal to 1 which means that results must fit + // 64-bit. + mult96bit(Frequency, n, W); + Frequency = div96bit(W, d); + return *this; + } + + Frequency = mulRes / d; + return *this; +} + +const BlockFrequency +BlockFrequency::operator*(const BranchProbability &Prob) const { + BlockFrequency Freq(Frequency); + Freq *= Prob; + return Freq; +} + +BlockFrequency &BlockFrequency::operator+=(const BlockFrequency &Freq) { + uint64_t Before = Freq.Frequency; + Frequency += Freq.Frequency; + + // If overflow, set frequency to the maximum value. + if (Frequency < Before) + Frequency = UINT64_MAX; + + return *this; +} + +const BlockFrequency +BlockFrequency::operator+(const BlockFrequency &Prob) const { + BlockFrequency Freq(Frequency); + Freq += Prob; + return Freq; +} + +void BlockFrequency::print(raw_ostream &OS) const { + OS << Frequency; +} + +namespace llvm { + +raw_ostream &operator<<(raw_ostream &OS, const BlockFrequency &Freq) { + Freq.print(OS); + return OS; +} + +} diff --git a/contrib/llvm/lib/Support/BranchProbability.cpp b/contrib/llvm/lib/Support/BranchProbability.cpp new file mode 100644 index 0000000..e8b83e5 --- /dev/null +++ b/contrib/llvm/lib/Support/BranchProbability.cpp @@ -0,0 +1,36 @@ +//===-------------- lib/Support/BranchProbability.cpp -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Branch Probability class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/BranchProbability.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +void BranchProbability::print(raw_ostream &OS) const { + OS << N << " / " << D << " = " << format("%g%%", ((double)N / D) * 100.0); +} + +void BranchProbability::dump() const { + dbgs() << *this << '\n'; +} + +namespace llvm { + +raw_ostream &operator<<(raw_ostream &OS, const BranchProbability &Prob) { + Prob.print(OS); + return OS; +} + +} diff --git a/contrib/llvm/lib/Support/COPYRIGHT.regex b/contrib/llvm/lib/Support/COPYRIGHT.regex new file mode 100644 index 0000000..a6392fd --- /dev/null +++ b/contrib/llvm/lib/Support/COPYRIGHT.regex @@ -0,0 +1,54 @@ +$OpenBSD: COPYRIGHT,v 1.3 2003/06/02 20:18:36 millert Exp $ + +Copyright 1992, 1993, 1994 Henry Spencer. All rights reserved. +This software is not subject to any license of the American Telephone +and Telegraph Company or of the Regents of the University of California. + +Permission is granted to anyone to use this software for any purpose on +any computer system, and to alter it and redistribute it, subject +to the following restrictions: + +1. The author is not responsible for the consequences of use of this + software, no matter how awful, even if they arise from flaws in it. + +2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. Since few users ever read sources, + credits must appear in the documentation. + +3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. Since few users + ever read sources, credits must appear in the documentation. + +4. This notice may not be removed or altered. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +/*- + * Copyright (c) 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)COPYRIGHT 8.1 (Berkeley) 3/16/94 + */ diff --git a/contrib/llvm/lib/Support/CommandLine.cpp b/contrib/llvm/lib/Support/CommandLine.cpp new file mode 100644 index 0000000..e6fdf16 --- /dev/null +++ b/contrib/llvm/lib/Support/CommandLine.cpp @@ -0,0 +1,1428 @@ +//===-- CommandLine.cpp - Command line parser implementation --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class implements a command line argument processor that is useful when +// creating a tool. It provides a simple, minimalistic interface that is easily +// extensible and supports nonlocal (library) command line options. +// +// Note that rather than trying to figure out what this code does, you could try +// reading the library documentation located in docs/CommandLine.html +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/Path.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Config/config.h" +#include <cerrno> +#include <cstdlib> +using namespace llvm; +using namespace cl; + +//===----------------------------------------------------------------------===// +// Template instantiations and anchors. +// +namespace llvm { namespace cl { +TEMPLATE_INSTANTIATION(class basic_parser<bool>); +TEMPLATE_INSTANTIATION(class basic_parser<boolOrDefault>); +TEMPLATE_INSTANTIATION(class basic_parser<int>); +TEMPLATE_INSTANTIATION(class basic_parser<unsigned>); +TEMPLATE_INSTANTIATION(class basic_parser<unsigned long long>); +TEMPLATE_INSTANTIATION(class basic_parser<double>); +TEMPLATE_INSTANTIATION(class basic_parser<float>); +TEMPLATE_INSTANTIATION(class basic_parser<std::string>); +TEMPLATE_INSTANTIATION(class basic_parser<char>); + +TEMPLATE_INSTANTIATION(class opt<unsigned>); +TEMPLATE_INSTANTIATION(class opt<int>); +TEMPLATE_INSTANTIATION(class opt<std::string>); +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() {} +void parser<boolOrDefault>::anchor() {} +void parser<int>::anchor() {} +void parser<unsigned>::anchor() {} +void parser<unsigned long long>::anchor() {} +void parser<double>::anchor() {} +void parser<float>::anchor() {} +void parser<std::string>::anchor() {} +void parser<char>::anchor() {} + +//===----------------------------------------------------------------------===// + +// Globals for name and overview of program. Program name is not a string to +// avoid static ctor/dtor issues. +static char ProgramName[80] = "<premain>"; +static const char *ProgramOverview = 0; + +// This collects additional help to be printed. +static ManagedStatic<std::vector<const char*> > MoreHelp; + +extrahelp::extrahelp(const char *Help) + : morehelp(Help) { + MoreHelp->push_back(Help); +} + +static bool OptionListChanged = false; + +// MarkOptionsChanged - Internal helper function. +void cl::MarkOptionsChanged() { + OptionListChanged = true; +} + +/// RegisteredOptionList - This is the list of the command line options that +/// have statically constructed themselves. +static Option *RegisteredOptionList = 0; + +void Option::addArgument() { + assert(NextRegistered == 0 && "argument multiply registered!"); + + NextRegistered = RegisteredOptionList; + RegisteredOptionList = this; + MarkOptionsChanged(); +} + + +//===----------------------------------------------------------------------===// +// Basic, shared command line option processing machinery. +// + +/// GetOptionInfo - Scan the list of registered options, turning them into data +/// structures that are easier to handle. +static void GetOptionInfo(SmallVectorImpl<Option*> &PositionalOpts, + SmallVectorImpl<Option*> &SinkOpts, + StringMap<Option*> &OptionsMap) { + SmallVector<const char*, 16> OptionNames; + Option *CAOpt = 0; // The ConsumeAfter option if it exists. + for (Option *O = RegisteredOptionList; O; O = O->getNextRegisteredOption()) { + // If this option wants to handle multiple option names, get the full set. + // This handles enum options like "-O1 -O2" etc. + O->getExtraOptionNames(OptionNames); + if (O->ArgStr[0]) + OptionNames.push_back(O->ArgStr); + + // Handle named options. + for (size_t i = 0, e = OptionNames.size(); i != e; ++i) { + // Add argument to the argument map! + if (OptionsMap.GetOrCreateValue(OptionNames[i], O).second != O) { + errs() << ProgramName << ": CommandLine Error: Argument '" + << OptionNames[i] << "' defined more than once!\n"; + } + } + + OptionNames.clear(); + + // Remember information about positional options. + if (O->getFormattingFlag() == cl::Positional) + PositionalOpts.push_back(O); + else if (O->getMiscFlags() & cl::Sink) // Remember sink options + SinkOpts.push_back(O); + else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) { + if (CAOpt) + O->error("Cannot specify more than one option with cl::ConsumeAfter!"); + CAOpt = O; + } + } + + if (CAOpt) + PositionalOpts.push_back(CAOpt); + + // Make sure that they are in order of registration not backwards. + std::reverse(PositionalOpts.begin(), PositionalOpts.end()); +} + + +/// LookupOption - Lookup the option specified by the specified option on the +/// command line. If there is a value specified (after an equal sign) return +/// that as well. This assumes that leading dashes have already been stripped. +static Option *LookupOption(StringRef &Arg, StringRef &Value, + const StringMap<Option*> &OptionsMap) { + // Reject all dashes. + if (Arg.empty()) return 0; + + size_t EqualPos = Arg.find('='); + + // If we have an equals sign, remember the value. + if (EqualPos == StringRef::npos) { + // Look up the option. + StringMap<Option*>::const_iterator I = OptionsMap.find(Arg); + return I != OptionsMap.end() ? I->second : 0; + } + + // If the argument before the = is a valid option name, we match. If not, + // return Arg unmolested. + StringMap<Option*>::const_iterator I = + OptionsMap.find(Arg.substr(0, EqualPos)); + if (I == OptionsMap.end()) return 0; + + Value = Arg.substr(EqualPos+1); + Arg = Arg.substr(0, EqualPos); + return I->second; +} + +/// LookupNearestOption - Lookup the closest match to the option specified by +/// the specified option on the command line. If there is a value specified +/// (after an equal sign) return that as well. This assumes that leading dashes +/// have already been stripped. +static Option *LookupNearestOption(StringRef Arg, + const StringMap<Option*> &OptionsMap, + std::string &NearestString) { + // Reject all dashes. + if (Arg.empty()) return 0; + + // Split on any equal sign. + std::pair<StringRef, StringRef> SplitArg = Arg.split('='); + StringRef &LHS = SplitArg.first; // LHS == Arg when no '=' is present. + StringRef &RHS = SplitArg.second; + + // Find the closest match. + Option *Best = 0; + unsigned BestDistance = 0; + for (StringMap<Option*>::const_iterator it = OptionsMap.begin(), + ie = OptionsMap.end(); it != ie; ++it) { + Option *O = it->second; + SmallVector<const char*, 16> OptionNames; + O->getExtraOptionNames(OptionNames); + if (O->ArgStr[0]) + OptionNames.push_back(O->ArgStr); + + bool PermitValue = O->getValueExpectedFlag() != cl::ValueDisallowed; + StringRef Flag = PermitValue ? LHS : Arg; + for (size_t i = 0, e = OptionNames.size(); i != e; ++i) { + StringRef Name = OptionNames[i]; + unsigned Distance = StringRef(Name).edit_distance( + Flag, /*AllowReplacements=*/true, /*MaxEditDistance=*/BestDistance); + if (!Best || Distance < BestDistance) { + Best = O; + BestDistance = Distance; + if (RHS.empty() || !PermitValue) + NearestString = OptionNames[i]; + else + NearestString = std::string(OptionNames[i]) + "=" + RHS.str(); + } + } + } + + return Best; +} + +/// CommaSeparateAndAddOccurence - A wrapper around Handler->addOccurence() that +/// does special handling of cl::CommaSeparated options. +static bool CommaSeparateAndAddOccurence(Option *Handler, unsigned pos, + StringRef ArgName, + StringRef Value, bool MultiArg = false) +{ + // Check to see if this option accepts a comma separated list of values. If + // it does, we have to split up the value into multiple values. + if (Handler->getMiscFlags() & CommaSeparated) { + StringRef Val(Value); + StringRef::size_type Pos = Val.find(','); + + while (Pos != StringRef::npos) { + // Process the portion before the comma. + if (Handler->addOccurrence(pos, ArgName, Val.substr(0, Pos), MultiArg)) + return true; + // Erase the portion before the comma, AND the comma. + Val = Val.substr(Pos+1); + Value.substr(Pos+1); // Increment the original value pointer as well. + // Check for another comma. + Pos = Val.find(','); + } + + Value = Val; + } + + if (Handler->addOccurrence(pos, ArgName, Value, MultiArg)) + return true; + + return false; +} + +/// ProvideOption - For Value, this differentiates between an empty value ("") +/// 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, + const char *const *argv, int &i) { + // Is this a multi-argument option? + unsigned NumAdditionalVals = Handler->getNumAdditionalVals(); + + // Enforce value requirements + switch (Handler->getValueExpectedFlag()) { + case ValueRequired: + if (Value.data() == 0) { // No value specified? + if (i+1 >= argc) + return Handler->error("requires a value!"); + // Steal the next argument, like for '-o filename' + Value = argv[++i]; + } + break; + case ValueDisallowed: + if (NumAdditionalVals > 0) + return Handler->error("multi-valued option specified" + " with ValueDisallowed modifier!"); + + if (Value.data()) + return Handler->error("does not allow a value! '" + + Twine(Value) + "' specified."); + break; + case ValueOptional: + break; + } + + // If this isn't a multi-arg option, just run the handler. + if (NumAdditionalVals == 0) + return CommaSeparateAndAddOccurence(Handler, i, ArgName, Value); + + // If it is, run the handle several times. + bool MultiArg = false; + + if (Value.data()) { + if (CommaSeparateAndAddOccurence(Handler, i, ArgName, Value, MultiArg)) + return true; + --NumAdditionalVals; + MultiArg = true; + } + + while (NumAdditionalVals > 0) { + if (i+1 >= argc) + return Handler->error("not enough values!"); + Value = argv[++i]; + + if (CommaSeparateAndAddOccurence(Handler, i, ArgName, Value, MultiArg)) + return true; + MultiArg = true; + --NumAdditionalVals; + } + return false; +} + +static bool ProvidePositionalOption(Option *Handler, StringRef Arg, int i) { + int Dummy = i; + return ProvideOption(Handler, Handler->ArgStr, Arg, 0, 0, Dummy); +} + + +// Option predicates... +static inline bool isGrouping(const Option *O) { + return O->getFormattingFlag() == cl::Grouping; +} +static inline bool isPrefixedOrGrouping(const Option *O) { + return isGrouping(O) || O->getFormattingFlag() == cl::Prefix; +} + +// getOptionPred - Check to see if there are any options that satisfy the +// specified predicate with names that are the prefixes in Name. This is +// checked by progressively stripping characters off of the name, checking to +// see if there options that satisfy the predicate. If we find one, return it, +// otherwise return null. +// +static Option *getOptionPred(StringRef Name, size_t &Length, + bool (*Pred)(const Option*), + const StringMap<Option*> &OptionsMap) { + + StringMap<Option*>::const_iterator OMI = OptionsMap.find(Name); + + // Loop while we haven't found an option and Name still has at least two + // characters in it (so that the next iteration will not be the empty + // string. + while (OMI == OptionsMap.end() && Name.size() > 1) { + Name = Name.substr(0, Name.size()-1); // Chop off the last character. + OMI = OptionsMap.find(Name); + } + + if (OMI != OptionsMap.end() && Pred(OMI->second)) { + Length = Name.size(); + return OMI->second; // Found one! + } + return 0; // No option found! +} + +/// HandlePrefixedOrGroupedOption - The specified argument string (which started +/// with at least one '-') does not fully match an available option. Check to +/// see if this is a prefix or grouped option. If so, split arg into output an +/// Arg/Value pair and return the Option to parse it with. +static Option *HandlePrefixedOrGroupedOption(StringRef &Arg, StringRef &Value, + bool &ErrorParsing, + const StringMap<Option*> &OptionsMap) { + if (Arg.size() == 1) return 0; + + // Do the lookup! + size_t Length = 0; + Option *PGOpt = getOptionPred(Arg, Length, isPrefixedOrGrouping, OptionsMap); + if (PGOpt == 0) return 0; + + // If the option is a prefixed option, then the value is simply the + // rest of the name... so fall through to later processing, by + // setting up the argument name flags and value fields. + if (PGOpt->getFormattingFlag() == cl::Prefix) { + Value = Arg.substr(Length); + Arg = Arg.substr(0, Length); + assert(OptionsMap.count(Arg) && OptionsMap.find(Arg)->second == PGOpt); + return PGOpt; + } + + // This must be a grouped option... handle them now. Grouping options can't + // have values. + assert(isGrouping(PGOpt) && "Broken getOptionPred!"); + + do { + // Move current arg name out of Arg into OneArgName. + StringRef OneArgName = Arg.substr(0, Length); + Arg = Arg.substr(Length); + + // Because ValueRequired is an invalid flag for grouped arguments, + // we don't need to pass argc/argv in. + assert(PGOpt->getValueExpectedFlag() != cl::ValueRequired && + "Option can not be cl::Grouping AND cl::ValueRequired!"); + int Dummy = 0; + ErrorParsing |= ProvideOption(PGOpt, OneArgName, + StringRef(), 0, 0, Dummy); + + // Get the next grouping option. + PGOpt = getOptionPred(Arg, Length, isGrouping, OptionsMap); + } while (PGOpt && Length != Arg.size()); + + // Return the last option with Arg cut down to just the last one. + return PGOpt; +} + + + +static bool RequiresValue(const Option *O) { + return O->getNumOccurrencesFlag() == cl::Required || + O->getNumOccurrencesFlag() == cl::OneOrMore; +} + +static bool EatsUnboundedNumberOfValues(const Option *O) { + return O->getNumOccurrencesFlag() == cl::ZeroOrMore || + O->getNumOccurrencesFlag() == cl::OneOrMore; +} + +/// ParseCStringVector - Break INPUT up wherever one or more +/// whitespace characters are found, and store the resulting tokens in +/// OUTPUT. The tokens stored in OUTPUT are dynamically allocated +/// using strdup(), so it is the caller's responsibility to free() +/// them later. +/// +static void ParseCStringVector(std::vector<char *> &OutputVector, + const char *Input) { + // Characters which will be treated as token separators: + StringRef Delims = " \v\f\t\r\n"; + + StringRef WorkStr(Input); + while (!WorkStr.empty()) { + // If the first character is a delimiter, strip them off. + if (Delims.find(WorkStr[0]) != StringRef::npos) { + size_t Pos = WorkStr.find_first_not_of(Delims); + if (Pos == StringRef::npos) Pos = WorkStr.size(); + WorkStr = WorkStr.substr(Pos); + continue; + } + + // Find position of first delimiter. + size_t Pos = WorkStr.find_first_of(Delims); + if (Pos == StringRef::npos) Pos = WorkStr.size(); + + // Everything from 0 to Pos is the next word to copy. + char *NewStr = (char*)malloc(Pos+1); + memcpy(NewStr, WorkStr.data(), Pos); + NewStr[Pos] = 0; + OutputVector.push_back(NewStr); + + WorkStr = WorkStr.substr(Pos); + } +} + +/// ParseEnvironmentOptions - An alternative entry point to the +/// CommandLine library, which allows you to read the program's name +/// from the caller (as PROGNAME) and its command-line arguments from +/// an environment variable (whose name is given in ENVVAR). +/// +void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, + const char *Overview, bool ReadResponseFiles) { + // Check args. + assert(progName && "Program name not specified"); + assert(envVar && "Environment variable name missing"); + + // Get the environment variable they want us to parse options out of. + const char *envValue = getenv(envVar); + if (!envValue) + return; + + // Get program's "name", which we wouldn't know without the caller + // telling us. + std::vector<char*> newArgv; + newArgv.push_back(strdup(progName)); + + // Parse the value of the environment variable into a "command line" + // and hand it off to ParseCommandLineOptions(). + ParseCStringVector(newArgv, envValue); + int newArgc = static_cast<int>(newArgv.size()); + ParseCommandLineOptions(newArgc, &newArgv[0], Overview, ReadResponseFiles); + + // Free all the strdup()ed strings. + for (std::vector<char*>::iterator i = newArgv.begin(), e = newArgv.end(); + i != e; ++i) + free(*i); +} + + +/// 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, const char*const* argv, + std::vector<char*>& newArgv) { + for (unsigned i = 1; i != argc; ++i) { + const char *arg = argv[i]; + + if (arg[0] == '@') { + sys::PathWithStatus respFile(++arg); + + // Check that the response file is not empty (mmap'ing empty + // files can be problematic). + const sys::FileStatus *FileStat = respFile.getFileStatus(); + if (FileStat && FileStat->getSize() != 0) { + + // If we could open the file, parse its contents, otherwise + // pass the @file option verbatim. + + // TODO: we should also support recursive loading of response files, + // since this is how gcc behaves. (From their man page: "The file may + // itself contain additional @file options; any such options will be + // processed recursively.") + + // Mmap the response file into memory. + OwningPtr<MemoryBuffer> respFilePtr; + if (!MemoryBuffer::getFile(respFile.c_str(), respFilePtr)) { + ParseCStringVector(newArgv, respFilePtr->getBufferStart()); + continue; + } + } + } + newArgv.push_back(strdup(arg)); + } +} + +void cl::ParseCommandLineOptions(int argc, const char * const *argv, + const char *Overview, bool ReadResponseFiles) { + // Process all registered options. + SmallVector<Option*, 4> PositionalOpts; + SmallVector<Option*, 4> SinkOpts; + StringMap<Option*> Opts; + GetOptionInfo(PositionalOpts, SinkOpts, Opts); + + assert((!Opts.empty() || !PositionalOpts.empty()) && + "No options specified!"); + + // Expand response files. + std::vector<char*> newArgv; + if (ReadResponseFiles) { + newArgv.push_back(strdup(argv[0])); + ExpandResponseFiles(argc, argv, newArgv); + argv = &newArgv[0]; + argc = static_cast<int>(newArgv.size()); + } + + // Copy the program name into ProgName, making sure not to overflow it. + std::string ProgName = sys::path::filename(argv[0]); + size_t Len = std::min(ProgName.size(), size_t(79)); + memcpy(ProgramName, ProgName.data(), Len); + ProgramName[Len] = '\0'; + + ProgramOverview = Overview; + bool ErrorParsing = false; + + // Check out the positional arguments to collect information about them. + unsigned NumPositionalRequired = 0; + + // Determine whether or not there are an unlimited number of positionals + bool HasUnlimitedPositionals = false; + + Option *ConsumeAfterOpt = 0; + if (!PositionalOpts.empty()) { + if (PositionalOpts[0]->getNumOccurrencesFlag() == cl::ConsumeAfter) { + assert(PositionalOpts.size() > 1 && + "Cannot specify cl::ConsumeAfter without a positional argument!"); + ConsumeAfterOpt = PositionalOpts[0]; + } + + // Calculate how many positional values are _required_. + bool UnboundedFound = false; + for (size_t i = ConsumeAfterOpt != 0, e = PositionalOpts.size(); + i != e; ++i) { + Option *Opt = PositionalOpts[i]; + if (RequiresValue(Opt)) + ++NumPositionalRequired; + else if (ConsumeAfterOpt) { + // ConsumeAfter cannot be combined with "optional" positional options + // unless there is only one positional argument... + if (PositionalOpts.size() > 2) + ErrorParsing |= + Opt->error("error - this positional option will never be matched, " + "because it does not Require a value, and a " + "cl::ConsumeAfter option is active!"); + } else if (UnboundedFound && !Opt->ArgStr[0]) { + // This option does not "require" a value... Make sure this option is + // not specified after an option that eats all extra arguments, or this + // one will never get any! + // + ErrorParsing |= Opt->error("error - option can never match, because " + "another positional argument will match an " + "unbounded number of values, and this option" + " does not require a value!"); + } + UnboundedFound |= EatsUnboundedNumberOfValues(Opt); + } + HasUnlimitedPositionals = UnboundedFound || ConsumeAfterOpt; + } + + // PositionalVals - A vector of "positional" arguments we accumulate into + // the process at the end. + // + SmallVector<std::pair<StringRef,unsigned>, 4> PositionalVals; + + // If the program has named positional arguments, and the name has been run + // across, keep track of which positional argument was named. Otherwise put + // the positional args into the PositionalVals list... + Option *ActivePositionalArg = 0; + + // Loop over all of the arguments... processing them. + bool DashDashFound = false; // Have we read '--'? + for (int i = 1; i < argc; ++i) { + Option *Handler = 0; + Option *NearestHandler = 0; + std::string NearestHandlerString; + StringRef Value; + StringRef ArgName = ""; + + // If the option list changed, this means that some command line + // option has just been registered or deregistered. This can occur in + // response to things like -load, etc. If this happens, rescan the options. + if (OptionListChanged) { + PositionalOpts.clear(); + SinkOpts.clear(); + Opts.clear(); + GetOptionInfo(PositionalOpts, SinkOpts, Opts); + OptionListChanged = false; + } + + // Check to see if this is a positional argument. This argument is + // considered to be positional if it doesn't start with '-', if it is "-" + // itself, or if we have seen "--" already. + // + if (argv[i][0] != '-' || argv[i][1] == 0 || DashDashFound) { + // Positional argument! + if (ActivePositionalArg) { + ProvidePositionalOption(ActivePositionalArg, argv[i], i); + continue; // We are done! + } + + if (!PositionalOpts.empty()) { + PositionalVals.push_back(std::make_pair(argv[i],i)); + + // All of the positional arguments have been fulfulled, give the rest to + // the consume after option... if it's specified... + // + if (PositionalVals.size() >= NumPositionalRequired && + ConsumeAfterOpt != 0) { + for (++i; i < argc; ++i) + PositionalVals.push_back(std::make_pair(argv[i],i)); + break; // Handle outside of the argument processing loop... + } + + // Delay processing positional arguments until the end... + continue; + } + } else if (argv[i][0] == '-' && argv[i][1] == '-' && argv[i][2] == 0 && + !DashDashFound) { + DashDashFound = true; // This is the mythical "--"? + continue; // Don't try to process it as an argument itself. + } else if (ActivePositionalArg && + (ActivePositionalArg->getMiscFlags() & PositionalEatsArgs)) { + // If there is a positional argument eating options, check to see if this + // option is another positional argument. If so, treat it as an argument, + // otherwise feed it to the eating positional. + ArgName = argv[i]+1; + // Eat leading dashes. + while (!ArgName.empty() && ArgName[0] == '-') + ArgName = ArgName.substr(1); + + Handler = LookupOption(ArgName, Value, Opts); + if (!Handler || Handler->getFormattingFlag() != cl::Positional) { + ProvidePositionalOption(ActivePositionalArg, argv[i], i); + continue; // We are done! + } + + } else { // We start with a '-', must be an argument. + ArgName = argv[i]+1; + // Eat leading dashes. + while (!ArgName.empty() && ArgName[0] == '-') + ArgName = ArgName.substr(1); + + Handler = LookupOption(ArgName, Value, Opts); + + // Check to see if this "option" is really a prefixed or grouped argument. + if (Handler == 0) + Handler = HandlePrefixedOrGroupedOption(ArgName, Value, + ErrorParsing, Opts); + + // Otherwise, look for the closest available option to report to the user + // in the upcoming error. + if (Handler == 0 && SinkOpts.empty()) + NearestHandler = LookupNearestOption(ArgName, Opts, + NearestHandlerString); + } + + if (Handler == 0) { + if (SinkOpts.empty()) { + errs() << ProgramName << ": Unknown command line argument '" + << argv[i] << "'. Try: '" << argv[0] << " -help'\n"; + + if (NearestHandler) { + // If we know a near match, report it as well. + errs() << ProgramName << ": Did you mean '-" + << NearestHandlerString << "'?\n"; + } + + ErrorParsing = true; + } else { + for (SmallVectorImpl<Option*>::iterator I = SinkOpts.begin(), + E = SinkOpts.end(); I != E ; ++I) + (*I)->addOccurrence(i, "", argv[i]); + } + continue; + } + + // If this is a named positional argument, just remember that it is the + // active one... + if (Handler->getFormattingFlag() == cl::Positional) + ActivePositionalArg = Handler; + else + ErrorParsing |= ProvideOption(Handler, ArgName, Value, argc, argv, i); + } + + // Check and handle positional arguments now... + if (NumPositionalRequired > PositionalVals.size()) { + errs() << ProgramName + << ": Not enough positional command line arguments specified!\n" + << "Must specify at least " << NumPositionalRequired + << " positional arguments: See: " << argv[0] << " -help\n"; + + ErrorParsing = true; + } else if (!HasUnlimitedPositionals && + PositionalVals.size() > PositionalOpts.size()) { + errs() << ProgramName + << ": Too many positional arguments specified!\n" + << "Can specify at most " << PositionalOpts.size() + << " positional arguments: See: " << argv[0] << " -help\n"; + ErrorParsing = true; + + } else if (ConsumeAfterOpt == 0) { + // Positional args have already been handled if ConsumeAfter is specified. + unsigned ValNo = 0, NumVals = static_cast<unsigned>(PositionalVals.size()); + for (size_t i = 0, e = PositionalOpts.size(); i != e; ++i) { + if (RequiresValue(PositionalOpts[i])) { + ProvidePositionalOption(PositionalOpts[i], PositionalVals[ValNo].first, + PositionalVals[ValNo].second); + ValNo++; + --NumPositionalRequired; // We fulfilled our duty... + } + + // If we _can_ give this option more arguments, do so now, as long as we + // do not give it values that others need. 'Done' controls whether the + // option even _WANTS_ any more. + // + bool Done = PositionalOpts[i]->getNumOccurrencesFlag() == cl::Required; + while (NumVals-ValNo > NumPositionalRequired && !Done) { + switch (PositionalOpts[i]->getNumOccurrencesFlag()) { + case cl::Optional: + Done = true; // Optional arguments want _at most_ one value + // FALL THROUGH + case cl::ZeroOrMore: // Zero or more will take all they can get... + case cl::OneOrMore: // One or more will take all they can get... + ProvidePositionalOption(PositionalOpts[i], + PositionalVals[ValNo].first, + PositionalVals[ValNo].second); + ValNo++; + break; + default: + llvm_unreachable("Internal error, unexpected NumOccurrences flag in " + "positional argument processing!"); + } + } + } + } else { + assert(ConsumeAfterOpt && NumPositionalRequired <= PositionalVals.size()); + unsigned ValNo = 0; + for (size_t j = 1, e = PositionalOpts.size(); j != e; ++j) + if (RequiresValue(PositionalOpts[j])) { + ErrorParsing |= ProvidePositionalOption(PositionalOpts[j], + PositionalVals[ValNo].first, + PositionalVals[ValNo].second); + ValNo++; + } + + // Handle the case where there is just one positional option, and it's + // optional. In this case, we want to give JUST THE FIRST option to the + // positional option and keep the rest for the consume after. The above + // loop would have assigned no values to positional options in this case. + // + if (PositionalOpts.size() == 2 && ValNo == 0 && !PositionalVals.empty()) { + ErrorParsing |= ProvidePositionalOption(PositionalOpts[1], + PositionalVals[ValNo].first, + PositionalVals[ValNo].second); + ValNo++; + } + + // Handle over all of the rest of the arguments to the + // cl::ConsumeAfter command line option... + for (; ValNo != PositionalVals.size(); ++ValNo) + ErrorParsing |= ProvidePositionalOption(ConsumeAfterOpt, + PositionalVals[ValNo].first, + PositionalVals[ValNo].second); + } + + // Loop over args and make sure all required args are specified! + for (StringMap<Option*>::iterator I = Opts.begin(), + E = Opts.end(); I != E; ++I) { + switch (I->second->getNumOccurrencesFlag()) { + case Required: + case OneOrMore: + if (I->second->getNumOccurrences() == 0) { + I->second->error("must be specified at least once!"); + ErrorParsing = true; + } + // Fall through + default: + break; + } + } + + // Now that we know if -debug is specified, we can use it. + // Note that if ReadResponseFiles == true, this must be done before the + // memory allocated for the expanded command line is free()d below. + DEBUG(dbgs() << "Args: "; + for (int i = 0; i < argc; ++i) + dbgs() << argv[i] << ' '; + dbgs() << '\n'; + ); + + // Free all of the memory allocated to the map. Command line options may only + // be processed once! + Opts.clear(); + PositionalOpts.clear(); + MoreHelp->clear(); + + // Free the memory allocated by ExpandResponseFiles. + if (ReadResponseFiles) { + // Free all the strdup()ed strings. + for (std::vector<char*>::iterator i = newArgv.begin(), e = newArgv.end(); + i != e; ++i) + free(*i); + } + + // If we had an error processing our arguments, don't let the program execute + if (ErrorParsing) exit(1); +} + +//===----------------------------------------------------------------------===// +// Option Base class implementation +// + +bool Option::error(const Twine &Message, StringRef ArgName) { + if (ArgName.data() == 0) ArgName = ArgStr; + if (ArgName.empty()) + errs() << HelpStr; // Be nice for positional arguments + else + errs() << ProgramName << ": for the -" << ArgName; + + errs() << " option: " << Message << "\n"; + return true; +} + +bool Option::addOccurrence(unsigned pos, StringRef ArgName, + StringRef Value, bool MultiArg) { + if (!MultiArg) + NumOccurrences++; // Increment the number of times we have been seen + + switch (getNumOccurrencesFlag()) { + case Optional: + if (NumOccurrences > 1) + return error("may only occur zero or one times!", ArgName); + break; + case Required: + if (NumOccurrences > 1) + return error("must occur exactly one time!", ArgName); + // Fall through + case OneOrMore: + case ZeroOrMore: + case ConsumeAfter: break; + } + + return handleOccurrence(pos, ArgName, Value); +} + + +// getValueStr - Get the value description string, using "DefaultMsg" if nothing +// has been specified yet. +// +static const char *getValueStr(const Option &O, const char *DefaultMsg) { + if (O.ValueStr[0] == 0) return DefaultMsg; + return O.ValueStr; +} + +//===----------------------------------------------------------------------===// +// cl::alias class implementation +// + +// Return the width of the option tag for printing... +size_t alias::getOptionWidth() const { + return std::strlen(ArgStr)+6; +} + +// Print out the option for the alias. +void alias::printOptionInfo(size_t GlobalWidth) const { + size_t L = std::strlen(ArgStr); + outs() << " -" << ArgStr; + outs().indent(GlobalWidth-L-6) << " - " << HelpStr << "\n"; +} + +//===----------------------------------------------------------------------===// +// Parser Implementation code... +// + +// basic_parser implementation +// + +// Return the width of the option tag for printing... +size_t basic_parser_impl::getOptionWidth(const Option &O) const { + size_t Len = std::strlen(O.ArgStr); + if (const char *ValName = getValueName()) + Len += std::strlen(getValueStr(O, ValName))+3; + + return Len + 6; +} + +// printOptionInfo - Print out information about this option. The +// to-be-maintained width is specified. +// +void basic_parser_impl::printOptionInfo(const Option &O, + size_t GlobalWidth) const { + outs() << " -" << O.ArgStr; + + if (const char *ValName = getValueName()) + outs() << "=<" << getValueStr(O, ValName) << '>'; + + outs().indent(GlobalWidth-getOptionWidth(O)) << " - " << O.HelpStr << '\n'; +} + +void basic_parser_impl::printOptionName(const Option &O, + size_t GlobalWidth) const { + outs() << " -" << O.ArgStr; + outs().indent(GlobalWidth-std::strlen(O.ArgStr)); +} + + +// parser<bool> implementation +// +bool parser<bool>::parse(Option &O, StringRef ArgName, + StringRef Arg, bool &Value) { + if (Arg == "" || Arg == "true" || Arg == "TRUE" || Arg == "True" || + Arg == "1") { + Value = true; + return false; + } + + if (Arg == "false" || Arg == "FALSE" || Arg == "False" || Arg == "0") { + Value = false; + return false; + } + return O.error("'" + Arg + + "' is invalid value for boolean argument! Try 0 or 1"); +} + +// parser<boolOrDefault> implementation +// +bool parser<boolOrDefault>::parse(Option &O, StringRef ArgName, + StringRef Arg, boolOrDefault &Value) { + if (Arg == "" || Arg == "true" || Arg == "TRUE" || Arg == "True" || + Arg == "1") { + Value = BOU_TRUE; + return false; + } + if (Arg == "false" || Arg == "FALSE" || Arg == "False" || Arg == "0") { + Value = BOU_FALSE; + return false; + } + + return O.error("'" + Arg + + "' is invalid value for boolean argument! Try 0 or 1"); +} + +// parser<int> implementation +// +bool parser<int>::parse(Option &O, StringRef ArgName, + StringRef Arg, int &Value) { + if (Arg.getAsInteger(0, Value)) + return O.error("'" + Arg + "' value invalid for integer argument!"); + return false; +} + +// parser<unsigned> implementation +// +bool parser<unsigned>::parse(Option &O, StringRef ArgName, + StringRef Arg, unsigned &Value) { + + if (Arg.getAsInteger(0, Value)) + return O.error("'" + Arg + "' value invalid for uint argument!"); + return false; +} + +// parser<unsigned long long> implementation +// +bool parser<unsigned long long>::parse(Option &O, StringRef ArgName, + StringRef Arg, unsigned long long &Value){ + + if (Arg.getAsInteger(0, Value)) + return O.error("'" + Arg + "' value invalid for uint argument!"); + return false; +} + +// parser<double>/parser<float> implementation +// +static bool parseDouble(Option &O, StringRef Arg, double &Value) { + SmallString<32> TmpStr(Arg.begin(), Arg.end()); + const char *ArgStart = TmpStr.c_str(); + char *End; + Value = strtod(ArgStart, &End); + if (*End != 0) + return O.error("'" + Arg + "' value invalid for floating point argument!"); + return false; +} + +bool parser<double>::parse(Option &O, StringRef ArgName, + StringRef Arg, double &Val) { + return parseDouble(O, Arg, Val); +} + +bool parser<float>::parse(Option &O, StringRef ArgName, + StringRef Arg, float &Val) { + double dVal; + if (parseDouble(O, Arg, dVal)) + return true; + Val = (float)dVal; + return false; +} + + + +// generic_parser_base implementation +// + +// findOption - Return the option number corresponding to the specified +// argument string. If the option is not found, getNumOptions() is returned. +// +unsigned generic_parser_base::findOption(const char *Name) { + unsigned e = getNumOptions(); + + for (unsigned i = 0; i != e; ++i) { + if (strcmp(getOption(i), Name) == 0) + return i; + } + return e; +} + + +// Return the width of the option tag for printing... +size_t generic_parser_base::getOptionWidth(const Option &O) const { + if (O.hasArgStr()) { + size_t Size = std::strlen(O.ArgStr)+6; + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) + Size = std::max(Size, std::strlen(getOption(i))+8); + return Size; + } else { + size_t BaseSize = 0; + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) + BaseSize = std::max(BaseSize, std::strlen(getOption(i))+8); + return BaseSize; + } +} + +// printOptionInfo - Print out information about this option. The +// to-be-maintained width is specified. +// +void generic_parser_base::printOptionInfo(const Option &O, + size_t GlobalWidth) const { + if (O.hasArgStr()) { + size_t L = std::strlen(O.ArgStr); + outs() << " -" << O.ArgStr; + outs().indent(GlobalWidth-L-6) << " - " << O.HelpStr << '\n'; + + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { + size_t NumSpaces = GlobalWidth-strlen(getOption(i))-8; + outs() << " =" << getOption(i); + outs().indent(NumSpaces) << " - " << getDescription(i) << '\n'; + } + } else { + if (O.HelpStr[0]) + outs() << " " << O.HelpStr << '\n'; + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { + size_t L = std::strlen(getOption(i)); + outs() << " -" << getOption(i); + outs().indent(GlobalWidth-L-8) << " - " << getDescription(i) << '\n'; + } + } +} + +static const size_t MaxOptWidth = 8; // arbitrary spacing for printOptionDiff + +// printGenericOptionDiff - Print the value of this option and it's default. +// +// "Generic" options have each value mapped to a name. +void generic_parser_base:: +printGenericOptionDiff(const Option &O, const GenericOptionValue &Value, + const GenericOptionValue &Default, + size_t GlobalWidth) const { + outs() << " -" << O.ArgStr; + outs().indent(GlobalWidth-std::strlen(O.ArgStr)); + + unsigned NumOpts = getNumOptions(); + for (unsigned i = 0; i != NumOpts; ++i) { + if (Value.compare(getOptionValue(i))) + continue; + + outs() << "= " << getOption(i); + size_t L = std::strlen(getOption(i)); + size_t NumSpaces = MaxOptWidth > L ? MaxOptWidth - L : 0; + outs().indent(NumSpaces) << " (default: "; + for (unsigned j = 0; j != NumOpts; ++j) { + if (Default.compare(getOptionValue(j))) + continue; + outs() << getOption(j); + break; + } + outs() << ")\n"; + return; + } + outs() << "= *unknown option value*\n"; +} + +// printOptionDiff - Specializations for printing basic value types. +// +#define PRINT_OPT_DIFF(T) \ + void parser<T>:: \ + printOptionDiff(const Option &O, T V, OptionValue<T> D, \ + size_t GlobalWidth) const { \ + printOptionName(O, GlobalWidth); \ + std::string Str; \ + { \ + raw_string_ostream SS(Str); \ + SS << V; \ + } \ + outs() << "= " << Str; \ + size_t NumSpaces = MaxOptWidth > Str.size() ? MaxOptWidth - Str.size() : 0;\ + outs().indent(NumSpaces) << " (default: "; \ + if (D.hasValue()) \ + outs() << D.getValue(); \ + else \ + outs() << "*no default*"; \ + outs() << ")\n"; \ + } \ + +PRINT_OPT_DIFF(bool) +PRINT_OPT_DIFF(boolOrDefault) +PRINT_OPT_DIFF(int) +PRINT_OPT_DIFF(unsigned) +PRINT_OPT_DIFF(unsigned long long) +PRINT_OPT_DIFF(double) +PRINT_OPT_DIFF(float) +PRINT_OPT_DIFF(char) + +void parser<std::string>:: +printOptionDiff(const Option &O, StringRef V, OptionValue<std::string> D, + size_t GlobalWidth) const { + printOptionName(O, GlobalWidth); + outs() << "= " << V; + size_t NumSpaces = MaxOptWidth > V.size() ? MaxOptWidth - V.size() : 0; + outs().indent(NumSpaces) << " (default: "; + if (D.hasValue()) + outs() << D.getValue(); + else + outs() << "*no default*"; + outs() << ")\n"; +} + +// Print a placeholder for options that don't yet support printOptionDiff(). +void basic_parser_impl:: +printOptionNoValue(const Option &O, size_t GlobalWidth) const { + printOptionName(O, GlobalWidth); + outs() << "= *cannot print option value*\n"; +} + +//===----------------------------------------------------------------------===// +// -help and -help-hidden option implementation +// + +static int OptNameCompare(const void *LHS, const void *RHS) { + typedef std::pair<const char *, Option*> pair_ty; + + 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. +static void +sortOpts(StringMap<Option*> &OptMap, + SmallVectorImpl< std::pair<const char *, Option*> > &Opts, + bool ShowHidden) { + SmallPtrSet<Option*, 128> OptionSet; // Duplicate option detection. + + for (StringMap<Option*>::iterator I = OptMap.begin(), E = OptMap.end(); + I != E; ++I) { + // Ignore really-hidden options. + if (I->second->getOptionHiddenFlag() == ReallyHidden) + continue; + + // Unless showhidden is set, ignore hidden flags. + if (I->second->getOptionHiddenFlag() == Hidden && !ShowHidden) + continue; + + // If we've already seen this option, don't add it to the list again. + if (!OptionSet.insert(I->second)) + continue; + + Opts.push_back(std::pair<const char *, Option*>(I->getKey().data(), + I->second)); + } + + // Sort the options list alphabetically. + qsort(Opts.data(), Opts.size(), sizeof(Opts[0]), OptNameCompare); +} + +namespace { + +class HelpPrinter { + size_t MaxArgLen; + const Option *EmptyArg; + const bool ShowHidden; + +public: + explicit HelpPrinter(bool showHidden) : ShowHidden(showHidden) { + EmptyArg = 0; + } + + void operator=(bool Value) { + if (Value == false) return; + + // Get all the options. + SmallVector<Option*, 4> PositionalOpts; + SmallVector<Option*, 4> SinkOpts; + StringMap<Option*> OptMap; + GetOptionInfo(PositionalOpts, SinkOpts, OptMap); + + SmallVector<std::pair<const char *, Option*>, 128> Opts; + sortOpts(OptMap, Opts, ShowHidden); + + if (ProgramOverview) + outs() << "OVERVIEW: " << ProgramOverview << "\n"; + + outs() << "USAGE: " << ProgramName << " [options]"; + + // Print out the positional options. + Option *CAOpt = 0; // The cl::ConsumeAfter option, if it exists... + if (!PositionalOpts.empty() && + PositionalOpts[0]->getNumOccurrencesFlag() == ConsumeAfter) + CAOpt = PositionalOpts[0]; + + for (size_t i = CAOpt != 0, e = PositionalOpts.size(); i != e; ++i) { + if (PositionalOpts[i]->ArgStr[0]) + outs() << " --" << PositionalOpts[i]->ArgStr; + outs() << " " << PositionalOpts[i]->HelpStr; + } + + // Print the consume after option info if it exists... + if (CAOpt) outs() << " " << CAOpt->HelpStr; + + outs() << "\n\n"; + + // Compute the maximum argument length... + MaxArgLen = 0; + for (size_t i = 0, e = Opts.size(); i != e; ++i) + MaxArgLen = std::max(MaxArgLen, Opts[i].second->getOptionWidth()); + + outs() << "OPTIONS:\n"; + for (size_t i = 0, e = Opts.size(); i != e; ++i) + Opts[i].second->printOptionInfo(MaxArgLen); + + // Print any extra help the user has declared. + for (std::vector<const char *>::iterator I = MoreHelp->begin(), + E = MoreHelp->end(); I != E; ++I) + outs() << *I; + MoreHelp->clear(); + + // Halt the program since help information was printed + exit(1); + } +}; +} // End anonymous namespace + +// Define the two HelpPrinter instances that are used to print out help, or +// help-hidden... +// +static HelpPrinter NormalPrinter(false); +static HelpPrinter HiddenPrinter(true); + +static cl::opt<HelpPrinter, true, parser<bool> > +HOp("help", cl::desc("Display available options (-help-hidden for more)"), + cl::location(NormalPrinter), cl::ValueDisallowed); + +static cl::opt<HelpPrinter, true, parser<bool> > +HHOp("help-hidden", cl::desc("Display all available options"), + cl::location(HiddenPrinter), cl::Hidden, cl::ValueDisallowed); + +static cl::opt<bool> +PrintOptions("print-options", + cl::desc("Print non-default options after command line parsing"), + cl::Hidden, cl::init(false)); + +static cl::opt<bool> +PrintAllOptions("print-all-options", + cl::desc("Print all option values after command line parsing"), + cl::Hidden, cl::init(false)); + +// Print the value of each option. +void cl::PrintOptionValues() { + if (!PrintOptions && !PrintAllOptions) return; + + // Get all the options. + SmallVector<Option*, 4> PositionalOpts; + SmallVector<Option*, 4> SinkOpts; + StringMap<Option*> OptMap; + GetOptionInfo(PositionalOpts, SinkOpts, OptMap); + + SmallVector<std::pair<const char *, Option*>, 128> Opts; + sortOpts(OptMap, Opts, /*ShowHidden*/true); + + // Compute the maximum argument length... + size_t MaxArgLen = 0; + for (size_t i = 0, e = Opts.size(); i != e; ++i) + MaxArgLen = std::max(MaxArgLen, Opts[i].second->getOptionWidth()); + + for (size_t i = 0, e = Opts.size(); i != e; ++i) + Opts[i].second->printOptionValue(MaxArgLen, PrintAllOptions); +} + +static void (*OverrideVersionPrinter)() = 0; + +static std::vector<void (*)()>* ExtraVersionPrinters = 0; + +namespace { +class VersionPrinter { +public: + void print() { + raw_ostream &OS = outs(); + OS << "LLVM (http://llvm.org/):\n" + << " " << PACKAGE_NAME << " version " << PACKAGE_VERSION; +#ifdef LLVM_VERSION_INFO + OS << LLVM_VERSION_INFO; +#endif + OS << "\n "; +#ifndef __OPTIMIZE__ + OS << "DEBUG build"; +#else + OS << "Optimized build"; +#endif +#ifndef NDEBUG + OS << " with assertions"; +#endif + std::string CPU = sys::getHostCPUName(); + if (CPU == "generic") CPU = "(unknown)"; + OS << ".\n" +#if (ENABLE_TIMESTAMPS == 1) + << " Built " << __DATE__ << " (" << __TIME__ << ").\n" +#endif + << " Default target: " << sys::getDefaultTargetTriple() << '\n' + << " Host CPU: " << CPU << '\n'; + } + void operator=(bool OptionWasSpecified) { + if (!OptionWasSpecified) return; + + if (OverrideVersionPrinter != 0) { + (*OverrideVersionPrinter)(); + exit(1); + } + print(); + + // Iterate over any registered extra printers and call them to add further + // information. + if (ExtraVersionPrinters != 0) { + outs() << '\n'; + for (std::vector<void (*)()>::iterator I = ExtraVersionPrinters->begin(), + E = ExtraVersionPrinters->end(); + I != E; ++I) + (*I)(); + } + + exit(1); + } +}; +} // End anonymous namespace + + +// Define the --version option that prints out the LLVM version for the tool +static VersionPrinter VersionPrinterInstance; + +static cl::opt<VersionPrinter, true, parser<bool> > +VersOp("version", cl::desc("Display the version of this program"), + cl::location(VersionPrinterInstance), cl::ValueDisallowed); + +// Utility function for printing the help message. +void cl::PrintHelpMessage() { + // This looks weird, but it actually prints the help message. The + // NormalPrinter variable is a HelpPrinter and the help gets printed when + // its operator= is invoked. That's because the "normal" usages of the + // help printer is to be assigned true/false depending on whether the + // -help option was given or not. Since we're circumventing that we have + // to make it look like -help was given, so we assign true. + NormalPrinter = true; +} + +/// Utility function for printing version number. +void cl::PrintVersionMessage() { + VersionPrinterInstance.print(); +} + +void cl::SetVersionPrinter(void (*func)()) { + OverrideVersionPrinter = func; +} + +void cl::AddExtraVersionPrinter(void (*func)()) { + if (ExtraVersionPrinters == 0) + ExtraVersionPrinters = new std::vector<void (*)()>; + + ExtraVersionPrinters->push_back(func); +} diff --git a/contrib/llvm/lib/Support/ConstantRange.cpp b/contrib/llvm/lib/Support/ConstantRange.cpp new file mode 100644 index 0000000..5206cf1 --- /dev/null +++ b/contrib/llvm/lib/Support/ConstantRange.cpp @@ -0,0 +1,679 @@ +//===-- ConstantRange.cpp - ConstantRange implementation ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Represent a range of possible values that may occur when the program is run +// for an integral value. This keeps track of a lower and upper bound for the +// constant, which MAY wrap around the end of the numeric range. To do this, it +// keeps track of a [lower, upper) bound, which specifies an interval just like +// STL iterators. When used with boolean values, the following are important +// ranges (other integral ranges use min/max values for special range values): +// +// [F, F) = {} = Empty set +// [T, F) = {T} +// [F, T) = {F} +// [T, T) = {F, T} = Full set +// +//===----------------------------------------------------------------------===// + +#include "llvm/InstrTypes.h" +#include "llvm/Support/ConstantRange.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +/// Initialize a full (the default) or empty set for the specified type. +/// +ConstantRange::ConstantRange(uint32_t BitWidth, bool Full) { + if (Full) + Lower = Upper = APInt::getMaxValue(BitWidth); + else + Lower = Upper = APInt::getMinValue(BitWidth); +} + +/// Initialize a range to hold the single specified value. +/// +ConstantRange::ConstantRange(const APInt &V) : Lower(V), Upper(V + 1) {} + +ConstantRange::ConstantRange(const APInt &L, const APInt &U) : + Lower(L), Upper(U) { + assert(L.getBitWidth() == U.getBitWidth() && + "ConstantRange with unequal bit widths"); + assert((L != U || (L.isMaxValue() || L.isMinValue())) && + "Lower == Upper, but they aren't min or max value!"); +} + +ConstantRange ConstantRange::makeICmpRegion(unsigned Pred, + const ConstantRange &CR) { + if (CR.isEmptySet()) + return CR; + + uint32_t W = CR.getBitWidth(); + switch (Pred) { + default: llvm_unreachable("Invalid ICmp predicate to makeICmpRegion()"); + case CmpInst::ICMP_EQ: + return CR; + case CmpInst::ICMP_NE: + if (CR.isSingleElement()) + return ConstantRange(CR.getUpper(), CR.getLower()); + return ConstantRange(W); + case CmpInst::ICMP_ULT: { + APInt UMax(CR.getUnsignedMax()); + if (UMax.isMinValue()) + return ConstantRange(W, /* empty */ false); + return ConstantRange(APInt::getMinValue(W), UMax); + } + case CmpInst::ICMP_SLT: { + APInt SMax(CR.getSignedMax()); + if (SMax.isMinSignedValue()) + return ConstantRange(W, /* empty */ false); + return ConstantRange(APInt::getSignedMinValue(W), SMax); + } + case CmpInst::ICMP_ULE: { + APInt UMax(CR.getUnsignedMax()); + if (UMax.isMaxValue()) + return ConstantRange(W); + return ConstantRange(APInt::getMinValue(W), UMax + 1); + } + case CmpInst::ICMP_SLE: { + APInt SMax(CR.getSignedMax()); + if (SMax.isMaxSignedValue()) + return ConstantRange(W); + return ConstantRange(APInt::getSignedMinValue(W), SMax + 1); + } + case CmpInst::ICMP_UGT: { + APInt UMin(CR.getUnsignedMin()); + if (UMin.isMaxValue()) + return ConstantRange(W, /* empty */ false); + return ConstantRange(UMin + 1, APInt::getNullValue(W)); + } + case CmpInst::ICMP_SGT: { + APInt SMin(CR.getSignedMin()); + if (SMin.isMaxSignedValue()) + return ConstantRange(W, /* empty */ false); + return ConstantRange(SMin + 1, APInt::getSignedMinValue(W)); + } + case CmpInst::ICMP_UGE: { + APInt UMin(CR.getUnsignedMin()); + if (UMin.isMinValue()) + return ConstantRange(W); + return ConstantRange(UMin, APInt::getNullValue(W)); + } + case CmpInst::ICMP_SGE: { + APInt SMin(CR.getSignedMin()); + if (SMin.isMinSignedValue()) + return ConstantRange(W); + return ConstantRange(SMin, APInt::getSignedMinValue(W)); + } + } +} + +/// isFullSet - Return true if this set contains all of the elements possible +/// for this data-type +bool ConstantRange::isFullSet() const { + return Lower == Upper && Lower.isMaxValue(); +} + +/// isEmptySet - Return true if this set contains no members. +/// +bool ConstantRange::isEmptySet() const { + return Lower == Upper && Lower.isMinValue(); +} + +/// isWrappedSet - Return true if this set wraps around the top of the range, +/// for example: [100, 8) +/// +bool ConstantRange::isWrappedSet() const { + return Lower.ugt(Upper); +} + +/// isSignWrappedSet - Return true if this set wraps around the INT_MIN of +/// its bitwidth, for example: i8 [120, 140). +/// +bool ConstantRange::isSignWrappedSet() const { + return contains(APInt::getSignedMaxValue(getBitWidth())) && + contains(APInt::getSignedMinValue(getBitWidth())); +} + +/// getSetSize - Return the number of elements in this set. +/// +APInt ConstantRange::getSetSize() const { + if (isEmptySet()) + return APInt(getBitWidth(), 0); + if (getBitWidth() == 1) { + if (Lower != Upper) // One of T or F in the set... + return APInt(2, 1); + return APInt(2, 2); // Must be full set... + } + + // Simply subtract the bounds... + return Upper - Lower; +} + +/// getUnsignedMax - Return the largest unsigned value contained in the +/// ConstantRange. +/// +APInt ConstantRange::getUnsignedMax() const { + if (isFullSet() || isWrappedSet()) + return APInt::getMaxValue(getBitWidth()); + return getUpper() - 1; +} + +/// getUnsignedMin - Return the smallest unsigned value contained in the +/// ConstantRange. +/// +APInt ConstantRange::getUnsignedMin() const { + if (isFullSet() || (isWrappedSet() && getUpper() != 0)) + return APInt::getMinValue(getBitWidth()); + return getLower(); +} + +/// getSignedMax - Return the largest signed value contained in the +/// ConstantRange. +/// +APInt ConstantRange::getSignedMax() const { + APInt SignedMax(APInt::getSignedMaxValue(getBitWidth())); + if (!isWrappedSet()) { + if (getLower().sle(getUpper() - 1)) + return getUpper() - 1; + return SignedMax; + } + if (getLower().isNegative() == getUpper().isNegative()) + return SignedMax; + return getUpper() - 1; +} + +/// getSignedMin - Return the smallest signed value contained in the +/// ConstantRange. +/// +APInt ConstantRange::getSignedMin() const { + APInt SignedMin(APInt::getSignedMinValue(getBitWidth())); + if (!isWrappedSet()) { + if (getLower().sle(getUpper() - 1)) + return getLower(); + return SignedMin; + } + if ((getUpper() - 1).slt(getLower())) { + if (getUpper() != SignedMin) + return SignedMin; + } + return getLower(); +} + +/// contains - Return true if the specified value is in the set. +/// +bool ConstantRange::contains(const APInt &V) const { + if (Lower == Upper) + return isFullSet(); + + if (!isWrappedSet()) + 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. +/// Two equal sets contain each other. The empty set contained by all other +/// sets. +/// +bool ConstantRange::contains(const ConstantRange &Other) const { + if (isFullSet() || Other.isEmptySet()) return true; + if (isEmptySet() || Other.isFullSet()) return false; + + if (!isWrappedSet()) { + if (Other.isWrappedSet()) + return false; + + return Lower.ule(Other.getLower()) && Other.getUpper().ule(Upper); + } + + if (!Other.isWrappedSet()) + return Other.getUpper().ule(Upper) || + Lower.ule(Other.getLower()); + + return Other.getUpper().ule(Upper) && Lower.ule(Other.getLower()); +} + +/// subtract - Subtract the specified constant from the endpoints of this +/// constant range. +ConstantRange ConstantRange::subtract(const APInt &Val) const { + assert(Val.getBitWidth() == getBitWidth() && "Wrong bit width"); + // If the set is empty or full, don't modify the endpoints. + if (Lower == Upper) + return *this; + return ConstantRange(Lower - Val, Upper - Val); +} + +/// intersectWith - Return the range that results from the intersection of this +/// range with another range. The resultant range is guaranteed to include all +/// elements contained in both input ranges, and to have the smallest possible +/// set size that does so. Because there may be two intersections with the +/// same set size, A.intersectWith(B) might not be equal to B.intersectWith(A). +ConstantRange ConstantRange::intersectWith(const ConstantRange &CR) const { + assert(getBitWidth() == CR.getBitWidth() && + "ConstantRange types don't agree!"); + + // Handle common cases. + if ( isEmptySet() || CR.isFullSet()) return *this; + if (CR.isEmptySet() || isFullSet()) return CR; + + if (!isWrappedSet() && CR.isWrappedSet()) + return CR.intersectWith(*this); + + if (!isWrappedSet() && !CR.isWrappedSet()) { + if (Lower.ult(CR.Lower)) { + if (Upper.ule(CR.Lower)) + return ConstantRange(getBitWidth(), false); + + if (Upper.ult(CR.Upper)) + return ConstantRange(CR.Lower, Upper); + + return CR; + } + if (Upper.ult(CR.Upper)) + return *this; + + if (Lower.ult(CR.Upper)) + return ConstantRange(Lower, CR.Upper); + + return ConstantRange(getBitWidth(), false); + } + + if (isWrappedSet() && !CR.isWrappedSet()) { + if (CR.Lower.ult(Upper)) { + if (CR.Upper.ult(Upper)) + return CR; + + if (CR.Upper.ult(Lower)) + return ConstantRange(CR.Lower, Upper); + + if (getSetSize().ult(CR.getSetSize())) + return *this; + return CR; + } + if (CR.Lower.ult(Lower)) { + if (CR.Upper.ule(Lower)) + return ConstantRange(getBitWidth(), false); + + return ConstantRange(Lower, CR.Upper); + } + return CR; + } + + if (CR.Upper.ult(Upper)) { + if (CR.Lower.ult(Upper)) { + if (getSetSize().ult(CR.getSetSize())) + return *this; + return CR; + } + + if (CR.Lower.ult(Lower)) + return ConstantRange(Lower, CR.Upper); + + return CR; + } + if (CR.Upper.ult(Lower)) { + if (CR.Lower.ult(Lower)) + return *this; + + return ConstantRange(CR.Lower, Upper); + } + if (getSetSize().ult(CR.getSetSize())) + return *this; + return CR; +} + + +/// unionWith - Return the range that results from the union of this range with +/// another range. The resultant range is guaranteed to include the elements of +/// both sets, but may contain more. For example, [3, 9) union [12,15) is +/// [3, 15), which includes 9, 10, and 11, which were not included in either +/// set before. +/// +ConstantRange ConstantRange::unionWith(const ConstantRange &CR) const { + assert(getBitWidth() == CR.getBitWidth() && + "ConstantRange types don't agree!"); + + if ( isFullSet() || CR.isEmptySet()) return *this; + if (CR.isFullSet() || isEmptySet()) return CR; + + if (!isWrappedSet() && CR.isWrappedSet()) return CR.unionWith(*this); + + if (!isWrappedSet() && !CR.isWrappedSet()) { + if (CR.Upper.ult(Lower) || Upper.ult(CR.Lower)) { + // If the two ranges are disjoint, find the smaller gap and bridge it. + APInt d1 = CR.Lower - Upper, d2 = Lower - CR.Upper; + if (d1.ult(d2)) + return ConstantRange(Lower, CR.Upper); + return ConstantRange(CR.Lower, Upper); + } + + APInt L = Lower, U = Upper; + if (CR.Lower.ult(L)) + L = CR.Lower; + if ((CR.Upper - 1).ugt(U - 1)) + U = CR.Upper; + + if (L == 0 && U == 0) + return ConstantRange(getBitWidth()); + + return ConstantRange(L, U); + } + + if (!CR.isWrappedSet()) { + // ------U L----- and ------U L----- : this + // L--U L--U : CR + if (CR.Upper.ule(Upper) || CR.Lower.uge(Lower)) + return *this; + + // ------U L----- : this + // L---------U : CR + if (CR.Lower.ule(Upper) && Lower.ule(CR.Upper)) + return ConstantRange(getBitWidth()); + + // ----U L---- : this + // L---U : CR + // <d1> <d2> + if (Upper.ule(CR.Lower) && CR.Upper.ule(Lower)) { + APInt d1 = CR.Lower - Upper, d2 = Lower - CR.Upper; + if (d1.ult(d2)) + return ConstantRange(Lower, CR.Upper); + return ConstantRange(CR.Lower, Upper); + } + + // ----U L----- : this + // L----U : CR + if (Upper.ult(CR.Lower) && Lower.ult(CR.Upper)) + return ConstantRange(CR.Lower, Upper); + + // ------U L---- : this + // L-----U : CR + assert(CR.Lower.ult(Upper) && CR.Upper.ult(Lower) && + "ConstantRange::unionWith missed a case with one range wrapped"); + return ConstantRange(Lower, CR.Upper); + } + + // ------U L---- and ------U L---- : this + // -U L----------- and ------------U L : CR + if (CR.Lower.ule(Upper) || Lower.ule(CR.Upper)) + return ConstantRange(getBitWidth()); + + APInt L = Lower, U = Upper; + if (CR.Upper.ugt(U)) + U = CR.Upper; + if (CR.Lower.ult(L)) + L = CR.Lower; + + return ConstantRange(L, U); +} + +/// zeroExtend - Return a new range in the specified integer type, which must +/// be strictly larger than the current type. The returned range will +/// correspond to the possible range of values as if the source range had been +/// zero extended. +ConstantRange ConstantRange::zeroExtend(uint32_t DstTySize) const { + if (isEmptySet()) return ConstantRange(DstTySize, /*isFullSet=*/false); + + unsigned SrcTySize = getBitWidth(); + assert(SrcTySize < DstTySize && "Not a value extension"); + if (isFullSet() || isWrappedSet()) + // Change into [0, 1 << src bit width) + return ConstantRange(APInt(DstTySize,0), APInt(DstTySize,1).shl(SrcTySize)); + + return ConstantRange(Lower.zext(DstTySize), Upper.zext(DstTySize)); +} + +/// signExtend - Return a new range in the specified integer type, which must +/// be strictly larger than the current type. The returned range will +/// correspond to the possible range of values as if the source range had been +/// sign extended. +ConstantRange ConstantRange::signExtend(uint32_t DstTySize) const { + if (isEmptySet()) return ConstantRange(DstTySize, /*isFullSet=*/false); + + unsigned SrcTySize = getBitWidth(); + assert(SrcTySize < DstTySize && "Not a value extension"); + if (isFullSet() || isSignWrappedSet()) { + return ConstantRange(APInt::getHighBitsSet(DstTySize,DstTySize-SrcTySize+1), + APInt::getLowBitsSet(DstTySize, SrcTySize-1) + 1); + } + + return ConstantRange(Lower.sext(DstTySize), Upper.sext(DstTySize)); +} + +/// truncate - Return a new range in the specified integer type, which must be +/// strictly smaller than the current type. The returned range will +/// 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 { + 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)); +} + +/// zextOrTrunc - make this range have the bit width given by \p DstTySize. The +/// value is zero extended, truncated, or left alone to make it that width. +ConstantRange ConstantRange::zextOrTrunc(uint32_t DstTySize) const { + unsigned SrcTySize = getBitWidth(); + if (SrcTySize > DstTySize) + return truncate(DstTySize); + if (SrcTySize < DstTySize) + return zeroExtend(DstTySize); + return *this; +} + +/// sextOrTrunc - make this range have the bit width given by \p DstTySize. The +/// value is sign extended, truncated, or left alone to make it that width. +ConstantRange ConstantRange::sextOrTrunc(uint32_t DstTySize) const { + unsigned SrcTySize = getBitWidth(); + if (SrcTySize > DstTySize) + return truncate(DstTySize); + if (SrcTySize < DstTySize) + return signExtend(DstTySize); + return *this; +} + +ConstantRange +ConstantRange::add(const ConstantRange &Other) const { + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + if (isFullSet() || Other.isFullSet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + + APInt Spread_X = getSetSize(), Spread_Y = Other.getSetSize(); + APInt NewLower = getLower() + Other.getLower(); + APInt NewUpper = getUpper() + Other.getUpper() - 1; + if (NewLower == NewUpper) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + + ConstantRange X = ConstantRange(NewLower, NewUpper); + if (X.getSetSize().ult(Spread_X) || X.getSetSize().ult(Spread_Y)) + // We've wrapped, therefore, full set. + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + + return X; +} + +ConstantRange +ConstantRange::sub(const ConstantRange &Other) const { + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + if (isFullSet() || Other.isFullSet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + + APInt Spread_X = getSetSize(), Spread_Y = Other.getSetSize(); + APInt NewLower = getLower() - Other.getUpper() + 1; + APInt NewUpper = getUpper() - Other.getLower(); + if (NewLower == NewUpper) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + + ConstantRange X = ConstantRange(NewLower, NewUpper); + if (X.getSetSize().ult(Spread_X) || X.getSetSize().ult(Spread_Y)) + // We've wrapped, therefore, full set. + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + + return X; +} + +ConstantRange +ConstantRange::multiply(const ConstantRange &Other) const { + // TODO: If either operand is a single element and the multiply is known to + // be non-wrapping, round the result min and max value to the appropriate + // multiple of that element. If wrapping is possible, at least adjust the + // range according to the greatest power-of-two factor of the single element. + + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + if (isFullSet() || Other.isFullSet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + + APInt this_min = getUnsignedMin().zext(getBitWidth() * 2); + APInt this_max = getUnsignedMax().zext(getBitWidth() * 2); + APInt Other_min = Other.getUnsignedMin().zext(getBitWidth() * 2); + APInt Other_max = Other.getUnsignedMax().zext(getBitWidth() * 2); + + ConstantRange Result_zext = ConstantRange(this_min * Other_min, + this_max * Other_max + 1); + return Result_zext.truncate(getBitWidth()); +} + +ConstantRange +ConstantRange::smax(const ConstantRange &Other) const { + // X smax Y is: range(smax(X_smin, Y_smin), + // smax(X_smax, Y_smax)) + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + APInt NewL = APIntOps::smax(getSignedMin(), Other.getSignedMin()); + APInt NewU = APIntOps::smax(getSignedMax(), Other.getSignedMax()) + 1; + if (NewU == NewL) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + return ConstantRange(NewL, NewU); +} + +ConstantRange +ConstantRange::umax(const ConstantRange &Other) const { + // X umax Y is: range(umax(X_umin, Y_umin), + // umax(X_umax, Y_umax)) + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + APInt NewL = APIntOps::umax(getUnsignedMin(), Other.getUnsignedMin()); + APInt NewU = APIntOps::umax(getUnsignedMax(), Other.getUnsignedMax()) + 1; + if (NewU == NewL) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + return ConstantRange(NewL, NewU); +} + +ConstantRange +ConstantRange::udiv(const ConstantRange &RHS) const { + if (isEmptySet() || RHS.isEmptySet() || RHS.getUnsignedMax() == 0) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + if (RHS.isFullSet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + + APInt Lower = getUnsignedMin().udiv(RHS.getUnsignedMax()); + + APInt RHS_umin = RHS.getUnsignedMin(); + if (RHS_umin == 0) { + // We want the lowest value in RHS excluding zero. Usually that would be 1 + // except for a range in the form of [X, 1) in which case it would be X. + if (RHS.getUpper() == 1) + RHS_umin = RHS.getLower(); + else + RHS_umin = APInt(getBitWidth(), 1); + } + + APInt Upper = getUnsignedMax().udiv(RHS_umin) + 1; + + // If the LHS is Full and the RHS is a wrapped interval containing 1 then + // this could occur. + if (Lower == Upper) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + + return ConstantRange(Lower, Upper); +} + +ConstantRange +ConstantRange::binaryAnd(const ConstantRange &Other) const { + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + + // TODO: replace this with something less conservative + + APInt umin = APIntOps::umin(Other.getUnsignedMax(), getUnsignedMax()); + if (umin.isAllOnesValue()) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + return ConstantRange(APInt::getNullValue(getBitWidth()), umin + 1); +} + +ConstantRange +ConstantRange::binaryOr(const ConstantRange &Other) const { + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + + // TODO: replace this with something less conservative + + APInt umax = APIntOps::umax(getUnsignedMin(), Other.getUnsignedMin()); + if (umax.isMinValue()) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + return ConstantRange(umax, APInt::getNullValue(getBitWidth())); +} + +ConstantRange +ConstantRange::shl(const ConstantRange &Other) const { + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + + APInt min = getUnsignedMin().shl(Other.getUnsignedMin()); + APInt max = getUnsignedMax().shl(Other.getUnsignedMax()); + + // there's no overflow! + APInt Zeros(getBitWidth(), getUnsignedMax().countLeadingZeros()); + if (Zeros.ugt(Other.getUnsignedMax())) + return ConstantRange(min, max + 1); + + // FIXME: implement the other tricky cases + return ConstantRange(getBitWidth(), /*isFullSet=*/true); +} + +ConstantRange +ConstantRange::lshr(const ConstantRange &Other) const { + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + + APInt max = getUnsignedMax().lshr(Other.getUnsignedMin()); + APInt min = getUnsignedMin().lshr(Other.getUnsignedMax()); + if (min == max + 1) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + + return ConstantRange(min, max + 1); +} + +ConstantRange ConstantRange::inverse() const { + if (isFullSet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + if (isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + return ConstantRange(Upper, Lower); +} + +/// print - Print out the bounds to a stream... +/// +void ConstantRange::print(raw_ostream &OS) const { + if (isFullSet()) + OS << "full-set"; + else if (isEmptySet()) + OS << "empty-set"; + else + OS << "[" << Lower << "," << Upper << ")"; +} + +/// dump - Allow printing from a debugger easily... +/// +void ConstantRange::dump() const { + print(dbgs()); +} diff --git a/contrib/llvm/lib/Support/CrashRecoveryContext.cpp b/contrib/llvm/lib/Support/CrashRecoveryContext.cpp new file mode 100644 index 0000000..e2af0bc --- /dev/null +++ b/contrib/llvm/lib/Support/CrashRecoveryContext.cpp @@ -0,0 +1,346 @@ +//===--- CrashRecoveryContext.cpp - Crash Recovery ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Config/config.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/ThreadLocal.h" +#include "llvm/Support/ErrorHandling.h" +#include <setjmp.h> +#include <cstdio> +using namespace llvm; + +namespace { + +struct CrashRecoveryContextImpl; + +static sys::ThreadLocal<const CrashRecoveryContextImpl> CurrentContext; + +struct CrashRecoveryContextImpl { + CrashRecoveryContext *CRC; + std::string Backtrace; + ::jmp_buf JumpBuffer; + volatile unsigned Failed : 1; + +public: + CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC), + Failed(false) { + CurrentContext.set(this); + } + ~CrashRecoveryContextImpl() { + CurrentContext.erase(); + } + + void HandleCrash() { + // Eliminate the current context entry, to avoid re-entering in case the + // cleanup code crashes. + CurrentContext.erase(); + + assert(!Failed && "Crash recovery context already failed!"); + Failed = true; + + // FIXME: Stash the backtrace. + + // Jump back to the RunSafely we were called under. + longjmp(JumpBuffer, 1); + } +}; + +} + +static sys::Mutex gCrashRecoveryContexMutex; +static bool gCrashRecoveryEnabled = false; + +static sys::ThreadLocal<const CrashRecoveryContextCleanup> + tlIsRecoveringFromCrash; + +CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {} + +CrashRecoveryContext::~CrashRecoveryContext() { + // Reclaim registered resources. + CrashRecoveryContextCleanup *i = head; + tlIsRecoveringFromCrash.set(head); + while (i) { + CrashRecoveryContextCleanup *tmp = i; + i = tmp->next; + tmp->cleanupFired = true; + tmp->recoverResources(); + delete tmp; + } + tlIsRecoveringFromCrash.erase(); + + CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; + delete CRCI; +} + +bool CrashRecoveryContext::isRecoveringFromCrash() { + return tlIsRecoveringFromCrash.get() != 0; +} + +CrashRecoveryContext *CrashRecoveryContext::GetCurrent() { + if (!gCrashRecoveryEnabled) + return 0; + + const CrashRecoveryContextImpl *CRCI = CurrentContext.get(); + if (!CRCI) + return 0; + + return CRCI->CRC; +} + +void CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup) +{ + if (!cleanup) + return; + if (head) + head->prev = cleanup; + cleanup->next = head; + head = cleanup; +} + +void +CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) { + if (!cleanup) + return; + if (cleanup == head) { + head = cleanup->next; + if (head) + head->prev = 0; + } + else { + cleanup->prev->next = cleanup->next; + if (cleanup->next) + cleanup->next->prev = cleanup->prev; + } + delete cleanup; +} + +#ifdef LLVM_ON_WIN32 + +#include "Windows/Windows.h" + +// On Windows, we can make use of vectored exception handling to +// catch most crashing situations. Note that this does mean +// we will be alerted of exceptions *before* structured exception +// handling has the opportunity to catch it. But that isn't likely +// to cause problems because nowhere in the project is SEH being +// used. +// +// Vectored exception handling is built on top of SEH, and so it +// works on a per-thread basis. +// +// The vectored exception handler functionality was added in Windows +// XP, so if support for older versions of Windows is required, +// it will have to be added. +// +// If we want to support as far back as Win2k, we could use the +// SetUnhandledExceptionFilter API, but there's a risk of that +// being entirely overwritten (it's not a chain). + +static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) +{ + // Lookup the current thread local recovery object. + const CrashRecoveryContextImpl *CRCI = CurrentContext.get(); + + if (!CRCI) { + // Something has gone horribly wrong, so let's just tell everyone + // to keep searching + CrashRecoveryContext::Disable(); + return EXCEPTION_CONTINUE_SEARCH; + } + + // TODO: We can capture the stack backtrace here and store it on the + // implementation if we so choose. + + // Handle the crash + const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash(); + + // 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"); +} + +// Because the Enable and Disable calls are static, it means that +// there may not actually be an Impl available, or even a current +// CrashRecoveryContext at all. So we make use of a thread-local +// exception table. The handles contained in here will either be +// non-NULL, valid VEH handles, or NULL. +static sys::ThreadLocal<const void> sCurrentExceptionHandle; + +void CrashRecoveryContext::Enable() { + sys::ScopedLock L(gCrashRecoveryContexMutex); + + if (gCrashRecoveryEnabled) + return; + + gCrashRecoveryEnabled = true; + + // We can set up vectored exception handling now. We will install our + // handler as the front of the list, though there's no assurances that + // it will remain at the front (another call could install itself before + // our handler). This 1) isn't likely, and 2) shouldn't cause problems. + PVOID handle = ::AddVectoredExceptionHandler(1, ExceptionHandler); + sCurrentExceptionHandle.set(handle); +} + +void CrashRecoveryContext::Disable() { + sys::ScopedLock L(gCrashRecoveryContexMutex); + + if (!gCrashRecoveryEnabled) + return; + + gCrashRecoveryEnabled = false; + + PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle.get()); + if (currentHandle) { + // Now we can remove the vectored exception handler from the chain + ::RemoveVectoredExceptionHandler(currentHandle); + + // Reset the handle in our thread-local set. + sCurrentExceptionHandle.set(NULL); + } +} + +#else + +// Generic POSIX implementation. +// +// This implementation relies on synchronous signals being delivered to the +// current thread. We use a thread local object to keep track of the active +// crash recovery context, and install signal handlers to invoke HandleCrash on +// the active object. +// +// This implementation does not to attempt to chain signal handlers in any +// reliable fashion -- if we get a signal outside of a crash recovery context we +// simply disable crash recovery and raise the signal again. + +#include <signal.h> + +static int Signals[] = { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP }; +static const unsigned NumSignals = sizeof(Signals) / sizeof(Signals[0]); +static struct sigaction PrevActions[NumSignals]; + +static void CrashRecoverySignalHandler(int Signal) { + // Lookup the current thread local recovery object. + const CrashRecoveryContextImpl *CRCI = CurrentContext.get(); + + if (!CRCI) { + // We didn't find a crash recovery context -- this means either we got a + // signal on a thread we didn't expect it on, the application got a signal + // outside of a crash recovery context, or something else went horribly + // wrong. + // + // Disable crash recovery and raise the signal again. The assumption here is + // that the enclosing application will terminate soon, and we won't want to + // attempt crash recovery again. + // + // This call of Disable isn't thread safe, but it doesn't actually matter. + CrashRecoveryContext::Disable(); + raise(Signal); + + // The signal will be thrown once the signal mask is restored. + return; + } + + // Unblock the signal we received. + sigset_t SigMask; + sigemptyset(&SigMask); + sigaddset(&SigMask, Signal); + sigprocmask(SIG_UNBLOCK, &SigMask, 0); + + if (CRCI) + const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash(); +} + +void CrashRecoveryContext::Enable() { + sys::ScopedLock L(gCrashRecoveryContexMutex); + + if (gCrashRecoveryEnabled) + return; + + gCrashRecoveryEnabled = true; + + // Setup the signal handler. + struct sigaction Handler; + Handler.sa_handler = CrashRecoverySignalHandler; + Handler.sa_flags = 0; + sigemptyset(&Handler.sa_mask); + + for (unsigned i = 0; i != NumSignals; ++i) { + sigaction(Signals[i], &Handler, &PrevActions[i]); + } +} + +void CrashRecoveryContext::Disable() { + sys::ScopedLock L(gCrashRecoveryContexMutex); + + if (!gCrashRecoveryEnabled) + return; + + gCrashRecoveryEnabled = false; + + // Restore the previous signal handlers. + for (unsigned i = 0; i != NumSignals; ++i) + sigaction(Signals[i], &PrevActions[i], 0); +} + +#endif + +bool CrashRecoveryContext::RunSafely(void (*Fn)(void*), void *UserData) { + // If crash recovery is disabled, do nothing. + if (gCrashRecoveryEnabled) { + assert(!Impl && "Crash recovery context already initialized!"); + CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this); + Impl = CRCI; + + if (setjmp(CRCI->JumpBuffer) != 0) { + return false; + } + } + + Fn(UserData); + return true; +} + +void CrashRecoveryContext::HandleCrash() { + CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; + assert(CRCI && "Crash recovery context never initialized!"); + CRCI->HandleCrash(); +} + +const std::string &CrashRecoveryContext::getBacktrace() const { + CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *) Impl; + assert(CRC && "Crash recovery context never initialized!"); + assert(CRC->Failed && "No crash was detected!"); + return CRC->Backtrace; +} + +// + +namespace { +struct RunSafelyOnThreadInfo { + void (*UserFn)(void*); + void *UserData; + CrashRecoveryContext *CRC; + bool Result; +}; +} + +static void RunSafelyOnThread_Dispatch(void *UserData) { + RunSafelyOnThreadInfo *Info = + reinterpret_cast<RunSafelyOnThreadInfo*>(UserData); + Info->Result = Info->CRC->RunSafely(Info->UserFn, Info->UserData); +} +bool CrashRecoveryContext::RunSafelyOnThread(void (*Fn)(void*), void *UserData, + unsigned RequestedStackSize) { + RunSafelyOnThreadInfo Info = { Fn, UserData, this, false }; + llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize); + return Info.Result; +} diff --git a/contrib/llvm/lib/Support/DAGDeltaAlgorithm.cpp b/contrib/llvm/lib/Support/DAGDeltaAlgorithm.cpp new file mode 100644 index 0000000..1e89c6a --- /dev/null +++ b/contrib/llvm/lib/Support/DAGDeltaAlgorithm.cpp @@ -0,0 +1,360 @@ +//===--- DAGDeltaAlgorithm.cpp - A DAG Minimization Algorithm --*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===// +// +// The algorithm we use attempts to exploit the dependency information by +// minimizing top-down. We start by constructing an initial root set R, and +// then iteratively: +// +// 1. Minimize the set R using the test predicate: +// P'(S) = P(S union pred*(S)) +// +// 2. Extend R to R' = R union pred(R). +// +// until a fixed point is reached. +// +// The idea is that we want to quickly prune entire portions of the graph, so we +// try to find high-level nodes that can be eliminated with all of their +// dependents. +// +// FIXME: The current algorithm doesn't actually provide a strong guarantee +// about the minimality of the result. The problem is that after adding nodes to +// the required set, we no longer consider them for elimination. For strictly +// well formed predicates, this doesn't happen, but it commonly occurs in +// practice when there are unmodelled dependencies. I believe we can resolve +// this by allowing the required set to be minimized as well, but need more test +// cases first. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/DAGDeltaAlgorithm.h" +#include "llvm/ADT/DeltaAlgorithm.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <iterator> +#include <map> +using namespace llvm; + +namespace { + +class DAGDeltaAlgorithmImpl { + friend class DeltaActiveSetHelper; + +public: + typedef DAGDeltaAlgorithm::change_ty change_ty; + typedef DAGDeltaAlgorithm::changeset_ty changeset_ty; + typedef DAGDeltaAlgorithm::changesetlist_ty changesetlist_ty; + typedef DAGDeltaAlgorithm::edge_ty edge_ty; + +private: + typedef std::vector<change_ty>::iterator pred_iterator_ty; + typedef std::vector<change_ty>::iterator succ_iterator_ty; + typedef std::set<change_ty>::iterator pred_closure_iterator_ty; + typedef std::set<change_ty>::iterator succ_closure_iterator_ty; + + DAGDeltaAlgorithm &DDA; + + const changeset_ty &Changes; + const std::vector<edge_ty> &Dependencies; + + std::vector<change_ty> Roots; + + /// Cache of failed test results. Successful test results are never cached + /// since we always reduce following a success. We maintain an independent + /// cache from that used by the individual delta passes because we may get + /// hits across multiple individual delta invocations. + mutable std::set<changeset_ty> FailedTestsCache; + + // FIXME: Gross. + std::map<change_ty, std::vector<change_ty> > Predecessors; + std::map<change_ty, std::vector<change_ty> > Successors; + + std::map<change_ty, std::set<change_ty> > PredClosure; + std::map<change_ty, std::set<change_ty> > SuccClosure; + +private: + pred_iterator_ty pred_begin(change_ty Node) { + assert(Predecessors.count(Node) && "Invalid node!"); + return Predecessors[Node].begin(); + } + pred_iterator_ty pred_end(change_ty Node) { + assert(Predecessors.count(Node) && "Invalid node!"); + return Predecessors[Node].end(); + } + + pred_closure_iterator_ty pred_closure_begin(change_ty Node) { + assert(PredClosure.count(Node) && "Invalid node!"); + return PredClosure[Node].begin(); + } + pred_closure_iterator_ty pred_closure_end(change_ty Node) { + assert(PredClosure.count(Node) && "Invalid node!"); + return PredClosure[Node].end(); + } + + succ_iterator_ty succ_begin(change_ty Node) { + assert(Successors.count(Node) && "Invalid node!"); + return Successors[Node].begin(); + } + succ_iterator_ty succ_end(change_ty Node) { + assert(Successors.count(Node) && "Invalid node!"); + return Successors[Node].end(); + } + + succ_closure_iterator_ty succ_closure_begin(change_ty Node) { + assert(SuccClosure.count(Node) && "Invalid node!"); + return SuccClosure[Node].begin(); + } + succ_closure_iterator_ty succ_closure_end(change_ty Node) { + assert(SuccClosure.count(Node) && "Invalid node!"); + return SuccClosure[Node].end(); + } + + void UpdatedSearchState(const changeset_ty &Changes, + const changesetlist_ty &Sets, + const changeset_ty &Required) { + DDA.UpdatedSearchState(Changes, Sets, Required); + } + + /// ExecuteOneTest - Execute a single test predicate on the change set \arg S. + bool ExecuteOneTest(const changeset_ty &S) { + // Check dependencies invariant. + DEBUG({ + for (changeset_ty::const_iterator it = S.begin(), + ie = S.end(); it != ie; ++it) + for (succ_iterator_ty it2 = succ_begin(*it), + ie2 = succ_end(*it); it2 != ie2; ++it2) + assert(S.count(*it2) && "Attempt to run invalid changeset!"); + }); + + return DDA.ExecuteOneTest(S); + } + +public: + DAGDeltaAlgorithmImpl(DAGDeltaAlgorithm &_DDA, + const changeset_ty &_Changes, + const std::vector<edge_ty> &_Dependencies); + + changeset_ty Run(); + + /// GetTestResult - Get the test result for the active set \arg Changes with + /// \arg Required changes from the cache, executing the test if necessary. + /// + /// \param Changes - The set of active changes being minimized, which should + /// have their pred closure included in the test. + /// \param Required - The set of changes which have previously been + /// established to be required. + /// \return - The test result. + bool GetTestResult(const changeset_ty &Changes, const changeset_ty &Required); +}; + +/// Helper object for minimizing an active set of changes. +class DeltaActiveSetHelper : public DeltaAlgorithm { + DAGDeltaAlgorithmImpl &DDAI; + + const changeset_ty &Required; + +protected: + /// UpdatedSearchState - Callback used when the search state changes. + virtual void UpdatedSearchState(const changeset_ty &Changes, + const changesetlist_ty &Sets) { + DDAI.UpdatedSearchState(Changes, Sets, Required); + } + + virtual bool ExecuteOneTest(const changeset_ty &S) { + return DDAI.GetTestResult(S, Required); + } + +public: + DeltaActiveSetHelper(DAGDeltaAlgorithmImpl &_DDAI, + const changeset_ty &_Required) + : DDAI(_DDAI), Required(_Required) {} +}; + +} + +DAGDeltaAlgorithmImpl::DAGDeltaAlgorithmImpl(DAGDeltaAlgorithm &_DDA, + const changeset_ty &_Changes, + const std::vector<edge_ty> + &_Dependencies) + : DDA(_DDA), + Changes(_Changes), + Dependencies(_Dependencies) +{ + for (changeset_ty::const_iterator it = Changes.begin(), + ie = Changes.end(); it != ie; ++it) { + Predecessors.insert(std::make_pair(*it, std::vector<change_ty>())); + Successors.insert(std::make_pair(*it, std::vector<change_ty>())); + } + for (std::vector<edge_ty>::const_iterator it = Dependencies.begin(), + ie = Dependencies.end(); it != ie; ++it) { + Predecessors[it->second].push_back(it->first); + Successors[it->first].push_back(it->second); + } + + // Compute the roots. + for (changeset_ty::const_iterator it = Changes.begin(), + ie = Changes.end(); it != ie; ++it) + if (succ_begin(*it) == succ_end(*it)) + Roots.push_back(*it); + + // Pre-compute the closure of the successor relation. + std::vector<change_ty> Worklist(Roots.begin(), Roots.end()); + while (!Worklist.empty()) { + change_ty Change = Worklist.back(); + Worklist.pop_back(); + + std::set<change_ty> &ChangeSuccs = SuccClosure[Change]; + for (pred_iterator_ty it = pred_begin(Change), + ie = pred_end(Change); it != ie; ++it) { + SuccClosure[*it].insert(Change); + SuccClosure[*it].insert(ChangeSuccs.begin(), ChangeSuccs.end()); + Worklist.push_back(*it); + } + } + + // Invert to form the predecessor closure map. + for (changeset_ty::const_iterator it = Changes.begin(), + ie = Changes.end(); it != ie; ++it) + PredClosure.insert(std::make_pair(*it, std::set<change_ty>())); + for (changeset_ty::const_iterator it = Changes.begin(), + ie = Changes.end(); it != ie; ++it) + for (succ_closure_iterator_ty it2 = succ_closure_begin(*it), + ie2 = succ_closure_end(*it); it2 != ie2; ++it2) + PredClosure[*it2].insert(*it); + + // Dump useful debug info. + DEBUG({ + llvm::errs() << "-- DAGDeltaAlgorithmImpl --\n"; + llvm::errs() << "Changes: ["; + for (changeset_ty::const_iterator it = Changes.begin(), + ie = Changes.end(); it != ie; ++it) { + if (it != Changes.begin()) llvm::errs() << ", "; + llvm::errs() << *it; + + if (succ_begin(*it) != succ_end(*it)) { + llvm::errs() << "("; + for (succ_iterator_ty it2 = succ_begin(*it), + ie2 = succ_end(*it); it2 != ie2; ++it2) { + if (it2 != succ_begin(*it)) llvm::errs() << ", "; + llvm::errs() << "->" << *it2; + } + llvm::errs() << ")"; + } + } + llvm::errs() << "]\n"; + + llvm::errs() << "Roots: ["; + for (std::vector<change_ty>::const_iterator it = Roots.begin(), + ie = Roots.end(); it != ie; ++it) { + if (it != Roots.begin()) llvm::errs() << ", "; + llvm::errs() << *it; + } + llvm::errs() << "]\n"; + + llvm::errs() << "Predecessor Closure:\n"; + for (changeset_ty::const_iterator it = Changes.begin(), + ie = Changes.end(); it != ie; ++it) { + llvm::errs() << format(" %-4d: [", *it); + for (pred_closure_iterator_ty it2 = pred_closure_begin(*it), + ie2 = pred_closure_end(*it); it2 != ie2; ++it2) { + if (it2 != pred_closure_begin(*it)) llvm::errs() << ", "; + llvm::errs() << *it2; + } + llvm::errs() << "]\n"; + } + + llvm::errs() << "Successor Closure:\n"; + for (changeset_ty::const_iterator it = Changes.begin(), + ie = Changes.end(); it != ie; ++it) { + llvm::errs() << format(" %-4d: [", *it); + for (succ_closure_iterator_ty it2 = succ_closure_begin(*it), + ie2 = succ_closure_end(*it); it2 != ie2; ++it2) { + if (it2 != succ_closure_begin(*it)) llvm::errs() << ", "; + llvm::errs() << *it2; + } + llvm::errs() << "]\n"; + } + + llvm::errs() << "\n\n"; + }); +} + +bool DAGDeltaAlgorithmImpl::GetTestResult(const changeset_ty &Changes, + const changeset_ty &Required) { + changeset_ty Extended(Required); + Extended.insert(Changes.begin(), Changes.end()); + for (changeset_ty::const_iterator it = Changes.begin(), + ie = Changes.end(); it != ie; ++it) + Extended.insert(pred_closure_begin(*it), pred_closure_end(*it)); + + if (FailedTestsCache.count(Extended)) + return false; + + bool Result = ExecuteOneTest(Extended); + if (!Result) + FailedTestsCache.insert(Extended); + + return Result; +} + +DAGDeltaAlgorithm::changeset_ty +DAGDeltaAlgorithmImpl::Run() { + // The current set of changes we are minimizing, starting at the roots. + changeset_ty CurrentSet(Roots.begin(), Roots.end()); + + // The set of required changes. + changeset_ty Required; + + // Iterate until the active set of changes is empty. Convergence is guaranteed + // assuming input was a DAG. + // + // Invariant: CurrentSet intersect Required == {} + // Invariant: Required == (Required union succ*(Required)) + while (!CurrentSet.empty()) { + DEBUG({ + llvm::errs() << "DAG_DD - " << CurrentSet.size() << " active changes, " + << Required.size() << " required changes\n"; + }); + + // Minimize the current set of changes. + DeltaActiveSetHelper Helper(*this, Required); + changeset_ty CurrentMinSet = Helper.Run(CurrentSet); + + // Update the set of required changes. Since + // CurrentMinSet subset CurrentSet + // and after the last iteration, + // succ(CurrentSet) subset Required + // then + // succ(CurrentMinSet) subset Required + // and our invariant on Required is maintained. + Required.insert(CurrentMinSet.begin(), CurrentMinSet.end()); + + // Replace the current set with the predecssors of the minimized set of + // active changes. + CurrentSet.clear(); + for (changeset_ty::const_iterator it = CurrentMinSet.begin(), + ie = CurrentMinSet.end(); it != ie; ++it) + CurrentSet.insert(pred_begin(*it), pred_end(*it)); + + // FIXME: We could enforce CurrentSet intersect Required == {} here if we + // wanted to protect against cyclic graphs. + } + + return Required; +} + +void DAGDeltaAlgorithm::anchor() { +} + +DAGDeltaAlgorithm::changeset_ty +DAGDeltaAlgorithm::Run(const changeset_ty &Changes, + const std::vector<edge_ty> &Dependencies) { + return DAGDeltaAlgorithmImpl(*this, Changes, Dependencies).Run(); +} diff --git a/contrib/llvm/lib/Support/DataExtractor.cpp b/contrib/llvm/lib/Support/DataExtractor.cpp new file mode 100644 index 0000000..dc21155 --- /dev/null +++ b/contrib/llvm/lib/Support/DataExtractor.cpp @@ -0,0 +1,175 @@ +//===-- DataExtractor.cpp -------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/SwapByteOrder.h" +using namespace llvm; + +template <typename T> +static T getU(uint32_t *offset_ptr, const DataExtractor *de, + bool isLittleEndian, const char *Data) { + T val = 0; + uint32_t offset = *offset_ptr; + if (de->isValidOffsetForDataOfSize(offset, sizeof(val))) { + std::memcpy(&val, &Data[offset], sizeof(val)); + if (sys::isLittleEndianHost() != isLittleEndian) + val = sys::SwapByteOrder(val); + + // Advance the offset + *offset_ptr += sizeof(val); + } + return val; +} + +template <typename T> +static T *getUs(uint32_t *offset_ptr, T *dst, uint32_t count, + const DataExtractor *de, bool isLittleEndian, const char *Data){ + uint32_t offset = *offset_ptr; + + if (count > 0 && de->isValidOffsetForDataOfSize(offset, sizeof(*dst)*count)) { + for (T *value_ptr = dst, *end = dst + count; value_ptr != end; + ++value_ptr, offset += sizeof(*dst)) + *value_ptr = getU<T>(offset_ptr, de, isLittleEndian, Data); + // Advance the offset + *offset_ptr = offset; + // Return a non-NULL pointer to the converted data as an indicator of + // success + return dst; + } + return NULL; +} + +uint8_t DataExtractor::getU8(uint32_t *offset_ptr) const { + return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data()); +} + +uint8_t * +DataExtractor::getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const { + return getUs<uint8_t>(offset_ptr, dst, count, this, IsLittleEndian, + Data.data()); +} + + +uint16_t DataExtractor::getU16(uint32_t *offset_ptr) const { + return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data()); +} + +uint16_t *DataExtractor::getU16(uint32_t *offset_ptr, uint16_t *dst, + uint32_t count) const { + return getUs<uint16_t>(offset_ptr, dst, count, this, IsLittleEndian, + Data.data()); +} + +uint32_t DataExtractor::getU32(uint32_t *offset_ptr) const { + return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data()); +} + +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()); +} + +uint64_t DataExtractor::getU64(uint32_t *offset_ptr) const { + return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data()); +} + +uint64_t *DataExtractor::getU64(uint32_t *offset_ptr, uint64_t *dst, + uint32_t count) const { + return getUs<uint64_t>(offset_ptr, dst, count, this, IsLittleEndian, + Data.data()); +} + +uint64_t +DataExtractor::getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const { + switch (byte_size) { + case 1: + return getU8(offset_ptr); + case 2: + return getU16(offset_ptr); + case 4: + return getU32(offset_ptr); + case 8: + return getU64(offset_ptr); + } + llvm_unreachable("getUnsigned unhandled case!"); +} + +int64_t +DataExtractor::getSigned(uint32_t *offset_ptr, uint32_t byte_size) const { + switch (byte_size) { + case 1: + return (int8_t)getU8(offset_ptr); + case 2: + return (int16_t)getU16(offset_ptr); + case 4: + return (int32_t)getU32(offset_ptr); + case 8: + return (int64_t)getU64(offset_ptr); + } + llvm_unreachable("getSigned unhandled case!"); +} + +const char *DataExtractor::getCStr(uint32_t *offset_ptr) const { + uint32_t offset = *offset_ptr; + StringRef::size_type pos = Data.find('\0', offset); + if (pos != StringRef::npos) { + *offset_ptr = pos + 1; + return Data.data() + offset; + } + return NULL; +} + +uint64_t DataExtractor::getULEB128(uint32_t *offset_ptr) const { + uint64_t result = 0; + if (Data.empty()) + return 0; + + unsigned shift = 0; + uint32_t offset = *offset_ptr; + uint8_t byte = 0; + + while (isValidOffset(offset)) { + byte = Data[offset++]; + result |= (byte & 0x7f) << shift; + shift += 7; + if ((byte & 0x80) == 0) + break; + } + + *offset_ptr = offset; + return result; +} + +int64_t DataExtractor::getSLEB128(uint32_t *offset_ptr) const { + int64_t result = 0; + if (Data.empty()) + return 0; + + unsigned shift = 0; + uint32_t offset = *offset_ptr; + uint8_t byte = 0; + + while (isValidOffset(offset)) { + byte = Data[offset++]; + result |= (byte & 0x7f) << shift; + shift += 7; + if ((byte & 0x80) == 0) + break; + } + + // Sign bit of byte is 2nd high order bit (0x40) + if (shift < 64 && (byte & 0x40)) + result |= -(1 << shift); + + *offset_ptr = offset; + return result; +} diff --git a/contrib/llvm/lib/Support/DataStream.cpp b/contrib/llvm/lib/Support/DataStream.cpp new file mode 100644 index 0000000..94d14a5 --- /dev/null +++ b/contrib/llvm/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/contrib/llvm/lib/Support/Debug.cpp b/contrib/llvm/lib/Support/Debug.cpp new file mode 100644 index 0000000..9fdb12e --- /dev/null +++ b/contrib/llvm/lib/Support/Debug.cpp @@ -0,0 +1,134 @@ +//===-- Debug.cpp - An easy way to add debug output to your code ----------===// +// +// 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 handle way of adding debugging information to your +// code, without it being enabled all of the time, and without having to add +// command line options to enable it. +// +// In particular, just wrap your code with the DEBUG() macro, and it will be +// enabled automatically if you specify '-debug' on the command-line. +// Alternatively, you can also use the SET_DEBUG_TYPE("foo") macro to specify +// that your debug code belongs to class "foo". Then, on the command line, you +// can specify '-debug-only=foo' to enable JUST the debug information for the +// foo class. +// +// When compiling in release mode, the -debug-* options and all code in DEBUG() +// statements disappears, so it does not effect the runtime of the code. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/circular_raw_ostream.h" +#include "llvm/Support/Signals.h" + +using namespace llvm; + +// All Debug.h functionality is a no-op in NDEBUG mode. +#ifndef NDEBUG +bool llvm::DebugFlag; // DebugFlag - Exported boolean set by the -debug option + +// -debug - Command line option to enable the DEBUG statements in the passes. +// This flag may only be enabled in debug builds. +static cl::opt<bool, true> +Debug("debug", cl::desc("Enable debug output"), cl::Hidden, + cl::location(DebugFlag)); + +// -debug-buffer-size - Buffer the last N characters of debug output +//until program termination. +static cl::opt<unsigned> +DebugBufferSize("debug-buffer-size", + cl::desc("Buffer the last N characters of debug output" + "until program termination. " + "[default 0 -- immediate print-out]"), + cl::Hidden, + cl::init(0)); + +static std::string CurrentDebugType; + +namespace { + +struct DebugOnlyOpt { + void operator=(const std::string &Val) const { + DebugFlag |= !Val.empty(); + CurrentDebugType = Val; + } +}; + +} + +static DebugOnlyOpt DebugOnlyOptLoc; + +static cl::opt<DebugOnlyOpt, true, cl::parser<std::string> > +DebugOnly("debug-only", cl::desc("Enable a specific type of debug output"), + cl::Hidden, cl::value_desc("debug string"), + cl::location(DebugOnlyOptLoc), cl::ValueRequired); + +// Signal handlers - dump debug output on termination. +static void debug_user_sig_handler(void *Cookie) { + // This is a bit sneaky. Since this is under #ifndef NDEBUG, we + // know that debug mode is enabled and dbgs() really is a + // circular_raw_ostream. If NDEBUG is defined, then dbgs() == + // errs() but this will never be invoked. + llvm::circular_raw_ostream *dbgout = + static_cast<llvm::circular_raw_ostream *>(&llvm::dbgs()); + dbgout->flushBufferWithBanner(); +} + +// isCurrentDebugType - Return true if the specified string is the debug type +// specified on the command line, or if none was specified on the command line +// with the -debug-only=X option. +// +bool llvm::isCurrentDebugType(const char *DebugType) { + return CurrentDebugType.empty() || DebugType == CurrentDebugType; +} + +/// SetCurrentDebugType - Set the current debug type, as if the -debug-only=X +/// option were specified. Note that DebugFlag also needs to be set to true for +/// debug output to be produced. +/// +void llvm::SetCurrentDebugType(const char *Type) { + CurrentDebugType = Type; +} + +/// dbgs - Return a circular-buffered debug stream. +raw_ostream &llvm::dbgs() { + // Do one-time initialization in a thread-safe way. + static struct dbgstream { + circular_raw_ostream strm; + + dbgstream() : + strm(errs(), "*** Debug Log Output ***\n", + (!EnableDebugBuffering || !DebugFlag) ? 0 : DebugBufferSize) { + if (EnableDebugBuffering && DebugFlag && DebugBufferSize != 0) + // TODO: Add a handler for SIGUSER1-type signals so the user can + // force a debug dump. + sys::AddSignalHandler(&debug_user_sig_handler, 0); + // Otherwise we've already set the debug stream buffer size to + // zero, disabling buffering so it will output directly to errs(). + } + } thestrm; + + return thestrm.strm; +} + +#else +// Avoid "has no symbols" warning. +namespace llvm { + /// dbgs - Return errs(). + raw_ostream &dbgs() { + return errs(); + } +} + +#endif + +/// EnableDebugBuffering - Turn on signal handler installation. +/// +bool llvm::EnableDebugBuffering = false; diff --git a/contrib/llvm/lib/Support/DeltaAlgorithm.cpp b/contrib/llvm/lib/Support/DeltaAlgorithm.cpp new file mode 100644 index 0000000..9e52874 --- /dev/null +++ b/contrib/llvm/lib/Support/DeltaAlgorithm.cpp @@ -0,0 +1,114 @@ +//===--- DeltaAlgorithm.cpp - A Set Minimization Algorithm -----*- 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/DeltaAlgorithm.h" +#include <algorithm> +#include <iterator> +using namespace llvm; + +DeltaAlgorithm::~DeltaAlgorithm() { +} + +bool DeltaAlgorithm::GetTestResult(const changeset_ty &Changes) { + if (FailedTestsCache.count(Changes)) + return false; + + bool Result = ExecuteOneTest(Changes); + if (!Result) + FailedTestsCache.insert(Changes); + + return Result; +} + +void DeltaAlgorithm::Split(const changeset_ty &S, changesetlist_ty &Res) { + // FIXME: Allow clients to provide heuristics for improved splitting. + + // FIXME: This is really slow. + changeset_ty LHS, RHS; + unsigned idx = 0, N = S.size() / 2; + for (changeset_ty::const_iterator it = S.begin(), + ie = S.end(); it != ie; ++it, ++idx) + ((idx < N) ? LHS : RHS).insert(*it); + if (!LHS.empty()) + Res.push_back(LHS); + if (!RHS.empty()) + Res.push_back(RHS); +} + +DeltaAlgorithm::changeset_ty +DeltaAlgorithm::Delta(const changeset_ty &Changes, + const changesetlist_ty &Sets) { + // Invariant: union(Res) == Changes + UpdatedSearchState(Changes, Sets); + + // If there is nothing left we can remove, we are done. + if (Sets.size() <= 1) + return Changes; + + // Look for a passing subset. + changeset_ty Res; + if (Search(Changes, Sets, Res)) + return Res; + + // Otherwise, partition the sets if possible; if not we are done. + changesetlist_ty SplitSets; + for (changesetlist_ty::const_iterator it = Sets.begin(), + ie = Sets.end(); it != ie; ++it) + Split(*it, SplitSets); + if (SplitSets.size() == Sets.size()) + return Changes; + + return Delta(Changes, SplitSets); +} + +bool DeltaAlgorithm::Search(const changeset_ty &Changes, + const changesetlist_ty &Sets, + changeset_ty &Res) { + // FIXME: Parallelize. + for (changesetlist_ty::const_iterator it = Sets.begin(), + ie = Sets.end(); it != ie; ++it) { + // If the test passes on this subset alone, recurse. + if (GetTestResult(*it)) { + changesetlist_ty Sets; + Split(*it, Sets); + Res = Delta(*it, Sets); + return true; + } + + // Otherwise, if we have more than two sets, see if test passes on the + // complement. + if (Sets.size() > 2) { + // FIXME: This is really slow. + changeset_ty Complement; + std::set_difference( + Changes.begin(), Changes.end(), it->begin(), it->end(), + std::insert_iterator<changeset_ty>(Complement, Complement.begin())); + if (GetTestResult(Complement)) { + changesetlist_ty ComplementSets; + ComplementSets.insert(ComplementSets.end(), Sets.begin(), it); + ComplementSets.insert(ComplementSets.end(), it + 1, Sets.end()); + Res = Delta(Complement, ComplementSets); + return true; + } + } + } + + return false; +} + +DeltaAlgorithm::changeset_ty DeltaAlgorithm::Run(const changeset_ty &Changes) { + // Check empty set first to quickly find poor test functions. + if (GetTestResult(changeset_ty())) + return changeset_ty(); + + // Otherwise run the real delta algorithm. + changesetlist_ty Sets; + Split(Changes, Sets); + + return Delta(Changes, Sets); +} diff --git a/contrib/llvm/lib/Support/Disassembler.cpp b/contrib/llvm/lib/Support/Disassembler.cpp new file mode 100644 index 0000000..c6d73bc --- /dev/null +++ b/contrib/llvm/lib/Support/Disassembler.cpp @@ -0,0 +1,75 @@ +//===- lib/Support/Disassembler.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the necessary glue to call external disassembler +// libraries. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/Disassembler.h" + +#include <cassert> +#include <iomanip> +#include <string> +#include <sstream> + +#if USE_UDIS86 +#include <udis86.h> +#endif + +using namespace llvm; + +bool llvm::sys::hasDisassembler() +{ +#if defined (__i386__) || defined (__amd64__) || defined (__x86_64__) + // We have option to enable udis86 library. +# if USE_UDIS86 + return true; +#else + return false; +#endif +#else + return false; +#endif +} + +std::string llvm::sys::disassembleBuffer(uint8_t* start, size_t length, + uint64_t pc) { + std::stringstream res; + +#if (defined (__i386__) || defined (__amd64__) || defined (__x86_64__)) \ + && USE_UDIS86 + unsigned bits; +# if defined(__i386__) + bits = 32; +# else + bits = 64; +# endif + + ud_t ud_obj; + + ud_init(&ud_obj); + ud_set_input_buffer(&ud_obj, start, length); + ud_set_mode(&ud_obj, bits); + ud_set_pc(&ud_obj, pc); + ud_set_syntax(&ud_obj, UD_SYN_ATT); + + res << std::setbase(16) + << std::setw(bits/4); + + while (ud_disassemble(&ud_obj)) { + res << ud_insn_off(&ud_obj) << ":\t" << ud_insn_asm(&ud_obj) << "\n"; + } +#else + res << "No disassembler available. See configure help for options.\n"; +#endif + + return res.str(); +} diff --git a/contrib/llvm/lib/Support/Dwarf.cpp b/contrib/llvm/lib/Support/Dwarf.cpp new file mode 100644 index 0000000..5c59a3e --- /dev/null +++ b/contrib/llvm/lib/Support/Dwarf.cpp @@ -0,0 +1,709 @@ +//===-- llvm/Support/Dwarf.cpp - Dwarf Framework ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for generic dwarf information. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Dwarf.h" +using namespace llvm; +using namespace dwarf; + +/// TagString - Return the string for the specified tag. +/// +const char *llvm::dwarf::TagString(unsigned Tag) { + switch (Tag) { + case DW_TAG_array_type: return "DW_TAG_array_type"; + case DW_TAG_class_type: return "DW_TAG_class_type"; + case DW_TAG_entry_point: return "DW_TAG_entry_point"; + case DW_TAG_enumeration_type: return "DW_TAG_enumeration_type"; + case DW_TAG_formal_parameter: return "DW_TAG_formal_parameter"; + case DW_TAG_imported_declaration: return "DW_TAG_imported_declaration"; + case DW_TAG_label: return "DW_TAG_label"; + case DW_TAG_lexical_block: return "DW_TAG_lexical_block"; + case DW_TAG_member: return "DW_TAG_member"; + case DW_TAG_pointer_type: return "DW_TAG_pointer_type"; + case DW_TAG_reference_type: return "DW_TAG_reference_type"; + case DW_TAG_compile_unit: return "DW_TAG_compile_unit"; + case DW_TAG_string_type: return "DW_TAG_string_type"; + case DW_TAG_structure_type: return "DW_TAG_structure_type"; + case DW_TAG_subroutine_type: return "DW_TAG_subroutine_type"; + case DW_TAG_typedef: return "DW_TAG_typedef"; + case DW_TAG_union_type: return "DW_TAG_union_type"; + case DW_TAG_unspecified_parameters: return "DW_TAG_unspecified_parameters"; + case DW_TAG_variant: return "DW_TAG_variant"; + case DW_TAG_common_block: return "DW_TAG_common_block"; + case DW_TAG_common_inclusion: return "DW_TAG_common_inclusion"; + case DW_TAG_inheritance: return "DW_TAG_inheritance"; + case DW_TAG_inlined_subroutine: return "DW_TAG_inlined_subroutine"; + case DW_TAG_module: return "DW_TAG_module"; + case DW_TAG_ptr_to_member_type: return "DW_TAG_ptr_to_member_type"; + case DW_TAG_set_type: return "DW_TAG_set_type"; + case DW_TAG_subrange_type: return "DW_TAG_subrange_type"; + case DW_TAG_with_stmt: return "DW_TAG_with_stmt"; + case DW_TAG_access_declaration: return "DW_TAG_access_declaration"; + case DW_TAG_base_type: return "DW_TAG_base_type"; + case DW_TAG_catch_block: return "DW_TAG_catch_block"; + case DW_TAG_const_type: return "DW_TAG_const_type"; + case DW_TAG_constant: return "DW_TAG_constant"; + case DW_TAG_enumerator: return "DW_TAG_enumerator"; + case DW_TAG_file_type: return "DW_TAG_file_type"; + case DW_TAG_friend: return "DW_TAG_friend"; + case DW_TAG_namelist: return "DW_TAG_namelist"; + case DW_TAG_namelist_item: return "DW_TAG_namelist_item"; + case DW_TAG_packed_type: return "DW_TAG_packed_type"; + case DW_TAG_subprogram: return "DW_TAG_subprogram"; + case DW_TAG_template_type_parameter: return "DW_TAG_template_type_parameter"; + case DW_TAG_template_value_parameter:return "DW_TAG_template_value_parameter"; + case DW_TAG_thrown_type: return "DW_TAG_thrown_type"; + case DW_TAG_try_block: return "DW_TAG_try_block"; + case DW_TAG_variant_part: return "DW_TAG_variant_part"; + case DW_TAG_variable: return "DW_TAG_variable"; + case DW_TAG_volatile_type: return "DW_TAG_volatile_type"; + case DW_TAG_dwarf_procedure: return "DW_TAG_dwarf_procedure"; + case DW_TAG_restrict_type: return "DW_TAG_restrict_type"; + case DW_TAG_interface_type: return "DW_TAG_interface_type"; + case DW_TAG_namespace: return "DW_TAG_namespace"; + case DW_TAG_imported_module: return "DW_TAG_imported_module"; + case DW_TAG_unspecified_type: return "DW_TAG_unspecified_type"; + case DW_TAG_partial_unit: return "DW_TAG_partial_unit"; + case DW_TAG_imported_unit: return "DW_TAG_imported_unit"; + case DW_TAG_condition: return "DW_TAG_condition"; + case DW_TAG_shared_type: return "DW_TAG_shared_type"; + case DW_TAG_lo_user: return "DW_TAG_lo_user"; + case DW_TAG_hi_user: return "DW_TAG_hi_user"; + case DW_TAG_auto_variable: return "DW_TAG_auto_variable"; + case DW_TAG_arg_variable: return "DW_TAG_arg_variable"; + case DW_TAG_return_variable: return "DW_TAG_return_variable"; + case DW_TAG_vector_type: return "DW_TAG_vector_type"; + case DW_TAG_rvalue_reference_type: return "DW_TAG_rvalue_reference_type"; + case DW_TAG_template_alias: return "DW_TAG_template_alias"; + case DW_TAG_MIPS_loop: return "DW_TAG_MIPS_loop"; + case DW_TAG_type_unit: return "DW_TAG_type_unit"; + case DW_TAG_format_label: return "DW_TAG_format_label"; + case DW_TAG_function_template: return "DW_TAG_function_template"; + case DW_TAG_class_template: return "DW_TAG_class_template"; + case DW_TAG_GNU_template_template_param: + return "DW_TAG_GNU_template_template_param"; + case DW_TAG_GNU_template_parameter_pack: + 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; +} + +/// ChildrenString - Return the string for the specified children flag. +/// +const char *llvm::dwarf::ChildrenString(unsigned Children) { + switch (Children) { + case DW_CHILDREN_no: return "DW_CHILDREN_no"; + case DW_CHILDREN_yes: return "DW_CHILDREN_yes"; + } + return 0; +} + +/// AttributeString - Return the string for the specified attribute. +/// +const char *llvm::dwarf::AttributeString(unsigned Attribute) { + switch (Attribute) { + case DW_AT_sibling: return "DW_AT_sibling"; + case DW_AT_location: return "DW_AT_location"; + case DW_AT_name: return "DW_AT_name"; + case DW_AT_ordering: return "DW_AT_ordering"; + case DW_AT_byte_size: return "DW_AT_byte_size"; + case DW_AT_bit_offset: return "DW_AT_bit_offset"; + case DW_AT_bit_size: return "DW_AT_bit_size"; + case DW_AT_stmt_list: return "DW_AT_stmt_list"; + case DW_AT_low_pc: return "DW_AT_low_pc"; + case DW_AT_high_pc: return "DW_AT_high_pc"; + case DW_AT_language: return "DW_AT_language"; + case DW_AT_discr: return "DW_AT_discr"; + case DW_AT_discr_value: return "DW_AT_discr_value"; + case DW_AT_visibility: return "DW_AT_visibility"; + case DW_AT_import: return "DW_AT_import"; + case DW_AT_string_length: return "DW_AT_string_length"; + case DW_AT_common_reference: return "DW_AT_common_reference"; + case DW_AT_comp_dir: return "DW_AT_comp_dir"; + case DW_AT_const_value: return "DW_AT_const_value"; + case DW_AT_containing_type: return "DW_AT_containing_type"; + case DW_AT_default_value: return "DW_AT_default_value"; + case DW_AT_inline: return "DW_AT_inline"; + case DW_AT_is_optional: return "DW_AT_is_optional"; + case DW_AT_lower_bound: return "DW_AT_lower_bound"; + case DW_AT_producer: return "DW_AT_producer"; + case DW_AT_prototyped: return "DW_AT_prototyped"; + case DW_AT_return_addr: return "DW_AT_return_addr"; + case DW_AT_start_scope: return "DW_AT_start_scope"; + case DW_AT_bit_stride: return "DW_AT_bit_stride"; + case DW_AT_upper_bound: return "DW_AT_upper_bound"; + case DW_AT_abstract_origin: return "DW_AT_abstract_origin"; + case DW_AT_accessibility: return "DW_AT_accessibility"; + case DW_AT_address_class: return "DW_AT_address_class"; + case DW_AT_artificial: return "DW_AT_artificial"; + case DW_AT_base_types: return "DW_AT_base_types"; + case DW_AT_calling_convention: return "DW_AT_calling_convention"; + case DW_AT_count: return "DW_AT_count"; + case DW_AT_data_member_location: return "DW_AT_data_member_location"; + case DW_AT_decl_column: return "DW_AT_decl_column"; + case DW_AT_decl_file: return "DW_AT_decl_file"; + case DW_AT_decl_line: return "DW_AT_decl_line"; + case DW_AT_declaration: return "DW_AT_declaration"; + case DW_AT_discr_list: return "DW_AT_discr_list"; + case DW_AT_encoding: return "DW_AT_encoding"; + case DW_AT_external: return "DW_AT_external"; + case DW_AT_frame_base: return "DW_AT_frame_base"; + case DW_AT_friend: return "DW_AT_friend"; + case DW_AT_identifier_case: return "DW_AT_identifier_case"; + case DW_AT_macro_info: return "DW_AT_macro_info"; + case DW_AT_namelist_item: return "DW_AT_namelist_item"; + case DW_AT_priority: return "DW_AT_priority"; + case DW_AT_segment: return "DW_AT_segment"; + case DW_AT_specification: return "DW_AT_specification"; + case DW_AT_static_link: return "DW_AT_static_link"; + case DW_AT_type: return "DW_AT_type"; + case DW_AT_use_location: return "DW_AT_use_location"; + case DW_AT_variable_parameter: return "DW_AT_variable_parameter"; + case DW_AT_virtuality: return "DW_AT_virtuality"; + case DW_AT_vtable_elem_location: return "DW_AT_vtable_elem_location"; + case DW_AT_allocated: return "DW_AT_allocated"; + case DW_AT_associated: return "DW_AT_associated"; + case DW_AT_data_location: return "DW_AT_data_location"; + case DW_AT_byte_stride: return "DW_AT_byte_stride"; + case DW_AT_entry_pc: return "DW_AT_entry_pc"; + case DW_AT_use_UTF8: return "DW_AT_use_UTF8"; + case DW_AT_extension: return "DW_AT_extension"; + case DW_AT_ranges: return "DW_AT_ranges"; + case DW_AT_trampoline: return "DW_AT_trampoline"; + case DW_AT_call_column: return "DW_AT_call_column"; + case DW_AT_call_file: return "DW_AT_call_file"; + case DW_AT_call_line: return "DW_AT_call_line"; + case DW_AT_description: return "DW_AT_description"; + case DW_AT_binary_scale: return "DW_AT_binary_scale"; + case DW_AT_decimal_scale: return "DW_AT_decimal_scale"; + case DW_AT_small: return "DW_AT_small"; + case DW_AT_decimal_sign: return "DW_AT_decimal_sign"; + case DW_AT_digit_count: return "DW_AT_digit_count"; + case DW_AT_picture_string: return "DW_AT_picture_string"; + case DW_AT_mutable: return "DW_AT_mutable"; + case DW_AT_threads_scaled: return "DW_AT_threads_scaled"; + case DW_AT_explicit: return "DW_AT_explicit"; + case DW_AT_object_pointer: return "DW_AT_object_pointer"; + case DW_AT_endianity: return "DW_AT_endianity"; + case DW_AT_elemental: return "DW_AT_elemental"; + case DW_AT_pure: return "DW_AT_pure"; + case DW_AT_recursive: return "DW_AT_recursive"; + case DW_AT_signature: return "DW_AT_signature"; + case DW_AT_main_subprogram: return "DW_AT_main_subprogram"; + case DW_AT_data_bit_offset: return "DW_AT_data_bit_offset"; + case DW_AT_const_expr: return "DW_AT_const_expr"; + case DW_AT_enum_class: return "DW_AT_enum_class"; + case DW_AT_linkage_name: return "DW_AT_linkage_name"; + case DW_AT_MIPS_loop_begin: return "DW_AT_MIPS_loop_begin"; + case DW_AT_MIPS_tail_loop_begin: return "DW_AT_MIPS_tail_loop_begin"; + case DW_AT_MIPS_epilog_begin: return "DW_AT_MIPS_epilog_begin"; + case DW_AT_MIPS_loop_unroll_factor: return "DW_AT_MIPS_loop_unroll_factor"; + case DW_AT_MIPS_software_pipeline_depth: + return "DW_AT_MIPS_software_pipeline_depth"; + case DW_AT_MIPS_linkage_name: return "DW_AT_MIPS_linkage_name"; + case DW_AT_MIPS_stride: return "DW_AT_MIPS_stride"; + case DW_AT_MIPS_abstract_name: return "DW_AT_MIPS_abstract_name"; + case DW_AT_MIPS_clone_origin: return "DW_AT_MIPS_clone_origin"; + case DW_AT_MIPS_has_inlines: return "DW_AT_MIPS_has_inlines"; + case DW_AT_MIPS_stride_byte: return "DW_AT_MIPS_stride_byte"; + case DW_AT_MIPS_stride_elem: return "DW_AT_MIPS_stride_elem"; + case DW_AT_MIPS_ptr_dopetype: return "DW_AT_MIPS_ptr_dopetype"; + case DW_AT_MIPS_allocatable_dopetype: + return "DW_AT_MIPS_allocatable_dopetype"; + case DW_AT_MIPS_assumed_shape_dopetype: + return "DW_AT_MIPS_assumed_shape_dopetype"; + case DW_AT_sf_names: return "DW_AT_sf_names"; + case DW_AT_src_info: return "DW_AT_src_info"; + case DW_AT_mac_info: return "DW_AT_mac_info"; + case DW_AT_src_coords: return "DW_AT_src_coords"; + case DW_AT_body_begin: return "DW_AT_body_begin"; + case DW_AT_body_end: return "DW_AT_body_end"; + case DW_AT_GNU_vector: return "DW_AT_GNU_vector"; + case DW_AT_GNU_template_name: return "DW_AT_GNU_template_name"; + case DW_AT_MIPS_assumed_size: return "DW_AT_MIPS_assumed_size"; + case DW_AT_lo_user: return "DW_AT_lo_user"; + case DW_AT_hi_user: return "DW_AT_hi_user"; + case DW_AT_APPLE_optimized: return "DW_AT_APPLE_optimized"; + case DW_AT_APPLE_flags: return "DW_AT_APPLE_flags"; + case DW_AT_APPLE_isa: return "DW_AT_APPLE_isa"; + case DW_AT_APPLE_block: return "DW_AT_APPLE_block"; + case DW_AT_APPLE_major_runtime_vers: return "DW_AT_APPLE_major_runtime_vers"; + case DW_AT_APPLE_runtime_class: return "DW_AT_APPLE_runtime_class"; + case DW_AT_APPLE_omit_frame_ptr: return "DW_AT_APPLE_omit_frame_ptr"; + case DW_AT_APPLE_property_name: return "DW_AT_APPLE_property_name"; + 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; +} + +/// FormEncodingString - Return the string for the specified form encoding. +/// +const char *llvm::dwarf::FormEncodingString(unsigned Encoding) { + switch (Encoding) { + case DW_FORM_addr: return "DW_FORM_addr"; + case DW_FORM_block2: return "DW_FORM_block2"; + case DW_FORM_block4: return "DW_FORM_block4"; + case DW_FORM_data2: return "DW_FORM_data2"; + case DW_FORM_data4: return "DW_FORM_data4"; + case DW_FORM_data8: return "DW_FORM_data8"; + case DW_FORM_string: return "DW_FORM_string"; + case DW_FORM_block: return "DW_FORM_block"; + case DW_FORM_block1: return "DW_FORM_block1"; + case DW_FORM_data1: return "DW_FORM_data1"; + case DW_FORM_flag: return "DW_FORM_flag"; + case DW_FORM_sdata: return "DW_FORM_sdata"; + case DW_FORM_strp: return "DW_FORM_strp"; + case DW_FORM_udata: return "DW_FORM_udata"; + case DW_FORM_ref_addr: return "DW_FORM_ref_addr"; + case DW_FORM_ref1: return "DW_FORM_ref1"; + case DW_FORM_ref2: return "DW_FORM_ref2"; + case DW_FORM_ref4: return "DW_FORM_ref4"; + case DW_FORM_ref8: return "DW_FORM_ref8"; + case DW_FORM_ref_udata: return "DW_FORM_ref_udata"; + case DW_FORM_indirect: return "DW_FORM_indirect"; + case DW_FORM_sec_offset: return "DW_FORM_sec_offset"; + case DW_FORM_exprloc: return "DW_FORM_exprloc"; + case DW_FORM_flag_present: return "DW_FORM_flag_present"; + case DW_FORM_ref_sig8: return "DW_FORM_ref_sig8"; + } + return 0; +} + +/// OperationEncodingString - Return the string for the specified operation +/// encoding. +const char *llvm::dwarf::OperationEncodingString(unsigned Encoding) { + switch (Encoding) { + case DW_OP_addr: return "DW_OP_addr"; + case DW_OP_deref: return "DW_OP_deref"; + case DW_OP_const1u: return "DW_OP_const1u"; + case DW_OP_const1s: return "DW_OP_const1s"; + case DW_OP_const2u: return "DW_OP_const2u"; + case DW_OP_const2s: return "DW_OP_const2s"; + case DW_OP_const4u: return "DW_OP_const4u"; + case DW_OP_const4s: return "DW_OP_const4s"; + case DW_OP_const8u: return "DW_OP_const8u"; + case DW_OP_const8s: return "DW_OP_const8s"; + case DW_OP_constu: return "DW_OP_constu"; + case DW_OP_consts: return "DW_OP_consts"; + case DW_OP_dup: return "DW_OP_dup"; + case DW_OP_drop: return "DW_OP_drop"; + case DW_OP_over: return "DW_OP_over"; + case DW_OP_pick: return "DW_OP_pick"; + case DW_OP_swap: return "DW_OP_swap"; + case DW_OP_rot: return "DW_OP_rot"; + case DW_OP_xderef: return "DW_OP_xderef"; + case DW_OP_abs: return "DW_OP_abs"; + case DW_OP_and: return "DW_OP_and"; + case DW_OP_div: return "DW_OP_div"; + case DW_OP_minus: return "DW_OP_minus"; + case DW_OP_mod: return "DW_OP_mod"; + case DW_OP_mul: return "DW_OP_mul"; + case DW_OP_neg: return "DW_OP_neg"; + case DW_OP_not: return "DW_OP_not"; + case DW_OP_or: return "DW_OP_or"; + case DW_OP_plus: return "DW_OP_plus"; + case DW_OP_plus_uconst: return "DW_OP_plus_uconst"; + case DW_OP_shl: return "DW_OP_shl"; + case DW_OP_shr: return "DW_OP_shr"; + case DW_OP_shra: return "DW_OP_shra"; + case DW_OP_xor: return "DW_OP_xor"; + case DW_OP_skip: return "DW_OP_skip"; + case DW_OP_bra: return "DW_OP_bra"; + case DW_OP_eq: return "DW_OP_eq"; + case DW_OP_ge: return "DW_OP_ge"; + case DW_OP_gt: return "DW_OP_gt"; + case DW_OP_le: return "DW_OP_le"; + case DW_OP_lt: return "DW_OP_lt"; + case DW_OP_ne: return "DW_OP_ne"; + case DW_OP_lit0: return "DW_OP_lit0"; + case DW_OP_lit1: return "DW_OP_lit1"; + case DW_OP_lit2: return "DW_OP_lit2"; + case DW_OP_lit3: return "DW_OP_lit3"; + case DW_OP_lit4: return "DW_OP_lit4"; + case DW_OP_lit5: return "DW_OP_lit5"; + case DW_OP_lit6: return "DW_OP_lit6"; + case DW_OP_lit7: return "DW_OP_lit7"; + case DW_OP_lit8: return "DW_OP_lit8"; + case DW_OP_lit9: return "DW_OP_lit9"; + case DW_OP_lit10: return "DW_OP_lit10"; + case DW_OP_lit11: return "DW_OP_lit11"; + case DW_OP_lit12: return "DW_OP_lit12"; + case DW_OP_lit13: return "DW_OP_lit13"; + case DW_OP_lit14: return "DW_OP_lit14"; + case DW_OP_lit15: return "DW_OP_lit15"; + case DW_OP_lit16: return "DW_OP_lit16"; + case DW_OP_lit17: return "DW_OP_lit17"; + case DW_OP_lit18: return "DW_OP_lit18"; + case DW_OP_lit19: return "DW_OP_lit19"; + case DW_OP_lit20: return "DW_OP_lit20"; + case DW_OP_lit21: return "DW_OP_lit21"; + case DW_OP_lit22: return "DW_OP_lit22"; + case DW_OP_lit23: return "DW_OP_lit23"; + case DW_OP_lit24: return "DW_OP_lit24"; + case DW_OP_lit25: return "DW_OP_lit25"; + case DW_OP_lit26: return "DW_OP_lit26"; + case DW_OP_lit27: return "DW_OP_lit27"; + case DW_OP_lit28: return "DW_OP_lit28"; + case DW_OP_lit29: return "DW_OP_lit29"; + case DW_OP_lit30: return "DW_OP_lit30"; + case DW_OP_lit31: return "DW_OP_lit31"; + case DW_OP_reg0: return "DW_OP_reg0"; + case DW_OP_reg1: return "DW_OP_reg1"; + case DW_OP_reg2: return "DW_OP_reg2"; + case DW_OP_reg3: return "DW_OP_reg3"; + case DW_OP_reg4: return "DW_OP_reg4"; + case DW_OP_reg5: return "DW_OP_reg5"; + case DW_OP_reg6: return "DW_OP_reg6"; + case DW_OP_reg7: return "DW_OP_reg7"; + case DW_OP_reg8: return "DW_OP_reg8"; + case DW_OP_reg9: return "DW_OP_reg9"; + case DW_OP_reg10: return "DW_OP_reg10"; + case DW_OP_reg11: return "DW_OP_reg11"; + case DW_OP_reg12: return "DW_OP_reg12"; + case DW_OP_reg13: return "DW_OP_reg13"; + case DW_OP_reg14: return "DW_OP_reg14"; + case DW_OP_reg15: return "DW_OP_reg15"; + case DW_OP_reg16: return "DW_OP_reg16"; + case DW_OP_reg17: return "DW_OP_reg17"; + case DW_OP_reg18: return "DW_OP_reg18"; + case DW_OP_reg19: return "DW_OP_reg19"; + case DW_OP_reg20: return "DW_OP_reg20"; + case DW_OP_reg21: return "DW_OP_reg21"; + case DW_OP_reg22: return "DW_OP_reg22"; + case DW_OP_reg23: return "DW_OP_reg23"; + case DW_OP_reg24: return "DW_OP_reg24"; + case DW_OP_reg25: return "DW_OP_reg25"; + case DW_OP_reg26: return "DW_OP_reg26"; + case DW_OP_reg27: return "DW_OP_reg27"; + case DW_OP_reg28: return "DW_OP_reg28"; + case DW_OP_reg29: return "DW_OP_reg29"; + case DW_OP_reg30: return "DW_OP_reg30"; + case DW_OP_reg31: return "DW_OP_reg31"; + case DW_OP_breg0: return "DW_OP_breg0"; + case DW_OP_breg1: return "DW_OP_breg1"; + case DW_OP_breg2: return "DW_OP_breg2"; + case DW_OP_breg3: return "DW_OP_breg3"; + case DW_OP_breg4: return "DW_OP_breg4"; + case DW_OP_breg5: return "DW_OP_breg5"; + case DW_OP_breg6: return "DW_OP_breg6"; + case DW_OP_breg7: return "DW_OP_breg7"; + case DW_OP_breg8: return "DW_OP_breg8"; + case DW_OP_breg9: return "DW_OP_breg9"; + case DW_OP_breg10: return "DW_OP_breg10"; + case DW_OP_breg11: return "DW_OP_breg11"; + case DW_OP_breg12: return "DW_OP_breg12"; + case DW_OP_breg13: return "DW_OP_breg13"; + case DW_OP_breg14: return "DW_OP_breg14"; + case DW_OP_breg15: return "DW_OP_breg15"; + case DW_OP_breg16: return "DW_OP_breg16"; + case DW_OP_breg17: return "DW_OP_breg17"; + case DW_OP_breg18: return "DW_OP_breg18"; + case DW_OP_breg19: return "DW_OP_breg19"; + case DW_OP_breg20: return "DW_OP_breg20"; + case DW_OP_breg21: return "DW_OP_breg21"; + case DW_OP_breg22: return "DW_OP_breg22"; + case DW_OP_breg23: return "DW_OP_breg23"; + case DW_OP_breg24: return "DW_OP_breg24"; + case DW_OP_breg25: return "DW_OP_breg25"; + case DW_OP_breg26: return "DW_OP_breg26"; + case DW_OP_breg27: return "DW_OP_breg27"; + case DW_OP_breg28: return "DW_OP_breg28"; + case DW_OP_breg29: return "DW_OP_breg29"; + case DW_OP_breg30: return "DW_OP_breg30"; + case DW_OP_breg31: return "DW_OP_breg31"; + case DW_OP_regx: return "DW_OP_regx"; + case DW_OP_fbreg: return "DW_OP_fbreg"; + case DW_OP_bregx: return "DW_OP_bregx"; + case DW_OP_piece: return "DW_OP_piece"; + case DW_OP_deref_size: return "DW_OP_deref_size"; + case DW_OP_xderef_size: return "DW_OP_xderef_size"; + case DW_OP_nop: return "DW_OP_nop"; + case DW_OP_push_object_address: return "DW_OP_push_object_address"; + case DW_OP_call2: return "DW_OP_call2"; + case DW_OP_call4: return "DW_OP_call4"; + case DW_OP_call_ref: return "DW_OP_call_ref"; + case DW_OP_form_tls_address: return "DW_OP_form_tls_address"; + case DW_OP_call_frame_cfa: return "DW_OP_call_frame_cfa"; + case DW_OP_bit_piece: return "DW_OP_bit_piece"; + case DW_OP_implicit_value: return "DW_OP_implicit_value"; + case DW_OP_stack_value: return "DW_OP_stack_value"; + case DW_OP_lo_user: return "DW_OP_lo_user"; + case DW_OP_hi_user: return "DW_OP_hi_user"; + } + return 0; +} + +/// AttributeEncodingString - Return the string for the specified attribute +/// encoding. +const char *llvm::dwarf::AttributeEncodingString(unsigned Encoding) { + switch (Encoding) { + case DW_ATE_address: return "DW_ATE_address"; + case DW_ATE_boolean: return "DW_ATE_boolean"; + case DW_ATE_complex_float: return "DW_ATE_complex_float"; + case DW_ATE_float: return "DW_ATE_float"; + case DW_ATE_signed: return "DW_ATE_signed"; + case DW_ATE_signed_char: return "DW_ATE_signed_char"; + case DW_ATE_unsigned: return "DW_ATE_unsigned"; + case DW_ATE_unsigned_char: return "DW_ATE_unsigned_char"; + case DW_ATE_imaginary_float: return "DW_ATE_imaginary_float"; + case DW_ATE_UTF: return "DW_ATE_UTF"; + case DW_ATE_packed_decimal: return "DW_ATE_packed_decimal"; + case DW_ATE_numeric_string: return "DW_ATE_numeric_string"; + case DW_ATE_edited: return "DW_ATE_edited"; + case DW_ATE_signed_fixed: return "DW_ATE_signed_fixed"; + case DW_ATE_unsigned_fixed: return "DW_ATE_unsigned_fixed"; + case DW_ATE_decimal_float: return "DW_ATE_decimal_float"; + case DW_ATE_lo_user: return "DW_ATE_lo_user"; + case DW_ATE_hi_user: return "DW_ATE_hi_user"; + } + return 0; +} + +/// DecimalSignString - Return the string for the specified decimal sign +/// attribute. +const char *llvm::dwarf::DecimalSignString(unsigned Sign) { + switch (Sign) { + case DW_DS_unsigned: return "DW_DS_unsigned"; + case DW_DS_leading_overpunch: return "DW_DS_leading_overpunch"; + case DW_DS_trailing_overpunch: return "DW_DS_trailing_overpunch"; + case DW_DS_leading_separate: return "DW_DS_leading_separate"; + case DW_DS_trailing_separate: return "DW_DS_trailing_separate"; + } + return 0; +} + +/// EndianityString - Return the string for the specified endianity. +/// +const char *llvm::dwarf::EndianityString(unsigned Endian) { + switch (Endian) { + case DW_END_default: return "DW_END_default"; + case DW_END_big: return "DW_END_big"; + case DW_END_little: return "DW_END_little"; + case DW_END_lo_user: return "DW_END_lo_user"; + case DW_END_hi_user: return "DW_END_hi_user"; + } + return 0; +} + +/// AccessibilityString - Return the string for the specified accessibility. +/// +const char *llvm::dwarf::AccessibilityString(unsigned Access) { + switch (Access) { + // Accessibility codes + case DW_ACCESS_public: return "DW_ACCESS_public"; + case DW_ACCESS_protected: return "DW_ACCESS_protected"; + case DW_ACCESS_private: return "DW_ACCESS_private"; + } + return 0; +} + +/// VisibilityString - Return the string for the specified visibility. +/// +const char *llvm::dwarf::VisibilityString(unsigned Visibility) { + switch (Visibility) { + case DW_VIS_local: return "DW_VIS_local"; + case DW_VIS_exported: return "DW_VIS_exported"; + case DW_VIS_qualified: return "DW_VIS_qualified"; + } + return 0; +} + +/// VirtualityString - Return the string for the specified virtuality. +/// +const char *llvm::dwarf::VirtualityString(unsigned Virtuality) { + switch (Virtuality) { + case DW_VIRTUALITY_none: return "DW_VIRTUALITY_none"; + case DW_VIRTUALITY_virtual: return "DW_VIRTUALITY_virtual"; + case DW_VIRTUALITY_pure_virtual: return "DW_VIRTUALITY_pure_virtual"; + } + return 0; +} + +/// LanguageString - Return the string for the specified language. +/// +const char *llvm::dwarf::LanguageString(unsigned Language) { + switch (Language) { + case DW_LANG_C89: return "DW_LANG_C89"; + case DW_LANG_C: return "DW_LANG_C"; + case DW_LANG_Ada83: return "DW_LANG_Ada83"; + case DW_LANG_C_plus_plus: return "DW_LANG_C_plus_plus"; + case DW_LANG_Cobol74: return "DW_LANG_Cobol74"; + case DW_LANG_Cobol85: return "DW_LANG_Cobol85"; + case DW_LANG_Fortran77: return "DW_LANG_Fortran77"; + case DW_LANG_Fortran90: return "DW_LANG_Fortran90"; + case DW_LANG_Pascal83: return "DW_LANG_Pascal83"; + case DW_LANG_Modula2: return "DW_LANG_Modula2"; + case DW_LANG_Java: return "DW_LANG_Java"; + case DW_LANG_C99: return "DW_LANG_C99"; + case DW_LANG_Ada95: return "DW_LANG_Ada95"; + case DW_LANG_Fortran95: return "DW_LANG_Fortran95"; + case DW_LANG_PLI: return "DW_LANG_PLI"; + case DW_LANG_ObjC: return "DW_LANG_ObjC"; + case DW_LANG_ObjC_plus_plus: return "DW_LANG_ObjC_plus_plus"; + case DW_LANG_UPC: return "DW_LANG_UPC"; + case DW_LANG_D: return "DW_LANG_D"; + case DW_LANG_lo_user: return "DW_LANG_lo_user"; + case DW_LANG_hi_user: return "DW_LANG_hi_user"; + } + return 0; +} + +/// CaseString - Return the string for the specified identifier case. +/// +const char *llvm::dwarf::CaseString(unsigned Case) { + switch (Case) { + case DW_ID_case_sensitive: return "DW_ID_case_sensitive"; + case DW_ID_up_case: return "DW_ID_up_case"; + case DW_ID_down_case: return "DW_ID_down_case"; + case DW_ID_case_insensitive: return "DW_ID_case_insensitive"; + } + return 0; +} + +/// ConventionString - Return the string for the specified calling convention. +/// +const char *llvm::dwarf::ConventionString(unsigned Convention) { + switch (Convention) { + case DW_CC_normal: return "DW_CC_normal"; + case DW_CC_program: return "DW_CC_program"; + case DW_CC_nocall: return "DW_CC_nocall"; + case DW_CC_lo_user: return "DW_CC_lo_user"; + case DW_CC_hi_user: return "DW_CC_hi_user"; + } + return 0; +} + +/// InlineCodeString - Return the string for the specified inline code. +/// +const char *llvm::dwarf::InlineCodeString(unsigned Code) { + switch (Code) { + case DW_INL_not_inlined: return "DW_INL_not_inlined"; + case DW_INL_inlined: return "DW_INL_inlined"; + case DW_INL_declared_not_inlined: return "DW_INL_declared_not_inlined"; + case DW_INL_declared_inlined: return "DW_INL_declared_inlined"; + } + return 0; +} + +/// ArrayOrderString - Return the string for the specified array order. +/// +const char *llvm::dwarf::ArrayOrderString(unsigned Order) { + switch (Order) { + case DW_ORD_row_major: return "DW_ORD_row_major"; + case DW_ORD_col_major: return "DW_ORD_col_major"; + } + return 0; +} + +/// DiscriminantString - Return the string for the specified discriminant +/// descriptor. +const char *llvm::dwarf::DiscriminantString(unsigned Discriminant) { + switch (Discriminant) { + case DW_DSC_label: return "DW_DSC_label"; + case DW_DSC_range: return "DW_DSC_range"; + } + return 0; +} + +/// LNStandardString - Return the string for the specified line number standard. +/// +const char *llvm::dwarf::LNStandardString(unsigned Standard) { + switch (Standard) { + case DW_LNS_copy: return "DW_LNS_copy"; + case DW_LNS_advance_pc: return "DW_LNS_advance_pc"; + case DW_LNS_advance_line: return "DW_LNS_advance_line"; + case DW_LNS_set_file: return "DW_LNS_set_file"; + case DW_LNS_set_column: return "DW_LNS_set_column"; + case DW_LNS_negate_stmt: return "DW_LNS_negate_stmt"; + case DW_LNS_set_basic_block: return "DW_LNS_set_basic_block"; + case DW_LNS_const_add_pc: return "DW_LNS_const_add_pc"; + case DW_LNS_fixed_advance_pc: return "DW_LNS_fixed_advance_pc"; + case DW_LNS_set_prologue_end: return "DW_LNS_set_prologue_end"; + case DW_LNS_set_epilogue_begin: return "DW_LNS_set_epilogue_begin"; + case DW_LNS_set_isa: return "DW_LNS_set_isa"; + } + return 0; +} + +/// LNExtendedString - Return the string for the specified line number extended +/// opcode encodings. +const char *llvm::dwarf::LNExtendedString(unsigned Encoding) { + switch (Encoding) { + // Line Number Extended Opcode Encodings + case DW_LNE_end_sequence: return "DW_LNE_end_sequence"; + case DW_LNE_set_address: return "DW_LNE_set_address"; + case DW_LNE_define_file: return "DW_LNE_define_file"; + case DW_LNE_set_discriminator: return "DW_LNE_set_discriminator"; + case DW_LNE_lo_user: return "DW_LNE_lo_user"; + case DW_LNE_hi_user: return "DW_LNE_hi_user"; + } + return 0; +} + +/// MacinfoString - Return the string for the specified macinfo type encodings. +/// +const char *llvm::dwarf::MacinfoString(unsigned Encoding) { + switch (Encoding) { + // Macinfo Type Encodings + case DW_MACINFO_define: return "DW_MACINFO_define"; + case DW_MACINFO_undef: return "DW_MACINFO_undef"; + case DW_MACINFO_start_file: return "DW_MACINFO_start_file"; + case DW_MACINFO_end_file: return "DW_MACINFO_end_file"; + case DW_MACINFO_vendor_ext: return "DW_MACINFO_vendor_ext"; + } + return 0; +} + +/// CallFrameString - Return the string for the specified call frame instruction +/// encodings. +const char *llvm::dwarf::CallFrameString(unsigned Encoding) { + switch (Encoding) { + case DW_CFA_advance_loc: return "DW_CFA_advance_loc"; + case DW_CFA_offset: return "DW_CFA_offset"; + case DW_CFA_restore: return "DW_CFA_restore"; + case DW_CFA_set_loc: return "DW_CFA_set_loc"; + case DW_CFA_advance_loc1: return "DW_CFA_advance_loc1"; + case DW_CFA_advance_loc2: return "DW_CFA_advance_loc2"; + case DW_CFA_advance_loc4: return "DW_CFA_advance_loc4"; + case DW_CFA_offset_extended: return "DW_CFA_offset_extended"; + case DW_CFA_restore_extended: return "DW_CFA_restore_extended"; + case DW_CFA_undefined: return "DW_CFA_undefined"; + case DW_CFA_same_value: return "DW_CFA_same_value"; + case DW_CFA_register: return "DW_CFA_register"; + case DW_CFA_remember_state: return "DW_CFA_remember_state"; + case DW_CFA_restore_state: return "DW_CFA_restore_state"; + case DW_CFA_def_cfa: return "DW_CFA_def_cfa"; + case DW_CFA_def_cfa_register: return "DW_CFA_def_cfa_register"; + case DW_CFA_def_cfa_offset: return "DW_CFA_def_cfa_offset"; + case DW_CFA_def_cfa_expression: return "DW_CFA_def_cfa_expression"; + case DW_CFA_expression: return "DW_CFA_expression"; + case DW_CFA_offset_extended_sf: return "DW_CFA_offset_extended_sf"; + case DW_CFA_def_cfa_sf: return "DW_CFA_def_cfa_sf"; + case DW_CFA_def_cfa_offset_sf: return "DW_CFA_def_cfa_offset_sf"; + case DW_CFA_val_offset: return "DW_CFA_val_offset"; + case DW_CFA_val_offset_sf: return "DW_CFA_val_offset_sf"; + case DW_CFA_val_expression: return "DW_CFA_val_expression"; + case DW_CFA_MIPS_advance_loc8: return "DW_CFA_MIPS_advance_loc8"; + case DW_CFA_GNU_window_save: return "DW_CFA_GNU_window_save"; + case DW_CFA_GNU_args_size: return "DW_CFA_GNU_args_size"; + case DW_CFA_lo_user: return "DW_CFA_lo_user"; + case DW_CFA_hi_user: return "DW_CFA_hi_user"; + } + return 0; +} diff --git a/contrib/llvm/lib/Support/DynamicLibrary.cpp b/contrib/llvm/lib/Support/DynamicLibrary.cpp new file mode 100644 index 0000000..fb02c07 --- /dev/null +++ b/contrib/llvm/lib/Support/DynamicLibrary.cpp @@ -0,0 +1,189 @@ +//===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system DynamicLibrary concept. +// +// FIXME: This file leaks ExplicitSymbols and OpenedHandles! +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Config/config.h" +#include <cstdio> +#include <cstring> + +// Collection of symbol name/value pairs to be searched prior to any libraries. +static llvm::StringMap<void *> *ExplicitSymbols = 0; + +namespace { + +struct ExplicitSymbolsDeleter { + ~ExplicitSymbolsDeleter() { + delete ExplicitSymbols; + } +}; + +} + +static ExplicitSymbolsDeleter Dummy; + + +static llvm::sys::SmartMutex<true>& getMutex() { + static llvm::sys::SmartMutex<true> HandlesMutex; + return HandlesMutex; +} + +void llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName, + void *symbolValue) { + SmartScopedLock<true> lock(getMutex()); + if (ExplicitSymbols == 0) + ExplicitSymbols = new llvm::StringMap<void*>(); + (*ExplicitSymbols)[symbolName] = symbolValue; +} + +char llvm::sys::DynamicLibrary::Invalid = 0; + +#ifdef LLVM_ON_WIN32 + +#include "Windows/DynamicLibrary.inc" + +#else + +#if HAVE_DLFCN_H +#include <dlfcn.h> +using namespace llvm; +using namespace llvm::sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +static DenseSet<void *> *OpenedHandles = 0; + +DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, + std::string *errMsg) { + SmartScopedLock<true> lock(getMutex()); + + void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL); + if (handle == 0) { + if (errMsg) *errMsg = dlerror(); + return DynamicLibrary(); + } + +#ifdef __CYGWIN__ + // Cygwin searches symbols only in the main + // with the handle of dlopen(NULL, RTLD_GLOBAL). + if (filename == NULL) + handle = RTLD_DEFAULT; +#endif + + if (OpenedHandles == 0) + OpenedHandles = new DenseSet<void *>(); + + // If we've already loaded this library, dlclose() the handle in order to + // keep the internal refcount at +1. + if (!OpenedHandles->insert(handle).second) + dlclose(handle); + + return DynamicLibrary(handle); +} + +void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) { + if (!isValid()) + return NULL; + return dlsym(Data, symbolName); +} + +#else + +using namespace llvm; +using namespace llvm::sys; + +DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, + std::string *errMsg) { + if (errMsg) *errMsg = "dlopen() not supported on this platform"; + return DynamicLibrary(); +} + +void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) { + return NULL; +} + +#endif + +namespace llvm { +void *SearchForAddressOfSpecialSymbol(const char* symbolName); +} + +void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) { + SmartScopedLock<true> Lock(getMutex()); + + // First check symbols added via AddSymbol(). + if (ExplicitSymbols) { + StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName); + + if (i != ExplicitSymbols->end()) + return i->second; + } + +#if HAVE_DLFCN_H + // Now search the libraries. + if (OpenedHandles) { + for (DenseSet<void *>::iterator I = OpenedHandles->begin(), + E = OpenedHandles->end(); I != E; ++I) { + //lt_ptr ptr = lt_dlsym(*I, symbolName); + void *ptr = dlsym(*I, symbolName); + if (ptr) { + return ptr; + } + } + } +#endif + + if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName)) + return Result; + +// This macro returns the address of a well-known, explicit symbol +#define EXPLICIT_SYMBOL(SYM) \ + if (!strcmp(symbolName, #SYM)) return &SYM + +// On linux we have a weird situation. The stderr/out/in symbols are both +// macros and global variables because of standards requirements. So, we +// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first. +#if defined(__linux__) + { + EXPLICIT_SYMBOL(stderr); + EXPLICIT_SYMBOL(stdout); + EXPLICIT_SYMBOL(stdin); + } +#else + // For everything else, we want to check to make sure the symbol isn't defined + // as a macro before using EXPLICIT_SYMBOL. + { +#ifndef stdin + EXPLICIT_SYMBOL(stdin); +#endif +#ifndef stdout + EXPLICIT_SYMBOL(stdout); +#endif +#ifndef stderr + EXPLICIT_SYMBOL(stderr); +#endif + } +#endif +#undef EXPLICIT_SYMBOL + + return 0; +} + +#endif // LLVM_ON_WIN32 diff --git a/contrib/llvm/lib/Support/Errno.cpp b/contrib/llvm/lib/Support/Errno.cpp new file mode 100644 index 0000000..18c6581 --- /dev/null +++ b/contrib/llvm/lib/Support/Errno.cpp @@ -0,0 +1,74 @@ +//===- Errno.cpp - errno support --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the errno wrappers. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Errno.h" +#include "llvm/Config/config.h" // Get autoconf configuration settings + +#if HAVE_STRING_H +#include <string.h> + +#if HAVE_ERRNO_H +#include <errno.h> +#endif + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +namespace llvm { +namespace sys { + +#if HAVE_ERRNO_H +std::string StrError() { + return StrError(errno); +} +#endif // HAVE_ERRNO_H + +std::string StrError(int errnum) { + const int MaxErrStrLen = 2000; + char buffer[MaxErrStrLen]; + buffer[0] = '\0'; + char* str = buffer; +#ifdef HAVE_STRERROR_R + // strerror_r is thread-safe. + if (errnum) +# if defined(__GLIBC__) && defined(_GNU_SOURCE) + // glibc defines its own incompatible version of strerror_r + // which may not use the buffer supplied. + str = strerror_r(errnum,buffer,MaxErrStrLen-1); +# else + strerror_r(errnum,buffer,MaxErrStrLen-1); +# endif +#elif HAVE_DECL_STRERROR_S // "Windows Secure API" + if (errnum) + strerror_s(buffer, errnum); +#elif defined(HAVE_STRERROR) + // Copy the thread un-safe result of strerror into + // the buffer as fast as possible to minimize impact + // of collision of strerror in multiple threads. + if (errnum) + strncpy(buffer,strerror(errnum),MaxErrStrLen-1); + buffer[MaxErrStrLen-1] = '\0'; +#else + // Strange that this system doesn't even have strerror + // but, oh well, just use a generic message + sprintf(buffer, "Error #%d", errnum); +#endif + return str; +} + +} // namespace sys +} // namespace llvm + +#endif // HAVE_STRING_H diff --git a/contrib/llvm/lib/Support/ErrorHandling.cpp b/contrib/llvm/lib/Support/ErrorHandling.cpp new file mode 100644 index 0000000..e6cc57d --- /dev/null +++ b/contrib/llvm/lib/Support/ErrorHandling.cpp @@ -0,0 +1,99 @@ +//===- lib/Support/ErrorHandling.cpp - Callbacks for errors ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an API used to indicate fatal error conditions. Non-fatal +// errors (most of them) should be handled through LLVMContext. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/Threading.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Config/config.h" +#include <cassert> +#include <cstdlib> + +#if defined(HAVE_UNISTD_H) +# include <unistd.h> +#endif +#if defined(_MSC_VER) +# include <io.h> +# include <fcntl.h> +#endif + +using namespace llvm; + +static fatal_error_handler_t ErrorHandler = 0; +static void *ErrorHandlerUserData = 0; + +void llvm::install_fatal_error_handler(fatal_error_handler_t handler, + void *user_data) { + assert(!llvm_is_multithreaded() && + "Cannot register error handlers after starting multithreaded mode!\n"); + assert(!ErrorHandler && "Error handler already registered!\n"); + ErrorHandler = handler; + ErrorHandlerUserData = user_data; +} + +void llvm::remove_fatal_error_handler() { + ErrorHandler = 0; +} + +void llvm::report_fatal_error(const char *Reason) { + report_fatal_error(Twine(Reason)); +} + +void llvm::report_fatal_error(const std::string &Reason) { + report_fatal_error(Twine(Reason)); +} + +void llvm::report_fatal_error(StringRef Reason) { + report_fatal_error(Twine(Reason)); +} + +void llvm::report_fatal_error(const Twine &Reason) { + if (ErrorHandler) { + ErrorHandler(ErrorHandlerUserData, Reason.str()); + } else { + // Blast the result out to stderr. We don't try hard to make sure this + // succeeds (e.g. handling EINTR) and we can't use errs() here because + // raw ostreams can call report_fatal_error. + SmallVector<char, 64> Buffer; + raw_svector_ostream OS(Buffer); + OS << "LLVM ERROR: " << Reason << "\n"; + StringRef MessageStr = OS.str(); + ssize_t written = ::write(2, MessageStr.data(), MessageStr.size()); + (void)written; // If something went wrong, we deliberately just give up. + } + + // If we reached here, we are failing ungracefully. Run the interrupt handlers + // to make sure any special cleanups get done, in particular that we remove + // files registered with RemoveFileOnSignal. + sys::RunInterruptHandlers(); + + exit(1); +} + +void llvm::llvm_unreachable_internal(const char *msg, const char *file, + unsigned line) { + // This code intentionally doesn't call the ErrorHandler callback, because + // llvm_unreachable is intended to be used to indicate "impossible" + // situations, and not legitimate runtime errors. + if (msg) + dbgs() << msg << "\n"; + dbgs() << "UNREACHABLE executed"; + if (file) + dbgs() << " at " << file << ":" << line; + dbgs() << "!\n"; + abort(); +} diff --git a/contrib/llvm/lib/Support/FileUtilities.cpp b/contrib/llvm/lib/Support/FileUtilities.cpp new file mode 100644 index 0000000..f9e9cf0 --- /dev/null +++ b/contrib/llvm/lib/Support/FileUtilities.cpp @@ -0,0 +1,280 @@ +//===- Support/FileUtilities.cpp - File System Utilities ------------------===// +// +// 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 family of utility functions which are useful for doing +// various things with files. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/system_error.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallString.h" +#include <cstdlib> +#include <cstring> +#include <cctype> +using namespace llvm; + +static bool isSignedChar(char C) { + return (C == '+' || C == '-'); +} + +static bool isExponentChar(char C) { + switch (C) { + case 'D': // Strange exponential notation. + case 'd': // Strange exponential notation. + case 'e': + case 'E': return true; + default: return false; + } +} + +static bool isNumberChar(char C) { + switch (C) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '.': return true; + default: return isSignedChar(C) || isExponentChar(C); + } +} + +static const char *BackupNumber(const char *Pos, const char *FirstChar) { + // If we didn't stop in the middle of a number, don't backup. + if (!isNumberChar(*Pos)) return Pos; + + // Otherwise, return to the start of the number. + bool HasPeriod = false; + while (Pos > FirstChar && isNumberChar(Pos[-1])) { + // Backup over at most one period. + if (Pos[-1] == '.') { + if (HasPeriod) + break; + HasPeriod = true; + } + + --Pos; + if (Pos > FirstChar && isSignedChar(Pos[0]) && !isExponentChar(Pos[-1])) + break; + } + return Pos; +} + +/// EndOfNumber - Return the first character that is not part of the specified +/// number. This assumes that the buffer is null terminated, so it won't fall +/// off the end. +static const char *EndOfNumber(const char *Pos) { + while (isNumberChar(*Pos)) + ++Pos; + return Pos; +} + +/// CompareNumbers - compare two numbers, returning true if they are different. +static bool CompareNumbers(const char *&F1P, const char *&F2P, + const char *F1End, const char *F2End, + double AbsTolerance, double RelTolerance, + std::string *ErrorMsg) { + const char *F1NumEnd, *F2NumEnd; + double V1 = 0.0, V2 = 0.0; + + // If one of the positions is at a space and the other isn't, chomp up 'til + // the end of the space. + while (isspace(*F1P) && F1P != F1End) + ++F1P; + while (isspace(*F2P) && F2P != F2End) + ++F2P; + + // If we stop on numbers, compare their difference. + if (!isNumberChar(*F1P) || !isNumberChar(*F2P)) { + // The diff failed. + F1NumEnd = F1P; + F2NumEnd = F2P; + } else { + // Note that some ugliness is built into this to permit support for numbers + // that use "D" or "d" as their exponential marker, e.g. "1.234D45". This + // occurs in 200.sixtrack in spec2k. + V1 = strtod(F1P, const_cast<char**>(&F1NumEnd)); + V2 = strtod(F2P, const_cast<char**>(&F2NumEnd)); + + if (*F1NumEnd == 'D' || *F1NumEnd == 'd') { + // Copy string into tmp buffer to replace the 'D' with an 'e'. + SmallString<200> StrTmp(F1P, EndOfNumber(F1NumEnd)+1); + // Strange exponential notation! + StrTmp[static_cast<unsigned>(F1NumEnd-F1P)] = 'e'; + + V1 = strtod(&StrTmp[0], const_cast<char**>(&F1NumEnd)); + F1NumEnd = F1P + (F1NumEnd-&StrTmp[0]); + } + + if (*F2NumEnd == 'D' || *F2NumEnd == 'd') { + // Copy string into tmp buffer to replace the 'D' with an 'e'. + SmallString<200> StrTmp(F2P, EndOfNumber(F2NumEnd)+1); + // Strange exponential notation! + StrTmp[static_cast<unsigned>(F2NumEnd-F2P)] = 'e'; + + V2 = strtod(&StrTmp[0], const_cast<char**>(&F2NumEnd)); + F2NumEnd = F2P + (F2NumEnd-&StrTmp[0]); + } + } + + if (F1NumEnd == F1P || F2NumEnd == F2P) { + if (ErrorMsg) { + *ErrorMsg = "FP Comparison failed, not a numeric difference between '"; + *ErrorMsg += F1P[0]; + *ErrorMsg += "' and '"; + *ErrorMsg += F2P[0]; + *ErrorMsg += "'"; + } + return true; + } + + // Check to see if these are inside the absolute tolerance + if (AbsTolerance < std::abs(V1-V2)) { + // Nope, check the relative tolerance... + double Diff; + if (V2) + Diff = std::abs(V1/V2 - 1.0); + else if (V1) + Diff = std::abs(V2/V1 - 1.0); + else + Diff = 0; // Both zero. + if (Diff > RelTolerance) { + if (ErrorMsg) { + raw_string_ostream(*ErrorMsg) + << "Compared: " << V1 << " and " << V2 << '\n' + << "abs. diff = " << std::abs(V1-V2) << " rel.diff = " << Diff << '\n' + << "Out of tolerance: rel/abs: " << RelTolerance << '/' + << AbsTolerance; + } + return true; + } + } + + // Otherwise, advance our read pointers to the end of the numbers. + F1P = F1NumEnd; F2P = F2NumEnd; + return false; +} + +/// DiffFilesWithTolerance - Compare the two files specified, returning 0 if the +/// files match, 1 if they are different, and 2 if there is a file error. This +/// function differs from DiffFiles in that you can specify an absolete and +/// relative FP error that is allowed to exist. If you specify a string to fill +/// in for the error option, it will set the string to an error message if an +/// error occurs, allowing the caller to distinguish between a failed diff and a +/// file system error. +/// +int llvm::DiffFilesWithTolerance(const sys::PathWithStatus &FileA, + const sys::PathWithStatus &FileB, + double AbsTol, double RelTol, + std::string *Error) { + const sys::FileStatus *FileAStat = FileA.getFileStatus(false, Error); + if (!FileAStat) + return 2; + const sys::FileStatus *FileBStat = FileB.getFileStatus(false, Error); + if (!FileBStat) + return 2; + + // Check for zero length files because some systems croak when you try to + // mmap an empty file. + size_t A_size = FileAStat->getSize(); + size_t B_size = FileBStat->getSize(); + + // If they are both zero sized then they're the same + if (A_size == 0 && B_size == 0) + return 0; + + // If only one of them is zero sized then they can't be the same + if ((A_size == 0 || B_size == 0)) { + if (Error) + *Error = "Files differ: one is zero-sized, the other isn't"; + return 1; + } + + // Now its safe to mmap the files into memory because both files + // have a non-zero size. + OwningPtr<MemoryBuffer> F1; + if (error_code ec = MemoryBuffer::getFile(FileA.c_str(), F1)) { + if (Error) + *Error = ec.message(); + return 2; + } + OwningPtr<MemoryBuffer> F2; + if (error_code ec = MemoryBuffer::getFile(FileB.c_str(), F2)) { + if (Error) + *Error = ec.message(); + return 2; + } + + // Okay, now that we opened the files, scan them for the first difference. + const char *File1Start = F1->getBufferStart(); + const char *File2Start = F2->getBufferStart(); + const char *File1End = F1->getBufferEnd(); + const char *File2End = F2->getBufferEnd(); + const char *F1P = File1Start; + const char *F2P = File2Start; + + // Are the buffers identical? Common case: Handle this efficiently. + if (A_size == B_size && + std::memcmp(File1Start, File2Start, A_size) == 0) + return 0; + + // Otherwise, we are done a tolerances are set. + if (AbsTol == 0 && RelTol == 0) { + if (Error) + *Error = "Files differ without tolerance allowance"; + return 1; // Files different! + } + + bool CompareFailed = false; + while (1) { + // Scan for the end of file or next difference. + while (F1P < File1End && F2P < File2End && *F1P == *F2P) + ++F1P, ++F2P; + + if (F1P >= File1End || F2P >= File2End) break; + + // Okay, we must have found a difference. Backup to the start of the + // current number each stream is at so that we can compare from the + // beginning. + F1P = BackupNumber(F1P, File1Start); + F2P = BackupNumber(F2P, File2Start); + + // Now that we are at the start of the numbers, compare them, exiting if + // they don't match. + if (CompareNumbers(F1P, F2P, File1End, File2End, AbsTol, RelTol, Error)) { + CompareFailed = true; + break; + } + } + + // Okay, we reached the end of file. If both files are at the end, we + // succeeded. + bool F1AtEnd = F1P >= File1End; + bool F2AtEnd = F2P >= File2End; + if (!CompareFailed && (!F1AtEnd || !F2AtEnd)) { + // Else, we might have run off the end due to a number: backup and retry. + if (F1AtEnd && isNumberChar(F1P[-1])) --F1P; + if (F2AtEnd && isNumberChar(F2P[-1])) --F2P; + F1P = BackupNumber(F1P, File1Start); + F2P = BackupNumber(F2P, File2Start); + + // Now that we are at the start of the numbers, compare them, exiting if + // they don't match. + if (CompareNumbers(F1P, F2P, File1End, File2End, AbsTol, RelTol, Error)) + CompareFailed = true; + + // If we found the end, we succeeded. + if (F1P < File1End || F2P < File2End) + CompareFailed = true; + } + + return CompareFailed; +} diff --git a/contrib/llvm/lib/Support/FoldingSet.cpp b/contrib/llvm/lib/Support/FoldingSet.cpp new file mode 100644 index 0000000..c6282c6 --- /dev/null +++ b/contrib/llvm/lib/Support/FoldingSet.cpp @@ -0,0 +1,408 @@ +//===-- Support/FoldingSet.cpp - Uniquing Hash Set --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a hash set that can be used to remove duplication of +// nodes in a graph. This code was originally created by Chris Lattner for use +// with SelectionDAGCSEMap, but was isolated to provide use across the llvm code +// set. +// +//===----------------------------------------------------------------------===// + +#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" +#include "llvm/Support/Host.h" +#include <cassert> +#include <cstring> +using namespace llvm; + +//===----------------------------------------------------------------------===// +// FoldingSetNodeIDRef Implementation + +/// ComputeHash - Compute a strong hash value for this FoldingSetNodeIDRef, +/// used to lookup the node in the FoldingSetImpl. +unsigned FoldingSetNodeIDRef::ComputeHash() const { + return static_cast<unsigned>(hash_combine_range(Data, Data+Size)); +} + +bool FoldingSetNodeIDRef::operator==(FoldingSetNodeIDRef RHS) const { + if (Size != RHS.Size) return false; + return memcmp(Data, RHS.Data, Size*sizeof(*Data)) == 0; +} + +//===----------------------------------------------------------------------===// +// FoldingSetNodeID Implementation + +/// Add* - Add various data types to Bit data. +/// +void FoldingSetNodeID::AddPointer(const void *Ptr) { + // Note: this adds pointers to the hash using sizes and endianness that + // depend on the host. It doesn't matter however, because hashing on + // pointer values in inherently unstable. Nothing should depend on the + // ordering of nodes in the folding set. + Bits.append(reinterpret_cast<unsigned *>(&Ptr), + reinterpret_cast<unsigned *>(&Ptr+1)); +} +void FoldingSetNodeID::AddInteger(signed I) { + Bits.push_back(I); +} +void FoldingSetNodeID::AddInteger(unsigned I) { + Bits.push_back(I); +} +void FoldingSetNodeID::AddInteger(long I) { + AddInteger((unsigned long)I); +} +void FoldingSetNodeID::AddInteger(unsigned long I) { + if (sizeof(long) == sizeof(int)) + AddInteger(unsigned(I)); + else if (sizeof(long) == sizeof(long long)) { + AddInteger((unsigned long long)I); + } else { + llvm_unreachable("unexpected sizeof(long)"); + } +} +void FoldingSetNodeID::AddInteger(long long I) { + AddInteger((unsigned long long)I); +} +void FoldingSetNodeID::AddInteger(unsigned long long I) { + AddInteger(unsigned(I)); + if ((uint64_t)(unsigned)I != I) + Bits.push_back(unsigned(I >> 32)); +} + +void FoldingSetNodeID::AddString(StringRef String) { + unsigned Size = String.size(); + Bits.push_back(Size); + if (!Size) return; + + unsigned Units = Size / 4; + unsigned Pos = 0; + const unsigned *Base = (const unsigned*) String.data(); + + // If the string is aligned do a bulk transfer. + if (!((intptr_t)Base & 3)) { + Bits.append(Base, Base + Units); + Pos = (Units + 1) * 4; + } else { + // Otherwise do it the hard way. + // To be compatible with above bulk transfer, we need to take endianness + // into account. + if (sys::isBigEndianHost()) { + for (Pos += 4; Pos <= Size; Pos += 4) { + unsigned V = ((unsigned char)String[Pos - 4] << 24) | + ((unsigned char)String[Pos - 3] << 16) | + ((unsigned char)String[Pos - 2] << 8) | + (unsigned char)String[Pos - 1]; + Bits.push_back(V); + } + } else { + assert(sys::isLittleEndianHost() && "Unexpected host endianness"); + for (Pos += 4; Pos <= Size; Pos += 4) { + unsigned V = ((unsigned char)String[Pos - 1] << 24) | + ((unsigned char)String[Pos - 2] << 16) | + ((unsigned char)String[Pos - 3] << 8) | + (unsigned char)String[Pos - 4]; + Bits.push_back(V); + } + } + } + + // With the leftover bits. + unsigned V = 0; + // Pos will have overshot size by 4 - #bytes left over. + // No need to take endianness into account here - this is always executed. + switch (Pos - Size) { + case 1: V = (V << 8) | (unsigned char)String[Size - 3]; // Fall thru. + case 2: V = (V << 8) | (unsigned char)String[Size - 2]; // Fall thru. + case 3: V = (V << 8) | (unsigned char)String[Size - 1]; break; + default: return; // Nothing left. + } + + Bits.push_back(V); +} + +// AddNodeID - Adds the Bit data of another ID to *this. +void FoldingSetNodeID::AddNodeID(const FoldingSetNodeID &ID) { + Bits.append(ID.Bits.begin(), ID.Bits.end()); +} + +/// ComputeHash - Compute a strong hash value for this FoldingSetNodeID, used to +/// lookup the node in the FoldingSetImpl. +unsigned FoldingSetNodeID::ComputeHash() const { + return FoldingSetNodeIDRef(Bits.data(), Bits.size()).ComputeHash(); +} + +/// operator== - Used to compare two nodes to each other. +/// +bool FoldingSetNodeID::operator==(const FoldingSetNodeID &RHS)const{ + return *this == FoldingSetNodeIDRef(RHS.Bits.data(), RHS.Bits.size()); +} + +/// operator== - Used to compare two nodes to each other. +/// +bool FoldingSetNodeID::operator==(FoldingSetNodeIDRef RHS) const { + return FoldingSetNodeIDRef(Bits.data(), Bits.size()) == RHS; +} + +/// Intern - Copy this node's data to a memory region allocated from the +/// given allocator and return a FoldingSetNodeIDRef describing the +/// interned data. +FoldingSetNodeIDRef +FoldingSetNodeID::Intern(BumpPtrAllocator &Allocator) const { + unsigned *New = Allocator.Allocate<unsigned>(Bits.size()); + std::uninitialized_copy(Bits.begin(), Bits.end(), New); + return FoldingSetNodeIDRef(New, Bits.size()); +} + +//===----------------------------------------------------------------------===// +/// Helper functions for FoldingSetImpl. + +/// GetNextPtr - In order to save space, each bucket is a +/// singly-linked-list. In order to make deletion more efficient, we make +/// the list circular, so we can delete a node without computing its hash. +/// The problem with this is that the start of the hash buckets are not +/// Nodes. If NextInBucketPtr is a bucket pointer, this method returns null: +/// use GetBucketPtr when this happens. +static FoldingSetImpl::Node *GetNextPtr(void *NextInBucketPtr) { + // The low bit is set if this is the pointer back to the bucket. + if (reinterpret_cast<intptr_t>(NextInBucketPtr) & 1) + return 0; + + return static_cast<FoldingSetImpl::Node*>(NextInBucketPtr); +} + + +/// testing. +static void **GetBucketPtr(void *NextInBucketPtr) { + intptr_t Ptr = reinterpret_cast<intptr_t>(NextInBucketPtr); + assert((Ptr & 1) && "Not a bucket pointer"); + return reinterpret_cast<void**>(Ptr & ~intptr_t(1)); +} + +/// GetBucketFor - Hash the specified node ID and return the hash bucket for +/// the specified ID. +static void **GetBucketFor(unsigned Hash, void **Buckets, unsigned NumBuckets) { + // NumBuckets is always a power of 2. + unsigned BucketNum = Hash & (NumBuckets-1); + return Buckets + BucketNum; +} + +/// AllocateBuckets - Allocated initialized bucket memory. +static void **AllocateBuckets(unsigned NumBuckets) { + void **Buckets = static_cast<void**>(calloc(NumBuckets+1, sizeof(void*))); + // Set the very last bucket to be a non-null "pointer". + Buckets[NumBuckets] = reinterpret_cast<void*>(-1); + return Buckets; +} + +//===----------------------------------------------------------------------===// +// FoldingSetImpl Implementation + +FoldingSetImpl::FoldingSetImpl(unsigned Log2InitSize) { + assert(5 < Log2InitSize && Log2InitSize < 32 && + "Initial hash table size out of range"); + NumBuckets = 1 << Log2InitSize; + Buckets = AllocateBuckets(NumBuckets); + NumNodes = 0; +} +FoldingSetImpl::~FoldingSetImpl() { + free(Buckets); +} +void FoldingSetImpl::clear() { + // Set all but the last bucket to null pointers. + memset(Buckets, 0, NumBuckets*sizeof(void*)); + + // Set the very last bucket to be a non-null "pointer". + Buckets[NumBuckets] = reinterpret_cast<void*>(-1); + + // Reset the node count to zero. + NumNodes = 0; +} + +/// GrowHashTable - Double the size of the hash table and rehash everything. +/// +void FoldingSetImpl::GrowHashTable() { + void **OldBuckets = Buckets; + unsigned OldNumBuckets = NumBuckets; + NumBuckets <<= 1; + + // Clear out new buckets. + Buckets = AllocateBuckets(NumBuckets); + NumNodes = 0; + + // Walk the old buckets, rehashing nodes into their new place. + FoldingSetNodeID TempID; + for (unsigned i = 0; i != OldNumBuckets; ++i) { + void *Probe = OldBuckets[i]; + if (!Probe) continue; + while (Node *NodeInBucket = GetNextPtr(Probe)) { + // Figure out the next link, remove NodeInBucket from the old link. + Probe = NodeInBucket->getNextInBucket(); + NodeInBucket->SetNextInBucket(0); + + // Insert the node into the new bucket, after recomputing the hash. + InsertNode(NodeInBucket, + GetBucketFor(ComputeNodeHash(NodeInBucket, TempID), + Buckets, NumBuckets)); + TempID.clear(); + } + } + + free(OldBuckets); +} + +/// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, +/// return it. If not, return the insertion token that will make insertion +/// faster. +FoldingSetImpl::Node +*FoldingSetImpl::FindNodeOrInsertPos(const FoldingSetNodeID &ID, + void *&InsertPos) { + 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, IDHash, TempID)) + return NodeInBucket; + TempID.clear(); + + Probe = NodeInBucket->getNextInBucket(); + } + + // Didn't find the node, return null with the bucket as the InsertPos. + InsertPos = Bucket; + return 0; +} + +/// InsertNode - Insert the specified node into the folding set, knowing that it +/// is not already in the map. InsertPos must be obtained from +/// FindNodeOrInsertPos. +void FoldingSetImpl::InsertNode(Node *N, void *InsertPos) { + assert(N->getNextInBucket() == 0); + // Do we need to grow the hashtable? + if (NumNodes+1 > NumBuckets*2) { + GrowHashTable(); + FoldingSetNodeID TempID; + InsertPos = GetBucketFor(ComputeNodeHash(N, TempID), Buckets, NumBuckets); + } + + ++NumNodes; + + /// The insert position is actually a bucket pointer. + void **Bucket = static_cast<void**>(InsertPos); + + void *Next = *Bucket; + + // If this is the first insertion into this bucket, its next pointer will be + // null. Pretend as if it pointed to itself, setting the low bit to indicate + // that it is a pointer to the bucket. + if (Next == 0) + Next = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(Bucket)|1); + + // Set the node's next pointer, and make the bucket point to the node. + N->SetNextInBucket(Next); + *Bucket = N; +} + +/// RemoveNode - Remove a node from the folding set, returning true if one was +/// removed or false if the node was not in the folding set. +bool FoldingSetImpl::RemoveNode(Node *N) { + // Because each bucket is a circular list, we don't need to compute N's hash + // to remove it. + void *Ptr = N->getNextInBucket(); + if (Ptr == 0) return false; // Not in folding set. + + --NumNodes; + N->SetNextInBucket(0); + + // Remember what N originally pointed to, either a bucket or another node. + void *NodeNextPtr = Ptr; + + // Chase around the list until we find the node (or bucket) which points to N. + while (true) { + if (Node *NodeInBucket = GetNextPtr(Ptr)) { + // Advance pointer. + Ptr = NodeInBucket->getNextInBucket(); + + // We found a node that points to N, change it to point to N's next node, + // removing N from the list. + if (Ptr == N) { + NodeInBucket->SetNextInBucket(NodeNextPtr); + return true; + } + } else { + void **Bucket = GetBucketPtr(Ptr); + Ptr = *Bucket; + + // If we found that the bucket points to N, update the bucket to point to + // whatever is next. + if (Ptr == N) { + *Bucket = NodeNextPtr; + return true; + } + } + } +} + +/// GetOrInsertNode - If there is an existing simple Node exactly +/// equal to the specified node, return it. Otherwise, insert 'N' and it +/// instead. +FoldingSetImpl::Node *FoldingSetImpl::GetOrInsertNode(FoldingSetImpl::Node *N) { + FoldingSetNodeID ID; + GetNodeProfile(N, ID); + void *IP; + if (Node *E = FindNodeOrInsertPos(ID, IP)) + return E; + InsertNode(N, IP); + return N; +} + +//===----------------------------------------------------------------------===// +// FoldingSetIteratorImpl Implementation + +FoldingSetIteratorImpl::FoldingSetIteratorImpl(void **Bucket) { + // Skip to the first non-null non-self-cycle bucket. + while (*Bucket != reinterpret_cast<void*>(-1) && + (*Bucket == 0 || GetNextPtr(*Bucket) == 0)) + ++Bucket; + + NodePtr = static_cast<FoldingSetNode*>(*Bucket); +} + +void FoldingSetIteratorImpl::advance() { + // If there is another link within this bucket, go to it. + void *Probe = NodePtr->getNextInBucket(); + + if (FoldingSetNode *NextNodeInBucket = GetNextPtr(Probe)) + NodePtr = NextNodeInBucket; + else { + // Otherwise, this is the last link in this bucket. + void **Bucket = GetBucketPtr(Probe); + + // Skip to the next non-null non-self-cycle bucket. + do { + ++Bucket; + } while (*Bucket != reinterpret_cast<void*>(-1) && + (*Bucket == 0 || GetNextPtr(*Bucket) == 0)); + + NodePtr = static_cast<FoldingSetNode*>(*Bucket); + } +} + +//===----------------------------------------------------------------------===// +// FoldingSetBucketIteratorImpl Implementation + +FoldingSetBucketIteratorImpl::FoldingSetBucketIteratorImpl(void **Bucket) { + Ptr = (*Bucket == 0 || GetNextPtr(*Bucket) == 0) ? (void*) Bucket : *Bucket; +} diff --git a/contrib/llvm/lib/Support/FormattedStream.cpp b/contrib/llvm/lib/Support/FormattedStream.cpp new file mode 100644 index 0000000..231ae48 --- /dev/null +++ b/contrib/llvm/lib/Support/FormattedStream.cpp @@ -0,0 +1,101 @@ +//===-- llvm/Support/FormattedStream.cpp - Formatted streams ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the implementation of formatted_raw_ostream. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Debug.h" +#include "llvm/Support/FormattedStream.h" +#include <algorithm> + +using namespace llvm; + +/// CountColumns - Examine the given char sequence and figure out which +/// column we end up in after output. +/// +static unsigned CountColumns(unsigned Column, const char *Ptr, size_t Size) { + // Keep track of the current column by scanning the string for + // special characters + + for (const char *End = Ptr + Size; Ptr != End; ++Ptr) { + ++Column; + if (*Ptr == '\n' || *Ptr == '\r') + Column = 0; + else if (*Ptr == '\t') + // Assumes tab stop = 8 characters. + Column += (8 - (Column & 0x7)) & 0x7; + } + + return Column; +} + +/// ComputeColumn - Examine the current output and figure out which +/// column we end up in after output. +void formatted_raw_ostream::ComputeColumn(const char *Ptr, size_t Size) { + // If our previous scan pointer is inside the buffer, assume we already + // scanned those bytes. This depends on raw_ostream to not change our buffer + // in unexpected ways. + if (Ptr <= Scanned && Scanned <= Ptr + Size) { + // Scan all characters added since our last scan to determine the new + // column. + ColumnScanned = CountColumns(ColumnScanned, Scanned, + Size - (Scanned - Ptr)); + } else + ColumnScanned = CountColumns(ColumnScanned, Ptr, Size); + + // Update the scanning pointer. + Scanned = Ptr + Size; +} + +/// PadToColumn - Align the output to some column number. +/// +/// \param NewCol - The column to move to. +/// +formatted_raw_ostream &formatted_raw_ostream::PadToColumn(unsigned NewCol) { + // Figure out what's in the buffer and add it to the column count. + ComputeColumn(getBufferStart(), GetNumBytesInBuffer()); + + // Output spaces until we reach the desired column. + indent(std::max(int(NewCol - ColumnScanned), 1)); + return *this; +} + +void formatted_raw_ostream::write_impl(const char *Ptr, size_t Size) { + // Figure out what's in the buffer and add it to the column count. + ComputeColumn(Ptr, Size); + + // Write the data to the underlying stream (which is unbuffered, so + // the data will be immediately written out). + TheStream->write(Ptr, Size); + + // Reset the scanning pointer. + Scanned = 0; +} + +/// fouts() - This returns a reference to a formatted_raw_ostream for +/// standard output. Use it like: fouts() << "foo" << "bar"; +formatted_raw_ostream &llvm::fouts() { + static formatted_raw_ostream S(outs()); + return S; +} + +/// ferrs() - This returns a reference to a formatted_raw_ostream for +/// standard error. Use it like: ferrs() << "foo" << "bar"; +formatted_raw_ostream &llvm::ferrs() { + static formatted_raw_ostream S(errs()); + return S; +} + +/// fdbgs() - This returns a reference to a formatted_raw_ostream for +/// the debug stream. Use it like: fdbgs() << "foo" << "bar"; +formatted_raw_ostream &llvm::fdbgs() { + static formatted_raw_ostream S(dbgs()); + return S; +} diff --git a/contrib/llvm/lib/Support/GraphWriter.cpp b/contrib/llvm/lib/Support/GraphWriter.cpp new file mode 100644 index 0000000..32126ec --- /dev/null +++ b/contrib/llvm/lib/Support/GraphWriter.cpp @@ -0,0 +1,199 @@ +//===-- GraphWriter.cpp - Implements GraphWriter support routines ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements misc. GraphWriter support routines. +// +//===----------------------------------------------------------------------===// + +#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) + switch (Str[i]) { + case '\n': + Str.insert(Str.begin()+i, '\\'); // Escape character... + ++i; + Str[i] = 'n'; + break; + case '\t': + Str.insert(Str.begin()+i, ' '); // Convert to two spaces + ++i; + Str[i] = ' '; + break; + case '\\': + if (i+1 != Str.length()) + switch (Str[i+1]) { + case 'l': continue; // don't disturb \l + case '|': case '{': case '}': + Str.erase(Str.begin()+i); continue; + default: break; + } + case '{': case '}': + case '<': case '>': + case '|': case '"': + Str.insert(Str.begin()+i, '\\'); // Escape character... + ++i; // don't infinite loop + break; + } + 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); + + std::vector<const char*> args; + args.push_back(Graphviz.c_str()); + args.push_back(Filename.c_str()); + args.push_back(0); + + errs() << "Running 'Graphviz' program... "; + if (!ExecGraphViewer(Graphviz, args, Filename, wait, ErrMsg)) + return; + +#elif HAVE_XDOT_PY + std::vector<const char*> args; + args.push_back(LLVM_PATH_XDOT_PY); + args.push_back(Filename.c_str()); + + switch (program) { + case GraphProgram::DOT: args.push_back("-f"); args.push_back("dot"); break; + case GraphProgram::FDP: args.push_back("-f"); args.push_back("fdp"); break; + case GraphProgram::NEATO: args.push_back("-f"); args.push_back("neato");break; + case GraphProgram::TWOPI: args.push_back("-f"); args.push_back("twopi");break; + 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 (!ExecGraphViewer(sys::Path(LLVM_PATH_XDOT_PY), args, Filename, wait, ErrMsg)) + return; + +#elif (HAVE_GV && (HAVE_DOT || HAVE_FDP || HAVE_NEATO || \ + HAVE_TWOPI || HAVE_CIRCO)) + sys::Path PSFilename = Filename; + PSFilename.appendSuffix("ps"); + + sys::Path prog; + + // Set default grapher +#if HAVE_CIRCO + prog = sys::Path(LLVM_PATH_CIRCO); +#endif +#if HAVE_TWOPI + prog = sys::Path(LLVM_PATH_TWOPI); +#endif +#if HAVE_NEATO + prog = sys::Path(LLVM_PATH_NEATO); +#endif +#if HAVE_FDP + prog = sys::Path(LLVM_PATH_FDP); +#endif +#if HAVE_DOT + prog = sys::Path(LLVM_PATH_DOT); +#endif + + // Find which program the user wants +#if HAVE_DOT + if (program == GraphProgram::DOT) + prog = sys::Path(LLVM_PATH_DOT); +#endif +#if (HAVE_FDP) + if (program == GraphProgram::FDP) + prog = sys::Path(LLVM_PATH_FDP); +#endif +#if (HAVE_NEATO) + if (program == GraphProgram::NEATO) + prog = sys::Path(LLVM_PATH_NEATO); +#endif +#if (HAVE_TWOPI) + if (program == GraphProgram::TWOPI) + prog = sys::Path(LLVM_PATH_TWOPI); +#endif +#if (HAVE_CIRCO) + if (program == GraphProgram::CIRCO) + prog = sys::Path(LLVM_PATH_CIRCO); +#endif + + std::vector<const char*> args; + args.push_back(prog.c_str()); + args.push_back("-Tps"); + args.push_back("-Nfontname=Courier"); + args.push_back("-Gsize=7.5,10"); + args.push_back(Filename.c_str()); + args.push_back("-o"); + args.push_back(PSFilename.c_str()); + args.push_back(0); + + errs() << "Running '" << prog.str() << "' program... "; + + if (!ExecGraphViewer(prog, args, Filename, wait, ErrMsg)) + return; + + sys::Path gv(LLVM_PATH_GV); + args.clear(); + args.push_back(gv.c_str()); + args.push_back(PSFilename.c_str()); + args.push_back("--spartan"); + args.push_back(0); + + ErrMsg.clear(); + if (!ExecGraphViewer(gv, args, PSFilename, wait, ErrMsg)) + return; + +#elif HAVE_DOTTY + sys::Path dotty(LLVM_PATH_DOTTY); + + std::vector<const char*> args; + args.push_back(dotty.c_str()); + args.push_back(Filename.c_str()); + args.push_back(0); + +// Dotty spawns another app and doesn't wait until it returns +#if defined (__MINGW32__) || defined (_WINDOWS) + wait = false; +#endif + errs() << "Running 'dotty' program... "; + if (!ExecGraphViewer(dotty, args, Filename, wait, ErrMsg)) + return; +#endif +} diff --git a/contrib/llvm/lib/Support/Hashing.cpp b/contrib/llvm/lib/Support/Hashing.cpp new file mode 100644 index 0000000..c69efb7 --- /dev/null +++ b/contrib/llvm/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/contrib/llvm/lib/Support/Host.cpp b/contrib/llvm/lib/Support/Host.cpp new file mode 100644 index 0000000..0f06964 --- /dev/null +++ b/contrib/llvm/lib/Support/Host.cpp @@ -0,0 +1,326 @@ +//===-- Host.cpp - Implement OS Host Concept --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system Host concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Host.h" +#include "llvm/Config/config.h" +#include <string.h> + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Host.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Host.inc" +#endif +#ifdef _MSC_VER +#include <intrin.h> +#endif + +//===----------------------------------------------------------------------===// +// +// Implementations of the CPU detection routines +// +//===----------------------------------------------------------------------===// + +using namespace llvm; + +#if defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86)\ + || defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) + +/// GetX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in the +/// specified arguments. If we can't run cpuid on the host, return true. +static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, + unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { +#if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) + #if defined(__GNUC__) + // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. + asm ("movq\t%%rbx, %%rsi\n\t" + "cpuid\n\t" + "xchgq\t%%rbx, %%rsi\n\t" + : "=a" (*rEAX), + "=S" (*rEBX), + "=c" (*rECX), + "=d" (*rEDX) + : "a" (value)); + return false; + #elif defined(_MSC_VER) + int registers[4]; + __cpuid(registers, value); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; + return false; + #else + return true; + #endif +#elif defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86) + #if defined(__GNUC__) + asm ("movl\t%%ebx, %%esi\n\t" + "cpuid\n\t" + "xchgl\t%%ebx, %%esi\n\t" + : "=a" (*rEAX), + "=S" (*rEBX), + "=c" (*rECX), + "=d" (*rEDX) + : "a" (value)); + return false; + #elif defined(_MSC_VER) + __asm { + mov eax,value + cpuid + mov esi,rEAX + mov dword ptr [esi],eax + mov esi,rEBX + mov dword ptr [esi],ebx + mov esi,rECX + mov dword ptr [esi],ecx + mov esi,rEDX + 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 +#else + return true; +#endif +} + +static void DetectX86FamilyModel(unsigned EAX, unsigned &Family, + unsigned &Model) { + Family = (EAX >> 8) & 0xf; // Bits 8 - 11 + Model = (EAX >> 4) & 0xf; // Bits 4 - 7 + if (Family == 6 || Family == 0xf) { + if (Family == 0xf) + // Examine extended family ID if family ID is F. + Family += (EAX >> 20) & 0xff; // Bits 20 - 27 + // Examine extended model ID if family ID is 6 or F. + Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 + } +} + +std::string sys::getHostCPUName() { + unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; + if (GetX86CpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX)) + return "generic"; + unsigned Family = 0; + unsigned Model = 0; + DetectX86FamilyModel(EAX, Family, Model); + + bool HasSSE3 = (ECX & 0x1); + GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + bool Em64T = (EDX >> 29) & 0x1; + + union { + unsigned u[3]; + char c[12]; + } text; + + GetX86CpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1); + if (memcmp(text.c, "GenuineIntel", 12) == 0) { + switch (Family) { + case 3: + return "i386"; + case 4: + switch (Model) { + case 0: // Intel486 DX processors + case 1: // Intel486 DX processors + case 2: // Intel486 SX processors + case 3: // Intel487 processors, IntelDX2 OverDrive processors, + // IntelDX2 processors + case 4: // Intel486 SL processor + case 5: // IntelSX2 processors + case 7: // Write-Back Enhanced IntelDX2 processors + case 8: // IntelDX4 OverDrive processors, IntelDX4 processors + default: return "i486"; + } + case 5: + switch (Model) { + case 1: // Pentium OverDrive processor for Pentium processor (60, 66), + // Pentium processors (60, 66) + case 2: // Pentium OverDrive processor for Pentium processor (75, 90, + // 100, 120, 133), Pentium processors (75, 90, 100, 120, 133, + // 150, 166, 200) + case 3: // Pentium OverDrive processors for Intel486 processor-based + // systems + return "pentium"; + + case 4: // Pentium OverDrive processor with MMX technology for Pentium + // processor (75, 90, 100, 120, 133), Pentium processor with + // MMX technology (166, 200) + return "pentium-mmx"; + + default: return "pentium"; + } + case 6: + switch (Model) { + case 1: // Pentium Pro processor + return "pentiumpro"; + + case 3: // Intel Pentium II OverDrive processor, Pentium II processor, + // model 03 + case 5: // Pentium II processor, model 05, Pentium II Xeon processor, + // model 05, and Intel Celeron processor, model 05 + case 6: // Celeron processor, model 06 + return "pentium2"; + + case 7: // Pentium III processor, model 07, and Pentium III Xeon + // processor, model 07 + case 8: // Pentium III processor, model 08, Pentium III Xeon processor, + // model 08, and Celeron processor, model 08 + case 10: // Pentium III Xeon processor, model 0Ah + case 11: // Pentium III processor, model 0Bh + return "pentium3"; + + case 9: // Intel Pentium M processor, Intel Celeron M processor model 09. + case 13: // Intel Pentium M processor, Intel Celeron M processor, model + // 0Dh. All processors are manufactured using the 90 nm process. + return "pentium-m"; + + case 14: // Intel Core Duo processor, Intel Core Solo processor, model + // 0Eh. All processors are manufactured using the 65 nm process. + return "yonah"; + + case 15: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile + // processor, Intel Core 2 Quad processor, Intel Core 2 Quad + // mobile processor, Intel Core 2 Extreme processor, Intel + // Pentium Dual-Core processor, Intel Xeon processor, model + // 0Fh. All processors are manufactured using the 65 nm process. + case 22: // Intel Celeron processor model 16h. All processors are + // manufactured using the 65 nm process + return "core2"; + + case 21: // Intel EP80579 Integrated Processor and Intel EP80579 + // Integrated Processor with Intel QuickAssist Technology + return "i686"; // FIXME: ??? + + case 23: // Intel Core 2 Extreme processor, Intel Xeon processor, model + // 17h. All processors are manufactured using the 45 nm process. + // + // 45nm: Penryn , Wolfdale, Yorkfield (XE) + return "penryn"; + + case 26: // Intel Core i7 processor and Intel Xeon processor. All + // processors are manufactured using the 45 nm process. + case 29: // Intel Xeon processor MP. All processors are manufactured using + // the 45 nm process. + case 30: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. + // As found in a Summer 2010 model iMac. + case 37: // Intel Core i7, laptop version. + case 44: // Intel Core i7 processor and Intel Xeon processor. All + // processors are manufactured using the 32 nm process. + return "corei7"; + + // SandyBridge: + case 42: // Intel Core i7 processor. All processors are manufactured + // using the 32 nm process. + case 45: + return "corei7-avx"; + + case 28: // Intel Atom processor. All processors are manufactured using + // the 45 nm process + return "atom"; + + default: return "i686"; + } + case 15: { + switch (Model) { + case 0: // Pentium 4 processor, Intel Xeon processor. All processors are + // model 00h and manufactured using the 0.18 micron process. + case 1: // Pentium 4 processor, Intel Xeon processor, Intel Xeon + // processor MP, and Intel Celeron processor. All processors are + // model 01h and manufactured using the 0.18 micron process. + case 2: // Pentium 4 processor, Mobile Intel Pentium 4 processor - M, + // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron + // processor, and Mobile Intel Celeron processor. All processors + // are model 02h and manufactured using the 0.13 micron process. + return (Em64T) ? "x86-64" : "pentium4"; + + case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D + // processor. All processors are model 03h and manufactured using + // the 90 nm process. + case 4: // Pentium 4 processor, Pentium 4 processor Extreme Edition, + // Pentium D processor, Intel Xeon processor, Intel Xeon + // processor MP, Intel Celeron D processor. All processors are + // model 04h and manufactured using the 90 nm process. + case 6: // Pentium 4 processor, Pentium D processor, Pentium processor + // Extreme Edition, Intel Xeon processor, Intel Xeon processor + // MP, Intel Celeron D processor. All processors are model 06h + // and manufactured using the 65 nm process. + return (Em64T) ? "nocona" : "prescott"; + + default: + return (Em64T) ? "x86-64" : "pentium4"; + } + } + + default: + return "generic"; + } + } else if (memcmp(text.c, "AuthenticAMD", 12) == 0) { + // FIXME: this poorly matches the generated SubtargetFeatureKV table. There + // appears to be no way to generate the wide variety of AMD-specific targets + // from the information returned from CPUID. + switch (Family) { + case 4: + return "i486"; + case 5: + switch (Model) { + case 6: + case 7: return "k6"; + case 8: return "k6-2"; + case 9: + case 13: return "k6-3"; + default: return "pentium"; + } + case 6: + switch (Model) { + case 4: return "athlon-tbird"; + case 6: + case 7: + case 8: return "athlon-mp"; + case 10: return "athlon-xp"; + default: return "athlon"; + } + case 15: + if (HasSSE3) + return "k8-sse3"; + switch (Model) { + case 1: return "opteron"; + case 5: return "athlon-fx"; // also opteron + default: return "athlon64"; + } + case 16: + return "amdfam10"; + case 20: + return "btver1"; + case 21: + return "bdver1"; + default: + return "generic"; + } + } + return "generic"; +} +#else +std::string sys::getHostCPUName() { + return "generic"; +} +#endif + +bool sys::getHostCPUFeatures(StringMap<bool> &Features){ + return false; +} diff --git a/contrib/llvm/lib/Support/IncludeFile.cpp b/contrib/llvm/lib/Support/IncludeFile.cpp new file mode 100644 index 0000000..e67acb3 --- /dev/null +++ b/contrib/llvm/lib/Support/IncludeFile.cpp @@ -0,0 +1,20 @@ +//===- lib/Support/IncludeFile.cpp - Ensure Linking Of Implementation -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the IncludeFile constructor. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/IncludeFile.h" + +using namespace llvm; + +// This constructor is used to ensure linking of other modules. See the +// llvm/Support/IncludeFile.h header for details. +IncludeFile::IncludeFile(const void*) {} diff --git a/contrib/llvm/lib/Support/IntEqClasses.cpp b/contrib/llvm/lib/Support/IntEqClasses.cpp new file mode 100644 index 0000000..1134495 --- /dev/null +++ b/contrib/llvm/lib/Support/IntEqClasses.cpp @@ -0,0 +1,70 @@ +//===-- llvm/ADT/IntEqClasses.cpp - Equivalence Classes of Integers -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Equivalence classes for small integers. This is a mapping of the integers +// 0 .. N-1 into M equivalence classes numbered 0 .. M-1. +// +// Initially each integer has its own equivalence class. Classes are joined by +// passing a representative member of each class to join(). +// +// Once the classes are built, compress() will number them 0 .. M-1 and prevent +// further changes. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/IntEqClasses.h" + +using namespace llvm; + +void IntEqClasses::grow(unsigned N) { + assert(NumClasses == 0 && "grow() called after compress()."); + EC.reserve(N); + while (EC.size() < N) + EC.push_back(EC.size()); +} + +void IntEqClasses::join(unsigned a, unsigned b) { + assert(NumClasses == 0 && "join() called after compress()."); + unsigned eca = EC[a]; + unsigned ecb = EC[b]; + // Update pointers while searching for the leaders, compressing the paths + // incrementally. The larger leader will eventually be updated, joining the + // classes. + while (eca != ecb) + if (eca < ecb) + EC[b] = eca, b = ecb, ecb = EC[b]; + else + EC[a] = ecb, a = eca, eca = EC[a]; +} + +unsigned IntEqClasses::findLeader(unsigned a) const { + assert(NumClasses == 0 && "findLeader() called after compress()."); + while (a != EC[a]) + a = EC[a]; + return a; +} + +void IntEqClasses::compress() { + if (NumClasses) + return; + for (unsigned i = 0, e = EC.size(); i != e; ++i) + EC[i] = (EC[i] == i) ? NumClasses++ : EC[EC[i]]; +} + +void IntEqClasses::uncompress() { + if (!NumClasses) + return; + SmallVector<unsigned, 8> Leader; + for (unsigned i = 0, e = EC.size(); i != e; ++i) + if (EC[i] < Leader.size()) + EC[i] = Leader[EC[i]]; + else + Leader.push_back(EC[i] = i); + NumClasses = 0; +} diff --git a/contrib/llvm/lib/Support/IntervalMap.cpp b/contrib/llvm/lib/Support/IntervalMap.cpp new file mode 100644 index 0000000..4dfcc40 --- /dev/null +++ b/contrib/llvm/lib/Support/IntervalMap.cpp @@ -0,0 +1,161 @@ +//===- lib/Support/IntervalMap.cpp - A sorted interval map ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the few non-templated functions in IntervalMap. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/IntervalMap.h" + +namespace llvm { +namespace IntervalMapImpl { + +void Path::replaceRoot(void *Root, unsigned Size, IdxPair Offsets) { + assert(!path.empty() && "Can't replace missing root"); + path.front() = Entry(Root, Size, Offsets.first); + path.insert(path.begin() + 1, Entry(subtree(0), Offsets.second)); +} + +NodeRef Path::getLeftSibling(unsigned Level) const { + // The root has no siblings. + if (Level == 0) + return NodeRef(); + + // Go up the tree until we can go left. + unsigned l = Level - 1; + while (l && path[l].offset == 0) + --l; + + // We can't go left. + if (path[l].offset == 0) + return NodeRef(); + + // NR is the subtree containing our left sibling. + NodeRef NR = path[l].subtree(path[l].offset - 1); + + // Keep right all the way down. + for (++l; l != Level; ++l) + NR = NR.subtree(NR.size() - 1); + return NR; +} + +void Path::moveLeft(unsigned Level) { + assert(Level != 0 && "Cannot move the root node"); + + // Go up the tree until we can go left. + unsigned l = 0; + if (valid()) { + l = Level - 1; + while (path[l].offset == 0) { + assert(l != 0 && "Cannot move beyond begin()"); + --l; + } + } else if (height() < Level) + // end() may have created a height=0 path. + path.resize(Level + 1, Entry(0, 0, 0)); + + // NR is the subtree containing our left sibling. + --path[l].offset; + NodeRef NR = subtree(l); + + // Get the rightmost node in the subtree. + for (++l; l != Level; ++l) { + path[l] = Entry(NR, NR.size() - 1); + NR = NR.subtree(NR.size() - 1); + } + path[l] = Entry(NR, NR.size() - 1); +} + +NodeRef Path::getRightSibling(unsigned Level) const { + // The root has no siblings. + if (Level == 0) + return NodeRef(); + + // Go up the tree until we can go right. + unsigned l = Level - 1; + while (l && atLastEntry(l)) + --l; + + // We can't go right. + if (atLastEntry(l)) + return NodeRef(); + + // NR is the subtree containing our right sibling. + NodeRef NR = path[l].subtree(path[l].offset + 1); + + // Keep left all the way down. + for (++l; l != Level; ++l) + NR = NR.subtree(0); + return NR; +} + +void Path::moveRight(unsigned Level) { + assert(Level != 0 && "Cannot move the root node"); + + // Go up the tree until we can go right. + unsigned l = Level - 1; + while (l && atLastEntry(l)) + --l; + + // NR is the subtree containing our right sibling. If we hit end(), we have + // offset(0) == node(0).size(). + if (++path[l].offset == path[l].size) + return; + NodeRef NR = subtree(l); + + for (++l; l != Level; ++l) { + path[l] = Entry(NR, 0); + NR = NR.subtree(0); + } + path[l] = Entry(NR, 0); +} + + +IdxPair distribute(unsigned Nodes, unsigned Elements, unsigned Capacity, + const unsigned *CurSize, unsigned NewSize[], + unsigned Position, bool Grow) { + assert(Elements + Grow <= Nodes * Capacity && "Not enough room for elements"); + assert(Position <= Elements && "Invalid position"); + if (!Nodes) + return IdxPair(); + + // Trivial algorithm: left-leaning even distribution. + const unsigned PerNode = (Elements + Grow) / Nodes; + const unsigned Extra = (Elements + Grow) % Nodes; + IdxPair PosPair = IdxPair(Nodes, 0); + unsigned Sum = 0; + for (unsigned n = 0; n != Nodes; ++n) { + Sum += NewSize[n] = PerNode + (n < Extra); + if (PosPair.first == Nodes && Sum > Position) + PosPair = IdxPair(n, Position - (Sum - NewSize[n])); + } + assert(Sum == Elements + Grow && "Bad distribution sum"); + + // Subtract the Grow element that was added. + if (Grow) { + assert(PosPair.first < Nodes && "Bad algebra"); + assert(NewSize[PosPair.first] && "Too few elements to need Grow"); + --NewSize[PosPair.first]; + } + +#ifndef NDEBUG + Sum = 0; + for (unsigned n = 0; n != Nodes; ++n) { + assert(NewSize[n] <= Capacity && "Overallocated node"); + Sum += NewSize[n]; + } + assert(Sum == Elements && "Bad distribution sum"); +#endif + + return PosPair; +} + +} // namespace IntervalMapImpl +} // namespace llvm + diff --git a/contrib/llvm/lib/Support/IntrusiveRefCntPtr.cpp b/contrib/llvm/lib/Support/IntrusiveRefCntPtr.cpp new file mode 100644 index 0000000..a8b4559 --- /dev/null +++ b/contrib/llvm/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/contrib/llvm/lib/Support/IsInf.cpp b/contrib/llvm/lib/Support/IsInf.cpp new file mode 100644 index 0000000..d6da0c9 --- /dev/null +++ b/contrib/llvm/lib/Support/IsInf.cpp @@ -0,0 +1,49 @@ +//===-- IsInf.cpp - Platform-independent wrapper around C99 isinf() -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Platform-independent wrapper around C99 isinf() +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" + +#if HAVE_ISINF_IN_MATH_H +# include <math.h> +#elif HAVE_ISINF_IN_CMATH +# include <cmath> +#elif HAVE_STD_ISINF_IN_CMATH +# include <cmath> +using std::isinf; +#elif HAVE_FINITE_IN_IEEEFP_H +// A handy workaround I found at http://www.unixguide.net/sun/faq ... +// apparently this has been a problem with Solaris for years. +# include <ieeefp.h> +static int isinf(double x) { return !finite(x) && x==x; } +#elif defined(_MSC_VER) +#include <float.h> +#define isinf(X) (!_finite(X)) +#elif defined(_AIX) && defined(__GNUC__) +// GCC's fixincludes seems to be removing the isinf() declaration from the +// system header /usr/include/math.h +# include <math.h> +static int isinf(double x) { return !finite(x) && x==x; } +#elif defined(__hpux) +// HP-UX is "special" +#include <math.h> +static int isinf(double x) { return ((x) == INFINITY) || ((x) == -INFINITY); } +#else +# error "Don't know how to get isinf()" +#endif + +namespace llvm { + +int IsInf(float f) { return isinf(f); } +int IsInf(double d) { return isinf(d); } + +} // end namespace llvm; diff --git a/contrib/llvm/lib/Support/IsNAN.cpp b/contrib/llvm/lib/Support/IsNAN.cpp new file mode 100644 index 0000000..bdfdfbf --- /dev/null +++ b/contrib/llvm/lib/Support/IsNAN.cpp @@ -0,0 +1,33 @@ +//===-- IsNAN.cpp ---------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Platform-independent wrapper around C99 isnan(). +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" + +#if HAVE_ISNAN_IN_MATH_H +# include <math.h> +#elif HAVE_ISNAN_IN_CMATH +# include <cmath> +#elif HAVE_STD_ISNAN_IN_CMATH +# include <cmath> +using std::isnan; +#elif defined(_MSC_VER) +#include <float.h> +#define isnan _isnan +#else +# error "Don't know how to get isnan()" +#endif + +namespace llvm { + int IsNAN(float f) { return isnan(f); } + int IsNAN(double d) { return isnan(d); } +} // end namespace llvm; diff --git a/contrib/llvm/lib/Support/JSONParser.cpp b/contrib/llvm/lib/Support/JSONParser.cpp new file mode 100644 index 0000000..5dfcf29 --- /dev/null +++ b/contrib/llvm/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/contrib/llvm/lib/Support/LockFileManager.cpp b/contrib/llvm/lib/Support/LockFileManager.cpp new file mode 100644 index 0000000..64404a1 --- /dev/null +++ b/contrib/llvm/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/contrib/llvm/lib/Support/ManagedStatic.cpp b/contrib/llvm/lib/Support/ManagedStatic.cpp new file mode 100644 index 0000000..098cccb --- /dev/null +++ b/contrib/llvm/lib/Support/ManagedStatic.cpp @@ -0,0 +1,81 @@ +//===-- ManagedStatic.cpp - Static Global wrapper -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the ManagedStatic class and llvm_shutdown(). +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Config/config.h" +#include "llvm/Support/Atomic.h" +#include <cassert> +using namespace llvm; + +static const ManagedStaticBase *StaticList = 0; + +void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(), + void (*Deleter)(void*)) const { + if (llvm_is_multithreaded()) { + llvm_acquire_global_lock(); + + 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. + Next = StaticList; + StaticList = this; + } + + llvm_release_global_lock(); + } else { + assert(Ptr == 0 && DeleterFn == 0 && Next == 0 && + "Partially initialized ManagedStatic!?"); + Ptr = Creator ? Creator() : 0; + DeleterFn = Deleter; + + // Add to list of managed statics. + Next = StaticList; + StaticList = this; + } +} + +void ManagedStaticBase::destroy() const { + assert(DeleterFn && "ManagedStatic not initialized correctly!"); + assert(StaticList == this && + "Not destroyed in reverse order of construction?"); + // Unlink from list. + StaticList = Next; + Next = 0; + + // Destroy memory. + DeleterFn(Ptr); + + // Cleanup. + Ptr = 0; + DeleterFn = 0; +} + +/// llvm_shutdown - Deallocate and destroy all ManagedStatic variables. +void llvm::llvm_shutdown() { + while (StaticList) + StaticList->destroy(); + + if (llvm_is_multithreaded()) llvm_stop_multithreaded(); +} diff --git a/contrib/llvm/lib/Support/Memory.cpp b/contrib/llvm/lib/Support/Memory.cpp new file mode 100644 index 0000000..ceaaa99 --- /dev/null +++ b/contrib/llvm/lib/Support/Memory.cpp @@ -0,0 +1,80 @@ +//===- Memory.cpp - Memory Handling Support ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some helpful functions for allocating memory and dealing +// with memory mapped files +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Memory.h" +#include "llvm/Support/Valgrind.h" +#include "llvm/Config/config.h" + +#if defined(__mips__) +#include <sys/cachectl.h> +#endif + +namespace llvm { +using namespace sys; +} + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Memory.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Memory.inc" +#endif + +extern "C" void sys_icache_invalidate(const void *Addr, size_t len); + +/// InvalidateInstructionCache - Before the JIT can run a block of code +/// that has been emitted it must invalidate the instruction cache on some +/// platforms. +void llvm::sys::Memory::InvalidateInstructionCache(const void *Addr, + size_t Len) { + +// icache invalidation for PPC and ARM. +#if defined(__APPLE__) + +# if (defined(__POWERPC__) || defined (__ppc__) || \ + defined(_POWER) || defined(_ARCH_PPC)) || defined(__arm__) + sys_icache_invalidate(Addr, Len); +# endif + +#else + +# if (defined(__POWERPC__) || defined (__ppc__) || \ + defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__) + const size_t LineSize = 32; + + const intptr_t Mask = ~(LineSize - 1); + const intptr_t StartLine = ((intptr_t) Addr) & Mask; + const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask; + + for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) + asm volatile("dcbf 0, %0" : : "r"(Line)); + asm volatile("sync"); + + for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) + asm volatile("icbi 0, %0" : : "r"(Line)); + asm volatile("isync"); +# elif defined(__arm__) && defined(__GNUC__) && !defined(__FreeBSD__) + // FIXME: Can we safely always call this for __GNUC__ everywhere? + char *Start = (char*) Addr; + char *End = Start + Len; + __clear_cache(Start, End); +# elif defined(__mips__) + cacheflush((char*)Addr, Len, BCACHE); +# endif + +#endif // end apple + + ValgrindDiscardTranslations(Addr, Len); +} diff --git a/contrib/llvm/lib/Support/MemoryBuffer.cpp b/contrib/llvm/lib/Support/MemoryBuffer.cpp new file mode 100644 index 0000000..16e5c7a --- /dev/null +++ b/contrib/llvm/lib/Support/MemoryBuffer.cpp @@ -0,0 +1,390 @@ +//===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the MemoryBuffer interface. +// +//===----------------------------------------------------------------------===// + +#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" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/system_error.h" +#include <cassert> +#include <cstdio> +#include <cstring> +#include <cerrno> +#include <new> +#include <sys/types.h> +#include <sys/stat.h> +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include <unistd.h> +#else +#include <io.h> +#endif +#include <fcntl.h> +using namespace llvm; + +//===----------------------------------------------------------------------===// +// MemoryBuffer implementation itself. +//===----------------------------------------------------------------------===// + +MemoryBuffer::~MemoryBuffer() { } + +/// init - Initialize this MemoryBuffer as a reference to externally allocated +/// memory, memory that we know is already null terminated. +void MemoryBuffer::init(const char *BufStart, const char *BufEnd, + bool RequiresNullTerminator) { + assert((!RequiresNullTerminator || BufEnd[0] == 0) && + "Buffer is not null terminated!"); + BufferStart = BufStart; + BufferEnd = BufEnd; +} + +//===----------------------------------------------------------------------===// +// MemoryBufferMem implementation. +//===----------------------------------------------------------------------===// + +/// CopyStringRef - Copies contents of a StringRef into a block of memory and +/// null-terminates it. +static void CopyStringRef(char *Memory, StringRef Data) { + memcpy(Memory, Data.data(), Data.size()); + Memory[Data.size()] = 0; // Null terminate string. +} + +/// GetNamedBuffer - Allocates a new MemoryBuffer with Name copied after it. +template <typename T> +static T *GetNamedBuffer(StringRef Buffer, StringRef Name, + bool RequiresNullTerminator) { + char *Mem = static_cast<char*>(operator new(sizeof(T) + Name.size() + 1)); + CopyStringRef(Mem + sizeof(T), Name); + return new (Mem) T(Buffer, RequiresNullTerminator); +} + +namespace { +/// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory. +class MemoryBufferMem : public MemoryBuffer { +public: + MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) { + init(InputData.begin(), InputData.end(), RequiresNullTerminator); + } + + virtual const char *getBufferIdentifier() const { + // The name is stored after the class itself. + return reinterpret_cast<const char*>(this + 1); + } + + virtual BufferKind getBufferKind() const { + return MemoryBuffer_Malloc; + } +}; +} + +/// getMemBuffer - Open the specified memory range as a MemoryBuffer. Note +/// that InputData must be a null terminated if RequiresNullTerminator is true! +MemoryBuffer *MemoryBuffer::getMemBuffer(StringRef InputData, + StringRef BufferName, + bool RequiresNullTerminator) { + return GetNamedBuffer<MemoryBufferMem>(InputData, BufferName, + RequiresNullTerminator); +} + +/// getMemBufferCopy - Open the specified memory range as a MemoryBuffer, +/// copying the contents and taking ownership of it. This has no requirements +/// on EndPtr[0]. +MemoryBuffer *MemoryBuffer::getMemBufferCopy(StringRef InputData, + StringRef BufferName) { + MemoryBuffer *Buf = getNewUninitMemBuffer(InputData.size(), BufferName); + if (!Buf) return 0; + memcpy(const_cast<char*>(Buf->getBufferStart()), InputData.data(), + InputData.size()); + return Buf; +} + +/// getNewUninitMemBuffer - Allocate a new MemoryBuffer of the specified size +/// that is not initialized. Note that the caller should initialize the +/// memory allocated by this method. The memory is owned by the MemoryBuffer +/// object. +MemoryBuffer *MemoryBuffer::getNewUninitMemBuffer(size_t Size, + StringRef BufferName) { + // Allocate space for the MemoryBuffer, the data and the name. It is important + // that MemoryBuffer and data are aligned so PointerIntPair works with them. + size_t AlignedStringLen = + RoundUpToAlignment(sizeof(MemoryBufferMem) + BufferName.size() + 1, + sizeof(void*)); // TODO: Is sizeof(void*) enough? + size_t RealLen = AlignedStringLen + Size + 1; + char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow)); + if (!Mem) return 0; + + // The name is stored after the class itself. + CopyStringRef(Mem + sizeof(MemoryBufferMem), BufferName); + + // The buffer begins after the name and must be aligned. + char *Buf = Mem + AlignedStringLen; + Buf[Size] = 0; // Null terminate buffer. + + return new (Mem) MemoryBufferMem(StringRef(Buf, Size), true); +} + +/// getNewMemBuffer - Allocate a new MemoryBuffer of the specified size that +/// is completely initialized to zeros. Note that the caller should +/// initialize the memory allocated by this method. The memory is owned by +/// the MemoryBuffer object. +MemoryBuffer *MemoryBuffer::getNewMemBuffer(size_t Size, StringRef BufferName) { + MemoryBuffer *SB = getNewUninitMemBuffer(Size, BufferName); + if (!SB) return 0; + memset(const_cast<char*>(SB->getBufferStart()), 0, Size); + return SB; +} + + +/// getFileOrSTDIN - Open the specified file as a MemoryBuffer, or open stdin +/// if the Filename is "-". If an error occurs, this returns null and fills +/// in *ErrStr with a reason. If stdin is empty, this API (unlike getSTDIN) +/// returns an empty buffer. +error_code MemoryBuffer::getFileOrSTDIN(StringRef Filename, + OwningPtr<MemoryBuffer> &result, + int64_t FileSize) { + if (Filename == "-") + return getSTDIN(result); + return getFile(Filename, result, FileSize); +} + +error_code MemoryBuffer::getFileOrSTDIN(const char *Filename, + OwningPtr<MemoryBuffer> &result, + int64_t FileSize) { + if (strcmp(Filename, "-") == 0) + return getSTDIN(result); + return getFile(Filename, result, FileSize); +} + +//===----------------------------------------------------------------------===// +// MemoryBuffer::getFile implementation. +//===----------------------------------------------------------------------===// + +namespace { +/// MemoryBufferMMapFile - This represents a file that was mapped in with the +/// sys::Path::MapInFilePages method. When destroyed, it calls the +/// sys::Path::UnMapFilePages method. +class MemoryBufferMMapFile : public MemoryBufferMem { +public: + MemoryBufferMMapFile(StringRef Buffer, bool RequiresNullTerminator) + : MemoryBufferMem(Buffer, RequiresNullTerminator) { } + + ~MemoryBufferMMapFile() { + static int PageSize = sys::Process::GetPageSize(); + + uintptr_t Start = reinterpret_cast<uintptr_t>(getBufferStart()); + size_t Size = getBufferSize(); + uintptr_t RealStart = Start & ~(PageSize - 1); + size_t RealSize = Size + (Start - RealStart); + + sys::Path::UnMapFilePages(reinterpret_cast<const char*>(RealStart), + RealSize); + } + + virtual BufferKind getBufferKind() const { + return MemoryBuffer_MMap; + } +}; +} + +error_code MemoryBuffer::getFile(StringRef Filename, + OwningPtr<MemoryBuffer> &result, + int64_t FileSize, + bool RequiresNullTerminator) { + // Ensure the path is null terminated. + SmallString<256> PathBuf(Filename.begin(), Filename.end()); + return MemoryBuffer::getFile(PathBuf.c_str(), result, FileSize, + RequiresNullTerminator); +} + +error_code MemoryBuffer::getFile(const char *Filename, + OwningPtr<MemoryBuffer> &result, + int64_t FileSize, + bool RequiresNullTerminator) { + int OpenFlags = O_RDONLY; +#ifdef O_BINARY + OpenFlags |= O_BINARY; // Open input file in binary mode on win32. +#endif + int FD = ::open(Filename, OpenFlags); + if (FD == -1) + return error_code(errno, posix_category()); + + error_code ret = getOpenFile(FD, Filename, result, FileSize, FileSize, + 0, RequiresNullTerminator); + close(FD); + return ret; +} + +static bool shouldUseMmap(int FD, + size_t FileSize, + size_t MapSize, + off_t Offset, + bool RequiresNullTerminator, + int PageSize) { + // We don't use mmap for small files because this can severely fragment our + // address space. + if (MapSize < 4096*4) + return false; + + if (!RequiresNullTerminator) + return true; + + + // If we don't know the file size, use fstat to find out. fstat on an open + // file descriptor is cheaper than stat on a random path. + // FIXME: this chunk of code is duplicated, but it avoids a fstat when + // RequiresNullTerminator = false and MapSize != -1. + if (FileSize == size_t(-1)) { + struct stat FileInfo; + // TODO: This should use fstat64 when available. + if (fstat(FD, &FileInfo) == -1) { + return error_code(errno, posix_category()); + } + FileSize = FileInfo.st_size; + } + + // If we need a null terminator and the end of the map is inside the file, + // we cannot use mmap. + size_t End = Offset + MapSize; + assert(End <= FileSize); + if (End != FileSize) + return false; + + // Don't try to map files that are exactly a multiple of the system page size + // if we need a null terminator. + if ((FileSize & (PageSize -1)) == 0) + return false; + + return true; +} + +error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, + OwningPtr<MemoryBuffer> &result, + uint64_t FileSize, uint64_t MapSize, + int64_t Offset, + bool RequiresNullTerminator) { + static int PageSize = sys::Process::GetPageSize(); + + // Default is to map the full file. + if (MapSize == uint64_t(-1)) { + // If we don't know the file size, use fstat to find out. fstat on an open + // file descriptor is cheaper than stat on a random path. + if (FileSize == uint64_t(-1)) { + struct stat FileInfo; + // TODO: This should use fstat64 when available. + if (fstat(FD, &FileInfo) == -1) { + return error_code(errno, posix_category()); + } + FileSize = FileInfo.st_size; + } + MapSize = FileSize; + } + + if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, + PageSize)) { + off_t RealMapOffset = Offset & ~(PageSize - 1); + off_t Delta = Offset - RealMapOffset; + size_t RealMapSize = MapSize + Delta; + + if (const char *Pages = sys::Path::MapInFilePages(FD, + RealMapSize, + RealMapOffset)) { + result.reset(GetNamedBuffer<MemoryBufferMMapFile>( + StringRef(Pages + Delta, MapSize), Filename, RequiresNullTerminator)); + + 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(); + } + } + + MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename); + if (!Buf) { + // Failed to create a buffer. The only way it can fail is if + // new(std::nothrow) returns 0. + return make_error_code(errc::not_enough_memory); + } + + OwningPtr<MemoryBuffer> SB(Buf); + 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()); + } + 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 error_code::success(); +} + +//===----------------------------------------------------------------------===// +// MemoryBuffer::getSTDIN implementation. +//===----------------------------------------------------------------------===// + +error_code MemoryBuffer::getSTDIN(OwningPtr<MemoryBuffer> &result) { + // Read in all of the data from stdin, we cannot mmap stdin. + // + // FIXME: That isn't necessarily true, we should try to mmap stdin and + // fallback if it fails. + sys::Program::ChangeStdinToBinary(); + + const ssize_t ChunkSize = 4096*4; + SmallString<ChunkSize> Buffer; + ssize_t ReadBytes; + // Read into Buffer until we hit EOF. + do { + Buffer.reserve(Buffer.size() + ChunkSize); + ReadBytes = read(0, Buffer.end(), ChunkSize); + if (ReadBytes == -1) { + if (errno == EINTR) continue; + return error_code(errno, posix_category()); + } + Buffer.set_size(Buffer.size() + ReadBytes); + } while (ReadBytes != 0); + + result.reset(getMemBufferCopy(Buffer, "<stdin>")); + return error_code::success(); +} diff --git a/contrib/llvm/lib/Support/MemoryObject.cpp b/contrib/llvm/lib/Support/MemoryObject.cpp new file mode 100644 index 0000000..b20ab89 --- /dev/null +++ b/contrib/llvm/lib/Support/MemoryObject.cpp @@ -0,0 +1,37 @@ +//===- MemoryObject.cpp - Abstract memory 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/MemoryObject.h" +using namespace llvm; + +MemoryObject::~MemoryObject() { +} + +int MemoryObject::readBytes(uint64_t address, + uint64_t size, + uint8_t* buf, + uint64_t* copied) const { + uint64_t current = address; + uint64_t limit = getBase() + getExtent(); + + if (current + size > limit) + return -1; + + while (current - address < size) { + if (readByte(current, &buf[(current - address)])) + return -1; + + current++; + } + + if (copied) + *copied = current - address; + + return 0; +} diff --git a/contrib/llvm/lib/Support/Mutex.cpp b/contrib/llvm/lib/Support/Mutex.cpp new file mode 100644 index 0000000..da5baab --- /dev/null +++ b/contrib/llvm/lib/Support/Mutex.cpp @@ -0,0 +1,128 @@ +//===- Mutex.cpp - Mutual Exclusion Lock ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the llvm::sys::Mutex class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/Mutex.h" + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +#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; +MutexImpl::MutexImpl( bool recursive) { } +MutexImpl::~MutexImpl() { } +bool MutexImpl::acquire() { return true; } +bool MutexImpl::release() { return true; } +bool MutexImpl::tryacquire() { return true; } +} +#else + +#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_MUTEX_LOCK) + +#include <cassert> +#include <pthread.h> +#include <stdlib.h> + +namespace llvm { +using namespace sys; + +// Construct a Mutex using pthread calls +MutexImpl::MutexImpl( bool recursive) + : data_(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); +#endif + + // Initialize the mutex + errorcode = pthread_mutex_init(mutex, &attr); + assert(errorcode == 0); + + // Destroy the attributes + errorcode = pthread_mutexattr_destroy(&attr); + assert(errorcode == 0); + + // Assign the data member + data_ = mutex; +} + +// Destruct a Mutex +MutexImpl::~MutexImpl() +{ + pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_); + assert(mutex != 0); + pthread_mutex_destroy(mutex); + free(mutex); +} + +bool +MutexImpl::acquire() +{ + 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() +{ + 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() +{ + pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_); + assert(mutex != 0); + + int errorcode = pthread_mutex_trylock(mutex); + return errorcode == 0; +} + +} + +#elif defined(LLVM_ON_UNIX) +#include "Unix/Mutex.inc" +#elif defined( LLVM_ON_WIN32) +#include "Windows/Mutex.inc" +#else +#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in Support/Mutex.cpp +#endif +#endif diff --git a/contrib/llvm/lib/Support/Path.cpp b/contrib/llvm/lib/Support/Path.cpp new file mode 100644 index 0000000..dcddeda --- /dev/null +++ b/contrib/llvm/lib/Support/Path.cpp @@ -0,0 +1,293 @@ +//===-- Path.cpp - Implement OS Path Concept --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system Path concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Path.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Config/config.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Endian.h" +#include <cassert> +#include <cstring> +#include <ostream> +using namespace llvm; +using namespace sys; +namespace { +using support::ulittle32_t; +} + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +bool Path::operator==(const Path &that) const { + return path == that.path; +} + +bool Path::operator<(const Path& that) const { + return path < that.path; +} + +LLVMFileType +sys::IdentifyFileType(const char *magic, unsigned length) { + assert(magic && "Invalid magic number string"); + assert(length >=4 && "Invalid magic number length"); + switch ((unsigned char)magic[0]) { + case 0xDE: // 0x0B17C0DE = BC wraper + if (magic[1] == (char)0xC0 && magic[2] == (char)0x17 && + magic[3] == (char)0x0B) + return Bitcode_FileType; + break; + case 'B': + if (magic[1] == 'C' && magic[2] == (char)0xC0 && magic[3] == (char)0xDE) + return Bitcode_FileType; + break; + case '!': + if (length >= 8) + if (memcmp(magic,"!<arch>\n",8) == 0) + return Archive_FileType; + break; + + case '\177': + if (magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') { + if (length >= 18 && magic[17] == 0) + switch (magic[16]) { + default: break; + case 1: return ELF_Relocatable_FileType; + case 2: return ELF_Executable_FileType; + case 3: return ELF_SharedObject_FileType; + case 4: return ELF_Core_FileType; + } + } + 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 (length >= 8 && magic[7] < 43) + // FIXME: Universal Binary of any type. + return Mach_O_DynamicallyLinkedSharedLib_FileType; + } + 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 (length >= 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 (length >= 14) type = magic[13] << 8 | magic[12]; + } + switch (type) { + default: break; + case 1: return Mach_O_Object_FileType; + case 2: return Mach_O_Executable_FileType; + case 3: return Mach_O_FixedVirtualMemorySharedLib_FileType; + case 4: return Mach_O_Core_FileType; + case 5: return Mach_O_PreloadExecutable_FileType; + case 6: return Mach_O_DynamicallyLinkedSharedLib_FileType; + case 7: return Mach_O_DynamicLinker_FileType; + case 8: return Mach_O_Bundle_FileType; + case 9: return Mach_O_DynamicallyLinkedSharedLibStub_FileType; + case 10: return Mach_O_DSYMCompanion_FileType; + } + 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 COFF_FileType; + + case 0x90: // PA-RISC Windows + case 0x68: // mc68K Windows + if (magic[1] == 0x02) + return COFF_FileType; + break; + + case 0x4d: // Possible MS-DOS stub on Windows PE file + if (magic[1] == 0x5a) { + uint32_t off = *reinterpret_cast<const ulittle32_t *>(magic + 0x3c); + // PE/COFF file, either EXE or DLL. + if (off < length && memcmp(magic + off, "PE\0\0",4) == 0) + return COFF_FileType; + } + break; + + case 0x64: // x86-64 Windows. + if (magic[1] == char(0x86)) + return COFF_FileType; + break; + + default: + break; + } + return Unknown_FileType; +} + +bool +Path::isArchive() const { + fs::file_magic type; + if (fs::identify_magic(str(), type)) + return false; + return type == fs::file_magic::archive; +} + +bool +Path::isDynamicLibrary() const { + fs::file_magic type; + if (fs::identify_magic(str(), type)) + return false; + switch (type) { + default: return false; + 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 { + fs::file_magic type; + if (fs::identify_magic(str(), type) || type == fs::file_magic::unknown) + return false; + return true; +} + +Path +Path::FindLibrary(std::string& name) { + std::vector<sys::Path> LibPaths; + GetSystemLibraryPaths(LibPaths); + for (unsigned i = 0; i < LibPaths.size(); ++i) { + sys::Path FullPath(LibPaths[i]); + FullPath.appendComponent("lib" + name + LTDL_SHLIB_EXT); + if (FullPath.isDynamicLibrary()) + return FullPath; + FullPath.eraseSuffix(); + FullPath.appendSuffix("a"); + if (FullPath.isArchive()) + return FullPath; + } + return sys::Path(); +} + +StringRef Path::GetDLLSuffix() { + return &(LTDL_SHLIB_EXT[1]); +} + +void +Path::appendSuffix(StringRef suffix) { + if (!suffix.empty()) { + path.append("."); + path.append(suffix); + } +} + +bool +Path::isBitcodeFile() const { + fs::file_magic type; + if (fs::identify_magic(str(), type)) + return false; + return type == fs::file_magic::bitcode; +} + +bool Path::hasMagicNumber(StringRef Magic) const { + std::string actualMagic; + if (getMagicNumber(actualMagic, static_cast<unsigned>(Magic.size()))) + return Magic == actualMagic; + return false; +} + +static void getPathList(const char*path, std::vector<Path>& Paths) { + const char* at = path; + const char* delim = strchr(at, PathSeparator); + Path tmpPath; + while (delim != 0) { + std::string tmp(at, size_t(delim-at)); + if (tmpPath.set(tmp)) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); + at = delim + 1; + delim = strchr(at, PathSeparator); + } + + if (*at != 0) + if (tmpPath.set(std::string(at))) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); +} + +static StringRef getDirnameCharSep(StringRef path, const char *Sep) { + assert(Sep[0] != '\0' && Sep[1] == '\0' && + "Sep must be a 1-character string literal."); + if (path.empty()) + return "."; + + // If the path is all slashes, return a single slash. + // Otherwise, remove all trailing slashes. + + signed pos = static_cast<signed>(path.size()) - 1; + + while (pos >= 0 && path[pos] == Sep[0]) + --pos; + + if (pos < 0) + return path[0] == Sep[0] ? Sep : "."; + + // Any slashes left? + signed i = 0; + + while (i < pos && path[i] != Sep[0]) + ++i; + + if (i == pos) // No slashes? Return "." + return "."; + + // There is at least one slash left. Remove all trailing non-slashes. + while (pos >= 0 && path[pos] != Sep[0]) + --pos; + + // Remove any trailing slashes. + while (pos >= 0 && path[pos] == Sep[0]) + --pos; + + if (pos < 0) + return path[0] == Sep[0] ? Sep : "."; + + return path.substr(0, pos+1); +} + +// Include the truly platform-specific parts of this class. +#if defined(LLVM_ON_UNIX) +#include "Unix/Path.inc" +#endif +#if defined(LLVM_ON_WIN32) +#include "Windows/Path.inc" +#endif diff --git a/contrib/llvm/lib/Support/PathV2.cpp b/contrib/llvm/lib/Support/PathV2.cpp new file mode 100644 index 0000000..e2a69a6 --- /dev/null +++ b/contrib/llvm/lib/Support/PathV2.cpp @@ -0,0 +1,919 @@ +//===-- PathV2.cpp - Implement OS Path Concept ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the operating system PathV2 API. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/PathV2.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" +#include <cctype> +#include <cstdio> +#include <cstring> + +namespace { + using llvm::StringRef; + using llvm::sys::path::is_separator; + +#ifdef LLVM_ON_WIN32 + const char *separators = "\\/"; + const char prefered_separator = '\\'; +#else + const char separators = '/'; + const char prefered_separator = '/'; +#endif + + StringRef find_first_component(StringRef path) { + // Look for this first component in the following order. + // * empty (in this case we return an empty string) + // * either C: or {//,\\}net. + // * {/,\} + // * {.,..} + // * {file,directory}name + + if (path.empty()) + return path; + +#ifdef LLVM_ON_WIN32 + // C: + if (path.size() >= 2 && std::isalpha(path[0]) && path[1] == ':') + return path.substr(0, 2); +#endif + + // //net + if ((path.size() > 2) && + is_separator(path[0]) && + path[0] == path[1] && + !is_separator(path[2])) { + // Find the next directory separator. + size_t end = path.find_first_of(separators, 2); + return path.substr(0, end); + } + + // {/,\} + if (is_separator(path[0])) + return path.substr(0, 1); + + if (path.startswith("..")) + return path.substr(0, 2); + + if (path[0] == '.') + return path.substr(0, 1); + + // * {file,directory}name + size_t end = path.find_first_of(separators, 2); + return path.substr(0, end); + } + + size_t filename_pos(StringRef str) { + if (str.size() == 2 && + is_separator(str[0]) && + str[0] == str[1]) + return 0; + + if (str.size() > 0 && is_separator(str[str.size() - 1])) + return str.size() - 1; + + size_t pos = str.find_last_of(separators, str.size() - 1); + +#ifdef LLVM_ON_WIN32 + if (pos == StringRef::npos) + pos = str.find_last_of(':', str.size() - 2); +#endif + + if (pos == StringRef::npos || + (pos == 1 && is_separator(str[0]))) + return 0; + + return pos + 1; + } + + size_t root_dir_start(StringRef str) { + // case "c:/" +#ifdef LLVM_ON_WIN32 + if (str.size() > 2 && + str[1] == ':' && + is_separator(str[2])) + return 2; +#endif + + // case "//" + if (str.size() == 2 && + is_separator(str[0]) && + str[0] == str[1]) + return StringRef::npos; + + // case "//net" + if (str.size() > 3 && + is_separator(str[0]) && + str[0] == str[1] && + !is_separator(str[2])) { + return str.find_first_of(separators, 2); + } + + // case "/" + if (str.size() > 0 && is_separator(str[0])) + return 0; + + return StringRef::npos; + } + + size_t parent_path_end(StringRef path) { + size_t end_pos = filename_pos(path); + + bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]); + + // Skip separators except for root dir. + size_t root_dir_pos = root_dir_start(path.substr(0, end_pos)); + + while(end_pos > 0 && + (end_pos - 1) != root_dir_pos && + is_separator(path[end_pos - 1])) + --end_pos; + + if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) + return StringRef::npos; + + return end_pos; + } +} // end unnamed namespace + +namespace llvm { +namespace sys { +namespace path { + +const_iterator begin(StringRef path) { + const_iterator i; + i.Path = path; + i.Component = find_first_component(path); + i.Position = 0; + return i; +} + +const_iterator end(StringRef path) { + const_iterator i; + i.Path = path; + i.Position = path.size(); + return i; +} + +const_iterator &const_iterator::operator++() { + assert(Position < Path.size() && "Tried to increment past end!"); + + // Increment Position to past the current component + Position += Component.size(); + + // Check for end. + if (Position == Path.size()) { + Component = StringRef(); + return *this; + } + + // Both POSIX and Windows treat paths that begin with exactly two separators + // specially. + bool was_net = Component.size() > 2 && + is_separator(Component[0]) && + Component[1] == Component[0] && + !is_separator(Component[2]); + + // Handle separators. + if (is_separator(Path[Position])) { + // Root dir. + if (was_net +#ifdef LLVM_ON_WIN32 + // c:/ + || Component.endswith(":") +#endif + ) { + Component = Path.substr(Position, 1); + return *this; + } + + // Skip extra separators. + while (Position != Path.size() && + is_separator(Path[Position])) { + ++Position; + } + + // Treat trailing '/' as a '.'. + if (Position == Path.size()) { + --Position; + Component = "."; + return *this; + } + } + + // Find next component. + size_t end_pos = Path.find_first_of(separators, Position); + Component = Path.slice(Position, end_pos); + + return *this; +} + +const_iterator &const_iterator::operator--() { + // If we're at the end and the previous char was a '/', return '.'. + if (Position == Path.size() && + Path.size() > 1 && + is_separator(Path[Position - 1]) +#ifdef LLVM_ON_WIN32 + && Path[Position - 2] != ':' +#endif + ) { + --Position; + Component = "."; + return *this; + } + + // Skip separators unless it's the root directory. + size_t root_dir_pos = root_dir_start(Path); + size_t end_pos = Position; + + while(end_pos > 0 && + (end_pos - 1) != root_dir_pos && + is_separator(Path[end_pos - 1])) + --end_pos; + + // Find next separator. + size_t start_pos = filename_pos(Path.substr(0, end_pos)); + Component = Path.slice(start_pos, end_pos); + Position = start_pos; + return *this; +} + +bool const_iterator::operator==(const const_iterator &RHS) const { + return Path.begin() == RHS.Path.begin() && + Position == RHS.Position; +} + +bool const_iterator::operator!=(const const_iterator &RHS) const { + return !(*this == RHS); +} + +ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const { + return Position - RHS.Position; +} + +const StringRef root_path(StringRef path) { + const_iterator b = begin(path), + pos = b, + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef LLVM_ON_WIN32 + b->endswith(":"); +#else + false; +#endif + + if (has_net || has_drive) { + if ((++pos != e) && is_separator((*pos)[0])) { + // {C:/,//net/}, so get the first two components. + return path.substr(0, b->size() + pos->size()); + } else { + // just {C:,//net}, return the first component. + return *b; + } + } + + // POSIX style root directory. + if (is_separator((*b)[0])) { + return *b; + } + } + + return StringRef(); +} + +const StringRef root_name(StringRef path) { + const_iterator b = begin(path), + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef LLVM_ON_WIN32 + b->endswith(":"); +#else + false; +#endif + + if (has_net || has_drive) { + // just {C:,//net}, return the first component. + return *b; + } + } + + // No path or no name. + return StringRef(); +} + +const StringRef root_directory(StringRef path) { + const_iterator b = begin(path), + pos = b, + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef LLVM_ON_WIN32 + b->endswith(":"); +#else + false; +#endif + + if ((has_net || has_drive) && + // {C:,//net}, skip to the next component. + (++pos != e) && is_separator((*pos)[0])) { + return *pos; + } + + // POSIX style root directory. + if (!has_net && is_separator((*b)[0])) { + return *b; + } + } + + // No path or no root. + return StringRef(); +} + +const StringRef relative_path(StringRef path) { + StringRef root = root_path(path); + return path.substr(root.size()); +} + +void append(SmallVectorImpl<char> &path, const Twine &a, + const Twine &b, + const Twine &c, + const Twine &d) { + SmallString<32> a_storage; + SmallString<32> b_storage; + SmallString<32> c_storage; + SmallString<32> d_storage; + + SmallVector<StringRef, 4> components; + if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage)); + if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage)); + if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage)); + if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage)); + + for (SmallVectorImpl<StringRef>::const_iterator i = components.begin(), + e = components.end(); + i != e; ++i) { + bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]); + bool component_has_sep = !i->empty() && is_separator((*i)[0]); + bool is_root_name = has_root_name(*i); + + if (path_has_sep) { + // Strip separators from beginning of component. + size_t loc = i->find_first_not_of(separators); + StringRef c = i->substr(loc); + + // Append it. + path.append(c.begin(), c.end()); + continue; + } + + if (!component_has_sep && !(path.empty() || is_root_name)) { + // Add a separator. + path.push_back(prefered_separator); + } + + path.append(i->begin(), i->end()); + } +} + +void append(SmallVectorImpl<char> &path, + const_iterator begin, const_iterator end) { + for (; begin != end; ++begin) + path::append(path, *begin); +} + +const StringRef parent_path(StringRef path) { + size_t end_pos = parent_path_end(path); + if (end_pos == StringRef::npos) + return StringRef(); + else + return path.substr(0, end_pos); +} + +void remove_filename(SmallVectorImpl<char> &path) { + size_t end_pos = parent_path_end(StringRef(path.begin(), path.size())); + if (end_pos != StringRef::npos) + path.set_size(end_pos); +} + +void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) { + StringRef p(path.begin(), path.size()); + SmallString<32> ext_storage; + StringRef ext = extension.toStringRef(ext_storage); + + // Erase existing extension. + size_t pos = p.find_last_of('.'); + if (pos != StringRef::npos && pos >= filename_pos(p)) + path.set_size(pos); + + // Append '.' if needed. + if (ext.size() > 0 && ext[0] != '.') + path.push_back('.'); + + // Append extension. + path.append(ext.begin(), ext.end()); +} + +void native(const Twine &path, SmallVectorImpl<char> &result) { + // Clear result. + result.clear(); +#ifdef LLVM_ON_WIN32 + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + result.reserve(p.size()); + for (StringRef::const_iterator i = p.begin(), + e = p.end(); + i != e; + ++i) { + if (*i == '/') + result.push_back('\\'); + else + result.push_back(*i); + } +#else + path.toVector(result); +#endif +} + +const StringRef filename(StringRef path) { + return *(--end(path)); +} + +const StringRef stem(StringRef path) { + StringRef fname = filename(path); + size_t pos = fname.find_last_of('.'); + if (pos == StringRef::npos) + return fname; + else + if ((fname.size() == 1 && fname == ".") || + (fname.size() == 2 && fname == "..")) + return fname; + else + return fname.substr(0, pos); +} + +const StringRef extension(StringRef path) { + StringRef fname = filename(path); + size_t pos = fname.find_last_of('.'); + if (pos == StringRef::npos) + return StringRef(); + else + if ((fname.size() == 1 && fname == ".") || + (fname.size() == 2 && fname == "..")) + return StringRef(); + else + return fname.substr(pos); +} + +bool is_separator(char value) { + switch(value) { +#ifdef LLVM_ON_WIN32 + case '\\': // fall through +#endif + case '/': return true; + default: return false; + } +} + +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; +#ifdef LLVM_ON_WIN32 + EnvironmentVariable = "TEMP"; +#else + EnvironmentVariable = "TMPDIR"; +#endif + if (char *RequestedDir = getenv(EnvironmentVariable)) { + result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); + return; + } + + // Fall back to a system default. + const char *DefaultResult; +#ifdef LLVM_ON_WIN32 + (void)erasedOnReboot; + DefaultResult = "C:\\TEMP"; +#else + if (erasedOnReboot) + DefaultResult = "/tmp"; + else + DefaultResult = "/var/tmp"; +#endif + result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); +} + +bool has_root_name(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_name(p).empty(); +} + +bool has_root_directory(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_directory(p).empty(); +} + +bool has_root_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_path(p).empty(); +} + +bool has_relative_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !relative_path(p).empty(); +} + +bool has_filename(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !filename(p).empty(); +} + +bool has_parent_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !parent_path(p).empty(); +} + +bool has_stem(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !stem(p).empty(); +} + +bool has_extension(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !extension(p).empty(); +} + +bool is_absolute(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + bool rootDir = has_root_directory(p), +#ifdef LLVM_ON_WIN32 + rootName = has_root_name(p); +#else + rootName = true; +#endif + + return rootDir && rootName; +} + +bool is_relative(const Twine &path) { + return !is_absolute(path); +} + +} // end namespace path + +namespace fs { + +error_code make_absolute(SmallVectorImpl<char> &path) { + StringRef p(path.data(), path.size()); + + 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 error_code::success(); + + // All of the following conditions will need the current directory. + SmallString<128> current_dir; + if (error_code ec = current_path(current_dir)) return ec; + + // Relative path. Prepend the current directory. + if (!rootName && !rootDirectory) { + // Append path to the current directory. + path::append(current_dir, p); + // Set path to the result. + path.swap(current_dir); + return error_code::success(); + } + + if (!rootName && rootDirectory) { + StringRef cdrn = path::root_name(current_dir); + SmallString<128> curDirRootName(cdrn.begin(), cdrn.end()); + path::append(curDirRootName, p); + // Set path to the result. + path.swap(curDirRootName); + return error_code::success(); + } + + if (rootName && !rootDirectory) { + StringRef pRootName = path::root_name(p); + StringRef bRootDirectory = path::root_directory(current_dir); + StringRef bRelativePath = path::relative_path(current_dir); + StringRef pRelativePath = path::relative_path(p); + + SmallString<128> res; + path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath); + path.swap(res); + return error_code::success(); + } + + llvm_unreachable("All rootName and rootDirectory combinations should have " + "occurred above!"); +} + +error_code create_directories(const Twine &path, bool &existed) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + StringRef parent = path::parent_path(p); + if (!parent.empty()) { + bool parent_exists; + if (error_code ec = fs::exists(parent, parent_exists)) return ec; + + if (!parent_exists) + if (error_code ec = create_directories(parent, existed)) return ec; + } + + return create_directory(p, existed); +} + +bool exists(file_status status) { + return status_known(status) && status.type() != file_type::file_not_found; +} + +bool status_known(file_status s) { + return s.type() != file_type::status_error; +} + +bool is_directory(file_status status) { + return status.type() == file_type::directory_file; +} + +error_code is_directory(const Twine &path, bool &result) { + file_status st; + if (error_code ec = status(path, st)) + return ec; + result = is_directory(st); + return error_code::success(); +} + +bool is_regular_file(file_status status) { + return status.type() == file_type::regular_file; +} + +error_code is_regular_file(const Twine &path, bool &result) { + file_status st; + if (error_code ec = status(path, st)) + return ec; + result = is_regular_file(st); + return error_code::success(); +} + +bool is_symlink(file_status status) { + return status.type() == file_type::symlink_file; +} + +error_code is_symlink(const Twine &path, bool &result) { + file_status st; + if (error_code ec = status(path, st)) + return ec; + result = is_symlink(st); + return error_code::success(); +} + +bool is_other(file_status status) { + return exists(status) && + !is_regular_file(status) && + !is_directory(status) && + !is_symlink(status); +} + +void directory_entry::replace_filename(const Twine &filename, file_status st) { + SmallString<128> path(Path.begin(), Path.end()); + path::remove_filename(path); + path::append(path, filename); + Path = path.str(); + Status = st; +} + +error_code has_magic(const Twine &path, const Twine &magic, bool &result) { + SmallString<32> MagicStorage; + StringRef Magic = magic.toStringRef(MagicStorage); + SmallString<32> Buffer; + + if (error_code ec = get_magic(path, Magic.size(), Buffer)) { + if (ec == errc::value_too_large) { + // Magic.size() > file_size(Path). + result = false; + return error_code::success(); + } + return ec; + } + + result = Magic == Buffer; + 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, 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 = identify_magic(Magic); + return error_code::success(); +} + +namespace { +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; + 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; + if (error_code ec = remove_all_r(i->path(), st.type(), count)) return ec; + } + bool obviously_this_exists; + if (error_code ec = remove(path, obviously_this_exists)) return ec; + assert(obviously_this_exists); + ++count; // Include the directory itself in the items removed. + } else { + bool obviously_this_exists; + if (error_code ec = remove(path, obviously_this_exists)) return ec; + assert(obviously_this_exists); + ++count; + } + + return error_code::success(); +} +} // end unnamed namespace + +error_code remove_all(const Twine &path, uint32_t &num_removed) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + file_status fs; + if (error_code ec = status(path, fs)) + return ec; + num_removed = 0; + return remove_all_r(p, fs.type(), num_removed); +} + +error_code directory_entry::status(file_status &result) const { + return fs::status(Path, result); +} + +} // end namespace fs +} // end namespace sys +} // end namespace llvm + +// Include the truly platform-specific parts. +#if defined(LLVM_ON_UNIX) +#include "Unix/PathV2.inc" +#endif +#if defined(LLVM_ON_WIN32) +#include "Windows/PathV2.inc" +#endif diff --git a/contrib/llvm/lib/Support/PluginLoader.cpp b/contrib/llvm/lib/Support/PluginLoader.cpp new file mode 100644 index 0000000..2924cfa --- /dev/null +++ b/contrib/llvm/lib/Support/PluginLoader.cpp @@ -0,0 +1,47 @@ +//===-- PluginLoader.cpp - Implement -load command line option ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the -load <plugin> command line option handler. +// +//===----------------------------------------------------------------------===// + +#define DONT_GET_PLUGIN_LOADER_OPTION +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PluginLoader.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/Mutex.h" +#include <vector> +using namespace llvm; + +static ManagedStatic<std::vector<std::string> > Plugins; +static ManagedStatic<sys::SmartMutex<true> > PluginsLock; + +void PluginLoader::operator=(const std::string &Filename) { + sys::SmartScopedLock<true> Lock(*PluginsLock); + std::string Error; + if (sys::DynamicLibrary::LoadLibraryPermanently(Filename.c_str(), &Error)) { + errs() << "Error opening '" << Filename << "': " << Error + << "\n -load request ignored.\n"; + } else { + Plugins->push_back(Filename); + } +} + +unsigned PluginLoader::getNumPlugins() { + sys::SmartScopedLock<true> Lock(*PluginsLock); + return Plugins.isConstructed() ? Plugins->size() : 0; +} + +std::string &PluginLoader::getPlugin(unsigned num) { + sys::SmartScopedLock<true> Lock(*PluginsLock); + assert(Plugins.isConstructed() && num < Plugins->size() && + "Asking for an out of bounds plugin"); + return (*Plugins)[num]; +} diff --git a/contrib/llvm/lib/Support/PrettyStackTrace.cpp b/contrib/llvm/lib/Support/PrettyStackTrace.cpp new file mode 100644 index 0000000..ef33073 --- /dev/null +++ b/contrib/llvm/lib/Support/PrettyStackTrace.cpp @@ -0,0 +1,133 @@ +//===- PrettyStackTrace.cpp - Pretty Crash Handling -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some helpful functions for dealing with the possibility of +// Unix signals occurring while your program is running. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" // Get autoconf configuration settings +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/ThreadLocal.h" +#include "llvm/ADT/SmallString.h" + +#ifdef HAVE_CRASHREPORTERCLIENT_H +#include <CrashReporterClient.h> +#endif + +using namespace llvm; + +namespace llvm { + bool DisablePrettyStackTrace = false; +} + +// FIXME: This should be thread local when llvm supports threads. +static sys::ThreadLocal<const PrettyStackTraceEntry> PrettyStackTraceHead; + +static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){ + unsigned NextID = 0; + if (Entry->getNextEntry()) + NextID = PrintStack(Entry->getNextEntry(), OS); + OS << NextID << ".\t"; + Entry->print(OS); + + return NextID+1; +} + +/// PrintCurStackTrace - Print the current stack trace to the specified stream. +static void PrintCurStackTrace(raw_ostream &OS) { + // Don't print an empty trace. + if (PrettyStackTraceHead.get() == 0) return; + + // If there are pretty stack frames registered, walk and emit them. + OS << "Stack dump:\n"; + + PrintStack(PrettyStackTraceHead.get(), OS); + OS.flush(); +} + +// Integrate with crash reporter libraries. +#if defined (__APPLE__) && HAVE_CRASHREPORTERCLIENT_H +// If any clients of llvm try to link to libCrashReporterClient.a themselves, +// only one crash info struct will be used. +extern "C" { +CRASH_REPORTER_CLIENT_HIDDEN +struct crashreporter_annotations_t gCRAnnotations + __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) + = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0 }; +} +#elif defined (__APPLE__) && HAVE_CRASHREPORTER_INFO +static const char *__crashreporter_info__ = 0; +asm(".desc ___crashreporter_info__, 0x10"); +#endif + + +/// CrashHandler - This callback is run if a fatal signal is delivered to the +/// process, it prints the pretty stack trace. +static void CrashHandler(void *) { +#ifndef __APPLE__ + // On non-apple systems, just emit the crash stack trace to stderr. + PrintCurStackTrace(errs()); +#else + // Otherwise, emit to a smallvector of chars, send *that* to stderr, but also + // put it into __crashreporter_info__. + SmallString<2048> TmpStr; + { + raw_svector_ostream Stream(TmpStr); + PrintCurStackTrace(Stream); + } + + if (!TmpStr.empty()) { +#ifdef HAVE_CRASHREPORTERCLIENT_H + // Cast to void to avoid warning. + (void)CRSetCrashLogMessage(std::string(TmpStr.str()).c_str()); +#elif HAVE_CRASHREPORTER_INFO + __crashreporter_info__ = strdup(std::string(TmpStr.str()).c_str()); +#endif + errs() << TmpStr.str(); + } + +#endif +} + +static bool RegisterCrashPrinter() { + if (!DisablePrettyStackTrace) + sys::AddSignalHandler(CrashHandler, 0); + return false; +} + +PrettyStackTraceEntry::PrettyStackTraceEntry() { + // The first time this is called, we register the crash printer. + static bool HandlerRegistered = RegisterCrashPrinter(); + (void)HandlerRegistered; + + // Link ourselves. + NextEntry = PrettyStackTraceHead.get(); + PrettyStackTraceHead.set(this); +} + +PrettyStackTraceEntry::~PrettyStackTraceEntry() { + assert(PrettyStackTraceHead.get() == this && + "Pretty stack trace entry destruction is out of order"); + PrettyStackTraceHead.set(getNextEntry()); +} + +void PrettyStackTraceString::print(raw_ostream &OS) const { + OS << Str << "\n"; +} + +void PrettyStackTraceProgram::print(raw_ostream &OS) const { + OS << "Program arguments: "; + // Print the argument list. + for (unsigned i = 0, e = ArgC; i != e; ++i) + OS << ArgV[i] << ' '; + OS << '\n'; +} diff --git a/contrib/llvm/lib/Support/Process.cpp b/contrib/llvm/lib/Support/Process.cpp new file mode 100644 index 0000000..88ca7c3 --- /dev/null +++ b/contrib/llvm/lib/Support/Process.cpp @@ -0,0 +1,33 @@ +//===-- Process.cpp - Implement OS Process Concept --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system Process concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Process.h" +#include "llvm/Config/config.h" + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +} + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Process.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Process.inc" +#endif diff --git a/contrib/llvm/lib/Support/Program.cpp b/contrib/llvm/lib/Support/Program.cpp new file mode 100644 index 0000000..75bc282 --- /dev/null +++ b/contrib/llvm/lib/Support/Program.cpp @@ -0,0 +1,57 @@ +//===-- Program.cpp - Implement OS Program Concept --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system Program concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Program.h" +#include "llvm/Config/config.h" +#include "llvm/Support/system_error.h" +using namespace llvm; +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +int +Program::ExecuteAndWait(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned secondsToWait, + unsigned memoryLimit, + std::string* ErrMsg) { + Program prg; + if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg)) + return prg.Wait(path, secondsToWait, ErrMsg); + else + return -1; +} + +void +Program::ExecuteNoWait(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned memoryLimit, + std::string* ErrMsg) { + Program prg; + prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg); +} + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Program.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Program.inc" +#endif diff --git a/contrib/llvm/lib/Support/RWMutex.cpp b/contrib/llvm/lib/Support/RWMutex.cpp new file mode 100644 index 0000000..6a34f2d --- /dev/null +++ b/contrib/llvm/lib/Support/RWMutex.cpp @@ -0,0 +1,125 @@ +//===- RWMutex.cpp - Reader/Writer Mutual Exclusion Lock --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the llvm::sys::RWMutex class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/RWMutex.h" +#include <cstring> + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +#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; +RWMutexImpl::RWMutexImpl() { } +RWMutexImpl::~RWMutexImpl() { } +bool RWMutexImpl::reader_acquire() { return true; } +bool RWMutexImpl::reader_release() { return true; } +bool RWMutexImpl::writer_acquire() { return true; } +bool RWMutexImpl::writer_release() { return true; } +} +#else + +#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_RWLOCK_INIT) + +#include <cassert> +#include <pthread.h> +#include <stdlib.h> + +namespace llvm { +using namespace sys; + +// Construct a RWMutex using pthread calls +RWMutexImpl::RWMutexImpl() + : data_(0) +{ + // 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)); +#endif + + // Initialize the rwlock + int errorcode = pthread_rwlock_init(rwlock, NULL); + (void)errorcode; + assert(errorcode == 0); + + // Assign the data member + data_ = rwlock; +} + +// Destruct a RWMutex +RWMutexImpl::~RWMutexImpl() +{ + pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); + assert(rwlock != 0); + pthread_rwlock_destroy(rwlock); + free(rwlock); +} + +bool +RWMutexImpl::reader_acquire() +{ + 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() +{ + 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() +{ + 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() +{ + pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); + assert(rwlock != 0); + + int errorcode = pthread_rwlock_unlock(rwlock); + return errorcode == 0; +} + +} + +#elif defined(LLVM_ON_UNIX) +#include "Unix/RWMutex.inc" +#elif defined( LLVM_ON_WIN32) +#include "Windows/RWMutex.inc" +#else +#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in Support/Mutex.cpp +#endif +#endif diff --git a/contrib/llvm/lib/Support/Regex.cpp b/contrib/llvm/lib/Support/Regex.cpp new file mode 100644 index 0000000..d293da0 --- /dev/null +++ b/contrib/llvm/lib/Support/Regex.cpp @@ -0,0 +1,168 @@ +//===-- Regex.cpp - Regular Expression matcher implementation -------------===// +// +// 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 POSIX regular expression matcher. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Regex.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/SmallVector.h" +#include "regex_impl.h" +#include <string> +using namespace llvm; + +Regex::Regex(StringRef regex, unsigned Flags) { + unsigned flags = 0; + preg = new llvm_regex(); + preg->re_endp = regex.end(); + if (Flags & IgnoreCase) + flags |= REG_ICASE; + if (Flags & Newline) + flags |= REG_NEWLINE; + error = llvm_regcomp(preg, regex.data(), flags|REG_EXTENDED|REG_PEND); +} + +Regex::~Regex() { + llvm_regfree(preg); + delete preg; +} + +bool Regex::isValid(std::string &Error) { + if (!error) + return true; + + size_t len = llvm_regerror(error, preg, NULL, 0); + + Error.resize(len); + llvm_regerror(error, preg, &Error[0], len); + return false; +} + +/// getNumMatches - In a valid regex, return the number of parenthesized +/// matches it contains. +unsigned Regex::getNumMatches() const { + return preg->re_nsub; +} + +bool Regex::match(StringRef String, SmallVectorImpl<StringRef> *Matches){ + unsigned nmatch = Matches ? preg->re_nsub+1 : 0; + + // pmatch needs to have at least one element. + SmallVector<llvm_regmatch_t, 8> pm; + pm.resize(nmatch > 0 ? nmatch : 1); + pm[0].rm_so = 0; + pm[0].rm_eo = String.size(); + + int rc = llvm_regexec(preg, String.data(), nmatch, pm.data(), REG_STARTEND); + + if (rc == REG_NOMATCH) + return false; + if (rc != 0) { + // regexec can fail due to invalid pattern or running out of memory. + error = rc; + return false; + } + + // There was a match. + + if (Matches) { // match position requested + Matches->clear(); + + for (unsigned i = 0; i != nmatch; ++i) { + if (pm[i].rm_so == -1) { + // this group didn't match + Matches->push_back(StringRef()); + continue; + } + assert(pm[i].rm_eo >= pm[i].rm_so); + Matches->push_back(StringRef(String.data()+pm[i].rm_so, + pm[i].rm_eo-pm[i].rm_so)); + } + } + + return true; +} + +std::string Regex::sub(StringRef Repl, StringRef String, + std::string *Error) { + SmallVector<StringRef, 8> Matches; + + // Reset error, if given. + if (Error && !Error->empty()) *Error = ""; + + // Return the input if there was no match. + if (!match(String, &Matches)) + return String; + + // Otherwise splice in the replacement string, starting with the prefix before + // the match. + std::string Res(String.begin(), Matches[0].begin()); + + // Then the replacement string, honoring possible substitutions. + while (!Repl.empty()) { + // Skip to the next escape. + std::pair<StringRef, StringRef> Split = Repl.split('\\'); + + // Add the skipped substring. + Res += Split.first; + + // Check for terminimation and trailing backslash. + if (Split.second.empty()) { + if (Repl.size() != Split.first.size() && + Error && Error->empty()) + *Error = "replacement string contained trailing backslash"; + break; + } + + // Otherwise update the replacement string and interpret escapes. + Repl = Split.second; + + // FIXME: We should have a StringExtras function for mapping C99 escapes. + switch (Repl[0]) { + // Treat all unrecognized characters as self-quoting. + default: + Res += Repl[0]; + Repl = Repl.substr(1); + break; + + // Single character escapes. + case 't': + Res += '\t'; + Repl = Repl.substr(1); + break; + case 'n': + Res += '\n'; + Repl = Repl.substr(1); + break; + + // Decimal escapes are backreferences. + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + // Extract the backreference number. + StringRef Ref = Repl.slice(0, Repl.find_first_not_of("0123456789")); + Repl = Repl.substr(Ref.size()); + + unsigned RefValue; + if (!Ref.getAsInteger(10, RefValue) && + RefValue < Matches.size()) + Res += Matches[RefValue]; + else if (Error && Error->empty()) + *Error = "invalid backreference string '" + Ref.str() + "'"; + break; + } + } + } + + // And finally the suffix. + Res += StringRef(Matches[0].end(), String.end() - Matches[0].end()); + + return Res; +} diff --git a/contrib/llvm/lib/Support/SearchForAddressOfSpecialSymbol.cpp b/contrib/llvm/lib/Support/SearchForAddressOfSpecialSymbol.cpp new file mode 100644 index 0000000..2d23902 --- /dev/null +++ b/contrib/llvm/lib/Support/SearchForAddressOfSpecialSymbol.cpp @@ -0,0 +1,58 @@ +//===- SearchForAddressOfSpecialSymbol.cpp - Function addresses -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file pulls the addresses of certain symbols out of the linker. It must +// include as few header files as possible because it declares the symbols as +// void*, which would conflict with the actual symbol type if any header +// declared it. +// +//===----------------------------------------------------------------------===// + +#include <string.h> + +// Must declare the symbols in the global namespace. +static void *DoSearch(const char* symbolName) { +#define EXPLICIT_SYMBOL(SYM) \ + extern void *SYM; if (!strcmp(symbolName, #SYM)) return &SYM + + // If this is darwin, it has some funky issues, try to solve them here. Some + // important symbols are marked 'private external' which doesn't allow + // SearchForAddressOfSymbol to find them. As such, we special case them here, + // there is only a small handful of them. + +#ifdef __APPLE__ + { + // __eprintf is sometimes used for assert() handling on x86. + // + // FIXME: Currently disabled when using Clang, as we don't always have our + // runtime support libraries available. +#ifndef __clang__ +#ifdef __i386__ + EXPLICIT_SYMBOL(__eprintf); +#endif +#endif + } +#endif + +#ifdef __CYGWIN__ + { + EXPLICIT_SYMBOL(_alloca); + EXPLICIT_SYMBOL(__main); + } +#endif + +#undef EXPLICIT_SYMBOL + return 0; +} + +namespace llvm { +void *SearchForAddressOfSpecialSymbol(const char* symbolName) { + return DoSearch(symbolName); +} +} // namespace llvm diff --git a/contrib/llvm/lib/Support/Signals.cpp b/contrib/llvm/lib/Support/Signals.cpp new file mode 100644 index 0000000..a117893 --- /dev/null +++ b/contrib/llvm/lib/Support/Signals.cpp @@ -0,0 +1,34 @@ +//===- Signals.cpp - Signal Handling support --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some helpful functions for dealing with the possibility of +// Unix signals occurring while your program is running. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Signals.h" +#include "llvm/Config/config.h" + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +} + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Signals.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Signals.inc" +#endif diff --git a/contrib/llvm/lib/Support/SmallPtrSet.cpp b/contrib/llvm/lib/Support/SmallPtrSet.cpp new file mode 100644 index 0000000..68d9c29 --- /dev/null +++ b/contrib/llvm/lib/Support/SmallPtrSet.cpp @@ -0,0 +1,280 @@ +//===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SmallPtrSet class. See SmallPtrSet.h for an +// overview of the algorithm. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/MathExtras.h" +#include <algorithm> +#include <cstdlib> + +using namespace llvm; + +void SmallPtrSetImpl::shrink_and_clear() { + assert(!isSmall() && "Can't shrink a small set!"); + free(CurArray); + + // Reduce the number of buckets. + CurArraySize = NumElements > 16 ? 1 << (Log2_32_Ceil(NumElements) + 1) : 32; + NumElements = NumTombstones = 0; + + // Install the new array. Clear all the buckets to empty. + CurArray = (const void**)malloc(sizeof(void*) * (CurArraySize+1)); + assert(CurArray && "Failed to allocate memory?"); + memset(CurArray, -1, CurArraySize*sizeof(void*)); + + // The end pointer, always valid, is set to a valid element to help the + // iterator. + CurArray[CurArraySize] = 0; +} + +bool SmallPtrSetImpl::insert_imp(const void * Ptr) { + if (isSmall()) { + // Check to see if it is already in the set. + for (const void **APtr = SmallArray, **E = SmallArray+NumElements; + APtr != E; ++APtr) + if (*APtr == Ptr) + return false; + + // Nope, there isn't. If we stay small, just 'pushback' now. + if (NumElements < CurArraySize-1) { + SmallArray[NumElements++] = Ptr; + return true; + } + // Otherwise, hit the big set case, which will call grow. + } + + if (NumElements*4 >= CurArraySize*3) { + // If more than 3/4 of the array is full, grow. + Grow(CurArraySize < 64 ? 128 : CurArraySize*2); + } else if (CurArraySize-(NumElements+NumTombstones) < CurArraySize/8) { + // If fewer of 1/8 of the array is empty (meaning that many are filled with + // tombstones), rehash. + Grow(CurArraySize); + } + + // Okay, we know we have space. Find a hash bucket. + const void **Bucket = const_cast<const void**>(FindBucketFor(Ptr)); + if (*Bucket == Ptr) return false; // Already inserted, good. + + // Otherwise, insert it! + if (*Bucket == getTombstoneMarker()) + --NumTombstones; + *Bucket = Ptr; + ++NumElements; // Track density. + return true; +} + +bool SmallPtrSetImpl::erase_imp(const void * Ptr) { + if (isSmall()) { + // Check to see if it is in the set. + for (const void **APtr = SmallArray, **E = SmallArray+NumElements; + APtr != E; ++APtr) + if (*APtr == Ptr) { + // If it is in the set, replace this element. + *APtr = E[-1]; + E[-1] = getEmptyMarker(); + --NumElements; + return true; + } + + return false; + } + + // Okay, we know we have space. Find a hash bucket. + void **Bucket = const_cast<void**>(FindBucketFor(Ptr)); + if (*Bucket != Ptr) return false; // Not in the set? + + // Set this as a tombstone. + *Bucket = getTombstoneMarker(); + --NumElements; + ++NumTombstones; + return true; +} + +const void * const *SmallPtrSetImpl::FindBucketFor(const void *Ptr) const { + unsigned Bucket = Hash(Ptr); + unsigned ArraySize = CurArraySize; + unsigned ProbeAmt = 1; + const void *const *Array = CurArray; + const void *const *Tombstone = 0; + while (1) { + // Found Ptr's bucket? + if (Array[Bucket] == Ptr) + return Array+Bucket; + + // If we found an empty bucket, the pointer doesn't exist in the set. + // Return a tombstone if we've seen one so far, or the empty bucket if + // not. + if (Array[Bucket] == getEmptyMarker()) + return Tombstone ? Tombstone : Array+Bucket; + + // If this is a tombstone, remember it. If Ptr ends up not in the set, we + // prefer to return it than something that would require more probing. + if (Array[Bucket] == getTombstoneMarker() && !Tombstone) + Tombstone = Array+Bucket; // Remember the first tombstone found. + + // It's a hash collision or a tombstone. Reprobe. + Bucket = (Bucket + ProbeAmt++) & (ArraySize-1); + } +} + +/// Grow - Allocate a larger backing store for the buckets and move it over. +/// +void SmallPtrSetImpl::Grow(unsigned NewSize) { + // Allocate at twice as many buckets, but at least 128. + unsigned OldSize = CurArraySize; + + const void **OldBuckets = CurArray; + bool WasSmall = isSmall(); + + // Install the new array. Clear all the buckets to empty. + CurArray = (const void**)malloc(sizeof(void*) * (NewSize+1)); + assert(CurArray && "Failed to allocate memory?"); + CurArraySize = NewSize; + memset(CurArray, -1, NewSize*sizeof(void*)); + + // The end pointer, always valid, is set to a valid element to help the + // iterator. + CurArray[NewSize] = 0; + + // Copy over all the elements. + if (WasSmall) { + // Small sets store their elements in order. + for (const void **BucketPtr = OldBuckets, **E = OldBuckets+NumElements; + BucketPtr != E; ++BucketPtr) { + const void *Elt = *BucketPtr; + *const_cast<void**>(FindBucketFor(Elt)) = const_cast<void*>(Elt); + } + } else { + // Copy over all valid entries. + for (const void **BucketPtr = OldBuckets, **E = OldBuckets+OldSize; + BucketPtr != E; ++BucketPtr) { + // Copy over the element if it is valid. + const void *Elt = *BucketPtr; + if (Elt != getTombstoneMarker() && Elt != getEmptyMarker()) + *const_cast<void**>(FindBucketFor(Elt)) = const_cast<void*>(Elt); + } + + free(OldBuckets); + NumTombstones = 0; + } +} + +SmallPtrSetImpl::SmallPtrSetImpl(const void **SmallStorage, + const SmallPtrSetImpl& that) { + SmallArray = SmallStorage; + + // If we're becoming small, prepare to insert into our stack space + if (that.isSmall()) { + CurArray = SmallArray; + // Otherwise, allocate new heap space (unless we were the same size) + } else { + CurArray = (const void**)malloc(sizeof(void*) * (that.CurArraySize+1)); + assert(CurArray && "Failed to allocate memory?"); + } + + // Copy over the new array size + CurArraySize = that.CurArraySize; + + // Copy over the contents from the other set + memcpy(CurArray, that.CurArray, sizeof(void*)*(CurArraySize+1)); + + NumElements = that.NumElements; + NumTombstones = that.NumTombstones; +} + +/// CopyFrom - implement operator= from a smallptrset that has the same pointer +/// type, but may have a different small size. +void SmallPtrSetImpl::CopyFrom(const SmallPtrSetImpl &RHS) { + if (isSmall() && RHS.isSmall()) + assert(CurArraySize == RHS.CurArraySize && + "Cannot assign sets with different small sizes"); + + // If we're becoming small, prepare to insert into our stack space + if (RHS.isSmall()) { + if (!isSmall()) + free(CurArray); + CurArray = SmallArray; + // Otherwise, allocate new heap space (unless we were the same size) + } else if (CurArraySize != RHS.CurArraySize) { + if (isSmall()) + CurArray = (const void**)malloc(sizeof(void*) * (RHS.CurArraySize+1)); + else + CurArray = (const void**)realloc(CurArray, sizeof(void*)*(RHS.CurArraySize+1)); + assert(CurArray && "Failed to allocate memory?"); + } + + // Copy over the new array size + CurArraySize = RHS.CurArraySize; + + // Copy over the contents from the other set + memcpy(CurArray, RHS.CurArray, sizeof(void*)*(CurArraySize+1)); + + NumElements = RHS.NumElements; + 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/contrib/llvm/lib/Support/SmallVector.cpp b/contrib/llvm/lib/Support/SmallVector.cpp new file mode 100644 index 0000000..a89f149 --- /dev/null +++ b/contrib/llvm/lib/Support/SmallVector.cpp @@ -0,0 +1,40 @@ +//===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SmallVector class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallVector.h" +using namespace llvm; + +/// grow_pod - This is an implementation of the grow() method which only works +/// on POD-like datatypes and is out of line to reduce code duplication. +void SmallVectorBase::grow_pod(size_t MinSizeInBytes, size_t TSize) { + size_t CurSizeBytes = size_in_bytes(); + size_t NewCapacityInBytes = 2 * capacity_in_bytes() + TSize; // Always grow. + if (NewCapacityInBytes < MinSizeInBytes) + NewCapacityInBytes = MinSizeInBytes; + + void *NewElts; + if (this->isSmall()) { + NewElts = malloc(NewCapacityInBytes); + + // Copy the elements over. No need to run dtors on PODs. + memcpy(NewElts, this->BeginX, CurSizeBytes); + } else { + // If this wasn't grown from the inline copy, grow the allocated space. + NewElts = realloc(this->BeginX, NewCapacityInBytes); + } + + this->EndX = (char*)NewElts+CurSizeBytes; + this->BeginX = NewElts; + this->CapacityX = (char*)this->BeginX + NewCapacityInBytes; +} + diff --git a/contrib/llvm/lib/Support/SourceMgr.cpp b/contrib/llvm/lib/Support/SourceMgr.cpp new file mode 100644 index 0000000..bbe36b2 --- /dev/null +++ b/contrib/llvm/lib/Support/SourceMgr.cpp @@ -0,0 +1,313 @@ +//===- SourceMgr.cpp - Manager for Simple Source Buffers & Diagnostics ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SourceMgr class. This class is used as a simple +// substrate for diagnostics, #include handling, and other low level things for +// simple parsers. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Twine.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" +using namespace llvm; + +namespace { + struct LineNoCacheTy { + int LastQueryBufferID; + const char *LastQuery; + unsigned LineNoOfQuery; + }; +} + +static LineNoCacheTy *getCache(void *Ptr) { + return (LineNoCacheTy*)Ptr; +} + + +SourceMgr::~SourceMgr() { + // Delete the line # cache if allocated. + if (LineNoCacheTy *Cache = getCache(LineNoCache)) + delete Cache; + + while (!Buffers.empty()) { + delete Buffers.back().Buffer; + Buffers.pop_back(); + } +} + +/// AddIncludeFile - Search for a file with the specified name in the current +/// directory or in one of the IncludeDirs. If no file is found, this returns +/// ~0, otherwise it returns the buffer ID of the stacked file. +unsigned SourceMgr::AddIncludeFile(const std::string &Filename, + SMLoc IncludeLoc, + std::string &IncludedFile) { + OwningPtr<MemoryBuffer> NewBuf; + IncludedFile = Filename; + MemoryBuffer::getFile(IncludedFile.c_str(), NewBuf); + + // If the file didn't exist directly, see if it's in an include path. + for (unsigned i = 0, e = IncludeDirectories.size(); i != e && !NewBuf; ++i) { + IncludedFile = IncludeDirectories[i] + "/" + Filename; + MemoryBuffer::getFile(IncludedFile.c_str(), NewBuf); + } + + if (NewBuf == 0) return ~0U; + + return AddNewSourceBuffer(NewBuf.take(), IncludeLoc); +} + + +/// FindBufferContainingLoc - Return the ID of the buffer containing the +/// specified location, returning -1 if not found. +int SourceMgr::FindBufferContainingLoc(SMLoc Loc) const { + for (unsigned i = 0, e = Buffers.size(); i != e; ++i) + if (Loc.getPointer() >= Buffers[i].Buffer->getBufferStart() && + // Use <= here so that a pointer to the null at the end of the buffer + // is included as part of the buffer. + Loc.getPointer() <= Buffers[i].Buffer->getBufferEnd()) + return i; + return -1; +} + +/// FindLineNumber - Find the line number for the specified location in the +/// specified file. This is not a fast method. +unsigned SourceMgr::FindLineNumber(SMLoc Loc, int BufferID) const { + if (BufferID == -1) BufferID = FindBufferContainingLoc(Loc); + assert(BufferID != -1 && "Invalid Location!"); + + MemoryBuffer *Buff = getBufferInfo(BufferID).Buffer; + + // Count the number of \n's between the start of the file and the specified + // location. + unsigned LineNo = 1; + + const char *Ptr = Buff->getBufferStart(); + + // If we have a line number cache, and if the query is to a later point in the + // same file, start searching from the last query location. This optimizes + // for the case when multiple diagnostics come out of one file in order. + if (LineNoCacheTy *Cache = getCache(LineNoCache)) + if (Cache->LastQueryBufferID == BufferID && + Cache->LastQuery <= Loc.getPointer()) { + Ptr = Cache->LastQuery; + LineNo = Cache->LineNoOfQuery; + } + + // Scan for the location being queried, keeping track of the number of lines + // we see. + for (; SMLoc::getFromPointer(Ptr) != Loc; ++Ptr) + if (*Ptr == '\n') ++LineNo; + + + // Allocate the line number cache if it doesn't exist. + if (LineNoCache == 0) + LineNoCache = new LineNoCacheTy(); + + // Update the line # cache. + LineNoCacheTy &Cache = *getCache(LineNoCache); + Cache.LastQueryBufferID = BufferID; + Cache.LastQuery = Ptr; + Cache.LineNoOfQuery = LineNo; + return LineNo; +} + +void SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const { + if (IncludeLoc == SMLoc()) return; // Top of stack. + + int CurBuf = FindBufferContainingLoc(IncludeLoc); + assert(CurBuf != -1 && "Invalid or unspecified location!"); + + PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS); + + OS << "Included from " + << getBufferInfo(CurBuf).Buffer->getBufferIdentifier() + << ":" << FindLineNumber(IncludeLoc, CurBuf) << ":\n"; +} + + +/// GetMessage - Return an SMDiagnostic at the specified location with the +/// specified string. +/// +/// @param Type - If non-null, the kind of message (e.g., "error") which is +/// prefixed to the message. +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. + int CurBuf = FindBufferContainingLoc(Loc); + assert(CurBuf != -1 && "Invalid or unspecified location!"); + + MemoryBuffer *CurMB = getBufferInfo(CurBuf).Buffer; + + // Scan backward to find the start of the line. + const char *LineStart = Loc.getPointer(); + while (LineStart != CurMB->getBufferStart() && + LineStart[-1] != '\n' && LineStart[-1] != '\r') + --LineStart; + + // 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, Kind, Msg.str(), + LineStr, ColRanges); +} + +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(Diagnostic, DiagContext); + return; + } + + raw_ostream &OS = errs(); + + int CurBuf = FindBufferContainingLoc(Loc); + assert(CurBuf != -1 && "Invalid or unspecified location!"); + PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS); + + Diagnostic.print(0, OS); +} + +//===----------------------------------------------------------------------===// +// SMDiagnostic Implementation +//===----------------------------------------------------------------------===// + +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 << ": "; + + if (!Filename.empty()) { + if (Filename == "-") + S << "<stdin>"; + else + S << Filename; + + if (LineNo != -1) { + S << ':' << LineNo; + if (ColumnNo != -1) + S << ':' << (ColumnNo+1); + } + 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) + return; + + // 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/contrib/llvm/lib/Support/Statistic.cpp b/contrib/llvm/lib/Support/Statistic.cpp new file mode 100644 index 0000000..d8a6ad3 --- /dev/null +++ b/contrib/llvm/lib/Support/Statistic.cpp @@ -0,0 +1,154 @@ +//===-- Statistic.cpp - Easy way to expose stats information --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the 'Statistic' class, which is designed to be an easy +// way to expose various success metrics from passes. These statistics are +// printed at the end of a run, when the -stats command line option is enabled +// on the command line. +// +// This is useful for reporting information like the number of instructions +// simplified, optimized or removed by various transformations, like this: +// +// static Statistic NumInstEliminated("GCSE", "Number of instructions killed"); +// +// Later, in the code: ++NumInstEliminated; +// +//===----------------------------------------------------------------------===// + +#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" +#include "llvm/ADT/StringExtras.h" +#include <algorithm> +#include <cstring> +using namespace llvm; + +// CreateInfoOutputFile - Return a file stream to print our output on. +namespace llvm { extern raw_ostream *CreateInfoOutputFile(); } + +/// -stats - Command line option to cause transformations to emit stats about +/// what they did. +/// +static cl::opt<bool> +Enabled("stats", cl::desc("Enable statistics output from program")); + + +namespace { +/// StatisticInfo - This class is used in a ManagedStatic so that it is created +/// on demand (when the first statistic is bumped) and destroyed only when +/// llvm_shutdown is called. We print statistics from the destructor. +class StatisticInfo { + std::vector<const Statistic*> Stats; + friend void llvm::PrintStatistics(); + friend void llvm::PrintStatistics(raw_ostream &OS); +public: + ~StatisticInfo(); + + void addStatistic(const Statistic *S) { + Stats.push_back(S); + } +}; +} + +static ManagedStatic<StatisticInfo> StatInfo; +static ManagedStatic<sys::SmartMutex<true> > StatLock; + +/// RegisterStatistic - The first time a statistic is bumped, this method is +/// called. +void Statistic::RegisterStatistic() { + // If stats are enabled, inform StatInfo that this statistic should be + // printed. + sys::SmartScopedLock<true> Writer(*StatLock); + if (!Initialized) { + if (Enabled) + StatInfo->addStatistic(this); + + TsanHappensBefore(this); + sys::MemoryFence(); + // Remember we have been registered. + TsanIgnoreWritesBegin(); + Initialized = true; + TsanIgnoreWritesEnd(); + } +} + +namespace { + +struct NameCompare { + bool operator()(const Statistic *LHS, const Statistic *RHS) const { + int Cmp = std::strcmp(LHS->getName(), RHS->getName()); + if (Cmp != 0) return Cmp < 0; + + // Secondary key is the description. + return std::strcmp(LHS->getDesc(), RHS->getDesc()) < 0; + } +}; + +} + +// Print information when destroyed, iff command line option is specified. +StatisticInfo::~StatisticInfo() { + llvm::PrintStatistics(); +} + +void llvm::EnableStatistics() { + Enabled.setValue(true); +} + +bool llvm::AreStatisticsEnabled() { + return Enabled; +} + +void llvm::PrintStatistics(raw_ostream &OS) { + StatisticInfo &Stats = *StatInfo; + + // Figure out how long the biggest Value and Name fields are. + unsigned MaxNameLen = 0, MaxValLen = 0; + for (size_t i = 0, e = Stats.Stats.size(); i != e; ++i) { + MaxValLen = std::max(MaxValLen, + (unsigned)utostr(Stats.Stats[i]->getValue()).size()); + MaxNameLen = std::max(MaxNameLen, + (unsigned)std::strlen(Stats.Stats[i]->getName())); + } + + // Sort the fields by name. + std::stable_sort(Stats.Stats.begin(), Stats.Stats.end(), NameCompare()); + + // Print out the statistics header... + OS << "===" << std::string(73, '-') << "===\n" + << " ... Statistics Collected ...\n" + << "===" << std::string(73, '-') << "===\n\n"; + + // Print all of the statistics. + 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(); + +} + +void llvm::PrintStatistics() { + StatisticInfo &Stats = *StatInfo; + + // Statistics not enabled? + if (Stats.Stats.empty()) return; + + // Get the stream to write to. + raw_ostream &OutStream = *CreateInfoOutputFile(); + PrintStatistics(OutStream); + delete &OutStream; // Close the file. +} diff --git a/contrib/llvm/lib/Support/StreamableMemoryObject.cpp b/contrib/llvm/lib/Support/StreamableMemoryObject.cpp new file mode 100644 index 0000000..c23f07b --- /dev/null +++ b/contrib/llvm/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/contrib/llvm/lib/Support/StringExtras.cpp b/contrib/llvm/lib/Support/StringExtras.cpp new file mode 100644 index 0000000..d77ad7f --- /dev/null +++ b/contrib/llvm/lib/Support/StringExtras.cpp @@ -0,0 +1,59 @@ +//===-- StringExtras.cpp - Implement the StringExtras header --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the StringExtras.h header +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +using namespace llvm; + +/// StrInStrNoCase - Portable version of strcasestr. Locates the first +/// occurrence of string 's1' in string 's2', ignoring case. Returns +/// the offset of s2 in s1 or npos if s2 cannot be found. +StringRef::size_type llvm::StrInStrNoCase(StringRef s1, StringRef s2) { + size_t N = s2.size(), M = s1.size(); + if (N > M) + return StringRef::npos; + for (size_t i = 0, e = M - N + 1; i != e; ++i) + if (s1.substr(i, N).equals_lower(s2)) + return i; + return StringRef::npos; +} + +/// getToken - This function extracts one token from source, ignoring any +/// leading characters that appear in the Delimiters string, and ending the +/// token at any of the characters that appear in the Delimiters string. If +/// there are no tokens in the source string, an empty string is returned. +/// The function returns a pair containing the extracted token and the +/// remaining tail string. +std::pair<StringRef, StringRef> llvm::getToken(StringRef Source, + StringRef Delimiters) { + // Figure out where the token starts. + StringRef::size_type Start = Source.find_first_not_of(Delimiters); + + // Find the next occurrence of the delimiter. + StringRef::size_type End = Source.find_first_of(Delimiters, Start); + + return std::make_pair(Source.slice(Start, End), Source.substr(End)); +} + +/// SplitString - Split up the specified string according to the specified +/// delimiters, appending the result fragments to the output list. +void llvm::SplitString(StringRef Source, + SmallVectorImpl<StringRef> &OutFragments, + StringRef Delimiters) { + std::pair<StringRef, StringRef> S = getToken(Source, Delimiters); + while (!S.first.empty()) { + OutFragments.push_back(S.first); + S = getToken(S.second, Delimiters); + } +} diff --git a/contrib/llvm/lib/Support/StringMap.cpp b/contrib/llvm/lib/Support/StringMap.cpp new file mode 100644 index 0000000..c131fe0 --- /dev/null +++ b/contrib/llvm/lib/Support/StringMap.cpp @@ -0,0 +1,237 @@ +//===--- StringMap.cpp - String Hash table map implementation -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the StringMap class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringExtras.h" +#include <cassert> +using namespace llvm; + +StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) { + ItemSize = itemSize; + + // If a size is specified, initialize the table with that many buckets. + if (InitSize) { + init(InitSize); + return; + } + + // Otherwise, initialize it with zero buckets to avoid the allocation. + TheTable = 0; + NumBuckets = 0; + NumItems = 0; + NumTombstones = 0; +} + +void StringMapImpl::init(unsigned InitSize) { + assert((InitSize & (InitSize-1)) == 0 && + "Init Size must be a power of 2 or zero!"); + NumBuckets = InitSize ? InitSize : 16; + NumItems = 0; + NumTombstones = 0; + + 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] = (StringMapEntryBase*)2; +} + + +/// LookupBucketFor - Look up the bucket that the specified string should end +/// up in. If it already exists as a key in the map, the Item pointer for the +/// specified bucket will be non-null. Otherwise, it will be null. In either +/// case, the FullHashValue field of the bucket will be set to the hash value +/// of the string. +unsigned StringMapImpl::LookupBucketFor(StringRef Name) { + unsigned HTSize = NumBuckets; + if (HTSize == 0) { // Hash table unallocated so far? + init(16); + HTSize = NumBuckets; + } + unsigned FullHashValue = HashString(Name); + unsigned BucketNo = FullHashValue & (HTSize-1); + unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1); + + unsigned ProbeAmt = 1; + int FirstTombstone = -1; + while (1) { + 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) { + HashTable[FirstTombstone] = FullHashValue; + return FirstTombstone; + } + + HashTable[BucketNo] = FullHashValue; + return BucketNo; + } + + if (BucketItem == getTombstoneVal()) { + // Skip over tombstones. However, remember the first one we see. + if (FirstTombstone == -1) FirstTombstone = BucketNo; + } 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 + // is important for cache locality. + + // Do the comparison like this because Name isn't necessarily + // null-terminated! + char *ItemStr = (char*)BucketItem+ItemSize; + if (Name == StringRef(ItemStr, BucketItem->getKeyLength())) { + // We found a match! + return BucketNo; + } + } + + // Okay, we didn't find the item. Probe to the next bucket. + BucketNo = (BucketNo+ProbeAmt) & (HTSize-1); + + // Use quadratic probing, it has fewer clumping artifacts than linear + // probing and has good cache behavior in the common case. + ++ProbeAmt; + } +} + + +/// FindKey - Look up the bucket that contains the specified key. If it exists +/// in the map, return the bucket number of the key. Otherwise return -1. +/// This does not modify the map. +int StringMapImpl::FindKey(StringRef Key) const { + unsigned HTSize = NumBuckets; + 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) { + 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 (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 + // is important for cache locality. + + // Do the comparison like this because NameStart isn't necessarily + // null-terminated! + char *ItemStr = (char*)BucketItem+ItemSize; + if (Key == StringRef(ItemStr, BucketItem->getKeyLength())) { + // We found a match! + return BucketNo; + } + } + + // Okay, we didn't find the item. Probe to the next bucket. + BucketNo = (BucketNo+ProbeAmt) & (HTSize-1); + + // Use quadratic probing, it has fewer clumping artifacts than linear + // probing and has good cache behavior in the common case. + ++ProbeAmt; + } +} + +/// RemoveKey - Remove the specified StringMapEntry from the table, but do not +/// delete it. This aborts if the value isn't in the table. +void StringMapImpl::RemoveKey(StringMapEntryBase *V) { + const char *VStr = (char*)V + ItemSize; + StringMapEntryBase *V2 = RemoveKey(StringRef(VStr, V->getKeyLength())); + (void)V2; + assert(V == V2 && "Didn't find key?"); +} + +/// RemoveKey - Remove the StringMapEntry for the specified key from the +/// table, returning it. If the key is not in the table, this returns null. +StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) { + int Bucket = FindKey(Key); + if (Bucket == -1) return 0; + + StringMapEntryBase *Result = TheTable[Bucket]; + TheTable[Bucket] = getTombstoneVal(); + --NumItems; + ++NumTombstones; + assert(NumItems + NumTombstones <= NumBuckets); + + return Result; +} + + + +/// RehashTable - Grow the table, redistributing values into the buckets with +/// 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), + // grow/rehash the table. + if (NumItems*4 > NumBuckets*3) { + NewSize = NumBuckets*2; + } else if (NumBuckets-(NumItems+NumTombstones) < NumBuckets/8) { + NewSize = NumBuckets; + } else { + return; + } + + // Allocate one extra bucket which will always be non-empty. This allows the + // iterators to stop at end. + StringMapEntryBase **NewTableArray = + (StringMapEntryBase **)calloc(NewSize+1, sizeof(StringMapEntryBase *) + + sizeof(unsigned)); + 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 (unsigned I = 0, E = NumBuckets; I != E; ++I) { + StringMapEntryBase *Bucket = TheTable[I]; + if (Bucket && Bucket != getTombstoneVal()) { + // Fast case, bucket available. + unsigned FullHash = HashTable[I]; + unsigned NewBucket = FullHash & (NewSize-1); + if (NewTableArray[NewBucket] == 0) { + NewTableArray[FullHash & (NewSize-1)] = Bucket; + NewHashArray[FullHash & (NewSize-1)] = FullHash; + continue; + } + + // Otherwise probe for a spot. + unsigned ProbeSize = 1; + do { + NewBucket = (NewBucket + ProbeSize++) & (NewSize-1); + } while (NewTableArray[NewBucket]); + + // Finally found a slot. Fill it in. + NewTableArray[NewBucket] = Bucket; + NewHashArray[NewBucket] = FullHash; + } + } + + free(TheTable); + + TheTable = NewTableArray; + NumBuckets = NewSize; + NumTombstones = 0; +} diff --git a/contrib/llvm/lib/Support/StringPool.cpp b/contrib/llvm/lib/Support/StringPool.cpp new file mode 100644 index 0000000..ff607cf --- /dev/null +++ b/contrib/llvm/lib/Support/StringPool.cpp @@ -0,0 +1,35 @@ +//===-- StringPool.cpp - Interned string pool -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the StringPool class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/StringPool.h" +#include "llvm/ADT/StringRef.h" + +using namespace llvm; + +StringPool::StringPool() {} + +StringPool::~StringPool() { + assert(InternTable.empty() && "PooledStringPtr leaked!"); +} + +PooledStringPtr StringPool::intern(StringRef Key) { + table_t::iterator I = InternTable.find(Key); + if (I != InternTable.end()) + return PooledStringPtr(&*I); + + entry_t *S = entry_t::Create(Key.begin(), Key.end()); + S->getValue().Pool = this; + InternTable.insert(S); + + return PooledStringPtr(S); +} diff --git a/contrib/llvm/lib/Support/StringRef.cpp b/contrib/llvm/lib/Support/StringRef.cpp new file mode 100644 index 0000000..abe570f --- /dev/null +++ b/contrib/llvm/lib/Support/StringRef.cpp @@ -0,0 +1,434 @@ +//===-- StringRef.cpp - Lightweight String References ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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; + +// MSVC emits references to this into the translation units which reference it. +#ifndef _MSC_VER +const size_t StringRef::npos; +#endif + +static char ascii_tolower(char x) { + if (x >= 'A' && x <= 'Z') + return x - 'A' + 'a'; + 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'; +} + +/// compare_lower - Compare strings, ignoring case. +int StringRef::compare_lower(StringRef RHS) const { + for (size_t I = 0, E = min(Length, RHS.Length); I != E; ++I) { + unsigned char LHC = ascii_tolower(Data[I]); + unsigned char RHC = ascii_tolower(RHS.Data[I]); + if (LHC != RHC) + return LHC < RHC ? -1 : 1; + } + + if (Length == RHS.Length) + return 0; + return Length < RHS.Length ? -1 : 1; +} + +/// compare_numeric - Compare strings, handle embedded numbers. +int StringRef::compare_numeric(StringRef RHS) const { + for (size_t I = 0, E = min(Length, RHS.Length); I != E; ++I) { + // Check for sequences of digits. + if (ascii_isdigit(Data[I]) && ascii_isdigit(RHS.Data[I])) { + // The longer sequence of numbers is considered larger. + // This doesn't really handle prefixed zeros well. + size_t J; + for (J = I + 1; J != E + 1; ++J) { + bool ld = J < Length && ascii_isdigit(Data[J]); + bool rd = J < RHS.Length && ascii_isdigit(RHS.Data[J]); + if (ld != rd) + return rd ? -1 : 1; + if (!rd) + break; + } + // The two number sequences have the same length (J-I), just memcmp them. + if (int Res = compareMemory(Data + I, RHS.Data + I, J - I)) + return Res < 0 ? -1 : 1; + // Identical number sequences, continue search after the numbers. + I = J - 1; + continue; + } + if (Data[I] != RHS.Data[I]) + return (unsigned char)Data[I] < (unsigned char)RHS.Data[I] ? -1 : 1; + } + if (Length == RHS.Length) + return 0; + return Length < RHS.Length ? -1 : 1; +} + +// Compute the edit distance between the two given strings. +unsigned StringRef::edit_distance(llvm::StringRef Other, + bool AllowReplacements, + unsigned MaxEditDistance) { + return llvm::ComputeEditDistance( + llvm::ArrayRef<char>(data(), size()), + llvm::ArrayRef<char>(Other.data(), Other.size()), + AllowReplacements, MaxEditDistance); +} + +//===----------------------------------------------------------------------===// +// String Operations +//===----------------------------------------------------------------------===// + +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; +} + +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; +} + +//===----------------------------------------------------------------------===// +// String Searching +//===----------------------------------------------------------------------===// + + +/// find - Search for the first string \arg Str in the string. +/// +/// \return - The index of the first occurrence of \arg Str, or npos if not +/// found. +size_t StringRef::find(StringRef Str, size_t From) const { + size_t N = Str.size(); + if (N > Length) + return npos; + + // 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; +} + +/// rfind - Search for the last string \arg Str in the string. +/// +/// \return - The index of the last occurrence of \arg Str, or npos if not +/// found. +size_t StringRef::rfind(StringRef Str) const { + size_t N = Str.size(); + if (N > Length) + return npos; + for (size_t i = Length - N + 1, e = 0; i != e;) { + --i; + if (substr(i, N).equals(Str)) + return i; + } + return npos; +} + +/// find_first_of - Find the first character in the string that is in \arg +/// Chars, or npos if not found. +/// +/// Note: O(size() + Chars.size()) +StringRef::size_type StringRef::find_first_of(StringRef Chars, + size_t From) const { + std::bitset<1 << CHAR_BIT> CharBits; + for (size_type i = 0; i != Chars.size(); ++i) + CharBits.set((unsigned char)Chars[i]); + + for (size_type i = min(From, Length), e = Length; i != e; ++i) + if (CharBits.test((unsigned char)Data[i])) + return i; + return npos; +} + +/// find_first_not_of - Find the first character in the string that is not +/// \arg C or npos if not found. +StringRef::size_type StringRef::find_first_not_of(char C, size_t From) const { + for (size_type i = min(From, Length), e = Length; i != e; ++i) + if (Data[i] != C) + return i; + return npos; +} + +/// find_first_not_of - Find the first character in the string that is not +/// in the string \arg Chars, or npos if not found. +/// +/// Note: O(size() + Chars.size()) +StringRef::size_type StringRef::find_first_not_of(StringRef Chars, + size_t From) const { + std::bitset<1 << CHAR_BIT> CharBits; + for (size_type i = 0; i != Chars.size(); ++i) + CharBits.set((unsigned char)Chars[i]); + + for (size_type i = min(From, Length), e = Length; i != e; ++i) + if (!CharBits.test((unsigned char)Data[i])) + return i; + return npos; +} + +/// find_last_of - Find the last character in the string that is in \arg C, +/// or npos if not found. +/// +/// Note: O(size() + Chars.size()) +StringRef::size_type StringRef::find_last_of(StringRef Chars, + size_t From) const { + std::bitset<1 << CHAR_BIT> CharBits; + for (size_type i = 0; i != Chars.size(); ++i) + CharBits.set((unsigned char)Chars[i]); + + for (size_type i = min(From, Length) - 1, e = -1; i != e; --i) + if (CharBits.test((unsigned char)Data[i])) + return i; + 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 +//===----------------------------------------------------------------------===// + +/// count - Return the number of non-overlapped occurrences of \arg Str in +/// the string. +size_t StringRef::count(StringRef Str) const { + size_t Count = 0; + size_t N = Str.size(); + if (N > Length) + return 0; + for (size_t i = 0, e = Length - N + 1; i != e; ++i) + if (substr(i, N).equals(Str)) + ++Count; + return Count; +} + +static unsigned GetAutoSenseRadix(StringRef &Str) { + if (Str.startswith("0x")) { + Str = Str.substr(2); + return 16; + } else if (Str.startswith("0b")) { + Str = Str.substr(2); + return 2; + } else if (Str.startswith("0")) { + return 8; + } else { + return 10; + } +} + + +/// GetAsUnsignedInteger - Workhorse method that converts a integer character +/// sequence of radix up to 36 to an unsigned long long value. +bool llvm::getAsUnsignedInteger(StringRef Str, unsigned Radix, + unsigned long long &Result) { + // Autosense radix if not specified. + if (Radix == 0) + Radix = GetAutoSenseRadix(Str); + + // Empty strings (after the radix autosense) are invalid. + if (Str.empty()) return true; + + // Parse all the bytes of the string given this radix. Watch for overflow. + Result = 0; + while (!Str.empty()) { + unsigned CharVal; + if (Str[0] >= '0' && Str[0] <= '9') + CharVal = Str[0]-'0'; + else if (Str[0] >= 'a' && Str[0] <= 'z') + CharVal = Str[0]-'a'+10; + else if (Str[0] >= 'A' && Str[0] <= 'Z') + CharVal = Str[0]-'A'+10; + else + return true; + + // If the parsed value is larger than the integer radix, the string is + // invalid. + if (CharVal >= Radix) + return true; + + // Add in this character. + unsigned long long PrevResult = Result; + Result = Result*Radix+CharVal; + + // Check for overflow. + if (Result < PrevResult) + return true; + + Str = Str.substr(1); + } + + return false; +} + +bool llvm::getAsSignedInteger(StringRef Str, unsigned Radix, + long long &Result) { + unsigned long long ULLVal; + + // Handle positive strings first. + 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; + Result = ULLVal; + return false; + } + + // Get the positive part of the value. + 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. + (long long)-ULLVal > 0) + return true; + + Result = -ULLVal; + return false; +} + +bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const { + StringRef Str = *this; + + // Autosense radix if not specified. + if (Radix == 0) + Radix = GetAutoSenseRadix(Str); + + assert(Radix > 1 && Radix <= 36); + + // Empty strings (after the radix autosense) are invalid. + if (Str.empty()) return true; + + // Skip leading zeroes. This can be a significant improvement if + // it means we don't need > 64 bits. + while (!Str.empty() && Str.front() == '0') + Str = Str.substr(1); + + // If it was nothing but zeroes.... + if (Str.empty()) { + Result = APInt(64, 0); + return false; + } + + // (Over-)estimate the required number of bits. + unsigned Log2Radix = 0; + while ((1U << Log2Radix) < Radix) Log2Radix++; + bool IsPowerOf2Radix = ((1U << Log2Radix) == Radix); + + unsigned BitWidth = Log2Radix * Str.size(); + if (BitWidth < Result.getBitWidth()) + BitWidth = Result.getBitWidth(); // don't shrink the result + else + Result = Result.zext(BitWidth); + + APInt RadixAP, CharAP; // unused unless !IsPowerOf2Radix + if (!IsPowerOf2Radix) { + // These must have the same bit-width as Result. + RadixAP = APInt(BitWidth, Radix); + CharAP = APInt(BitWidth, 0); + } + + // Parse all the bytes of the string given this radix. + Result = 0; + while (!Str.empty()) { + unsigned CharVal; + if (Str[0] >= '0' && Str[0] <= '9') + CharVal = Str[0]-'0'; + else if (Str[0] >= 'a' && Str[0] <= 'z') + CharVal = Str[0]-'a'+10; + else if (Str[0] >= 'A' && Str[0] <= 'Z') + CharVal = Str[0]-'A'+10; + else + return true; + + // If the parsed value is larger than the integer radix, the string is + // invalid. + if (CharVal >= Radix) + return true; + + // Add in this character. + if (IsPowerOf2Radix) { + Result <<= Log2Radix; + Result |= CharVal; + } else { + Result *= RadixAP; + CharAP = CharVal; + Result += CharAP; + } + + Str = Str.substr(1); + } + + return false; +} + + +// Implementation of StringRef hashing. +hash_code llvm::hash_value(StringRef S) { + return hash_combine_range(S.begin(), S.end()); +} diff --git a/contrib/llvm/lib/Support/SystemUtils.cpp b/contrib/llvm/lib/Support/SystemUtils.cpp new file mode 100644 index 0000000..54b5e97 --- /dev/null +++ b/contrib/llvm/lib/Support/SystemUtils.cpp @@ -0,0 +1,55 @@ +//===- SystemUtils.cpp - Utilities for low-level system tasks -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains functions used to do a variety of low-level, often +// system-specific, tasks. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/SystemUtils.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +bool llvm::CheckBitcodeOutputToConsole(raw_ostream &stream_to_check, + bool print_warning) { + if (stream_to_check.is_displayed()) { + if (print_warning) { + errs() << "WARNING: You're attempting to print out a bitcode file.\n" + "This is inadvisable as it may cause display problems. If\n" + "you REALLY want to taste LLVM bitcode first-hand, you\n" + "can force output with the `-f' option.\n\n"; + } + return true; + } + return false; +} + +/// PrependMainExecutablePath - Prepend the path to the program being executed +/// to \p ExeName, given the value of argv[0] and the address of main() +/// itself. This allows us to find another LLVM tool if it is built in the same +/// directory. An empty string is returned on error; note that this function +/// just mainpulates the path and doesn't check for executability. +/// @brief Find a named executable. +sys::Path llvm::PrependMainExecutablePath(const std::string &ExeName, + const char *Argv0, void *MainAddr) { + // Check the directory that the calling program is in. We can do + // this if ProgramPath contains at least one / character, indicating that it + // is a relative path to the executable itself. + sys::Path Result = sys::Path::GetMainExecutable(Argv0, MainAddr); + Result.eraseComponent(); + + if (!Result.isEmpty()) { + Result.appendComponent(ExeName); + Result.appendSuffix(sys::Path::GetEXESuffix()); + } + + return Result; +} diff --git a/contrib/llvm/lib/Support/TargetRegistry.cpp b/contrib/llvm/lib/Support/TargetRegistry.cpp new file mode 100644 index 0000000..53c8d84 --- /dev/null +++ b/contrib/llvm/lib/Support/TargetRegistry.cpp @@ -0,0 +1,122 @@ +//===--- TargetRegistry.cpp - Target registration -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/TargetRegistry.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <vector> +using namespace llvm; + +// Clients are responsible for avoid race conditions in registration. +static Target *FirstTarget = 0; + +TargetRegistry::iterator TargetRegistry::begin() { + return iterator(FirstTarget); +} + +const Target *TargetRegistry::lookupTarget(const std::string &TT, + std::string &Error) { + // Provide special warning when no targets are initialized. + if (begin() == end()) { + Error = "Unable to find target for this triple (no targets are registered)"; + return 0; + } + const Target *Best = 0, *EquallyBest = 0; + unsigned BestQuality = 0; + for (iterator it = begin(), ie = end(); it != ie; ++it) { + if (unsigned Qual = it->TripleMatchQualityFn(TT)) { + if (!Best || Qual > BestQuality) { + Best = &*it; + EquallyBest = 0; + BestQuality = Qual; + } else if (Qual == BestQuality) + EquallyBest = &*it; + } + } + + if (!Best) { + Error = "No available targets are compatible with this triple, " + "see -version for the available targets."; + return 0; + } + + // Otherwise, take the best target, but make sure we don't have two equally + // good best targets. + if (EquallyBest) { + Error = std::string("Cannot choose between targets \"") + + Best->Name + "\" and \"" + EquallyBest->Name + "\""; + return 0; + } + + return Best; +} + +void TargetRegistry::RegisterTarget(Target &T, + const char *Name, + const char *ShortDesc, + Target::TripleMatchQualityFnTy TQualityFn, + bool HasJIT) { + assert(Name && ShortDesc && TQualityFn && + "Missing required target information!"); + + // Check if this target has already been initialized, we allow this as a + // convenience to some clients. + if (T.Name) + return; + + // Add to the list of targets. + T.Next = FirstTarget; + FirstTarget = &T; + + T.Name = Name; + T.ShortDesc = ShortDesc; + T.TripleMatchQualityFn = TQualityFn; + T.HasJIT = HasJIT; +} + +const Target *TargetRegistry::getClosestTargetForJIT(std::string &Error) { + const Target *TheTarget = lookupTarget(sys::getDefaultTargetTriple(), Error); + + if (TheTarget && !TheTarget->hasJIT()) { + Error = "No JIT compatible target available for this host"; + return 0; + } + + return TheTarget; +} + +static int TargetArraySortFn(const void *LHS, const void *RHS) { + typedef std::pair<StringRef, const Target*> pair_ty; + return ((const pair_ty*)LHS)->first.compare(((const pair_ty*)RHS)->first); +} + +void TargetRegistry::printRegisteredTargetsForVersion() { + std::vector<std::pair<StringRef, const Target*> > Targets; + size_t Width = 0; + for (TargetRegistry::iterator I = TargetRegistry::begin(), + E = TargetRegistry::end(); + I != E; ++I) { + Targets.push_back(std::make_pair(I->getName(), &*I)); + Width = std::max(Width, Targets.back().first.size()); + } + array_pod_sort(Targets.begin(), Targets.end(), TargetArraySortFn); + + raw_ostream &OS = outs(); + OS << " Registered Targets:\n"; + for (unsigned i = 0, e = Targets.size(); i != e; ++i) { + OS << " " << Targets[i].first; + OS.indent(Width - Targets[i].first.size()) << " - " + << Targets[i].second->getShortDescription() << '\n'; + } + if (Targets.empty()) + OS << " (none)\n"; +} diff --git a/contrib/llvm/lib/Support/ThreadLocal.cpp b/contrib/llvm/lib/Support/ThreadLocal.cpp new file mode 100644 index 0000000..08b12b6 --- /dev/null +++ b/contrib/llvm/lib/Support/ThreadLocal.cpp @@ -0,0 +1,84 @@ +//===- ThreadLocal.cpp - Thread Local Data ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the llvm::sys::ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/ThreadLocal.h" + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +#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; +ThreadLocalImpl::ThreadLocalImpl() { } +ThreadLocalImpl::~ThreadLocalImpl() { } +void ThreadLocalImpl::setInstance(const void* d) { data = const_cast<void*>(d);} +const void* ThreadLocalImpl::getInstance() { return data; } +void ThreadLocalImpl::removeInstance() { data = 0; } +} +#else + +#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_GETSPECIFIC) + +#include <cassert> +#include <pthread.h> +#include <stdlib.h> + +namespace llvm { +using namespace sys; + +ThreadLocalImpl::ThreadLocalImpl() : data(0) { + pthread_key_t* key = new pthread_key_t; + int errorcode = pthread_key_create(key, NULL); + assert(errorcode == 0); + (void) errorcode; + data = (void*)key; +} + +ThreadLocalImpl::~ThreadLocalImpl() { + pthread_key_t* key = static_cast<pthread_key_t*>(data); + int errorcode = pthread_key_delete(*key); + assert(errorcode == 0); + (void) errorcode; + delete key; +} + +void ThreadLocalImpl::setInstance(const void* d) { + pthread_key_t* key = static_cast<pthread_key_t*>(data); + int errorcode = pthread_setspecific(*key, d); + assert(errorcode == 0); + (void) errorcode; +} + +const void* ThreadLocalImpl::getInstance() { + pthread_key_t* key = static_cast<pthread_key_t*>(data); + return pthread_getspecific(*key); +} + +void ThreadLocalImpl::removeInstance() { + setInstance(0); +} + +} + +#elif defined(LLVM_ON_UNIX) +#include "Unix/ThreadLocal.inc" +#elif defined( LLVM_ON_WIN32) +#include "Windows/ThreadLocal.inc" +#else +#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 set in Support/ThreadLocal.cpp +#endif +#endif diff --git a/contrib/llvm/lib/Support/Threading.cpp b/contrib/llvm/lib/Support/Threading.cpp new file mode 100644 index 0000000..7483225 --- /dev/null +++ b/contrib/llvm/lib/Support/Threading.cpp @@ -0,0 +1,147 @@ +//===-- llvm/Support/Threading.cpp- Control multithreading mode --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements llvm_start_multithreaded() and friends. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Threading.h" +#include "llvm/Support/Atomic.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Config/config.h" +#include <cassert> + +using namespace llvm; + +static bool multithreaded_mode = false; + +static sys::Mutex* global_lock = 0; + +bool llvm::llvm_start_multithreaded() { +#if LLVM_ENABLE_THREADS != 0 + assert(!multithreaded_mode && "Already multithreaded!"); + multithreaded_mode = true; + global_lock = new sys::Mutex(true); + + // We fence here to ensure that all initialization is complete BEFORE we + // return from llvm_start_multithreaded(). + sys::MemoryFence(); + return true; +#else + return false; +#endif +} + +void llvm::llvm_stop_multithreaded() { +#if LLVM_ENABLE_THREADS != 0 + assert(multithreaded_mode && "Not currently multithreaded!"); + + // We fence here to insure that all threaded operations are complete BEFORE we + // return from llvm_stop_multithreaded(). + sys::MemoryFence(); + + multithreaded_mode = false; + delete global_lock; +#endif +} + +bool llvm::llvm_is_multithreaded() { + return multithreaded_mode; +} + +void llvm::llvm_acquire_global_lock() { + if (multithreaded_mode) global_lock->acquire(); +} + +void llvm::llvm_release_global_lock() { + if (multithreaded_mode) global_lock->release(); +} + +#if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H) +#include <pthread.h> + +struct ThreadInfo { + void (*UserFn)(void *); + void *UserData; +}; +static void *ExecuteOnThread_Dispatch(void *Arg) { + ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(Arg); + TI->UserFn(TI->UserData); + return 0; +} + +void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, + unsigned RequestedStackSize) { + ThreadInfo Info = { Fn, UserData }; + pthread_attr_t Attr; + pthread_t Thread; + + // Construct the attributes object. + if (::pthread_attr_init(&Attr) != 0) + return; + + // Set the requested stack size, if given. + if (RequestedStackSize != 0) { + if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0) + goto error; + } + + // Construct and execute the thread. + if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0) + goto error; + + // Wait for the thread and clean up. + ::pthread_join(Thread, 0); + + error: + ::pthread_attr_destroy(&Attr); +} +#elif LLVM_ENABLE_THREADS!=0 && defined(LLVM_ON_WIN32) +#include "Windows/Windows.h" +#include <process.h> + +struct ThreadInfo { + void (*func)(void*); + void *param; +}; + +static unsigned __stdcall ThreadCallback(void *param) { + struct ThreadInfo *info = reinterpret_cast<struct ThreadInfo *>(param); + info->func(info->param); + + return 0; +} + +void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, + unsigned RequestedStackSize) { + struct ThreadInfo param = { Fn, UserData }; + + HANDLE hThread = (HANDLE)::_beginthreadex(NULL, + RequestedStackSize, ThreadCallback, + ¶m, 0, NULL); + + if (hThread) { + // We actually don't care whether the wait succeeds or fails, in + // the same way we don't care whether the pthread_join call succeeds + // or fails. There's not much we could do if this were to fail. But + // on success, this call will wait until the thread finishes executing + // before returning. + (void)::WaitForSingleObject(hThread, INFINITE); + ::CloseHandle(hThread); + } +} +#else +// Support for non-Win32, non-pthread implementation. +void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, + unsigned RequestedStackSize) { + (void) RequestedStackSize; + Fn(UserData); +} + +#endif diff --git a/contrib/llvm/lib/Support/TimeValue.cpp b/contrib/llvm/lib/Support/TimeValue.cpp new file mode 100644 index 0000000..1a0f7bc --- /dev/null +++ b/contrib/llvm/lib/Support/TimeValue.cpp @@ -0,0 +1,57 @@ +//===-- TimeValue.cpp - Implement OS TimeValue Concept ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the operating system TimeValue concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/TimeValue.h" +#include "llvm/Config/config.h" + +namespace llvm { +using namespace sys; + +const TimeValue TimeValue::MinTime = TimeValue ( INT64_MIN,0 ); +const TimeValue TimeValue::MaxTime = TimeValue ( INT64_MAX,0 ); +const TimeValue TimeValue::ZeroTime = TimeValue ( 0,0 ); +const TimeValue TimeValue::PosixZeroTime = TimeValue ( -946684800,0 ); +const TimeValue TimeValue::Win32ZeroTime = TimeValue ( -12591158400ULL,0 ); + +void +TimeValue::normalize( void ) { + if ( nanos_ >= NANOSECONDS_PER_SECOND ) { + do { + seconds_++; + nanos_ -= NANOSECONDS_PER_SECOND; + } while ( nanos_ >= NANOSECONDS_PER_SECOND ); + } else if (nanos_ <= -NANOSECONDS_PER_SECOND ) { + do { + seconds_--; + nanos_ += NANOSECONDS_PER_SECOND; + } while (nanos_ <= -NANOSECONDS_PER_SECOND); + } + + if (seconds_ >= 1 && nanos_ < 0) { + seconds_--; + nanos_ += NANOSECONDS_PER_SECOND; + } else if (seconds_ < 0 && nanos_ > 0) { + seconds_++; + nanos_ -= NANOSECONDS_PER_SECOND; + } +} + +} + +/// Include the platform specific portion of TimeValue class +#ifdef LLVM_ON_UNIX +#include "Unix/TimeValue.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/TimeValue.inc" +#endif diff --git a/contrib/llvm/lib/Support/Timer.cpp b/contrib/llvm/lib/Support/Timer.cpp new file mode 100644 index 0000000..598e8ad --- /dev/null +++ b/contrib/llvm/lib/Support/Timer.cpp @@ -0,0 +1,389 @@ +//===-- Timer.cpp - Interval Timing Support -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Interval Timing implementation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Timer.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/Process.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringMap.h" +using namespace llvm; + +// CreateInfoOutputFile - Return a file stream to print our output on. +namespace llvm { extern raw_ostream *CreateInfoOutputFile(); } + +// getLibSupportInfoOutputFilename - This ugly hack is brought to you courtesy +// of constructor/destructor ordering being unspecified by C++. Basically the +// problem is that a Statistic object gets destroyed, which ends up calling +// 'GetLibSupportInfoOutputFile()' (below), which calls this function. +// LibSupportInfoOutputFilename used to be a global variable, but sometimes it +// would get destroyed before the Statistic, causing havoc to ensue. We "fix" +// this by creating the string the first time it is needed and never destroying +// it. +static ManagedStatic<std::string> LibSupportInfoOutputFilename; +static std::string &getLibSupportInfoOutputFilename() { + return *LibSupportInfoOutputFilename; +} + +static ManagedStatic<sys::SmartMutex<true> > TimerLock; + +namespace { + static cl::opt<bool> + TrackSpace("track-memory", cl::desc("Enable -time-passes memory " + "tracking (this may be slow)"), + cl::Hidden); + + static cl::opt<std::string, true> + InfoOutputFilename("info-output-file", cl::value_desc("filename"), + cl::desc("File to append -stats and -timer output to"), + cl::Hidden, cl::location(getLibSupportInfoOutputFilename())); +} + +// CreateInfoOutputFile - Return a file stream to print our output on. +raw_ostream *llvm::CreateInfoOutputFile() { + const std::string &OutputFilename = getLibSupportInfoOutputFilename(); + if (OutputFilename.empty()) + return new raw_fd_ostream(2, false); // stderr. + if (OutputFilename == "-") + return new raw_fd_ostream(1, false); // stdout. + + // Append mode is used because the info output file is opened and closed + // each time -stats or -time-passes wants to print output to it. To + // compensate for this, the test-suite Makefiles have code to delete the + // info output file before running commands which write to it. + std::string Error; + raw_ostream *Result = new raw_fd_ostream(OutputFilename.c_str(), + Error, raw_fd_ostream::F_Append); + if (Error.empty()) + return Result; + + errs() << "Error opening info-output-file '" + << OutputFilename << " for appending!\n"; + delete Result; + return new raw_fd_ostream(2, false); // stderr. +} + + +static TimerGroup *DefaultTimerGroup = 0; +static TimerGroup *getDefaultTimerGroup() { + TimerGroup *tmp = DefaultTimerGroup; + sys::MemoryFence(); + if (tmp) return tmp; + + llvm_acquire_global_lock(); + tmp = DefaultTimerGroup; + if (!tmp) { + tmp = new TimerGroup("Miscellaneous Ungrouped Timers"); + sys::MemoryFence(); + DefaultTimerGroup = tmp; + } + llvm_release_global_lock(); + + return tmp; +} + +//===----------------------------------------------------------------------===// +// Timer Implementation +//===----------------------------------------------------------------------===// + +void Timer::init(StringRef N) { + assert(TG == 0 && "Timer already initialized"); + Name.assign(N.begin(), N.end()); + Started = false; + TG = getDefaultTimerGroup(); + TG->addTimer(*this); +} + +void Timer::init(StringRef N, TimerGroup &tg) { + assert(TG == 0 && "Timer already initialized"); + Name.assign(N.begin(), N.end()); + Started = false; + TG = &tg; + TG->addTimer(*this); +} + +Timer::~Timer() { + if (!TG) return; // Never initialized, or already cleared. + TG->removeTimer(*this); +} + +static inline size_t getMemUsage() { + if (!TrackSpace) return 0; + return sys::Process::GetMallocUsage(); +} + +TimeRecord TimeRecord::getCurrentTime(bool Start) { + TimeRecord Result; + sys::TimeValue now(0,0), user(0,0), sys(0,0); + + if (Start) { + Result.MemUsed = getMemUsage(); + sys::Process::GetTimeUsage(now, user, sys); + } else { + sys::Process::GetTimeUsage(now, user, sys); + Result.MemUsed = getMemUsage(); + } + + Result.WallTime = now.seconds() + now.microseconds() / 1000000.0; + Result.UserTime = user.seconds() + user.microseconds() / 1000000.0; + Result.SystemTime = sys.seconds() + sys.microseconds() / 1000000.0; + return Result; +} + +static ManagedStatic<std::vector<Timer*> > ActiveTimers; + +void Timer::startTimer() { + Started = true; + ActiveTimers->push_back(this); + Time -= TimeRecord::getCurrentTime(true); +} + +void Timer::stopTimer() { + Time += TimeRecord::getCurrentTime(false); + + if (ActiveTimers->back() == this) { + ActiveTimers->pop_back(); + } else { + std::vector<Timer*>::iterator I = + std::find(ActiveTimers->begin(), ActiveTimers->end(), this); + assert(I != ActiveTimers->end() && "stop but no startTimer?"); + ActiveTimers->erase(I); + } +} + +static void printVal(double Val, double Total, raw_ostream &OS) { + if (Total < 1e-7) // Avoid dividing by zero. + OS << " ----- "; + else + OS << format(" %7.4f (%5.1f%%)", Val, Val*100/Total); +} + +void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const { + if (Total.getUserTime()) + printVal(getUserTime(), Total.getUserTime(), OS); + if (Total.getSystemTime()) + printVal(getSystemTime(), Total.getSystemTime(), OS); + if (Total.getProcessTime()) + printVal(getProcessTime(), Total.getProcessTime(), OS); + printVal(getWallTime(), Total.getWallTime(), OS); + + OS << " "; + + if (Total.getMemUsed()) + OS << format("%9" PRId64 " ", (int64_t)getMemUsed()); +} + + +//===----------------------------------------------------------------------===// +// NamedRegionTimer Implementation +//===----------------------------------------------------------------------===// + +namespace { + +typedef StringMap<Timer> Name2TimerMap; + +class Name2PairMap { + StringMap<std::pair<TimerGroup*, Name2TimerMap> > Map; +public: + ~Name2PairMap() { + for (StringMap<std::pair<TimerGroup*, Name2TimerMap> >::iterator + I = Map.begin(), E = Map.end(); I != E; ++I) + delete I->second.first; + } + + Timer &get(StringRef Name, StringRef GroupName) { + sys::SmartScopedLock<true> L(*TimerLock); + + std::pair<TimerGroup*, Name2TimerMap> &GroupEntry = Map[GroupName]; + + if (!GroupEntry.first) + GroupEntry.first = new TimerGroup(GroupName); + + Timer &T = GroupEntry.second[Name]; + if (!T.isInitialized()) + T.init(Name, *GroupEntry.first); + return T; + } +}; + +} + +static ManagedStatic<Name2TimerMap> NamedTimers; +static ManagedStatic<Name2PairMap> NamedGroupedTimers; + +static Timer &getNamedRegionTimer(StringRef Name) { + sys::SmartScopedLock<true> L(*TimerLock); + + Timer &T = (*NamedTimers)[Name]; + if (!T.isInitialized()) + T.init(Name); + return T; +} + +NamedRegionTimer::NamedRegionTimer(StringRef Name, + bool Enabled) + : TimeRegion(!Enabled ? 0 : &getNamedRegionTimer(Name)) {} + +NamedRegionTimer::NamedRegionTimer(StringRef Name, StringRef GroupName, + bool Enabled) + : TimeRegion(!Enabled ? 0 : &NamedGroupedTimers->get(Name, GroupName)) {} + +//===----------------------------------------------------------------------===// +// TimerGroup Implementation +//===----------------------------------------------------------------------===// + +/// TimerGroupList - This is the global list of TimerGroups, maintained by the +/// TimerGroup ctor/dtor and is protected by the TimerLock lock. +static TimerGroup *TimerGroupList = 0; + +TimerGroup::TimerGroup(StringRef name) + : Name(name.begin(), name.end()), FirstTimer(0) { + + // Add the group to TimerGroupList. + sys::SmartScopedLock<true> L(*TimerLock); + if (TimerGroupList) + TimerGroupList->Prev = &Next; + Next = TimerGroupList; + Prev = &TimerGroupList; + TimerGroupList = this; +} + +TimerGroup::~TimerGroup() { + // If the timer group is destroyed before the timers it owns, accumulate and + // print the timing data. + while (FirstTimer != 0) + removeTimer(*FirstTimer); + + // Remove the group from the TimerGroupList. + sys::SmartScopedLock<true> L(*TimerLock); + *Prev = Next; + if (Next) + Next->Prev = Prev; +} + + +void TimerGroup::removeTimer(Timer &T) { + sys::SmartScopedLock<true> L(*TimerLock); + + // If the timer was started, move its data to TimersToPrint. + if (T.Started) + TimersToPrint.push_back(std::make_pair(T.Time, T.Name)); + + T.TG = 0; + + // Unlink the timer from our list. + *T.Prev = T.Next; + if (T.Next) + T.Next->Prev = T.Prev; + + // Print the report when all timers in this group are destroyed if some of + // them were started. + if (FirstTimer != 0 || TimersToPrint.empty()) + return; + + raw_ostream *OutStream = CreateInfoOutputFile(); + PrintQueuedTimers(*OutStream); + delete OutStream; // Close the file. +} + +void TimerGroup::addTimer(Timer &T) { + sys::SmartScopedLock<true> L(*TimerLock); + + // Add the timer to our list. + if (FirstTimer) + FirstTimer->Prev = &T.Next; + T.Next = FirstTimer; + T.Prev = &FirstTimer; + FirstTimer = &T; +} + +void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { + // Sort the timers in descending order by amount of time taken. + std::sort(TimersToPrint.begin(), TimersToPrint.end()); + + TimeRecord Total; + for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i) + Total += TimersToPrint[i].first; + + // Print out timing header. + OS << "===" << std::string(73, '-') << "===\n"; + // Figure out how many spaces to indent TimerGroup name. + unsigned Padding = (80-Name.length())/2; + if (Padding > 80) Padding = 0; // Don't allow "negative" numbers + OS.indent(Padding) << Name << '\n'; + OS << "===" << std::string(73, '-') << "===\n"; + + // If this is not an collection of ungrouped times, print the total time. + // Ungrouped timers don't really make sense to add up. We still print the + // TOTAL line to make the percentages make sense. + 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()) + OS << " ---User Time---"; + if (Total.getSystemTime()) + OS << " --System Time--"; + if (Total.getProcessTime()) + OS << " --User+System--"; + OS << " ---Wall Time---"; + if (Total.getMemUsed()) + OS << " ---Mem---"; + OS << " --- Name ---\n"; + + // Loop through all of the timing data, printing it out. + for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i) { + const std::pair<TimeRecord, std::string> &Entry = TimersToPrint[e-i-1]; + Entry.first.print(Total, OS); + OS << Entry.second << '\n'; + } + + Total.print(Total, OS); + OS << "Total\n\n"; + OS.flush(); + + TimersToPrint.clear(); +} + +/// print - Print any started timers in this group and zero them. +void TimerGroup::print(raw_ostream &OS) { + sys::SmartScopedLock<true> L(*TimerLock); + + // See if any of our timers were started, if so add them to TimersToPrint and + // reset them. + for (Timer *T = FirstTimer; T; T = T->Next) { + if (!T->Started) continue; + TimersToPrint.push_back(std::make_pair(T->Time, T->Name)); + + // Clear out the time. + T->Started = 0; + T->Time = TimeRecord(); + } + + // If any timers were started, print the group. + if (!TimersToPrint.empty()) + PrintQueuedTimers(OS); +} + +/// printAll - This static method prints all timers and clears them all out. +void TimerGroup::printAll(raw_ostream &OS) { + sys::SmartScopedLock<true> L(*TimerLock); + + for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next) + TG->print(OS); +} diff --git a/contrib/llvm/lib/Support/ToolOutputFile.cpp b/contrib/llvm/lib/Support/ToolOutputFile.cpp new file mode 100644 index 0000000..e7ca927 --- /dev/null +++ b/contrib/llvm/lib/Support/ToolOutputFile.cpp @@ -0,0 +1,43 @@ +//===--- ToolOutputFile.cpp - Implement the tool_output_file class --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This implements the tool_output_file class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/Signals.h" +using namespace llvm; + +tool_output_file::CleanupInstaller::CleanupInstaller(const char *filename) + : Filename(filename), Keep(false) { + // Arrange for the file to be deleted if the process is killed. + if (Filename != "-") + sys::RemoveFileOnSignal(sys::Path(Filename)); +} + +tool_output_file::CleanupInstaller::~CleanupInstaller() { + // Delete the file if the client hasn't told us not to. + if (!Keep && Filename != "-") + sys::Path(Filename).eraseFromDisk(); + + // Ok, the file is successfully written and closed, or deleted. There's no + // further need to clean it up on signals. + if (Filename != "-") + sys::DontRemoveFileOnSignal(sys::Path(Filename)); +} + +tool_output_file::tool_output_file(const char *filename, std::string &ErrorInfo, + unsigned Flags) + : Installer(filename), + OS(filename, ErrorInfo, Flags) { + // If open fails, no cleanup is needed. + if (!ErrorInfo.empty()) + Installer.Keep = true; +} diff --git a/contrib/llvm/lib/Support/Triple.cpp b/contrib/llvm/lib/Support/Triple.cpp new file mode 100644 index 0000000..44a1b38 --- /dev/null +++ b/contrib/llvm/lib/Support/Triple.cpp @@ -0,0 +1,760 @@ +//===--- Triple.cpp - Target triple helper class --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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 UnknownArch: return "unknown"; + + case arm: return "arm"; + case cellspu: return "cellspu"; + case hexagon: return "hexagon"; + case mips: return "mips"; + case mipsel: return "mipsel"; + case mips64: return "mips64"; + case mips64el:return "mips64el"; + case msp430: return "msp430"; + case ppc64: return "powerpc64"; + case ppc: return "powerpc"; + case r600: return "r600"; + case sparc: return "sparc"; + case sparcv9: return "sparcv9"; + case tce: return "tce"; + case thumb: return "thumb"; + case x86: return "i386"; + case x86_64: return "x86_64"; + case xcore: return "xcore"; + case mblaze: return "mblaze"; + case ptx32: return "ptx32"; + case ptx64: return "ptx64"; + case le32: return "le32"; + case amdil: return "amdil"; + } + + llvm_unreachable("Invalid ArchType!"); +} + +const char *Triple::getArchTypePrefix(ArchType Kind) { + switch (Kind) { + default: + return 0; + + case arm: + case thumb: return "arm"; + + case cellspu: return "spu"; + + case ppc64: + case ppc: return "ppc"; + + case mblaze: return "mblaze"; + + case hexagon: return "hexagon"; + + case r600: return "r600"; + + case sparcv9: + case sparc: return "sparc"; + + case x86: + case x86_64: return "x86"; + + case xcore: return "xcore"; + + case ptx32: return "ptx"; + case ptx64: return "ptx"; + case le32: return "le32"; + case amdil: return "amdil"; + } +} + +const char *Triple::getVendorTypeName(VendorType Kind) { + switch (Kind) { + case UnknownVendor: return "unknown"; + + case Apple: return "apple"; + case PC: return "pc"; + case SCEI: return "scei"; + case BGP: return "bgp"; + case BGQ: return "bgq"; + } + + llvm_unreachable("Invalid VendorType!"); +} + +const char *Triple::getOSTypeName(OSType Kind) { + switch (Kind) { + case UnknownOS: return "unknown"; + + case AuroraUX: return "auroraux"; + case Cygwin: return "cygwin"; + case Darwin: return "darwin"; + case DragonFly: return "dragonfly"; + case FreeBSD: return "freebsd"; + case IOS: return "ios"; + case KFreeBSD: return "kfreebsd"; + case Linux: return "linux"; + case Lv2: return "lv2"; + case MacOSX: return "macosx"; + case MinGW32: return "mingw32"; + case NetBSD: return "netbsd"; + case OpenBSD: return "openbsd"; + 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"; + } + + 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"; + } + + llvm_unreachable("Invalid EnvironmentType!"); +} + +Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { + 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) { + // See arch(3) and llvm-gcc's driver-driver.c. We don't implement support for + // archs which Darwin doesn't use. + + // The matching this routine does is fairly pointless, since it is neither the + // complete architecture list, nor a reasonable subset. The problem is that + // historically the driver driver accepts this and also ties its -march= + // handling to the architecture name, so we need to be careful before removing + // support for it. + + // This code must be kept in sync with Clang's Darwin specific argument + // translation. + + 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. +const char *Triple::getArchNameForAssembler() { + if (!isOSDarwin() && getVendor() != Triple::Apple) + 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); +} + +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); +} + +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); +} + +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); +} + +/// \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())) { +} + +/// \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; + 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 + // known vendor, preferentially use it for the vendor, etc. This avoids silly + // component movement when a component parses as (eg) both a valid arch and a + // valid os. + ArchType Arch = UnknownArch; + if (Components.size() > 0) + Arch = parseArch(Components[0]); + VendorType Vendor = UnknownVendor; + if (Components.size() > 1) + Vendor = parseVendor(Components[1]); + OSType OS = UnknownOS; + if (Components.size() > 2) + OS = parseOS(Components[2]); + EnvironmentType Environment = UnknownEnvironment; + if (Components.size() > 3) + Environment = parseEnvironment(Components[3]); + + // Note which components are already in their final position. These will not + // be moved. + bool Found[4]; + Found[0] = Arch != UnknownArch; + Found[1] = Vendor != UnknownVendor; + Found[2] = OS != UnknownOS; + Found[3] = Environment != UnknownEnvironment; + + // If they are not there already, permute the components into their canonical + // positions by seeing if they parse as a valid architecture, and if so moving + // the component to the architecture position etc. + for (unsigned Pos = 0; Pos != array_lengthof(Found); ++Pos) { + if (Found[Pos]) + continue; // Already in the canonical position. + + for (unsigned Idx = 0; Idx != Components.size(); ++Idx) { + // Do not reparse any components that already matched. + if (Idx < array_lengthof(Found) && Found[Idx]) + continue; + + // Does this component parse as valid for the target position? + bool Valid = false; + StringRef Comp = Components[Idx]; + switch (Pos) { + default: llvm_unreachable("unexpected component type!"); + case 0: + Arch = parseArch(Comp); + Valid = Arch != UnknownArch; + break; + case 1: + Vendor = parseVendor(Comp); + Valid = Vendor != UnknownVendor; + break; + case 2: + OS = parseOS(Comp); + Valid = OS != UnknownOS; + break; + case 3: + Environment = parseEnvironment(Comp); + Valid = Environment != UnknownEnvironment; + break; + } + if (!Valid) + continue; // Nope, try the next component. + + // Move the component to the target position, pushing any non-fixed + // components that are in the way to the right. This tends to give + // good results in the common cases of a forgotten vendor component + // or a wrongly positioned environment. + if (Pos < Idx) { + // Insert left, pushing the existing components to the right. For + // example, a-b-i386 -> i386-a-b when moving i386 to the front. + StringRef CurrentComponent(""); // The empty component. + // Replace the component we are moving with an empty component. + std::swap(CurrentComponent, Components[Idx]); + // Insert the component being moved at Pos, displacing any existing + // components to the right. + for (unsigned i = Pos; !CurrentComponent.empty(); ++i) { + // Skip over any fixed components. + 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]); + } + } else if (Pos > Idx) { + // Push right by inserting empty components until the component at Idx + // reaches the target position Pos. For example, pc-a -> -pc-a when + // moving pc to the second position. + do { + // Insert one empty component at Idx. + StringRef CurrentComponent(""); // The empty component. + for (unsigned i = Idx; i < Components.size();) { + // 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]); + // If it was placed on top of an empty component then we are done. + if (CurrentComponent.empty()) + break; + // Advance to the next component, skipping any fixed components. + while (++i < array_lengthof(Found) && Found[i]) + ; + } + // The last component was pushed off the end - append it. + if (!CurrentComponent.empty()) + Components.push_back(CurrentComponent); + + // Advance Idx to the component's new position. + 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 && + "Component moved wrong!"); + Found[Pos] = true; + break; + } + } + + // Special case logic goes here. At this point Arch, Vendor and OS have the + // correct values for the computed components. + + // Stick the corrected components back together to form the normalized string. + std::string Normalized; + for (unsigned i = 0, e = Components.size(); i != e; ++i) { + if (i) Normalized += '-'; + Normalized += Components[i]; + } + return Normalized; +} + +StringRef Triple::getArchName() const { + return StringRef(Data).split('-').first; // Isolate first component +} + +StringRef Triple::getVendorName() const { + StringRef Tmp = StringRef(Data).split('-').second; // Strip first component + return Tmp.split('-').first; // Isolate second component +} + +StringRef Triple::getOSName() const { + StringRef Tmp = StringRef(Data).split('-').second; // Strip first component + Tmp = Tmp.split('-').second; // Strip second component + return Tmp.split('-').first; // Isolate third component +} + +StringRef Triple::getEnvironmentName() const { + StringRef Tmp = StringRef(Data).split('-').second; // Strip first component + Tmp = Tmp.split('-').second; // Strip second component + return Tmp.split('-').second; // Strip third component +} + +StringRef Triple::getOSAndEnvironmentName() const { + StringRef Tmp = StringRef(Data).split('-').second; // Strip first component + return Tmp.split('-').second; // Strip second component +} + +static unsigned EatNumber(StringRef &Str) { + assert(!Str.empty() && Str[0] >= '0' && Str[0] <= '9' && "Not a number"); + unsigned Result = 0; + + do { + // Consume the leading digit. + Result = Result*10 + (Str[0] - '0'); + + // Eat the digit. + Str = Str.substr(1); + } while (!Str.empty() && Str[0] >= '0' && Str[0] <= '9'); + + return Result; +} + +void Triple::getOSVersion(unsigned &Major, unsigned &Minor, + unsigned &Micro) const { + StringRef OSName = getOSName(); + + // Assume that the OS portion of the triple starts with the canonical name. + StringRef OSTypeName = getOSTypeName(getOS()); + if (OSName.startswith(OSTypeName)) + OSName = OSName.substr(OSTypeName.size()); + + // Any unset version defaults to 0. + Major = Minor = Micro = 0; + + // Parse up to three components. + unsigned *Components[3] = { &Major, &Minor, &Micro }; + for (unsigned i = 0; i != 3; ++i) { + if (OSName.empty() || OSName[0] < '0' || OSName[0] > '9') + break; + + // Consume the leading number. + *Components[i] = EatNumber(OSName); + + // Consume the separator, if present. + if (OSName.startswith(".")) + OSName = OSName.substr(1); + } +} + +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) { + *this = Triple(Str); +} + +void Triple::setArch(ArchType Kind) { + setArchName(getArchTypeName(Kind)); +} + +void Triple::setVendor(VendorType Kind) { + setVendorName(getVendorTypeName(Kind)); +} + +void Triple::setOS(OSType Kind) { + setOSName(getOSTypeName(Kind)); +} + +void Triple::setEnvironment(EnvironmentType Kind) { + setEnvironmentName(getEnvironmentTypeName(Kind)); +} + +void Triple::setArchName(StringRef Str) { + // Work around a miscompilation bug for Twines in gcc 4.0.3. + SmallString<64> Triple; + Triple += Str; + Triple += "-"; + Triple += getVendorName(); + Triple += "-"; + Triple += getOSAndEnvironmentName(); + setTriple(Triple.str()); +} + +void Triple::setVendorName(StringRef Str) { + setTriple(getArchName() + "-" + Str + "-" + getOSAndEnvironmentName()); +} + +void Triple::setOSName(StringRef Str) { + if (hasEnvironment()) + setTriple(getArchName() + "-" + getVendorName() + "-" + Str + + "-" + getEnvironmentName()); + else + setTriple(getArchName() + "-" + getVendorName() + "-" + Str); +} + +void Triple::setEnvironmentName(StringRef Str) { + setTriple(getArchName() + "-" + getVendorName() + "-" + getOSName() + + "-" + 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/contrib/llvm/lib/Support/Twine.cpp b/contrib/llvm/lib/Support/Twine.cpp new file mode 100644 index 0000000..3d04bc3 --- /dev/null +++ b/contrib/llvm/lib/Support/Twine.cpp @@ -0,0 +1,171 @@ +//===-- Twine.cpp - Fast Temporary String Concatenation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Twine.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +std::string Twine::str() const { + // If we're storing only a std::string, just return it. + if (LHSKind == StdStringKind && RHSKind == EmptyKind) + return *LHS.stdString; + + // Otherwise, flatten and copy the contents first. + SmallString<256> Vec; + return toStringRef(Vec).str(); +} + +void Twine::toVector(SmallVectorImpl<char> &Out) const { + raw_svector_ostream OS(Out); + print(OS); +} + +StringRef Twine::toStringRef(SmallVectorImpl<char> &Out) const { + if (isSingleStringRef()) + return getSingleStringRef(); + toVector(Out); + return StringRef(Out.data(), Out.size()); +} + +StringRef Twine::toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const { + if (isUnary()) { + switch (getLHSKind()) { + case CStringKind: + // Already null terminated, yay! + return StringRef(LHS.cString); + case StdStringKind: { + const std::string *str = LHS.stdString; + return StringRef(str->c_str(), str->size()); + } + default: + break; + } + } + toVector(Out); + Out.push_back(0); + Out.pop_back(); + return StringRef(Out.data(), Out.size()); +} + +void Twine::printOneChild(raw_ostream &OS, Child Ptr, + NodeKind Kind) const { + switch (Kind) { + case Twine::NullKind: break; + case Twine::EmptyKind: break; + case Twine::TwineKind: + Ptr.twine->print(OS); + break; + case Twine::CStringKind: + OS << Ptr.cString; + break; + case Twine::StdStringKind: + OS << *Ptr.stdString; + break; + case Twine::StringRefKind: + OS << *Ptr.stringRef; + break; + case Twine::CharKind: + OS << Ptr.character; + break; + case Twine::DecUIKind: + OS << Ptr.decUI; + break; + case Twine::DecIKind: + OS << Ptr.decI; + break; + case Twine::DecULKind: + OS << *Ptr.decUL; + break; + case Twine::DecLKind: + OS << *Ptr.decL; + break; + case Twine::DecULLKind: + OS << *Ptr.decULL; + break; + case Twine::DecLLKind: + OS << *Ptr.decLL; + break; + case Twine::UHexKind: + OS.write_hex(*Ptr.uHex); + break; + } +} + +void Twine::printOneChildRepr(raw_ostream &OS, Child Ptr, + NodeKind Kind) const { + switch (Kind) { + case Twine::NullKind: + OS << "null"; break; + case Twine::EmptyKind: + OS << "empty"; break; + case Twine::TwineKind: + OS << "rope:"; + Ptr.twine->printRepr(OS); + break; + case Twine::CStringKind: + OS << "cstring:\"" + << Ptr.cString << "\""; + break; + case Twine::StdStringKind: + OS << "std::string:\"" + << Ptr.stdString << "\""; + break; + case Twine::StringRefKind: + OS << "stringref:\"" + << Ptr.stringRef << "\""; + break; + case Twine::CharKind: + OS << "char:\"" << Ptr.character << "\""; + break; + case Twine::DecUIKind: + OS << "decUI:\"" << Ptr.decUI << "\""; + break; + case Twine::DecIKind: + OS << "decI:\"" << Ptr.decI << "\""; + break; + case Twine::DecULKind: + OS << "decUL:\"" << *Ptr.decUL << "\""; + break; + case Twine::DecLKind: + OS << "decL:\"" << *Ptr.decL << "\""; + break; + case Twine::DecULLKind: + OS << "decULL:\"" << *Ptr.decULL << "\""; + break; + case Twine::DecLLKind: + OS << "decLL:\"" << *Ptr.decLL << "\""; + break; + case Twine::UHexKind: + OS << "uhex:\"" << Ptr.uHex << "\""; + break; + } +} + +void Twine::print(raw_ostream &OS) const { + printOneChild(OS, LHS, getLHSKind()); + printOneChild(OS, RHS, getRHSKind()); +} + +void Twine::printRepr(raw_ostream &OS) const { + OS << "(Twine "; + printOneChildRepr(OS, LHS, getLHSKind()); + OS << " "; + printOneChildRepr(OS, RHS, getRHSKind()); + OS << ")"; +} + +void Twine::dump() const { + print(llvm::dbgs()); +} + +void Twine::dumpRepr() const { + printRepr(llvm::dbgs()); +} diff --git a/contrib/llvm/lib/Support/Unix/Host.inc b/contrib/llvm/lib/Support/Unix/Host.inc new file mode 100644 index 0000000..7f79db0 --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/Host.inc @@ -0,0 +1,69 @@ + //===- llvm/Support/Unix/Host.inc -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the UNIX Host support. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/ADT/StringRef.h" +#include "Unix.h" +#include <sys/utsname.h> +#include <cctype> +#include <string> +#include <cstdlib> // ::getenv + +using namespace llvm; + +#ifdef __FreeBSD__ +std::string sys::getDefaultTargetTriple() { + return LLVM_DEFAULT_TARGET_TRIPLE; +} +#else // __FreeBSD__ +static std::string getOSVersion() { + struct utsname info; + + if (uname(&info)) + return ""; + + return info.release; +} + +std::string sys::getDefaultTargetTriple() { + StringRef TargetTripleString(LLVM_DEFAULT_TARGET_TRIPLE); + std::pair<StringRef, StringRef> ArchSplit = TargetTripleString.split('-'); + + // Normalize the arch, since the target triple may not actually match the target. + std::string Arch = ArchSplit.first; + + std::string Triple(Arch); + Triple += '-'; + Triple += ArchSplit.second; + + // Force i<N>86 to i386. + if (Triple[0] == 'i' && isdigit(Triple[1]) && + Triple[2] == '8' && Triple[3] == '6') + Triple[1] = '3'; + + // On darwin, we want to update the version to match that of the + // target. + std::string::size_type DarwinDashIdx = Triple.find("-darwin"); + if (DarwinDashIdx != std::string::npos) { + Triple.resize(DarwinDashIdx + strlen("-darwin")); + Triple += getOSVersion(); + } + + return Triple; +} +#endif // __FreeBSD__ diff --git a/contrib/llvm/lib/Support/Unix/Memory.inc b/contrib/llvm/lib/Support/Unix/Memory.inc new file mode 100644 index 0000000..5a57a28 --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/Memory.inc @@ -0,0 +1,151 @@ +//===- Unix/Memory.cpp - Generic UNIX System Configuration ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some functions for various memory management utilities. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Process.h" + +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + +#ifdef __APPLE__ +#include <mach/mach.h> +#endif + +/// AllocateRWX - Allocate a slab of memory with read/write/execute +/// permissions. This is typically used for JIT applications where we want +/// to emit code to the memory then jump to it. Getting this type of memory +/// is very OS specific. +/// +llvm::sys::MemoryBlock +llvm::sys::Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, + std::string *ErrMsg) { + if (NumBytes == 0) return MemoryBlock(); + + size_t pageSize = Process::GetPageSize(); + size_t NumPages = (NumBytes+pageSize-1)/pageSize; + + int fd = -1; +#ifdef NEED_DEV_ZERO_FOR_MMAP + static int zero_fd = open("/dev/zero", O_RDWR); + if (zero_fd == -1) { + MakeErrMsg(ErrMsg, "Can't open /dev/zero device"); + return MemoryBlock(); + } + fd = zero_fd; +#endif + + int flags = MAP_PRIVATE | +#ifdef HAVE_MMAP_ANONYMOUS + MAP_ANONYMOUS +#else + MAP_ANON +#endif + ; + + void* start = NearBlock ? (unsigned char*)NearBlock->base() + + NearBlock->size() : 0; + +#if defined(__APPLE__) && defined(__arm__) + void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_EXEC, + flags, fd, 0); +#else + void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC, + flags, fd, 0); +#endif + if (pa == MAP_FAILED) { + if (NearBlock) //Try again without a near hint + return AllocateRWX(NumBytes, 0); + + MakeErrMsg(ErrMsg, "Can't allocate RWX Memory"); + return MemoryBlock(); + } + +#if defined(__APPLE__) && defined(__arm__) + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)pa, + (vm_size_t)(pageSize*NumPages), 0, + VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); + if (KERN_SUCCESS != kr) { + MakeErrMsg(ErrMsg, "vm_protect max RX failed"); + return sys::MemoryBlock(); + } + + kr = vm_protect(mach_task_self(), (vm_address_t)pa, + (vm_size_t)(pageSize*NumPages), 0, + VM_PROT_READ | VM_PROT_WRITE); + if (KERN_SUCCESS != kr) { + MakeErrMsg(ErrMsg, "vm_protect RW failed"); + return sys::MemoryBlock(); + } +#endif + + MemoryBlock result; + result.Address = pa; + result.Size = NumPages*pageSize; + + return result; +} + +bool llvm::sys::Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { + if (M.Address == 0 || M.Size == 0) return false; + if (0 != ::munmap(M.Address, M.Size)) + return MakeErrMsg(ErrMsg, "Can't release RWX Memory"); + return false; +} + +bool llvm::sys::Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) { +#if defined(__APPLE__) && defined(__arm__) + if (M.Address == 0 || M.Size == 0) return false; + sys::Memory::InvalidateInstructionCache(M.Address, M.Size); + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, + (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_WRITE); + return KERN_SUCCESS == kr; +#else + return true; +#endif +} + +bool llvm::sys::Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { +#if defined(__APPLE__) && defined(__arm__) + if (M.Address == 0 || M.Size == 0) return false; + sys::Memory::InvalidateInstructionCache(M.Address, M.Size); + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, + (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); + return KERN_SUCCESS == kr; +#else + return true; +#endif +} + +bool llvm::sys::Memory::setRangeWritable(const void *Addr, size_t Size) { +#if defined(__APPLE__) && defined(__arm__) + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, + (vm_size_t)Size, 0, + VM_PROT_READ | VM_PROT_WRITE); + return KERN_SUCCESS == kr; +#else + return true; +#endif +} + +bool llvm::sys::Memory::setRangeExecutable(const void *Addr, size_t Size) { +#if defined(__APPLE__) && defined(__arm__) + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, + (vm_size_t)Size, 0, + VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); + return KERN_SUCCESS == kr; +#else + return true; +#endif +} diff --git a/contrib/llvm/lib/Support/Unix/Mutex.inc b/contrib/llvm/lib/Support/Unix/Mutex.inc new file mode 100644 index 0000000..fe6b170 --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/Mutex.inc @@ -0,0 +1,43 @@ +//===- llvm/Support/Unix/Mutex.inc - Unix Mutex Implementation ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific (non-pthread) Mutex class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +namespace llvm +{ +using namespace sys; + +MutexImpl::MutexImpl( bool recursive) +{ +} + +MutexImpl::~MutexImpl() +{ +} + +bool +MutexImpl::release() +{ + return true; +} + +bool +MutexImpl::tryacquire( void ) +{ + return true; +} + +} diff --git a/contrib/llvm/lib/Support/Unix/Path.inc b/contrib/llvm/lib/Support/Unix/Path.inc new file mode 100644 index 0000000..ddc1e0f --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/Path.inc @@ -0,0 +1,890 @@ +//===- llvm/Support/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific portion of the Path class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_UTIME_H +#include <utime.h> +#endif +#if HAVE_TIME_H +#include <time.h> +#endif +#if HAVE_DIRENT_H +# include <dirent.h> +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# if HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# if HAVE_NDIR_H +# include <ndir.h> +# endif +#endif + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#ifdef __APPLE__ +#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__ +# undef HAVE_MKDTEMP +#endif + +namespace { +inline bool lastIsSlash(const std::string& path) { + return !path.empty() && path[path.length() - 1] == '/'; +} + +} + +namespace llvm { +using namespace sys; + +const char sys::PathSeparator = ':'; + +StringRef Path::GetEXESuffix() { + return StringRef(); +} + +Path::Path(StringRef p) + : path(p) {} + +Path::Path(const char *StrStart, unsigned StrLen) + : path(StrStart, StrLen) {} + +Path& +Path::operator=(StringRef that) { + path.assign(that.data(), that.size()); + return *this; +} + +bool +Path::isValid() const { + // Empty paths are considered invalid here. + // This code doesn't check MAXPATHLEN because there's no need. Nothing in + // LLVM manipulates Paths with fixed-sizes arrays, and if the OS can't + // handle names longer than some limit, it'll report this on demand using + // ENAMETOLONG. + return !path.empty(); +} + +bool +Path::isAbsolute(const char *NameStart, unsigned NameLen) { + assert(NameStart); + if (NameLen == 0) + return false; + return NameStart[0] == '/'; +} + +bool +Path::isAbsolute() const { + if (path.empty()) + return false; + return path[0] == '/'; +} + +Path +Path::GetRootDirectory() { + Path result; + result.set("/"); + return result; +} + +Path +Path::GetTemporaryDirectory(std::string *ErrMsg) { +#if defined(HAVE_MKDTEMP) + // The best way is with mkdtemp but that's not available on many systems, + // Linux and FreeBSD have it. Others probably won't. + char pathname[] = "/tmp/llvm_XXXXXX"; + if (0 == mkdtemp(pathname)) { + MakeErrMsg(ErrMsg, + std::string(pathname) + ": can't create temporary directory"); + return Path(); + } + return Path(pathname); +#elif defined(HAVE_MKSTEMP) + // If no mkdtemp is available, mkstemp can be used to create a temporary file + // which is then removed and created as a directory. We prefer this over + // mktemp because of mktemp's inherent security and threading risks. We still + // have a slight race condition from the time the temporary file is created to + // the time it is re-created as a directoy. + char pathname[] = "/tmp/llvm_XXXXXX"; + int fd = 0; + if (-1 == (fd = mkstemp(pathname))) { + MakeErrMsg(ErrMsg, + std::string(pathname) + ": can't create temporary directory"); + return Path(); + } + ::close(fd); + ::unlink(pathname); // start race condition, ignore errors + if (-1 == ::mkdir(pathname, S_IRWXU)) { // end race condition + MakeErrMsg(ErrMsg, + std::string(pathname) + ": can't create temporary directory"); + return Path(); + } + return Path(pathname); +#elif defined(HAVE_MKTEMP) + // If a system doesn't have mkdtemp(3) or mkstemp(3) but it does have + // mktemp(3) then we'll assume that system (e.g. AIX) has a reasonable + // implementation of mktemp(3) and doesn't follow BSD 4.3's lead of replacing + // the XXXXXX with the pid of the process and a letter. That leads to only + // twenty six temporary files that can be generated. + char pathname[] = "/tmp/llvm_XXXXXX"; + char *TmpName = ::mktemp(pathname); + if (TmpName == 0) { + MakeErrMsg(ErrMsg, + std::string(TmpName) + ": can't create unique directory name"); + return Path(); + } + if (-1 == ::mkdir(TmpName, S_IRWXU)) { + MakeErrMsg(ErrMsg, + std::string(TmpName) + ": can't create temporary directory"); + return Path(); + } + return Path(TmpName); +#else + // This is the worst case implementation. tempnam(3) leaks memory unless its + // on an SVID2 (or later) system. On BSD 4.3 it leaks. tmpnam(3) has thread + // issues. The mktemp(3) function doesn't have enough variability in the + // temporary name generated. So, we provide our own implementation that + // increments an integer from a random number seeded by the current time. This + // should be sufficiently unique that we don't have many collisions between + // processes. Generally LLVM processes don't run very long and don't use very + // many temporary files so this shouldn't be a big issue for LLVM. + static time_t num = ::time(0); + char pathname[MAXPATHLEN]; + do { + num++; + sprintf(pathname, "/tmp/llvm_%010u", unsigned(num)); + } while ( 0 == access(pathname, F_OK ) ); + if (-1 == ::mkdir(pathname, S_IRWXU)) { + MakeErrMsg(ErrMsg, + std::string(pathname) + ": can't create temporary directory"); + return Path(); + } + return Path(pathname); +#endif +} + +void +Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) { +#ifdef LTDL_SHLIBPATH_VAR + char* env_var = getenv(LTDL_SHLIBPATH_VAR); + if (env_var != 0) { + getPathList(env_var,Paths); + } +#endif + // FIXME: Should this look at LD_LIBRARY_PATH too? + Paths.push_back(sys::Path("/usr/local/lib/")); + Paths.push_back(sys::Path("/usr/X11R6/lib/")); + Paths.push_back(sys::Path("/usr/lib/")); + Paths.push_back(sys::Path("/lib/")); +} + +void +Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) { + char * env_var = getenv("LLVM_LIB_SEARCH_PATH"); + if (env_var != 0) { + getPathList(env_var,Paths); + } +#ifdef LLVM_LIBDIR + { + Path tmpPath; + if (tmpPath.set(LLVM_LIBDIR)) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); + } +#endif + GetSystemLibraryPaths(Paths); +} + +Path +Path::GetUserHomeDirectory() { + const char* home = getenv("HOME"); + Path result; + if (home && result.set(home)) + return result; + result.set("/"); + return result; +} + +Path +Path::GetCurrentDirectory() { + char pathname[MAXPATHLEN]; + if (!getcwd(pathname, MAXPATHLEN)) { + assert(false && "Could not query current working directory."); + return Path(); + } + + return Path(pathname); +} + +#if defined(__FreeBSD__) || defined (__NetBSD__) || \ + 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) +{ + struct stat sb; + + snprintf(buf, PATH_MAX, "%s/%s", dir, bin); + if (realpath(buf, ret) == NULL) + return (1); + if (stat(buf, &sb) != 0) + return (1); + + return (0); +} + +static char * +getprogpath(char ret[PATH_MAX], const char *bin) +{ + char *pv, *s, *t, buf[PATH_MAX]; + + /* First approach: absolute path. */ + if (bin[0] == '/') { + if (test_dir(buf, ret, "/", bin) == 0) + return (ret); + return (NULL); + } + + /* Second approach: relative path. */ + if (strchr(bin, '/') != NULL) { + if (getcwd(buf, PATH_MAX) == NULL) + return (NULL); + if (test_dir(buf, ret, buf, bin) == 0) + return (ret); + return (NULL); + } + + /* Third approach: $PATH */ + if ((pv = getenv("PATH")) == NULL) + return (NULL); + s = pv = strdup(pv); + if (pv == NULL) + return (NULL); + while ((t = strsep(&s, ":")) != NULL) { + if (test_dir(buf, ret, t, bin) == 0) { + free(pv); + return (ret); + } + } + free(pv); + return (NULL); +} +#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__ + +/// GetMainExecutable - Return the path to the main executable, given the +/// value of argv[0] from program startup. +Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { +#if defined(__APPLE__) + // On OS X the executable path is saved to the stack by dyld. Reading it + // from there is much faster than calling dladdr, especially for large + // binaries with symbols. + char exe_path[MAXPATHLEN]; + uint32_t size = sizeof(exe_path); + if (_NSGetExecutablePath(exe_path, &size) == 0) { + char link_path[MAXPATHLEN]; + if (realpath(exe_path, link_path)) + return Path(link_path); + } +#elif defined(__FreeBSD__) || defined (__NetBSD__) || \ + defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) + char exe_path[PATH_MAX]; + + if (getprogpath(exe_path, argv0) != NULL) + return Path(exe_path); +#elif defined(__linux__) || defined(__CYGWIN__) + char exe_path[MAXPATHLEN]; + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)); + if (len >= 0) + return Path(StringRef(exe_path, len)); +#elif defined(HAVE_DLFCN_H) + // Use dladdr to get executable path if available. + Dl_info DLInfo; + int err = dladdr(MainAddr, &DLInfo); + if (err == 0) + return Path(); + + // If the filename is a symlink, we need to resolve and return the location of + // the actual executable. + char link_path[MAXPATHLEN]; + if (realpath(DLInfo.dli_fname, link_path)) + return Path(link_path); +#else +#error GetMainExecutable is not implemented on this host yet. +#endif + return Path(); +} + + +StringRef Path::getDirname() const { + return getDirnameCharSep(path, "/"); +} + +StringRef +Path::getBasename() const { + // Find the last slash + std::string::size_type slash = path.rfind('/'); + if (slash == std::string::npos) + slash = 0; + else + slash++; + + std::string::size_type dot = path.rfind('.'); + if (dot == std::string::npos || dot < slash) + return StringRef(path).substr(slash); + else + return StringRef(path).substr(slash, dot - slash); +} + +StringRef +Path::getSuffix() const { + // Find the last slash + std::string::size_type slash = path.rfind('/'); + if (slash == std::string::npos) + slash = 0; + else + slash++; + + std::string::size_type dot = path.rfind('.'); + if (dot == std::string::npos || dot < slash) + return StringRef(); + else + return StringRef(path).substr(dot + 1); +} + +bool Path::getMagicNumber(std::string &Magic, unsigned len) const { + assert(len < 1024 && "Request for magic string too long"); + char Buf[1025]; + int fd = ::open(path.c_str(), O_RDONLY); + if (fd < 0) + return false; + ssize_t bytes_read = ::read(fd, Buf, len); + ::close(fd); + if (ssize_t(len) != bytes_read) + return false; + Magic.assign(Buf, len); + return true; +} + +bool +Path::exists() const { + return 0 == access(path.c_str(), F_OK ); +} + +bool +Path::isDirectory() const { + struct stat buf; + if (0 != stat(path.c_str(), &buf)) + return false; + return ((buf.st_mode & S_IFMT) == S_IFDIR) ? true : false; +} + +bool +Path::isSymLink() const { + struct stat buf; + if (0 != lstat(path.c_str(), &buf)) + return false; + return S_ISLNK(buf.st_mode); +} + + +bool +Path::canRead() const { + return 0 == access(path.c_str(), R_OK); +} + +bool +Path::canWrite() const { + return 0 == access(path.c_str(), W_OK); +} + +bool +Path::isRegularFile() const { + // Get the status so we can determine if it's a file or directory + struct stat buf; + + if (0 != stat(path.c_str(), &buf)) + return false; + + if (S_ISREG(buf.st_mode)) + return true; + + return false; +} + +bool +Path::canExecute() const { + if (0 != access(path.c_str(), R_OK | X_OK )) + return false; + struct stat buf; + if (0 != stat(path.c_str(), &buf)) + return false; + if (!S_ISREG(buf.st_mode)) + return false; + return true; +} + +StringRef +Path::getLast() const { + // Find the last slash + size_t pos = path.rfind('/'); + + // Handle the corner cases + if (pos == std::string::npos) + return path; + + // If the last character is a slash + if (pos == path.length()-1) { + // Find the second to last slash + size_t pos2 = path.rfind('/', pos-1); + if (pos2 == std::string::npos) + return StringRef(path).substr(0,pos); + else + return StringRef(path).substr(pos2+1,pos-pos2-1); + } + // Return everything after the last slash + return StringRef(path).substr(pos+1); +} + +const FileStatus * +PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const { + if (!fsIsValid || update) { + struct stat buf; + if (0 != stat(path.c_str(), &buf)) { + MakeErrMsg(ErrStr, path + ": can't get status of file"); + return 0; + } + status.fileSize = buf.st_size; + status.modTime.fromEpochTime(buf.st_mtime); + status.mode = buf.st_mode; + status.user = buf.st_uid; + status.group = buf.st_gid; + status.uniqueID = uint64_t(buf.st_ino); + status.isDir = S_ISDIR(buf.st_mode); + status.isFile = S_ISREG(buf.st_mode); + fsIsValid = true; + } + return &status; +} + +static bool AddPermissionBits(const Path &File, int bits) { + // Get the umask value from the operating system. We want to use it + // when changing the file's permissions. Since calling umask() sets + // the umask and returns its old value, we must call it a second + // time to reset it to the user's preference. + int mask = umask(0777); // The arg. to umask is arbitrary. + umask(mask); // Restore the umask. + + // Get the file's current mode. + struct stat buf; + if (0 != stat(File.c_str(), &buf)) + return false; + // Change the file to have whichever permissions bits from 'bits' + // that the umask would not disable. + if ((chmod(File.c_str(), (buf.st_mode | (bits & ~mask)))) == -1) + return false; + return true; +} + +bool Path::makeReadableOnDisk(std::string* ErrMsg) { + if (!AddPermissionBits(*this, 0444)) + return MakeErrMsg(ErrMsg, path + ": can't make file readable"); + return false; +} + +bool Path::makeWriteableOnDisk(std::string* ErrMsg) { + if (!AddPermissionBits(*this, 0222)) + return MakeErrMsg(ErrMsg, path + ": can't make file writable"); + return false; +} + +bool Path::makeExecutableOnDisk(std::string* ErrMsg) { + if (!AddPermissionBits(*this, 0111)) + return MakeErrMsg(ErrMsg, path + ": can't make file executable"); + return false; +} + +bool +Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const { + DIR* direntries = ::opendir(path.c_str()); + if (direntries == 0) + return MakeErrMsg(ErrMsg, path + ": can't open directory"); + + std::string dirPath = path; + if (!lastIsSlash(dirPath)) + dirPath += '/'; + + result.clear(); + struct dirent* de = ::readdir(direntries); + for ( ; de != 0; de = ::readdir(direntries)) { + if (de->d_name[0] != '.') { + Path aPath(dirPath + (const char*)de->d_name); + struct stat st; + if (0 != lstat(aPath.path.c_str(), &st)) { + if (S_ISLNK(st.st_mode)) + continue; // dangling symlink -- ignore + return MakeErrMsg(ErrMsg, + aPath.path + ": can't determine file object type"); + } + result.insert(aPath); + } + } + + closedir(direntries); + return false; +} + +bool +Path::set(StringRef a_path) { + if (a_path.empty()) + return false; + path = a_path; + return true; +} + +bool +Path::appendComponent(StringRef name) { + if (name.empty()) + return false; + if (!lastIsSlash(path)) + path += '/'; + path += name; + return true; +} + +bool +Path::eraseComponent() { + size_t slashpos = path.rfind('/',path.size()); + if (slashpos == 0 || slashpos == std::string::npos) { + path.erase(); + return true; + } + if (slashpos == path.size() - 1) + slashpos = path.rfind('/',slashpos-1); + if (slashpos == std::string::npos) { + path.erase(); + return true; + } + path.erase(slashpos); + return true; +} + +bool +Path::eraseSuffix() { + size_t dotpos = path.rfind('.',path.size()); + size_t slashpos = path.rfind('/',path.size()); + if (dotpos != std::string::npos) { + if (slashpos == std::string::npos || dotpos > slashpos+1) { + path.erase(dotpos, path.size()-dotpos); + return true; + } + } + return false; +} + +static bool createDirectoryHelper(char* beg, char* end, bool create_parents) { + + if (access(beg, R_OK | W_OK) == 0) + return false; + + if (create_parents) { + + char* c = end; + + for (; c != beg; --c) + if (*c == '/') { + + // Recurse to handling the parent directory. + *c = '\0'; + bool x = createDirectoryHelper(beg, c, create_parents); + *c = '/'; + + // Return if we encountered an error. + if (x) + return true; + + break; + } + } + + return mkdir(beg, S_IRWXU | S_IRWXG) != 0; +} + +bool +Path::createDirectoryOnDisk( bool create_parents, std::string* ErrMsg ) { + // Get a writeable copy of the path name + std::string pathname(path); + + // Null-terminate the last component + size_t lastchar = path.length() - 1 ; + + if (pathname[lastchar] != '/') + ++lastchar; + + pathname[lastchar] = '\0'; + + if (createDirectoryHelper(&pathname[0], &pathname[lastchar], create_parents)) + return MakeErrMsg(ErrMsg, pathname + ": can't create directory"); + + return false; +} + +bool +Path::createFileOnDisk(std::string* ErrMsg) { + // Create the file + int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR); + if (fd < 0) + return MakeErrMsg(ErrMsg, path + ": can't create file"); + ::close(fd); + return false; +} + +bool +Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) { + // Make this into a unique file name + if (makeUnique( reuse_current, ErrMsg )) + return true; + + // create the file + int fd = ::open(path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (fd < 0) + return MakeErrMsg(ErrMsg, path + ": can't create temporary file"); + ::close(fd); + return false; +} + +bool +Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const { + // Get the status so we can determine if it's a file or directory. + struct stat buf; + if (0 != stat(path.c_str(), &buf)) { + MakeErrMsg(ErrStr, path + ": can't get status of file"); + return true; + } + + // Note: this check catches strange situations. In all cases, LLVM should + // only be involved in the creation and deletion of regular files. This + // check ensures that what we're trying to erase is a regular file. It + // effectively prevents LLVM from erasing things like /dev/null, any block + // special file, or other things that aren't "regular" files. + if (S_ISREG(buf.st_mode)) { + if (unlink(path.c_str()) != 0) + return MakeErrMsg(ErrStr, path + ": can't destroy file"); + return false; + } + + if (!S_ISDIR(buf.st_mode)) { + if (ErrStr) *ErrStr = "not a file or directory"; + return true; + } + + if (remove_contents) { + // Recursively descend the directory to remove its contents. + std::string cmd = "/bin/rm -rf " + path; + if (system(cmd.c_str()) != 0) { + MakeErrMsg(ErrStr, path + ": failed to recursively remove directory."); + return true; + } + return false; + } + + // Otherwise, try to just remove the one directory. + std::string pathname(path); + size_t lastchar = path.length() - 1; + if (pathname[lastchar] == '/') + pathname[lastchar] = '\0'; + else + pathname[lastchar+1] = '\0'; + + if (rmdir(pathname.c_str()) != 0) + return MakeErrMsg(ErrStr, pathname + ": can't erase directory"); + return false; +} + +bool +Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) { + if (0 != ::rename(path.c_str(), newName.c_str())) + return MakeErrMsg(ErrMsg, std::string("can't rename '") + path + "' as '" + + newName.str() + "'"); + return false; +} + +bool +Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrStr) const { + struct utimbuf utb; + utb.actime = si.modTime.toPosixTime(); + utb.modtime = utb.actime; + if (0 != ::utime(path.c_str(),&utb)) + return MakeErrMsg(ErrStr, path + ": can't set file modification time"); + if (0 != ::chmod(path.c_str(),si.mode)) + return MakeErrMsg(ErrStr, path + ": can't set mode"); + return false; +} + +bool +sys::CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg){ + int inFile = -1; + int outFile = -1; + inFile = ::open(Src.c_str(), O_RDONLY); + if (inFile == -1) + return MakeErrMsg(ErrMsg, Src.str() + + ": can't open source file to copy"); + + outFile = ::open(Dest.c_str(), O_WRONLY|O_CREAT, 0666); + if (outFile == -1) { + ::close(inFile); + return MakeErrMsg(ErrMsg, Dest.str() + + ": can't create destination file for copy"); + } + + char Buffer[16*1024]; + while (ssize_t Amt = ::read(inFile, Buffer, 16*1024)) { + if (Amt == -1) { + if (errno != EINTR && errno != EAGAIN) { + ::close(inFile); + ::close(outFile); + return MakeErrMsg(ErrMsg, Src.str()+": can't read source file"); + } + } else { + char *BufPtr = Buffer; + while (Amt) { + ssize_t AmtWritten = ::write(outFile, BufPtr, Amt); + if (AmtWritten == -1) { + if (errno != EINTR && errno != EAGAIN) { + ::close(inFile); + ::close(outFile); + return MakeErrMsg(ErrMsg, Dest.str() + + ": can't write destination file"); + } + } else { + Amt -= AmtWritten; + BufPtr += AmtWritten; + } + } + } + } + ::close(inFile); + ::close(outFile); + return false; +} + +bool +Path::makeUnique(bool reuse_current, std::string* ErrMsg) { + bool Exists; + if (reuse_current && (fs::exists(path, Exists) || !Exists)) + return false; // File doesn't exist already, just use it! + + // Append an XXXXXX pattern to the end of the file for use with mkstemp, + // mktemp or our own implementation. + // This uses std::vector instead of SmallVector to avoid a dependence on + // libSupport. And performance isn't critical here. + std::vector<char> Buf; + Buf.resize(path.size()+8); + char *FNBuffer = &Buf[0]; + path.copy(FNBuffer,path.size()); + bool isdir; + if (!fs::is_directory(path, isdir) && isdir) + strcpy(FNBuffer+path.size(), "/XXXXXX"); + else + strcpy(FNBuffer+path.size(), "-XXXXXX"); + +#if defined(HAVE_MKSTEMP) + int TempFD; + if ((TempFD = mkstemp(FNBuffer)) == -1) + return MakeErrMsg(ErrMsg, path + ": can't make unique filename"); + + // We don't need to hold the temp file descriptor... we will trust that no one + // will overwrite/delete the file before we can open it again. + close(TempFD); + + // Save the name + path = FNBuffer; + + // By default mkstemp sets the mode to 0600, so update mode bits now. + AddPermissionBits (*this, 0666); +#elif defined(HAVE_MKTEMP) + // If we don't have mkstemp, use the old and obsolete mktemp function. + if (mktemp(FNBuffer) == 0) + return MakeErrMsg(ErrMsg, path + ": can't make unique filename"); + + // Save the name + path = FNBuffer; +#else + // Okay, looks like we have to do it all by our lonesome. + static unsigned FCounter = 0; + // Try to initialize with unique value. + if (FCounter == 0) FCounter = ((unsigned)getpid() & 0xFFFF) << 8; + char* pos = strstr(FNBuffer, "XXXXXX"); + do { + if (++FCounter > 0xFFFFFF) { + return MakeErrMsg(ErrMsg, + path + ": can't make unique filename: too many files"); + } + sprintf(pos, "%06X", FCounter); + path = FNBuffer; + } while (exists()); + // POSSIBLE SECURITY BUG: An attacker can easily guess the name and exploit + // LLVM. +#endif + return false; +} + +const char *Path::MapInFilePages(int FD, size_t FileSize, off_t Offset) { + int Flags = MAP_PRIVATE; +#ifdef MAP_FILE + Flags |= MAP_FILE; +#endif + void *BasePtr = ::mmap(0, FileSize, PROT_READ, Flags, FD, Offset); + if (BasePtr == MAP_FAILED) + return 0; + return (const char*)BasePtr; +} + +void Path::UnMapFilePages(const char *BasePtr, size_t FileSize) { + ::munmap((void*)BasePtr, FileSize); +} + +} // end llvm namespace diff --git a/contrib/llvm/lib/Support/Unix/PathV2.inc b/contrib/llvm/lib/Support/Unix/PathV2.inc new file mode 100644 index 0000000..edb101e --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/PathV2.inc @@ -0,0 +1,516 @@ +//===- llvm/Support/Unix/PathV2.cpp - Unix Path Implementation --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific implementation of the PathV2 API. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#if HAVE_DIRENT_H +# include <dirent.h> +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# if HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# if HAVE_NDIR_H +# include <ndir.h> +# endif +#endif +#if HAVE_STDIO_H +#include <stdio.h> +#endif +#if HAVE_LIMITS_H +#include <limits.h> +#endif + +// For GNU Hurd +#if defined(__GNU__) && !defined(PATH_MAX) +# define PATH_MAX 4096 +#endif + +using namespace llvm; + +namespace { + /// This class automatically closes the given file descriptor when it goes out + /// of scope. You can take back explicit ownership of the file descriptor by + /// calling take(). The destructor does not verify that close was successful. + /// Therefore, never allow this class to call close on a file descriptor that + /// has been read from or written to. + struct AutoFD { + int FileDescriptor; + + AutoFD(int fd) : FileDescriptor(fd) {} + ~AutoFD() { + if (FileDescriptor >= 0) + ::close(FileDescriptor); + } + + int take() { + int ret = FileDescriptor; + FileDescriptor = -1; + return ret; + } + + operator int() const {return FileDescriptor;} + }; + + error_code TempDir(SmallVectorImpl<char> &result) { + // FIXME: Don't use TMPDIR if program is SUID or SGID enabled. + const char *dir = 0; + (dir = std::getenv("TMPDIR" )) || + (dir = std::getenv("TMP" )) || + (dir = std::getenv("TEMP" )) || + (dir = std::getenv("TEMPDIR")) || +#ifdef P_tmpdir + (dir = P_tmpdir) || +#endif + (dir = "/tmp"); + + result.clear(); + StringRef d(dir); + result.append(d.begin(), d.end()); + return error_code::success(); + } +} + +namespace llvm { +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) { + // See if there was a real error. + if (errno != errc::not_enough_memory) + return error_code(errno, system_category()); + // Otherwise there just wasn't enough space. + result.reserve(result.capacity() * 2); + } else + break; + } + + result.set_size(strlen(result.data())); + return error_code::success(); +} + +error_code copy_file(const Twine &from, const Twine &to, copy_option copt) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); + + const size_t buf_sz = 32768; + char buffer[buf_sz]; + int from_file = -1, to_file = -1; + + // Open from. + if ((from_file = ::open(f.begin(), O_RDONLY)) < 0) + return error_code(errno, system_category()); + AutoFD from_fd(from_file); + + // Stat from. + struct stat from_stat; + if (::stat(f.begin(), &from_stat) != 0) + return error_code(errno, system_category()); + + // Setup to flags. + int to_flags = O_CREAT | O_WRONLY; + if (copt == copy_option::fail_if_exists) + to_flags |= O_EXCL; + + // Open to. + if ((to_file = ::open(t.begin(), to_flags, from_stat.st_mode)) < 0) + return error_code(errno, system_category()); + AutoFD to_fd(to_file); + + // Copy! + ssize_t sz, sz_read = 1, sz_write; + while (sz_read > 0 && + (sz_read = ::read(from_fd, buffer, buf_sz)) > 0) { + // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), + // Marc Rochkind, Addison-Wesley, 2004, page 94 + sz_write = 0; + do { + if ((sz = ::write(to_fd, buffer + sz_write, sz_read - sz_write)) < 0) { + sz_read = sz; // cause read loop termination. + break; // error. + } + sz_write += sz; + } while (sz_write < sz_read); + } + + // After all the file operations above the return value of close actually + // matters. + if (::close(from_fd.take()) < 0) sz_read = -1; + if (::close(to_fd.take()) < 0) sz_read = -1; + + // Check for errors. + if (sz_read < 0) + return error_code(errno, system_category()); + + return error_code::success(); +} + +error_code create_directory(const Twine &path, bool &existed) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) { + if (errno != errc::file_exists) + return error_code(errno, system_category()); + existed = true; + } else + existed = false; + + return error_code::success(); +} + +error_code create_hard_link(const Twine &to, const Twine &from) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); + + if (::link(t.begin(), f.begin()) == -1) + return error_code(errno, system_category()); + + return error_code::success(); +} + +error_code create_symlink(const Twine &to, const Twine &from) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); + + if (::symlink(t.begin(), f.begin()) == -1) + return error_code(errno, system_category()); + + return error_code::success(); +} + +error_code remove(const Twine &path, bool &existed) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + if (::remove(p.begin()) == -1) { + if (errno != errc::no_such_file_or_directory) + return error_code(errno, system_category()); + existed = false; + } else + existed = true; + + return error_code::success(); +} + +error_code rename(const Twine &from, const Twine &to) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); + + if (::rename(f.begin(), t.begin()) == -1) { + // If it's a cross device link, copy then delete, otherwise return the error + if (errno == EXDEV) { + if (error_code ec = copy_file(from, to, copy_option::overwrite_if_exists)) + return ec; + bool Existed; + if (error_code ec = remove(from, Existed)) + return ec; + } else + return error_code(errno, system_category()); + } + + return error_code::success(); +} + +error_code resize_file(const Twine &path, uint64_t size) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + if (::truncate(p.begin(), size) == -1) + return error_code(errno, system_category()); + + return error_code::success(); +} + +error_code exists(const Twine &path, bool &result) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + struct stat status; + if (::stat(p.begin(), &status) == -1) { + if (errno != errc::no_such_file_or_directory) + return error_code(errno, system_category()); + result = false; + } else + result = true; + + return error_code::success(); +} + +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; +} + +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) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + struct stat status; + if (::stat(p.begin(), &status) == -1) + return error_code(errno, system_category()); + if (!S_ISREG(status.st_mode)) + return make_error_code(errc::operation_not_permitted); + + result = status.st_size; + return error_code::success(); +} + +error_code status(const Twine &path, file_status &result) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + struct stat status; + if (::stat(p.begin(), &status) != 0) { + error_code ec(errno, system_category()); + if (ec == errc::no_such_file_or_directory) + result = file_status(file_type::file_not_found); + else + result = file_status(file_type::status_error); + return ec; + } + + if (S_ISDIR(status.st_mode)) + result = file_status(file_type::directory_file); + else if (S_ISREG(status.st_mode)) + result = file_status(file_type::regular_file); + else if (S_ISBLK(status.st_mode)) + result = file_status(file_type::block_file); + else if (S_ISCHR(status.st_mode)) + result = file_status(file_type::character_file); + else if (S_ISFIFO(status.st_mode)) + result = file_status(file_type::fifo_file); + else if (S_ISSOCK(status.st_mode)) + result = file_status(file_type::socket_file); + else + result = file_status(file_type::type_unknown); + + 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, + SmallVectorImpl<char> &result_path, + bool makeAbsolute) { + SmallString<128> Model; + model.toVector(Model); + // Null terminate. + Model.c_str(); + + if (makeAbsolute) { + // Make model absolute by prepending a temp directory if it's not already. + bool absolute = path::is_absolute(Twine(Model)); + if (!absolute) { + SmallString<128> TDir; + if (error_code ec = TempDir(TDir)) return ec; + path::append(TDir, Twine(Model)); + Model.swap(TDir); + } + } + + // Replace '%' with random chars. From here on, DO NOT modify model. It may be + // needed if the randomly chosen path already exists. + SmallString<128> RandomPath; + RandomPath.reserve(Model.size() + 1); + ::srand(::time(NULL)); + +retry_random_path: + // This is opened here instead of above to make it easier to track when to + // close it. Collisions should be rare enough for the possible extra syscalls + // not to matter. + FILE *RandomSource = ::fopen("/dev/urandom", "r"); + RandomPath.set_size(0); + for (SmallVectorImpl<char>::const_iterator i = Model.begin(), + e = Model.end(); i != e; ++i) { + if (*i == '%') { + char val = 0; + if (RandomSource) + val = fgetc(RandomSource); + else + val = ::rand(); + RandomPath.push_back("0123456789abcdef"[val & 15]); + } else + RandomPath.push_back(*i); + } + + if (RandomSource) + ::fclose(RandomSource); + + // Try to open + create the file. +rety_open_create: + int RandomFD = ::open(RandomPath.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); + if (RandomFD == -1) { + // If the file existed, try again, otherwise, error. + if (errno == errc::file_exists) + goto retry_random_path; + // The path prefix doesn't exist. + if (errno == errc::no_such_file_or_directory) { + StringRef p(RandomPath.begin(), RandomPath.size()); + SmallString<64> dir_to_create; + for (path::const_iterator i = path::begin(p), + e = --path::end(p); i != e; ++i) { + path::append(dir_to_create, *i); + bool Exists; + if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec; + if (!Exists) { + // Don't try to create network paths. + if (i->size() > 2 && (*i)[0] == '/' && + (*i)[1] == '/' && + (*i)[2] != '/') + return make_error_code(errc::no_such_file_or_directory); + if (::mkdir(dir_to_create.c_str(), 0700) == -1) + return error_code(errno, system_category()); + } + } + goto rety_open_create; + } + return error_code(errno, system_category()); + } + + // Make the path absolute. + char real_path_buff[PATH_MAX + 1]; + if (realpath(RandomPath.c_str(), real_path_buff) == NULL) { + int error = errno; + ::close(RandomFD); + ::unlink(RandomPath.c_str()); + return error_code(error, system_category()); + } + + result_path.clear(); + StringRef d(real_path_buff); + result_path.append(d.begin(), d.end()); + + result_fd = RandomFD; + return error_code::success(); +} + +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) + return error_code(errno, system_category()); + + it.IterationHandle = reinterpret_cast<intptr_t>(directory); + // Add something for replace_filename to replace. + path::append(path_null, "."); + it.CurrentEntry = directory_entry(path_null.str()); + return directory_iterator_increment(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 error_code::success(); +} + +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) { + return error_code(errno, system_category()); + } else if (cur_dir != 0) { + StringRef name(cur_dir->d_name, NAMLEN(cur_dir)); + if ((name.size() == 1 && name[0] == '.') || + (name.size() == 2 && name[0] == '.' && name[1] == '.')) + return directory_iterator_increment(it); + it.CurrentEntry.replace_filename(name); + } else + return directory_iterator_destruct(it); + + return error_code::success(); +} + +error_code get_magic(const Twine &path, uint32_t len, + SmallVectorImpl<char> &result) { + SmallString<128> PathStorage; + StringRef Path = path.toNullTerminatedStringRef(PathStorage); + result.set_size(0); + + // Open path. + std::FILE *file = std::fopen(Path.data(), "rb"); + if (file == 0) + return error_code(errno, system_category()); + + // Reserve storage. + result.reserve(len); + + // Read magic! + size_t size = std::fread(result.data(), 1, len, file); + if (std::ferror(file) != 0) { + std::fclose(file); + return error_code(errno, system_category()); + } else if (size != result.size()) { + if (std::feof(file) != 0) { + std::fclose(file); + result.set_size(size); + return make_error_code(errc::value_too_large); + } + } + std::fclose(file); + result.set_size(len); + return error_code::success(); +} + +} // end namespace fs +} // end namespace sys +} // end namespace llvm diff --git a/contrib/llvm/lib/Support/Unix/Process.inc b/contrib/llvm/lib/Support/Unix/Process.inc new file mode 100644 index 0000000..2d7fd38 --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/Process.inc @@ -0,0 +1,295 @@ +//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the generic Unix implementation of the Process class. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif +// DragonFly BSD has deprecated <malloc.h> for <stdlib.h> instead, +// Unix.h includes this for us already. +#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) +#include <malloc.h> +#endif +#ifdef HAVE_MALLOC_MALLOC_H +#include <malloc/malloc.h> +#endif +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif +#ifdef HAVE_TERMIOS_H +# include <termios.h> +#endif + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +using namespace llvm; +using namespace sys; + +unsigned +Process::GetPageSize() +{ +#if defined(__CYGWIN__) + // On Cygwin, getpagesize() returns 64k but the page size for the purposes of + // memory protection and mmap() is 4k. + // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492 + const int page_size = 0x1000; +#elif defined(HAVE_GETPAGESIZE) + const int page_size = ::getpagesize(); +#elif defined(HAVE_SYSCONF) + long page_size = ::sysconf(_SC_PAGE_SIZE); +#else +#warning Cannot get the page size on this machine +#endif + return static_cast<unsigned>(page_size); +} + +size_t Process::GetMallocUsage() { +#if defined(HAVE_MALLINFO) + struct mallinfo mi; + mi = ::mallinfo(); + return mi.uordblks; +#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) + malloc_statistics_t Stats; + malloc_zone_statistics(malloc_default_zone(), &Stats); + return Stats.size_in_use; // darwin +#elif defined(HAVE_SBRK) + // Note this is only an approximation and more closely resembles + // the value returned by mallinfo in the arena field. + static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0)); + char *EndOfMemory = (char*)sbrk(0); + if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) + return EndOfMemory - StartOfMemory; + else + return 0; +#else +#warning Cannot get malloc info on this platform + return 0; +#endif +} + +size_t +Process::GetTotalMemoryUsage() +{ +#if defined(HAVE_MALLINFO) + struct mallinfo mi = ::mallinfo(); + return mi.uordblks + mi.hblkhd; +#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) + malloc_statistics_t Stats; + malloc_zone_statistics(malloc_default_zone(), &Stats); + return Stats.size_allocated; // darwin +#elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__) + struct rusage usage; + ::getrusage(RUSAGE_SELF, &usage); + return usage.ru_maxrss; +#else +#warning Cannot get total memory size on this platform + return 0; +#endif +} + +void +Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time, + TimeValue& sys_time) +{ + elapsed = TimeValue::now(); +#if defined(HAVE_GETRUSAGE) + struct rusage usage; + ::getrusage(RUSAGE_SELF, &usage); + user_time = TimeValue( + static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ), + static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec * + TimeValue::NANOSECONDS_PER_MICROSECOND ) ); + sys_time = TimeValue( + static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ), + static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec * + TimeValue::NANOSECONDS_PER_MICROSECOND ) ); +#else +#warning Cannot get usage times on this platform + user_time.seconds(0); + user_time.microseconds(0); + sys_time.seconds(0); + sys_time.microseconds(0); +#endif +} + +int Process::GetCurrentUserId() { + return getuid(); +} + +int Process::GetCurrentGroupId() { + return getgid(); +} + +#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) +#include <mach/mach.h> +#endif + +// Some LLVM programs such as bugpoint produce core files as a normal part of +// their operation. To prevent the disk from filling up, this function +// does what's necessary to prevent their generation. +void Process::PreventCoreFiles() { +#if HAVE_SETRLIMIT + struct rlimit rlim; + rlim.rlim_cur = rlim.rlim_max = 0; + setrlimit(RLIMIT_CORE, &rlim); +#endif + +#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 + mach_msg_type_number_t Count = 0; + exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; + exception_port_t OriginalPorts[EXC_TYPES_COUNT]; + exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; + thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; + kern_return_t err = + task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, + &Count, OriginalPorts, OriginalBehaviors, + OriginalFlavors); + if (err == KERN_SUCCESS) { + // replace each with MACH_PORT_NULL. + for (unsigned i = 0; i != Count; ++i) + task_set_exception_ports(mach_task_self(), OriginalMasks[i], + MACH_PORT_NULL, OriginalBehaviors[i], + OriginalFlavors[i]); + } + + // Disable crash reporting on Mac OS X 10.5 + signal(SIGABRT, _exit); + signal(SIGILL, _exit); + signal(SIGFPE, _exit); + signal(SIGSEGV, _exit); + signal(SIGBUS, _exit); +#endif +} + +bool Process::StandardInIsUserInput() { + return FileDescriptorIsDisplayed(STDIN_FILENO); +} + +bool Process::StandardOutIsDisplayed() { + return FileDescriptorIsDisplayed(STDOUT_FILENO); +} + +bool Process::StandardErrIsDisplayed() { + return FileDescriptorIsDisplayed(STDERR_FILENO); +} + +bool Process::FileDescriptorIsDisplayed(int fd) { +#if HAVE_ISATTY + return isatty(fd); +#else + // If we don't have isatty, just return false. + return false; +#endif +} + +static unsigned getColumns(int FileID) { + // If COLUMNS is defined in the environment, wrap to that many columns. + if (const char *ColumnsStr = std::getenv("COLUMNS")) { + int Columns = std::atoi(ColumnsStr); + if (Columns > 0) + return Columns; + } + + unsigned Columns = 0; + +#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) + // Try to determine the width of the terminal. + struct winsize ws; + if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) + Columns = ws.ws_col; +#endif + + return Columns; +} + +unsigned Process::StandardOutColumns() { + if (!StandardOutIsDisplayed()) + return 0; + + return getColumns(1); +} + +unsigned Process::StandardErrColumns() { + if (!StandardErrIsDisplayed()) + return 0; + + return getColumns(2); +} + +static bool terminalHasColors() { + if (const char *term = std::getenv("TERM")) { + // Most modern terminals support ANSI escape sequences for colors. + // We could check terminfo, or have a list of known terms that support + // colors, but that would be overkill. + // The user can always ask for no colors by setting TERM to dumb, or + // using a commandline flag. + return strcmp(term, "dumb") != 0; + } + return false; +} + +bool Process::StandardOutHasColors() { + if (!StandardOutIsDisplayed()) + return false; + return terminalHasColors(); +} + +bool Process::StandardErrHasColors() { + if (!StandardErrIsDisplayed()) + return false; + return terminalHasColors(); +} + +bool Process::ColorNeedsFlush() { + // No, we use ANSI escape sequences. + return false; +} + +#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" + +#define ALLCOLORS(FGBG,BOLD) {\ + COLOR(FGBG, "0", BOLD),\ + COLOR(FGBG, "1", BOLD),\ + COLOR(FGBG, "2", BOLD),\ + COLOR(FGBG, "3", BOLD),\ + COLOR(FGBG, "4", BOLD),\ + COLOR(FGBG, "5", BOLD),\ + COLOR(FGBG, "6", BOLD),\ + COLOR(FGBG, "7", BOLD)\ + } + +static const char colorcodes[2][2][8][10] = { + { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, + { ALLCOLORS("4",""), ALLCOLORS("4","1;") } +}; + +const char *Process::OutputColor(char code, bool bold, bool bg) { + return colorcodes[bg?1:0][bold?1:0][code&7]; +} + +const char *Process::OutputBold(bool bg) { + return "\033[1m"; +} + +const char *Process::ResetColor() { + return "\033[0m"; +} diff --git a/contrib/llvm/lib/Support/Unix/Program.inc b/contrib/llvm/lib/Support/Unix/Program.inc new file mode 100644 index 0000000..e5990d0 --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/Program.inc @@ -0,0 +1,430 @@ +//===- llvm/Support/Unix/Program.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific portion of the Program class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include <llvm/Config/config.h> +#include "llvm/Support/FileSystem.h" +#include "Unix.h" +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif +#if HAVE_SIGNAL_H +#include <signal.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_POSIX_SPAWN +#include <spawn.h> +#if !defined(__APPLE__) + extern char **environ; +#else +#include <crt_externs.h> // _NSGetEnviron +#endif +#endif + +namespace llvm { +using namespace sys; + +Program::Program() : Data_(0) {} + +Program::~Program() {} + +unsigned Program::GetPid() const { + uint64_t pid = reinterpret_cast<uint64_t>(Data_); + return static_cast<unsigned>(pid); +} + +// This function just uses the PATH environment variable to find the program. +Path +Program::FindProgramByName(const std::string& progName) { + + // Check some degenerate cases + if (progName.length() == 0) // no program + return Path(); + Path temp; + if (!temp.set(progName)) // invalid name + return Path(); + // Use the given path verbatim if it contains any slashes; this matches + // the behavior of sh(1) and friends. + if (progName.find('/') != std::string::npos) + return temp; + + // At this point, the file name is valid and does not contain slashes. Search + // for it through the directories specified in the PATH environment variable. + + // Get the path. If its empty, we can't do anything to find it. + const char *PathStr = getenv("PATH"); + if (PathStr == 0) + return Path(); + + // Now we have a colon separated list of directories to search; try them. + size_t PathLen = strlen(PathStr); + while (PathLen) { + // Find the first colon... + const char *Colon = std::find(PathStr, PathStr+PathLen, ':'); + + // Check to see if this first directory contains the executable... + Path FilePath; + if (FilePath.set(std::string(PathStr,Colon))) { + FilePath.appendComponent(progName); + if (FilePath.canExecute()) + return FilePath; // Found the executable! + } + + // Nope it wasn't in this directory, check the next path in the list! + PathLen -= Colon-PathStr; + PathStr = Colon; + + // Advance past duplicate colons + while (*PathStr == ':') { + PathStr++; + PathLen--; + } + } + return Path(); +} + +static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) { + if (Path == 0) // Noop + return false; + const char *File; + if (Path->isEmpty()) + // Redirect empty paths to /dev/null + File = "/dev/null"; + else + File = Path->c_str(); + + // Open the file + int InFD = open(File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666); + if (InFD == -1) { + MakeErrMsg(ErrMsg, "Cannot open file '" + std::string(File) + "' for " + + (FD == 0 ? "input" : "output")); + return true; + } + + // Install it as the requested FD + if (dup2(InFD, FD) == -1) { + MakeErrMsg(ErrMsg, "Cannot dup2"); + close(InFD); + return true; + } + close(InFD); // Close the original FD + return false; +} + +#ifdef HAVE_POSIX_SPAWN +static bool RedirectIO_PS(const Path *Path, int FD, std::string *ErrMsg, + posix_spawn_file_actions_t *FileActions) { + if (Path == 0) // Noop + return false; + const char *File; + if (Path->isEmpty()) + // Redirect empty paths to /dev/null + File = "/dev/null"; + else + File = Path->c_str(); + + if (int Err = posix_spawn_file_actions_addopen(FileActions, FD, + File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666)) + return MakeErrMsg(ErrMsg, "Cannot dup2", Err); + return false; +} +#endif + +static void TimeOutHandler(int Sig) { +} + +static void SetMemoryLimits (unsigned size) +{ +#if HAVE_SYS_RESOURCE_H && HAVE_GETRLIMIT && HAVE_SETRLIMIT + struct rlimit r; + __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576; + + // Heap size + getrlimit (RLIMIT_DATA, &r); + r.rlim_cur = limit; + setrlimit (RLIMIT_DATA, &r); +#ifdef RLIMIT_RSS + // Resident set size. + getrlimit (RLIMIT_RSS, &r); + r.rlim_cur = limit; + setrlimit (RLIMIT_RSS, &r); +#endif +#ifdef RLIMIT_AS // e.g. NetBSD doesn't have it. + // Virtual memory. + getrlimit (RLIMIT_AS, &r); + r.rlim_cur = limit; + setrlimit (RLIMIT_AS, &r); +#endif +#endif +} + +bool +Program::Execute(const Path &path, const char **args, const char **envp, + const Path **redirects, unsigned memoryLimit, + std::string *ErrMsg) { + // If this OS has posix_spawn and there is no memory limit being implied, use + // posix_spawn. It is more efficient than fork/exec. +#ifdef HAVE_POSIX_SPAWN + if (memoryLimit == 0) { + posix_spawn_file_actions_t FileActionsStore; + posix_spawn_file_actions_t *FileActions = 0; + + if (redirects) { + FileActions = &FileActionsStore; + posix_spawn_file_actions_init(FileActions); + + // Redirect stdin/stdout. + if (RedirectIO_PS(redirects[0], 0, ErrMsg, FileActions) || + RedirectIO_PS(redirects[1], 1, ErrMsg, FileActions)) + return false; + if (redirects[1] == 0 || redirects[2] == 0 || + *redirects[1] != *redirects[2]) { + // Just redirect stderr + if (RedirectIO_PS(redirects[2], 2, ErrMsg, FileActions)) return false; + } else { + // If stdout and stderr should go to the same place, redirect stderr + // to the FD already open for stdout. + if (int Err = posix_spawn_file_actions_adddup2(FileActions, 1, 2)) + return !MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout", Err); + } + } + + if (!envp) +#if !defined(__APPLE__) + envp = const_cast<const char **>(environ); +#else + // environ is missing in dylibs. + envp = const_cast<const char **>(*_NSGetEnviron()); +#endif + + // Explicitly initialized to prevent what appears to be a valgrind false + // positive. + pid_t PID = 0; + int Err = posix_spawn(&PID, path.c_str(), FileActions, /*attrp*/0, + const_cast<char **>(args), const_cast<char **>(envp)); + + if (FileActions) + posix_spawn_file_actions_destroy(FileActions); + + if (Err) + return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err); + + Data_ = reinterpret_cast<void*>(PID); + return true; + } +#endif + + // Create a child process. + int child = fork(); + switch (child) { + // An error occurred: Return to the caller. + case -1: + MakeErrMsg(ErrMsg, "Couldn't fork"); + return false; + + // Child process: Execute the program. + case 0: { + // Redirect file descriptors... + if (redirects) { + // Redirect stdin + if (RedirectIO(redirects[0], 0, ErrMsg)) { return false; } + // Redirect stdout + if (RedirectIO(redirects[1], 1, ErrMsg)) { return false; } + if (redirects[1] && redirects[2] && + *(redirects[1]) == *(redirects[2])) { + // If stdout and stderr should go to the same place, redirect stderr + // to the FD already open for stdout. + if (-1 == dup2(1,2)) { + MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout"); + return false; + } + } else { + // Just redirect stderr + if (RedirectIO(redirects[2], 2, ErrMsg)) { return false; } + } + } + + // Set memory limits + if (memoryLimit!=0) { + SetMemoryLimits(memoryLimit); + } + + // Execute! + if (envp != 0) + execve(path.c_str(), + const_cast<char **>(args), + const_cast<char **>(envp)); + else + execv(path.c_str(), + const_cast<char **>(args)); + // If the execve() failed, we should exit. Follow Unix protocol and + // return 127 if the executable was not found, and 126 otherwise. + // Use _exit rather than exit so that atexit functions and static + // object destructors cloned from the parent process aren't + // redundantly run, and so that any data buffered in stdio buffers + // cloned from the parent aren't redundantly written out. + _exit(errno == ENOENT ? 127 : 126); + } + + // Parent process: Break out of the switch to do our processing. + default: + break; + } + + Data_ = reinterpret_cast<void*>(child); + + return true; +} + +int +Program::Wait(const sys::Path &path, + unsigned secondsToWait, + std::string* ErrMsg) +{ +#ifdef HAVE_SYS_WAIT_H + struct sigaction Act, Old; + + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return -1; + } + + // Install a timeout handler. The handler itself does nothing, but the simple + // fact of having a handler at all causes the wait below to return with EINTR, + // unlike if we used SIG_IGN. + if (secondsToWait) { + memset(&Act, 0, sizeof(Act)); + Act.sa_handler = TimeOutHandler; + sigemptyset(&Act.sa_mask); + sigaction(SIGALRM, &Act, &Old); + alarm(secondsToWait); + } + + // Parent process: Wait for the child process to terminate. + int status; + uint64_t pid = reinterpret_cast<uint64_t>(Data_); + pid_t child = static_cast<pid_t>(pid); + while (waitpid(pid, &status, 0) != child) + if (secondsToWait && errno == EINTR) { + // Kill the child. + kill(child, SIGKILL); + + // Turn off the alarm and restore the signal handler + alarm(0); + sigaction(SIGALRM, &Old, 0); + + // Wait for child to die + if (wait(&status) != child) + MakeErrMsg(ErrMsg, "Child timed out but wouldn't die"); + else + MakeErrMsg(ErrMsg, "Child timed out", 0); + + return -2; // Timeout detected + } else if (errno != EINTR) { + MakeErrMsg(ErrMsg, "Error waiting for child process"); + return -1; + } + + // We exited normally without timeout, so turn off the timer. + if (secondsToWait) { + alarm(0); + sigaction(SIGALRM, &Old, 0); + } + + // Return the proper exit status. Detect error conditions + // so we can return -1 for them and set ErrMsg informatively. + int result = 0; + if (WIFEXITED(status)) { + result = WEXITSTATUS(status); +#ifdef HAVE_POSIX_SPAWN + // The posix_spawn child process returns 127 on any kind of error. + // Following the POSIX convention for command-line tools (which posix_spawn + // itself apparently does not), check to see if the failure was due to some + // reason other than the file not existing, and return 126 in this case. + bool Exists; + if (result == 127 && !llvm::sys::fs::exists(path.str(), Exists) && Exists) + result = 126; +#endif + if (result == 127) { + if (ErrMsg) + *ErrMsg = llvm::sys::StrError(ENOENT); + return -1; + } + if (result == 126) { + if (ErrMsg) + *ErrMsg = "Program could not be executed"; + return -1; + } + } else if (WIFSIGNALED(status)) { + if (ErrMsg) { + *ErrMsg = strsignal(WTERMSIG(status)); +#ifdef WCOREDUMP + if (WCOREDUMP(status)) + *ErrMsg += " (core dumped)"; +#endif + } + // Return a special value to indicate that the process received an unhandled + // signal during execution as opposed to failing to execute. + return -2; + } + return result; +#else + if (ErrMsg) + *ErrMsg = "Program::Wait is not implemented on this platform yet!"; + return -1; +#endif +} + +bool +Program::Kill(std::string* ErrMsg) { + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return true; + } + + uint64_t pid64 = reinterpret_cast<uint64_t>(Data_); + pid_t pid = static_cast<pid_t>(pid64); + + if (kill(pid, SIGKILL) != 0) { + MakeErrMsg(ErrMsg, "The process couldn't be killed!"); + return true; + } + + return false; +} + +error_code Program::ChangeStdinToBinary(){ + // Do nothing, as Unix doesn't differentiate between text and binary. + return make_error_code(errc::success); +} + +error_code Program::ChangeStdoutToBinary(){ + // Do nothing, as Unix doesn't differentiate between text and binary. + return make_error_code(errc::success); +} + +error_code Program::ChangeStderrToBinary(){ + // Do nothing, as Unix doesn't differentiate between text and binary. + return make_error_code(errc::success); +} + +} diff --git a/contrib/llvm/lib/Support/Unix/README.txt b/contrib/llvm/lib/Support/Unix/README.txt new file mode 100644 index 0000000..3d547c2 --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/README.txt @@ -0,0 +1,16 @@ +llvm/lib/Support/Unix README +=========================== + +This directory provides implementations of the lib/System classes that +are common to two or more variants of UNIX. For example, the directory +structure underneath this directory could look like this: + +Unix - only code that is truly generic to all UNIX platforms + Posix - code that is specific to Posix variants of UNIX + SUS - code that is specific to the Single Unix Specification + SysV - code that is specific to System V variants of UNIX + +As a rule, only those directories actually needing to be created should be +created. Also, further subdirectories could be created to reflect versions of +the various standards. For example, under SUS there could be v1, v2, and v3 +subdirectories to reflect the three major versions of SUS. diff --git a/contrib/llvm/lib/Support/Unix/RWMutex.inc b/contrib/llvm/lib/Support/Unix/RWMutex.inc new file mode 100644 index 0000000..40e87ff --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/RWMutex.inc @@ -0,0 +1,43 @@ +//= llvm/Support/Unix/RWMutex.inc - Unix Reader/Writer Mutual Exclusion Lock =// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific (non-pthread) RWMutex class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +namespace llvm { + +using namespace sys; + +RWMutexImpl::RWMutexImpl() { } + +RWMutexImpl::~RWMutexImpl() { } + +bool RWMutexImpl::reader_acquire() { + return true; +} + +bool RWMutexImpl::reader_release() { + return true; +} + +bool RWMutexImpl::writer_acquire() { + return true; +} + +bool RWMutexImpl::writer_release() { + return true; +} + +} diff --git a/contrib/llvm/lib/Support/Unix/Signals.inc b/contrib/llvm/lib/Support/Unix/Signals.inc new file mode 100644 index 0000000..c9ec9fc --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/Signals.inc @@ -0,0 +1,323 @@ +//===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some helpful functions for dealing with the possibility of +// Unix signals occurring while your program is running. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Mutex.h" +#include <vector> +#include <algorithm> +#if HAVE_EXECINFO_H +# include <execinfo.h> // For backtrace(). +#endif +#if HAVE_SIGNAL_H +#include <signal.h> +#endif +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_DLFCN_H && __GNUG__ +#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. + +static SmartMutex<true> SignalsMutex; + +/// InterruptFunction - The function to call if ctrl-c is pressed. +static void (*InterruptFunction)() = 0; + +static std::vector<sys::Path> FilesToRemove; +static std::vector<std::pair<void(*)(void*), void*> > CallBacksToRun; + +// IntSigs - Signals that may interrupt the program at any time. +static const int IntSigs[] = { + SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2 +}; +static const int *const IntSigsEnd = + IntSigs + sizeof(IntSigs) / sizeof(IntSigs[0]); + +// KillSigs - Signals that are synchronous with the program that will cause it +// to die. +static const int KillSigs[] = { + SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV +#ifdef SIGSYS + , SIGSYS +#endif +#ifdef SIGXCPU + , SIGXCPU +#endif +#ifdef SIGXFSZ + , SIGXFSZ +#endif +#ifdef SIGEMT + , SIGEMT +#endif +}; +static const int *const KillSigsEnd = + KillSigs + sizeof(KillSigs) / sizeof(KillSigs[0]); + +static unsigned NumRegisteredSignals = 0; +static struct { + struct sigaction SA; + int SigNo; +} RegisteredSignalInfo[(sizeof(IntSigs)+sizeof(KillSigs))/sizeof(KillSigs[0])]; + + +static void RegisterHandler(int Signal) { + assert(NumRegisteredSignals < + sizeof(RegisteredSignalInfo)/sizeof(RegisteredSignalInfo[0]) && + "Out of space for signal handlers!"); + + struct sigaction NewHandler; + + NewHandler.sa_handler = SignalHandler; + NewHandler.sa_flags = SA_NODEFER|SA_RESETHAND; + sigemptyset(&NewHandler.sa_mask); + + // Install the new handler, save the old one in RegisteredSignalInfo. + sigaction(Signal, &NewHandler, + &RegisteredSignalInfo[NumRegisteredSignals].SA); + RegisteredSignalInfo[NumRegisteredSignals].SigNo = Signal; + ++NumRegisteredSignals; +} + +static void RegisterHandlers() { + // If the handlers are already registered, we're done. + if (NumRegisteredSignals != 0) return; + + std::for_each(IntSigs, IntSigsEnd, RegisterHandler); + std::for_each(KillSigs, KillSigsEnd, RegisterHandler); +} + +static void UnregisterHandlers() { + // Restore all of the signal handlers to how they were before we showed up. + for (unsigned i = 0, e = NumRegisteredSignals; i != e; ++i) + sigaction(RegisteredSignalInfo[i].SigNo, + &RegisteredSignalInfo[i].SA, 0); + NumRegisteredSignals = 0; +} + + +/// RemoveFilesToRemove - Process the FilesToRemove list. This function +/// should be called with the SignalsMutex lock held. +static void RemoveFilesToRemove() { + while (!FilesToRemove.empty()) { + FilesToRemove.back().eraseFromDisk(true); + FilesToRemove.pop_back(); + } +} + +// SignalHandler - The signal handler that runs. +static RETSIGTYPE SignalHandler(int Sig) { + // Restore the signal behavior to default, so that the program actually + // crashes when we return and the signal reissues. This also ensures that if + // we crash in our signal handler that the program will terminate immediately + // instead of recursing in the signal handler. + UnregisterHandlers(); + + // Unmask all potentially blocked kill signals. + sigset_t SigMask; + sigfillset(&SigMask); + sigprocmask(SIG_UNBLOCK, &SigMask, 0); + + SignalsMutex.acquire(); + RemoveFilesToRemove(); + + if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) { + if (InterruptFunction) { + void (*IF)() = InterruptFunction; + SignalsMutex.release(); + InterruptFunction = 0; + IF(); // run the interrupt function. + return; + } + + SignalsMutex.release(); + raise(Sig); // Execute the default handler. + return; + } + + SignalsMutex.release(); + + // Otherwise if it is a fault (like SEGV) run any handler. + for (unsigned i = 0, e = CallBacksToRun.size(); i != e; ++i) + CallBacksToRun[i].first(CallBacksToRun[i].second); +} + +void llvm::sys::RunInterruptHandlers() { + SignalsMutex.acquire(); + RemoveFilesToRemove(); + SignalsMutex.release(); +} + +void llvm::sys::SetInterruptFunction(void (*IF)()) { + SignalsMutex.acquire(); + InterruptFunction = IF; + SignalsMutex.release(); + RegisterHandlers(); +} + +// RemoveFileOnSignal - The public API +bool llvm::sys::RemoveFileOnSignal(const sys::Path &Filename, + std::string* ErrMsg) { + SignalsMutex.acquire(); + FilesToRemove.push_back(Filename); + + SignalsMutex.release(); + + RegisterHandlers(); + return false; +} + +// DontRemoveFileOnSignal - The public API +void llvm::sys::DontRemoveFileOnSignal(const sys::Path &Filename) { + SignalsMutex.acquire(); + std::vector<sys::Path>::reverse_iterator I = + std::find(FilesToRemove.rbegin(), FilesToRemove.rend(), Filename); + if (I != FilesToRemove.rend()) + FilesToRemove.erase(I.base()-1); + SignalsMutex.release(); +} + +/// AddSignalHandler - Add a function to be called when a signal is delivered +/// to the process. The handler can have a cookie passed to it to identify +/// what instance of the handler it is. +void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { + CallBacksToRun.push_back(std::make_pair(FnPtr, Cookie)); + RegisterHandlers(); +} + + +// PrintStackTrace - In the case of a program crash or fault, print out a stack +// trace so that the user has an indication of why and where we died. +// +// On glibc systems we have the 'backtrace' function, which works nicely, but +// doesn't demangle symbols. +static void PrintStackTrace(void *) { +#ifdef HAVE_BACKTRACE + static void* StackTrace[256]; + // Use backtrace() to output a backtrace on Linux systems with glibc. + int depth = backtrace(StackTrace, + static_cast<int>(array_lengthof(StackTrace))); +#if HAVE_DLFCN_H && __GNUG__ + int width = 0; + for (int i = 0; i < depth; ++i) { + Dl_info dlinfo; + dladdr(StackTrace[i], &dlinfo); + const char* name = strrchr(dlinfo.dli_fname, '/'); + + int nwidth; + if (name == NULL) nwidth = strlen(dlinfo.dli_fname); + else nwidth = strlen(name) - 1; + + if (nwidth > width) width = nwidth; + } + + for (int i = 0; i < depth; ++i) { + Dl_info dlinfo; + dladdr(StackTrace[i], &dlinfo); + + fprintf(stderr, "%-2d", i); + + const char* name = strrchr(dlinfo.dli_fname, '/'); + if (name == NULL) fprintf(stderr, " %-*s", width, dlinfo.dli_fname); + else fprintf(stderr, " %-*s", width, name+1); + + fprintf(stderr, " %#0*lx", + (int)(sizeof(void*) * 2) + 2, (unsigned long)StackTrace[i]); + + if (dlinfo.dli_sname != NULL) { + int res; + fputc(' ', stderr); + char* d = abi::__cxa_demangle(dlinfo.dli_sname, NULL, NULL, &res); + if (d == NULL) fputs(dlinfo.dli_sname, stderr); + else fputs(d, stderr); + free(d); + + fprintf(stderr, " + %tu",(char*)StackTrace[i]-(char*)dlinfo.dli_saddr); + } + fputc('\n', stderr); + } +#else + backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); +#endif +#endif +} + +/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or +/// 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 +} + + +/***/ + +// On Darwin, raise sends a signal to the main thread instead of the current +// thread. This has the unfortunate effect that assert() and abort() will end up +// bypassing our crash recovery attempts. We work around this for anything in +// the same linkage unit by just defining our own versions of the assert handler +// and abort. + +#ifdef __APPLE__ + +#include <signal.h> +#include <pthread.h> + +int raise(int sig) { + return pthread_kill(pthread_self(), sig); +} + +void __assert_rtn(const char *func, + const char *file, + int line, + const char *expr) { + if (func) + fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", + expr, func, file, line); + else + fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n", + expr, file, line); + abort(); +} + +void abort() { + raise(SIGABRT); + usleep(1000); + __builtin_trap(); +} + +#endif diff --git a/contrib/llvm/lib/Support/Unix/ThreadLocal.inc b/contrib/llvm/lib/Support/Unix/ThreadLocal.inc new file mode 100644 index 0000000..2b4c901 --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/ThreadLocal.inc @@ -0,0 +1,26 @@ +//=== llvm/Support/Unix/ThreadLocal.inc - Unix Thread Local Data -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific (non-pthread) ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +namespace llvm { +using namespace sys; +ThreadLocalImpl::ThreadLocalImpl() { } +ThreadLocalImpl::~ThreadLocalImpl() { } +void ThreadLocalImpl::setInstance(const void* d) { data = const_cast<void*>(d);} +const void* ThreadLocalImpl::getInstance() { return data; } +void ThreadLocalImpl::removeInstance() { setInstance(0); } +} diff --git a/contrib/llvm/lib/Support/Unix/TimeValue.inc b/contrib/llvm/lib/Support/Unix/TimeValue.inc new file mode 100644 index 0000000..5cf5a9d --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/TimeValue.inc @@ -0,0 +1,56 @@ +//===- Unix/TimeValue.cpp - Unix TimeValue Implementation -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific portion of the TimeValue class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "Unix.h" + +namespace llvm { + using namespace sys; + +std::string TimeValue::str() const { + char buffer[32]; + + time_t ourTime = time_t(this->toEpochTime()); +#ifdef __hpux +// note that the following line needs -D_REENTRANT on HP-UX to be picked up + asctime_r(localtime(&ourTime), buffer); +#else + ::asctime_r(::localtime(&ourTime), buffer); +#endif + + std::string result(buffer); + return result.substr(0,24); +} + +TimeValue TimeValue::now() { + struct timeval the_time; + timerclear(&the_time); + if (0 != ::gettimeofday(&the_time,0)) { + // This is *really* unlikely to occur because the only gettimeofday + // errors concern the timezone parameter which we're passing in as 0. + // In the unlikely case it does happen, just return MinTime, no error + // message needed. + return MinTime; + } + + return TimeValue( + static_cast<TimeValue::SecondsType>( the_time.tv_sec + PosixZeroTime.seconds_ ), + static_cast<TimeValue::NanoSecondsType>( the_time.tv_usec * + NANOSECONDS_PER_MICROSECOND ) ); +} + +} diff --git a/contrib/llvm/lib/Support/Unix/Unix.h b/contrib/llvm/lib/Support/Unix/Unix.h new file mode 100644 index 0000000..b7be311 --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/Unix.h @@ -0,0 +1,87 @@ +//===- llvm/Support/Unix/Unix.h - Common Unix Include File -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines things specific to Unix implementations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_UNIX_UNIX_H +#define LLVM_SYSTEM_UNIX_UNIX_H + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on all UNIX variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" // Get autoconf configuration settings +#include "llvm/Support/Errno.h" +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <cerrno> +#include <string> +#include <algorithm> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#ifdef HAVE_ASSERT_H +#include <assert.h> +#endif + +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#ifdef HAVE_SYS_WAIT_H +# include <sys/wait.h> +#endif + +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif + +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +/// This function builds an error message into \p ErrMsg using the \p prefix +/// string and the Unix error number given by \p errnum. If errnum is -1, the +/// default then the value of errno is used. +/// @brief Make an error message +/// +/// If the error number can be converted to a string, it will be +/// separated from prefix by ": ". +static inline bool MakeErrMsg( + std::string* ErrMsg, const std::string& prefix, int errnum = -1) { + if (!ErrMsg) + return true; + if (errnum == -1) + errnum = errno; + *ErrMsg = prefix + ": " + llvm::sys::StrError(errnum); + return true; +} + +#endif diff --git a/contrib/llvm/lib/Support/Unix/system_error.inc b/contrib/llvm/lib/Support/Unix/system_error.inc new file mode 100644 index 0000000..681e919 --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/system_error.inc @@ -0,0 +1,34 @@ +//===- llvm/Support/Unix/system_error.inc - Unix error_code ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Unix specific implementation of the error_code +// and error_condition classes. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +using namespace llvm; + +std::string +_system_error_category::message(int ev) const { + return _do_message::message(ev); +} + +error_condition +_system_error_category::default_error_condition(int ev) const { +#ifdef ELAST + if (ev > ELAST) + return error_condition(ev, system_category()); +#endif // ELAST + return error_condition(ev, generic_category()); +} diff --git a/contrib/llvm/lib/Support/Valgrind.cpp b/contrib/llvm/lib/Support/Valgrind.cpp new file mode 100644 index 0000000..2b250a3 --- /dev/null +++ b/contrib/llvm/lib/Support/Valgrind.cpp @@ -0,0 +1,67 @@ +//===-- Valgrind.cpp - Implement Valgrind communication ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines Valgrind communication methods, if HAVE_VALGRIND_VALGRIND_H is +// defined. If we have valgrind.h but valgrind isn't running, its macros are +// no-ops. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Valgrind.h" +#include "llvm/Config/config.h" + +#if HAVE_VALGRIND_VALGRIND_H +#include <valgrind/valgrind.h> + +static bool InitNotUnderValgrind() { + return !RUNNING_ON_VALGRIND; +} + +// This bool is negated from what we'd expect because code may run before it +// gets initialized. If that happens, it will appear to be 0 (false), and we +// want that to cause the rest of the code in this file to run the +// Valgrind-provided macros. +static const bool NotUnderValgrind = InitNotUnderValgrind(); + +bool llvm::sys::RunningOnValgrind() { + if (NotUnderValgrind) + return false; + return RUNNING_ON_VALGRIND; +} + +void llvm::sys::ValgrindDiscardTranslations(const void *Addr, size_t Len) { + if (NotUnderValgrind) + return; + + VALGRIND_DISCARD_TRANSLATIONS(Addr, Len); +} + +#else // !HAVE_VALGRIND_VALGRIND_H + +bool llvm::sys::RunningOnValgrind() { + return false; +} + +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/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc new file mode 100644 index 0000000..83da82a --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc @@ -0,0 +1,163 @@ +//===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of DynamicLibrary. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" + +#ifdef __MINGW32__ + #include <imagehlp.h> +#else + #include <dbghelp.h> +#endif + +#ifdef _MSC_VER + #include <ntverp.h> +#endif + +#ifdef __MINGW32__ + #if (HAVE_LIBIMAGEHLP != 1) + #error "libimagehlp.a should be present" + #endif +#else + #pragma comment(lib, "dbghelp.lib") +#endif + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code. +//===----------------------------------------------------------------------===// + +static DenseSet<HMODULE> *OpenedHandles; + +extern "C" { + + static BOOL CALLBACK ELM_Callback(WIN32_ELMCB_PCSTR ModuleName, + ULONG_PTR ModuleBase, + ULONG ModuleSize, + PVOID UserContext) + { + // Ignore VC++ runtimes prior to 7.1. Somehow some of them get loaded + // into the process. + if (stricmp(ModuleName, "msvci70") != 0 && + stricmp(ModuleName, "msvcirt") != 0 && + stricmp(ModuleName, "msvcp50") != 0 && + stricmp(ModuleName, "msvcp60") != 0 && + stricmp(ModuleName, "msvcp70") != 0 && + stricmp(ModuleName, "msvcr70") != 0 && +#ifndef __MINGW32__ + // Mingw32 uses msvcrt.dll by default. Don't ignore it. + // Otherwise, user should be aware, what he's doing :) + stricmp(ModuleName, "msvcrt") != 0 && +#endif + stricmp(ModuleName, "msvcrt20") != 0 && + stricmp(ModuleName, "msvcrt40") != 0) { + OpenedHandles->insert((HMODULE)ModuleBase); + } + return TRUE; + } +} + +DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, + std::string *errMsg) { + SmartScopedLock<true> lock(getMutex()); + + if (!filename) { + // When no file is specified, enumerate all DLLs and EXEs in the process. + if (OpenedHandles == 0) + OpenedHandles = new DenseSet<HMODULE>(); + + EnumerateLoadedModules(GetCurrentProcess(), ELM_Callback, 0); + // Dummy library that represents "search all handles". + // This is mostly to ensure that the return value still shows up as "valid". + return DynamicLibrary(&OpenedHandles); + } + + HMODULE a_handle = LoadLibrary(filename); + + if (a_handle == 0) { + MakeErrMsg(errMsg, std::string(filename) + ": Can't open : "); + return DynamicLibrary(); + } + + if (OpenedHandles == 0) + OpenedHandles = new DenseSet<HMODULE>(); + + // If we've already loaded this library, FreeLibrary() the handle in order to + // keep the internal refcount at +1. + if (!OpenedHandles->insert(a_handle).second) + FreeLibrary(a_handle); + + return DynamicLibrary(a_handle); +} + +// Stack probing routines are in the support library (e.g. libgcc), but we don't +// have dynamic linking on windows. Provide a hook. +#define EXPLICIT_SYMBOL(SYM) \ + extern "C" { extern void *SYM; } +#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO) + +#include "explicit_symbols.inc" + +#undef EXPLICIT_SYMBOL +#undef EXPLICIT_SYMBOL2 + +void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { + SmartScopedLock<true> Lock(getMutex()); + + // First check symbols added via AddSymbol(). + if (ExplicitSymbols) { + StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName); + + if (i != ExplicitSymbols->end()) + return i->second; + } + + // Now search the libraries. + if (OpenedHandles) { + for (DenseSet<HMODULE>::iterator I = OpenedHandles->begin(), + E = OpenedHandles->end(); I != E; ++I) { + FARPROC ptr = GetProcAddress((HMODULE)*I, symbolName); + if (ptr) { + return (void *)(intptr_t)ptr; + } + } + } + + #define EXPLICIT_SYMBOL(SYM) \ + if (!strcmp(symbolName, #SYM)) return (void*)&SYM; + #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \ + if (!strcmp(symbolName, #SYMFROM)) return (void*)&SYMTO; + + { + #include "explicit_symbols.inc" + } + + #undef EXPLICIT_SYMBOL + #undef EXPLICIT_SYMBOL2 + + return 0; +} + + +void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) { + if (!isValid()) + return NULL; + if (Data == &OpenedHandles) + return SearchForAddressOfSymbol(symbolName); + return (void *)(intptr_t)GetProcAddress((HMODULE)Data, symbolName); +} + + +} diff --git a/contrib/llvm/lib/Support/Windows/Host.inc b/contrib/llvm/lib/Support/Windows/Host.inc new file mode 100644 index 0000000..2e6d6f1 --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/Host.inc @@ -0,0 +1,22 @@ +//===- llvm/Support/Win32/Host.inc -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 Host support. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include <cstdio> +#include <string> + +using namespace llvm; + +std::string sys::getDefaultTargetTriple() { + return LLVM_DEFAULT_TARGET_TRIPLE; +} diff --git a/contrib/llvm/lib/Support/Windows/Memory.inc b/contrib/llvm/lib/Support/Windows/Memory.inc new file mode 100644 index 0000000..fcc7283 --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/Memory.inc @@ -0,0 +1,120 @@ +//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of various Memory +// management utilities +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Process.h" + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +MemoryBlock Memory::AllocateRWX(size_t NumBytes, + const MemoryBlock *NearBlock, + std::string *ErrMsg) { + if (NumBytes == 0) return MemoryBlock(); + + static const size_t pageSize = Process::GetPageSize(); + size_t NumPages = (NumBytes+pageSize-1)/pageSize; + + PVOID start = NearBlock ? static_cast<unsigned char *>(NearBlock->base()) + + NearBlock->size() : NULL; + + void *pa = VirtualAlloc(start, NumPages*pageSize, MEM_RESERVE | MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + if (pa == NULL) { + if (NearBlock) { + // Try again without the NearBlock hint + return AllocateRWX(NumBytes, NULL, ErrMsg); + } + MakeErrMsg(ErrMsg, "Can't allocate RWX Memory: "); + return MemoryBlock(); + } + + MemoryBlock result; + result.Address = pa; + result.Size = NumPages*pageSize; + return result; +} + +bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { + if (M.Address == 0 || M.Size == 0) return false; + if (!VirtualFree(M.Address, 0, MEM_RELEASE)) + return MakeErrMsg(ErrMsg, "Can't release RWX Memory: "); + return false; +} + +static DWORD getProtection(const void *addr) { + MEMORY_BASIC_INFORMATION info; + if (sizeof(info) == ::VirtualQuery(addr, &info, sizeof(info))) { + return info.Protect; + } + return 0; +} + +bool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) { + if (!setRangeWritable(M.Address, M.Size)) { + return MakeErrMsg(ErrMsg, "Cannot set memory to writeable: "); + } + return true; +} + +bool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) { + if (!setRangeExecutable(M.Address, M.Size)) { + return MakeErrMsg(ErrMsg, "Cannot set memory to executable: "); + } + return true; +} + +bool Memory::setRangeWritable(const void *Addr, size_t Size) { + DWORD prot = getProtection(Addr); + if (!prot) + return false; + + if (prot == PAGE_EXECUTE || prot == PAGE_EXECUTE_READ) { + prot = PAGE_EXECUTE_READWRITE; + } else if (prot == PAGE_NOACCESS || prot == PAGE_READONLY) { + prot = PAGE_READWRITE; + } + + DWORD oldProt; + sys::Memory::InvalidateInstructionCache(Addr, Size); + return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) + == TRUE; +} + +bool Memory::setRangeExecutable(const void *Addr, size_t Size) { + DWORD prot = getProtection(Addr); + if (!prot) + return false; + + if (prot == PAGE_NOACCESS) { + prot = PAGE_EXECUTE; + } else if (prot == PAGE_READONLY) { + prot = PAGE_EXECUTE_READ; + } else if (prot == PAGE_READWRITE) { + prot = PAGE_EXECUTE_READWRITE; + } + + DWORD oldProt; + sys::Memory::InvalidateInstructionCache(Addr, Size); + return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) + == TRUE; +} + +} diff --git a/contrib/llvm/lib/Support/Windows/Mutex.inc b/contrib/llvm/lib/Support/Windows/Mutex.inc new file mode 100644 index 0000000..583dc63 --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/Mutex.inc @@ -0,0 +1,58 @@ +//===- llvm/Support/Win32/Mutex.inc - Win32 Mutex Implementation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 specific (non-pthread) Mutex class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include "llvm/Support/Mutex.h" + +namespace llvm { +using namespace sys; + +MutexImpl::MutexImpl(bool /*recursive*/) +{ + data_ = new CRITICAL_SECTION; + InitializeCriticalSection((LPCRITICAL_SECTION)data_); +} + +MutexImpl::~MutexImpl() +{ + DeleteCriticalSection((LPCRITICAL_SECTION)data_); + delete (LPCRITICAL_SECTION)data_; + data_ = 0; +} + +bool +MutexImpl::acquire() +{ + EnterCriticalSection((LPCRITICAL_SECTION)data_); + return true; +} + +bool +MutexImpl::release() +{ + LeaveCriticalSection((LPCRITICAL_SECTION)data_); + return true; +} + +bool +MutexImpl::tryacquire() +{ + return TryEnterCriticalSection((LPCRITICAL_SECTION)data_); +} + +} diff --git a/contrib/llvm/lib/Support/Windows/Path.inc b/contrib/llvm/lib/Support/Windows/Path.inc new file mode 100644 index 0000000..d8dc522 --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/Path.inc @@ -0,0 +1,914 @@ +//===- llvm/Support/Win32/Path.cpp - Win32 Path Implementation ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Path class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include <malloc.h> +#include <cstdio> + +// We need to undo a macro defined in Windows.h, otherwise we won't compile: +#undef CopyFile +#undef GetCurrentDirectory + +// Windows happily accepts either forward or backward slashes, though any path +// returned by a Win32 API will have backward slashes. As LLVM code basically +// assumes forward slashes are used, backward slashs are converted where they +// can be introduced into a path. +// +// Another invariant is that a path ends with a slash if and only if the path +// is a root directory. Any other use of a trailing slash is stripped. Unlike +// in Unix, Windows has a rather complicated notion of a root path and this +// invariant helps simply the code. + +static void FlipBackSlashes(std::string& s) { + for (size_t i = 0; i < s.size(); i++) + if (s[i] == '\\') + s[i] = '/'; +} + +namespace llvm { +namespace sys { + +const char PathSeparator = ';'; + +StringRef Path::GetEXESuffix() { + return "exe"; +} + +Path::Path(llvm::StringRef p) + : path(p) { + FlipBackSlashes(path); +} + +Path::Path(const char *StrStart, unsigned StrLen) + : path(StrStart, StrLen) { + FlipBackSlashes(path); +} + +Path& +Path::operator=(StringRef that) { + path.assign(that.data(), that.size()); + FlipBackSlashes(path); + return *this; +} + +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. + pos = path.rfind(':',len); + size_t rootslash = 0; + if (pos != std::string::npos) { + if (pos != 1 || !isalpha(path[0]) || len < 3) + return false; + rootslash = 2; + } + + // Look for a UNC path, and if found adjust our notion of the root slash. + if (len > 3 && path[0] == '/' && path[1] == '/') { + rootslash = path.find('/', 2); + if (rootslash == std::string::npos) + rootslash = 0; + } + + // Check for illegal characters. + if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012" + "\013\014\015\016\017\020\021\022\023\024\025\026" + "\027\030\031\032\033\034\035\036\037") + != std::string::npos) + return false; + + // Remove trailing slash, unless it's a root slash. + if (len > rootslash+1 && path[len-1] == '/') + path.erase(--len); + + // Check each component for legality. + for (pos = 0; pos < len; ++pos) { + // A component may not end in a space. + if (path[pos] == ' ') { + 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 (pos+1 == len || path[pos+1] == '/') { + // Unless it is the pseudo-directory "."... + if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':') + return true; + // or "..". + if (pos > 0 && path[pos-1] == '.') { + if (pos == 1 || path[pos-2] == '/' || path[pos-2] == ':') + return true; + } + return false; + } + } + } + + return true; +} + +void Path::makeAbsolute() { + TCHAR FullPath[MAX_PATH + 1] = {0}; + LPTSTR FilePart = NULL; + + DWORD RetLength = ::GetFullPathNameA(path.c_str(), + sizeof(FullPath)/sizeof(FullPath[0]), + FullPath, &FilePart); + + if (0 == RetLength) { + // FIXME: Report the error GetLastError() + assert(0 && "Unable to make absolute path!"); + } else if (RetLength > MAX_PATH) { + // FIXME: Report too small buffer (needed RetLength bytes). + assert(0 && "Unable to make absolute path!"); + } else { + path = FullPath; + } +} + +bool +Path::isAbsolute(const char *NameStart, unsigned NameLen) { + assert(NameStart); + // FIXME: This does not handle correctly an absolute path starting from + // a drive letter or in UNC format. + switch (NameLen) { + case 0: + return false; + case 1: + case 2: + return NameStart[0] == '/'; + default: + return + (NameStart[0] == '/' || (NameStart[1] == ':' && NameStart[2] == '/')) || + (NameStart[0] == '\\' || (NameStart[1] == ':' && NameStart[2] == '\\')); + } +} + +bool +Path::isAbsolute() const { + // FIXME: This does not handle correctly an absolute path starting from + // a drive letter or in UNC format. + switch (path.length()) { + case 0: + return false; + case 1: + case 2: + return path[0] == '/'; + default: + return path[0] == '/' || (path[1] == ':' && path[2] == '/'); + } +} + +static Path *TempDirectory; + +Path +Path::GetTemporaryDirectory(std::string* ErrMsg) { + if (TempDirectory) + return *TempDirectory; + + char pathname[MAX_PATH]; + if (!GetTempPath(MAX_PATH, pathname)) { + if (ErrMsg) + *ErrMsg = "Can't determine temporary directory"; + return Path(); + } + + Path result; + result.set(pathname); + + // Append a subdirectory passed on our process id so multiple LLVMs don't + // step on each other's toes. +#ifdef __MINGW32__ + // Mingw's Win32 header files are broken. + sprintf(pathname, "LLVM_%u", unsigned(GetCurrentProcessId())); +#else + sprintf(pathname, "LLVM_%u", GetCurrentProcessId()); +#endif + result.appendComponent(pathname); + + // If there's a directory left over from a previous LLVM execution that + // happened to have the same process id, get rid of it. + result.eraseFromDisk(true); + + // And finally (re-)create the empty directory. + result.createDirectoryOnDisk(false); + TempDirectory = new Path(result); + return *TempDirectory; +} + +// FIXME: the following set of functions don't map to Windows very well. +Path +Path::GetRootDirectory() { + // This is the only notion that that Windows has of a root directory. Nothing + // is here except for drives. + return Path("file:///"); +} + +void +Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) { + char buff[MAX_PATH]; + // Generic form of C:\Windows\System32 + HRESULT res = SHGetFolderPathA(NULL, + CSIDL_FLAG_CREATE | CSIDL_SYSTEM, + NULL, + SHGFP_TYPE_CURRENT, + buff); + if (res != S_OK) { + assert(0 && "Failed to get system directory"); + return; + } + Paths.push_back(sys::Path(buff)); + + // Reset buff. + buff[0] = 0; + // Generic form of C:\Windows + res = SHGetFolderPathA(NULL, + CSIDL_FLAG_CREATE | CSIDL_WINDOWS, + NULL, + SHGFP_TYPE_CURRENT, + buff); + if (res != S_OK) { + assert(0 && "Failed to get windows directory"); + return; + } + Paths.push_back(sys::Path(buff)); +} + +void +Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) { + char * env_var = getenv("LLVM_LIB_SEARCH_PATH"); + if (env_var != 0) { + getPathList(env_var,Paths); + } +#ifdef LLVM_LIBDIR + { + Path tmpPath; + if (tmpPath.set(LLVM_LIBDIR)) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); + } +#endif + GetSystemLibraryPaths(Paths); +} + +Path +Path::GetUserHomeDirectory() { + char buff[MAX_PATH]; + HRESULT res = SHGetFolderPathA(NULL, + CSIDL_FLAG_CREATE | CSIDL_APPDATA, + NULL, + SHGFP_TYPE_CURRENT, + buff); + if (res != S_OK) + assert(0 && "Failed to get user home directory"); + return Path(buff); +} + +Path +Path::GetCurrentDirectory() { + char pathname[MAX_PATH]; + ::GetCurrentDirectoryA(MAX_PATH,pathname); + return Path(pathname); +} + +/// GetMainExecutable - Return the path to the main executable, given the +/// value of argv[0] from program startup. +Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { + char pathname[MAX_PATH]; + DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH); + return ret != MAX_PATH ? Path(pathname) : Path(); +} + + +// FIXME: the above set of functions don't map to Windows very well. + + +StringRef Path::getDirname() const { + return getDirnameCharSep(path, "/"); +} + +StringRef +Path::getBasename() const { + // Find the last slash + size_t slash = path.rfind('/'); + if (slash == std::string::npos) + slash = 0; + else + slash++; + + size_t dot = path.rfind('.'); + if (dot == std::string::npos || dot < slash) + return StringRef(path).substr(slash); + else + return StringRef(path).substr(slash, dot - slash); +} + +StringRef +Path::getSuffix() const { + // Find the last slash + size_t slash = path.rfind('/'); + if (slash == std::string::npos) + slash = 0; + else + slash++; + + size_t dot = path.rfind('.'); + if (dot == std::string::npos || dot < slash) + return StringRef(""); + else + return StringRef(path).substr(dot + 1); +} + +bool +Path::exists() const { + DWORD attr = GetFileAttributes(path.c_str()); + return attr != INVALID_FILE_ATTRIBUTES; +} + +bool +Path::isDirectory() const { + DWORD attr = GetFileAttributes(path.c_str()); + return (attr != INVALID_FILE_ATTRIBUTES) && + (attr & FILE_ATTRIBUTE_DIRECTORY); +} + +bool +Path::isSymLink() const { + DWORD attributes = GetFileAttributes(path.c_str()); + + if (attributes == INVALID_FILE_ATTRIBUTES) + // There's no sane way to report this :(. + assert(0 && "GetFileAttributes returned INVALID_FILE_ATTRIBUTES"); + + // This isn't exactly what defines a NTFS symlink, but it is only true for + // paths that act like a symlink. + return attributes & FILE_ATTRIBUTE_REPARSE_POINT; +} + +bool +Path::canRead() const { + // FIXME: take security attributes into account. + DWORD attr = GetFileAttributes(path.c_str()); + return attr != INVALID_FILE_ATTRIBUTES; +} + +bool +Path::canWrite() const { + // FIXME: take security attributes into account. + DWORD attr = GetFileAttributes(path.c_str()); + return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY); +} + +bool +Path::canExecute() const { + // FIXME: take security attributes into account. + DWORD attr = GetFileAttributes(path.c_str()); + return attr != INVALID_FILE_ATTRIBUTES; +} + +bool +Path::isRegularFile() const { + bool res; + if (fs::is_regular_file(path, res)) + return false; + return res; +} + +StringRef +Path::getLast() const { + // Find the last slash + size_t pos = path.rfind('/'); + + // Handle the corner cases + if (pos == std::string::npos) + return path; + + // If the last character is a slash, we have a root directory + if (pos == path.length()-1) + return path; + + // Return everything after the last slash + return StringRef(path).substr(pos+1); +} + +const FileStatus * +PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const { + if (!fsIsValid || update) { + WIN32_FILE_ATTRIBUTE_DATA fi; + if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) { + MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) + + ": Can't get status: "); + return 0; + } + + status.fileSize = fi.nFileSizeHigh; + status.fileSize <<= sizeof(fi.nFileSizeHigh)*8; + status.fileSize += fi.nFileSizeLow; + + status.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777; + status.user = 9999; // Not applicable to Windows, so... + status.group = 9999; // Not applicable to Windows, so... + + // FIXME: this is only unique if the file is accessed by the same file path. + // How do we do this for C:\dir\file and ..\dir\file ? Unix has inode + // numbers, but the concept doesn't exist in Windows. + status.uniqueID = 0; + for (unsigned i = 0; i < path.length(); ++i) + status.uniqueID += path[i]; + + ULARGE_INTEGER ui; + ui.LowPart = fi.ftLastWriteTime.dwLowDateTime; + ui.HighPart = fi.ftLastWriteTime.dwHighDateTime; + status.modTime.fromWin32Time(ui.QuadPart); + + status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; + fsIsValid = true; + } + return &status; +} + +bool Path::makeReadableOnDisk(std::string* ErrMsg) { + // All files are readable on Windows (ignoring security attributes). + return false; +} + +bool Path::makeWriteableOnDisk(std::string* ErrMsg) { + DWORD attr = GetFileAttributes(path.c_str()); + + // If it doesn't exist, we're done. + if (attr == INVALID_FILE_ATTRIBUTES) + return false; + + if (attr & FILE_ATTRIBUTE_READONLY) { + if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) { + MakeErrMsg(ErrMsg, std::string(path) + ": Can't make file writable: "); + return true; + } + } + return false; +} + +bool Path::makeExecutableOnDisk(std::string* ErrMsg) { + // All files are executable on Windows (ignoring security attributes). + return false; +} + +bool +Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const { + WIN32_FILE_ATTRIBUTE_DATA fi; + if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) { + MakeErrMsg(ErrMsg, path + ": can't get status of file"); + return true; + } + + if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + if (ErrMsg) + *ErrMsg = path + ": not a directory"; + return true; + } + + result.clear(); + WIN32_FIND_DATA fd; + std::string searchpath = path; + if (path.size() == 0 || searchpath[path.size()-1] == '/') + searchpath += "*"; + else + searchpath += "/*"; + + HANDLE h = FindFirstFile(searchpath.c_str(), &fd); + if (h == INVALID_HANDLE_VALUE) { + if (GetLastError() == ERROR_FILE_NOT_FOUND) + return true; // not really an error, now is it? + MakeErrMsg(ErrMsg, path + ": Can't read directory: "); + return true; + } + + do { + if (fd.cFileName[0] == '.') + continue; + Path aPath(path); + aPath.appendComponent(&fd.cFileName[0]); + result.insert(aPath); + } while (FindNextFile(h, &fd)); + + DWORD err = GetLastError(); + FindClose(h); + if (err != ERROR_NO_MORE_FILES) { + SetLastError(err); + MakeErrMsg(ErrMsg, path + ": Can't read directory: "); + return true; + } + return false; +} + +bool +Path::set(StringRef a_path) { + if (a_path.empty()) + return false; + std::string save(path); + path = a_path; + FlipBackSlashes(path); + if (!isValid()) { + path = save; + return false; + } + return true; +} + +bool +Path::appendComponent(StringRef name) { + if (name.empty()) + return false; + std::string save(path); + if (!path.empty()) { + size_t last = path.size() - 1; + if (path[last] != '/') + path += '/'; + } + path += name; + if (!isValid()) { + path = save; + return false; + } + return true; +} + +bool +Path::eraseComponent() { + size_t slashpos = path.rfind('/',path.size()); + if (slashpos == path.size() - 1 || slashpos == std::string::npos) + return false; + std::string save(path); + path.erase(slashpos); + if (!isValid()) { + path = save; + return false; + } + return true; +} + +bool +Path::eraseSuffix() { + size_t dotpos = path.rfind('.',path.size()); + size_t slashpos = path.rfind('/',path.size()); + if (dotpos != std::string::npos) { + if (slashpos == std::string::npos || dotpos > slashpos+1) { + std::string save(path); + path.erase(dotpos, path.size()-dotpos); + if (!isValid()) { + path = save; + return false; + } + return true; + } + } + return false; +} + +inline bool PathMsg(std::string* ErrMsg, const char* pathname, const char*msg) { + if (ErrMsg) + *ErrMsg = std::string(pathname) + ": " + std::string(msg); + return true; +} + +bool +Path::createDirectoryOnDisk(bool create_parents, std::string* ErrMsg) { + // Get a writeable copy of the path name + size_t len = path.length(); + char *pathname = reinterpret_cast<char *>(_alloca(len+2)); + path.copy(pathname, len); + pathname[len] = 0; + + // Make sure it ends with a slash. + if (len == 0 || pathname[len - 1] != '/') { + pathname[len] = '/'; + pathname[++len] = 0; + } + + // Determine starting point for initial / search. + char *next = pathname; + if (pathname[0] == '/' && pathname[1] == '/') { + // Skip host name. + next = strchr(pathname+2, '/'); + if (next == NULL) + return PathMsg(ErrMsg, pathname, "badly formed remote directory"); + + // Skip share name. + next = strchr(next+1, '/'); + if (next == NULL) + return PathMsg(ErrMsg, pathname,"badly formed remote directory"); + + next++; + if (*next == 0) + return PathMsg(ErrMsg, pathname, "badly formed remote directory"); + + } else { + if (pathname[1] == ':') + next += 2; // skip drive letter + if (*next == '/') + next++; // skip root directory + } + + // If we're supposed to create intermediate directories + if (create_parents) { + // Loop through the directory components until we're done + while (*next) { + next = strchr(next, '/'); + *next = 0; + if (!CreateDirectory(pathname, NULL) && + GetLastError() != ERROR_ALREADY_EXISTS) + return MakeErrMsg(ErrMsg, + std::string(pathname) + ": Can't create directory: "); + *next++ = '/'; + } + } else { + // Drop trailing slash. + pathname[len-1] = 0; + if (!CreateDirectory(pathname, NULL) && + GetLastError() != ERROR_ALREADY_EXISTS) { + return MakeErrMsg(ErrMsg, std::string(pathname) + + ": Can't create directory: "); + } + } + return false; +} + +bool +Path::createFileOnDisk(std::string* ErrMsg) { + // Create the file + HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + return MakeErrMsg(ErrMsg, path + ": Can't create file: "); + + CloseHandle(h); + return false; +} + +bool +Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const { + WIN32_FILE_ATTRIBUTE_DATA fi; + if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) + return true; + + if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + // If it doesn't exist, we're done. + bool Exists; + if (fs::exists(path, Exists) || !Exists) + return false; + + char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3)); + int lastchar = path.length() - 1 ; + path.copy(pathname, lastchar+1); + + // Make path end with '/*'. + if (pathname[lastchar] != '/') + pathname[++lastchar] = '/'; + pathname[lastchar+1] = '*'; + pathname[lastchar+2] = 0; + + if (remove_contents) { + WIN32_FIND_DATA fd; + HANDLE h = FindFirstFile(pathname, &fd); + + // It's a bad idea to alter the contents of a directory while enumerating + // its contents. So build a list of its contents first, then destroy them. + + if (h != INVALID_HANDLE_VALUE) { + std::vector<Path> list; + + do { + if (strcmp(fd.cFileName, ".") == 0) + continue; + if (strcmp(fd.cFileName, "..") == 0) + continue; + + Path aPath(path); + aPath.appendComponent(&fd.cFileName[0]); + list.push_back(aPath); + } while (FindNextFile(h, &fd)); + + DWORD err = GetLastError(); + FindClose(h); + if (err != ERROR_NO_MORE_FILES) { + SetLastError(err); + return MakeErrMsg(ErrStr, path + ": Can't read directory: "); + } + + for (std::vector<Path>::iterator I = list.begin(); I != list.end(); + ++I) { + Path &aPath = *I; + aPath.eraseFromDisk(true); + } + } else { + if (GetLastError() != ERROR_FILE_NOT_FOUND) + return MakeErrMsg(ErrStr, path + ": Can't read directory: "); + } + } + + pathname[lastchar] = 0; + if (!RemoveDirectory(pathname)) + return MakeErrMsg(ErrStr, + std::string(pathname) + ": Can't destroy directory: "); + return false; + } else { + // Read-only files cannot be deleted on Windows. Must remove the read-only + // attribute first. + if (fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + if (!SetFileAttributes(path.c_str(), + fi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)) + return MakeErrMsg(ErrStr, path + ": Can't destroy file: "); + } + + if (!DeleteFile(path.c_str())) + return MakeErrMsg(ErrStr, path + ": Can't destroy file: "); + return false; + } +} + +bool Path::getMagicNumber(std::string& Magic, unsigned len) const { + assert(len < 1024 && "Request for magic string too long"); + char* buf = reinterpret_cast<char*>(alloca(len)); + + HANDLE h = CreateFile(path.c_str(), + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (h == INVALID_HANDLE_VALUE) + return false; + + DWORD nRead = 0; + BOOL ret = ReadFile(h, buf, len, &nRead, NULL); + CloseHandle(h); + + if (!ret || nRead != len) + return false; + + Magic = std::string(buf, len); + return true; +} + +bool +Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) { + if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING)) + return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path + + "': "); + return false; +} + +bool +Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const { + // FIXME: should work on directories also. + if (!si.isFile) { + return true; + } + + HANDLE h = CreateFile(path.c_str(), + FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (h == INVALID_HANDLE_VALUE) + return true; + + BY_HANDLE_FILE_INFORMATION bhfi; + if (!GetFileInformationByHandle(h, &bhfi)) { + DWORD err = GetLastError(); + CloseHandle(h); + SetLastError(err); + return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: "); + } + + ULARGE_INTEGER ui; + ui.QuadPart = si.modTime.toWin32Time(); + FILETIME ft; + ft.dwLowDateTime = ui.LowPart; + ft.dwHighDateTime = ui.HighPart; + BOOL ret = SetFileTime(h, NULL, &ft, &ft); + DWORD err = GetLastError(); + CloseHandle(h); + if (!ret) { + SetLastError(err); + return MakeErrMsg(ErrMsg, path + ": SetFileTime: "); + } + + // Best we can do with Unix permission bits is to interpret the owner + // writable bit. + if (si.mode & 0200) { + if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + if (!SetFileAttributes(path.c_str(), + bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)) + return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: "); + } + } else { + if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { + if (!SetFileAttributes(path.c_str(), + bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY)) + return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: "); + } + } + + return false; +} + +bool +CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg) { + // Can't use CopyFile macro defined in Windows.h because it would mess up the + // above line. We use the expansion it would have in a non-UNICODE build. + if (!::CopyFileA(Src.c_str(), Dest.c_str(), false)) + return MakeErrMsg(ErrMsg, "Can't copy '" + Src.str() + + "' to '" + Dest.str() + "': "); + return false; +} + +bool +Path::makeUnique(bool reuse_current, std::string* ErrMsg) { + bool Exists; + if (reuse_current && (fs::exists(path, Exists) || !Exists)) + return false; // File doesn't exist already, just use it! + + // Reserve space for -XXXXXX at the end. + char *FNBuffer = (char*) alloca(path.size()+8); + unsigned offset = path.size(); + path.copy(FNBuffer, offset); + + // Find a numeric suffix that isn't used by an existing file. Assume there + // won't be more than 1 million files with the same prefix. Probably a safe + // bet. + static int FCounter = -1; + if (FCounter < 0) { + // Give arbitrary initial seed. + // FIXME: We should use sys::fs::unique_file() in future. + LARGE_INTEGER cnt64; + DWORD x = GetCurrentProcessId(); + x = (x << 16) | (x >> 16); + if (QueryPerformanceCounter(&cnt64)) // RDTSC + x ^= cnt64.HighPart ^ cnt64.LowPart; + FCounter = x % 1000000; + } + do { + sprintf(FNBuffer+offset, "-%06u", FCounter); + if (++FCounter > 999999) + FCounter = 0; + path = FNBuffer; + } while (!fs::exists(path, Exists) && Exists); + return false; +} + +bool +Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) { + // Make this into a unique file name + makeUnique(reuse_current, ErrMsg); + + // Now go and create it + HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + return MakeErrMsg(ErrMsg, path + ": can't create file"); + + CloseHandle(h); + return false; +} + +/// MapInFilePages - Not yet implemented on win32. +const char *Path::MapInFilePages(int FD, size_t FileSize, off_t Offset) { + return 0; +} + +/// MapInFilePages - Not yet implemented on win32. +void Path::UnMapFilePages(const char *Base, size_t FileSize) { + assert(0 && "NOT IMPLEMENTED"); +} + +} +} diff --git a/contrib/llvm/lib/Support/Windows/PathV2.inc b/contrib/llvm/lib/Support/Windows/PathV2.inc new file mode 100644 index 0000000..e9ce5d9 --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/PathV2.inc @@ -0,0 +1,748 @@ +//===- llvm/Support/Windows/PathV2.inc - Windows Path Impl ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Windows specific implementation of the PathV2 API. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Windows code that +//=== is guaranteed to work on *all* Windows variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include <fcntl.h> +#include <io.h> +#include <sys/stat.h> +#include <sys/types.h> + +// MinGW doesn't define this. +#ifndef _ERRNO_T_DEFINED +#define _ERRNO_T_DEFINED +typedef int errno_t; +#endif + +using namespace llvm; + +namespace { + typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)( + /*__in*/ LPCWSTR lpSymlinkFileName, + /*__in*/ LPCWSTR lpTargetFileName, + /*__in*/ DWORD dwFlags); + + PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW( + ::GetProcAddress(::GetModuleHandleA("kernel32.dll"), + "CreateSymbolicLinkW")); + + error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16) { + int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + utf8.begin(), utf8.size(), + utf16.begin(), 0); + + if (len == 0) + return windows_error(::GetLastError()); + + utf16.reserve(len + 1); + utf16.set_size(len); + + len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + utf8.begin(), utf8.size(), + utf16.begin(), utf16.size()); + + if (len == 0) + return windows_error(::GetLastError()); + + // Make utf16 null terminated. + utf16.push_back(0); + utf16.pop_back(); + + return error_code::success(); + } + + error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, + SmallVectorImpl<char> &utf8) { + // Get length. + int len = ::WideCharToMultiByte(CP_UTF8, 0, + utf16, utf16_len, + utf8.begin(), 0, + NULL, NULL); + + if (len == 0) + return windows_error(::GetLastError()); + + utf8.reserve(len); + utf8.set_size(len); + + // Now do the actual conversion. + len = ::WideCharToMultiByte(CP_UTF8, 0, + utf16, utf16_len, + utf8.data(), utf8.size(), + NULL, NULL); + + if (len == 0) + return windows_error(::GetLastError()); + + // Make utf8 null terminated. + utf8.push_back(0); + utf8.pop_back(); + + return error_code::success(); + } + + error_code TempDir(SmallVectorImpl<wchar_t> &result) { + retry_temp_dir: + DWORD len = ::GetTempPathW(result.capacity(), result.begin()); + + if (len == 0) + return windows_error(::GetLastError()); + + if (len > result.capacity()) { + result.reserve(len); + goto retry_temp_dir; + } + + result.set_size(len); + return error_code::success(); + } + + bool is_separator(const wchar_t value) { + switch (value) { + case L'\\': + case L'/': + return true; + default: + return false; + } + } +} + +namespace llvm { +namespace sys { +namespace fs { + +error_code current_path(SmallVectorImpl<char> &result) { + SmallVector<wchar_t, 128> cur_path; + cur_path.reserve(128); +retry_cur_dir: + DWORD len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); + + // A zero return value indicates a failure other than insufficient space. + if (len == 0) + return windows_error(::GetLastError()); + + // If there's insufficient space, the len returned is larger than the len + // given. + if (len > cur_path.capacity()) { + cur_path.reserve(len); + goto retry_cur_dir; + } + + cur_path.set_size(len); + // cur_path now holds the current directory in utf-16. Convert to utf-8. + + // Find out how much space we need. Sadly, this function doesn't return the + // size needed unless you tell it the result size is 0, which means you + // _always_ have to call it twice. + len = ::WideCharToMultiByte(CP_UTF8, 0, + cur_path.data(), cur_path.size(), + result.data(), 0, + NULL, NULL); + + if (len == 0) + return make_error_code(windows_error(::GetLastError())); + + result.reserve(len); + result.set_size(len); + // Now do the actual conversion. + len = ::WideCharToMultiByte(CP_UTF8, 0, + cur_path.data(), cur_path.size(), + result.data(), result.size(), + NULL, NULL); + if (len == 0) + return windows_error(::GetLastError()); + + return error_code::success(); +} + +error_code copy_file(const Twine &from, const Twine &to, copy_option copt) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toStringRef(from_storage); + StringRef t = to.toStringRef(to_storage); + + // Convert to utf-16. + SmallVector<wchar_t, 128> wide_from; + SmallVector<wchar_t, 128> wide_to; + if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; + if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; + + // Copy the file. + BOOL res = ::CopyFileW(wide_from.begin(), wide_to.begin(), + copt != copy_option::overwrite_if_exists); + + if (res == 0) + return windows_error(::GetLastError()); + + return error_code::success(); +} + +error_code create_directory(const Twine &path, bool &existed) { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; + + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { + error_code ec = windows_error(::GetLastError()); + if (ec == windows_error::already_exists) + existed = true; + else + return ec; + } else + existed = false; + + return error_code::success(); +} + +error_code create_hard_link(const Twine &to, const Twine &from) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toStringRef(from_storage); + StringRef t = to.toStringRef(to_storage); + + // Convert to utf-16. + SmallVector<wchar_t, 128> wide_from; + SmallVector<wchar_t, 128> wide_to; + if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; + if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; + + if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) + return windows_error(::GetLastError()); + + return error_code::success(); +} + +error_code create_symlink(const Twine &to, const Twine &from) { + // Only do it if the function is available at runtime. + if (!create_symbolic_link_api) + return make_error_code(errc::function_not_supported); + + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toStringRef(from_storage); + StringRef t = to.toStringRef(to_storage); + + // Convert to utf-16. + SmallVector<wchar_t, 128> wide_from; + SmallVector<wchar_t, 128> wide_to; + if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; + if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; + + if (!create_symbolic_link_api(wide_from.begin(), wide_to.begin(), 0)) + return windows_error(::GetLastError()); + + return error_code::success(); +} + +error_code remove(const Twine &path, bool &existed) { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; + + file_status st; + if (error_code ec = status(path, st)) + return ec; + + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + if (st.type() == file_type::directory_file) { + if (!::RemoveDirectoryW(c_str(path_utf16))) { + error_code ec = windows_error(::GetLastError()); + if (ec != windows_error::file_not_found) + return ec; + existed = false; + } else + existed = true; + } else { + if (!::DeleteFileW(c_str(path_utf16))) { + error_code ec = windows_error(::GetLastError()); + if (ec != windows_error::file_not_found) + return ec; + existed = false; + } else + existed = true; + } + + return error_code::success(); +} + +error_code rename(const Twine &from, const Twine &to) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toStringRef(from_storage); + StringRef t = to.toStringRef(to_storage); + + // Convert to utf-16. + SmallVector<wchar_t, 128> wide_from; + SmallVector<wchar_t, 128> wide_to; + if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; + if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; + + if (!::MoveFileExW(wide_from.begin(), wide_to.begin(), + MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) + return windows_error(::GetLastError()); + + return error_code::success(); +} + +error_code resize_file(const Twine &path, uint64_t size) { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; + + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + int fd = ::_wopen(path_utf16.begin(), O_BINARY, S_IREAD | S_IWRITE); + if (fd == -1) + return error_code(errno, generic_category()); +#ifdef HAVE__CHSIZE_S + errno_t error = ::_chsize_s(fd, size); +#else + errno_t error = ::_chsize(fd, size); +#endif + ::close(fd); + return error_code(error, generic_category()); +} + +error_code exists(const Twine &path, bool &result) { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; + + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + DWORD attributes = ::GetFileAttributesW(path_utf16.begin()); + + if (attributes == INVALID_FILE_ATTRIBUTES) { + // See if the file didn't actually exist. + error_code ec = make_error_code(windows_error(::GetLastError())); + if (ec != windows_error::file_not_found && + ec != windows_error::path_not_found) + return ec; + result = false; + } else + result = true; + return error_code::success(); +} + +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; +} + +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) { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; + + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + WIN32_FILE_ATTRIBUTE_DATA FileData; + if (!::GetFileAttributesExW(path_utf16.begin(), + ::GetFileExInfoStandard, + &FileData)) + return windows_error(::GetLastError()); + + result = + (uint64_t(FileData.nFileSizeHigh) << (sizeof(FileData.nFileSizeLow) * 8)) + + FileData.nFileSizeLow; + + return error_code::success(); +} + +static bool isReservedName(StringRef path) { + // This list of reserved names comes from MSDN, at: + // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx + static const char *sReservedNames[] = { "nul", "con", "prn", "aux", + "com1", "com2", "com3", "com4", "com5", "com6", + "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", + "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" }; + + // First, check to see if this is a device namespace, which always + // starts with \\.\, since device namespaces are not legal file paths. + if (path.startswith("\\\\.\\")) + return true; + + // Then compare against the list of ancient reserved names + for (size_t i = 0; i < sizeof(sReservedNames) / sizeof(const char *); ++i) { + if (path.equals_lower(sReservedNames[i])) + return true; + } + + // The path isn't what we consider reserved. + return false; +} + +error_code status(const Twine &path, file_status &result) { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; + + StringRef path8 = path.toStringRef(path_storage); + if (isReservedName(path8)) { + result = file_status(file_type::character_file); + return error_code::success(); + } + + if (error_code ec = UTF8ToUTF16(path8, path_utf16)) + return ec; + + DWORD attr = ::GetFileAttributesW(path_utf16.begin()); + if (attr == INVALID_FILE_ATTRIBUTES) + goto handle_status_error; + + // Handle reparse points. + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { + 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; + } + + if (attr & FILE_ATTRIBUTE_DIRECTORY) + result = file_status(file_type::directory_file); + 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 error_code::success(); + +handle_status_error: + error_code ec = windows_error(::GetLastError()); + if (ec == windows_error::file_not_found || + ec == windows_error::path_not_found) + result = file_status(file_type::file_not_found); + else if (ec == windows_error::sharing_violation) + result = file_status(file_type::type_unknown); + else { + result = file_status(file_type::status_error); + return ec; + } + + return error_code::success(); +} + +error_code unique_file(const Twine &model, int &result_fd, + SmallVectorImpl<char> &result_path, + bool makeAbsolute) { + // Use result_path as temp storage. + result_path.set_size(0); + StringRef m = model.toStringRef(result_path); + + SmallVector<wchar_t, 128> model_utf16; + if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec; + + 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; + // Handle c: by removing it. + if (model_utf16.size() > 2 && model_utf16[1] == L':') { + model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2); + } + model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end()); + } + } + + // Replace '%' with random chars. From here on, DO NOT modify model. It may be + // needed if the randomly chosen path already exists. + SmallVector<wchar_t, 128> random_path_utf16; + + // Get a Crypto Provider for CryptGenRandom. + HCRYPTPROV HCPC; + if (!::CryptAcquireContextW(&HCPC, + NULL, + NULL, + PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + return windows_error(::GetLastError()); + ScopedCryptContext CryptoProvider(HCPC); + +retry_random_path: + random_path_utf16.set_size(0); + for (SmallVectorImpl<wchar_t>::const_iterator i = model_utf16.begin(), + e = model_utf16.end(); + i != e; ++i) { + if (*i == L'%') { + BYTE val = 0; + if (!::CryptGenRandom(CryptoProvider, 1, &val)) + return windows_error(::GetLastError()); + random_path_utf16.push_back("0123456789abcdef"[val & 15]); + } + else + random_path_utf16.push_back(*i); + } + // Make random_path_utf16 null terminated. + random_path_utf16.push_back(0); + random_path_utf16.pop_back(); + + // Try to create + open the path. +retry_create_file: + HANDLE TempFileHandle = ::CreateFileW(random_path_utf16.begin(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + // Return ERROR_FILE_EXISTS if the file + // already exists. + CREATE_NEW, + FILE_ATTRIBUTE_TEMPORARY, + NULL); + if (TempFileHandle == INVALID_HANDLE_VALUE) { + // If the file existed, try again, otherwise, error. + error_code ec = windows_error(::GetLastError()); + if (ec == windows_error::file_exists) + goto retry_random_path; + // Check for non-existing parent directories. + if (ec == windows_error::path_not_found) { + // Create the directories using result_path as temp storage. + if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), + random_path_utf16.size(), result_path)) + return ec; + StringRef p(result_path.begin(), result_path.size()); + SmallString<64> dir_to_create; + for (path::const_iterator i = path::begin(p), + e = --path::end(p); i != e; ++i) { + path::append(dir_to_create, *i); + bool Exists; + if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec; + if (!Exists) { + // If c: doesn't exist, bail. + if (i->endswith(":")) + return ec; + + SmallVector<wchar_t, 64> dir_to_create_utf16; + if (error_code ec = UTF8ToUTF16(dir_to_create, dir_to_create_utf16)) + return ec; + + // Create the directory. + if (!::CreateDirectoryW(dir_to_create_utf16.begin(), NULL)) + return windows_error(::GetLastError()); + } + } + goto retry_create_file; + } + return ec; + } + + // Set result_path to the utf-8 representation of the path. + if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), + random_path_utf16.size(), result_path)) { + ::CloseHandle(TempFileHandle); + ::DeleteFileW(random_path_utf16.begin()); + return ec; + } + + // Convert the Windows API file handle into a C-runtime handle. + int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0); + if (fd == -1) { + ::CloseHandle(TempFileHandle); + ::DeleteFileW(random_path_utf16.begin()); + // MSDN doesn't say anything about _open_osfhandle setting errno or + // GetLastError(), so just return invalid_handle. + return windows_error::invalid_handle; + } + + result_fd = fd; + return error_code::success(); +} + +error_code get_magic(const Twine &path, uint32_t len, + SmallVectorImpl<char> &result) { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; + result.set_size(0); + + // Convert path to UTF-16. + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + // Open file. + HANDLE file = ::CreateFileW(c_str(path_utf16), + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_READONLY, + NULL); + if (file == INVALID_HANDLE_VALUE) + return windows_error(::GetLastError()); + + // Allocate buffer. + result.reserve(len); + + // Get magic! + DWORD bytes_read = 0; + BOOL read_success = ::ReadFile(file, result.data(), len, &bytes_read, NULL); + error_code ec = windows_error(::GetLastError()); + ::CloseHandle(file); + if (!read_success || (bytes_read != len)) { + // Set result size to the number of bytes read if it's valid. + if (bytes_read <= len) + result.set_size(bytes_read); + // ERROR_HANDLE_EOF is mapped to errc::value_too_large. + return ec; + } + + result.set_size(len); + return error_code::success(); +} + +error_code detail::directory_iterator_construct(detail::DirIterState &it, + StringRef path){ + SmallVector<wchar_t, 128> path_utf16; + + if (error_code ec = UTF8ToUTF16(path, + path_utf16)) + return ec; + + // Convert path to the format that Windows is happy with. + if (path_utf16.size() > 0 && + !is_separator(path_utf16[path.size() - 1]) && + path_utf16[path.size() - 1] != L':') { + path_utf16.push_back(L'\\'); + path_utf16.push_back(L'*'); + } else { + path_utf16.push_back(L'*'); + } + + // Get the first directory entry. + WIN32_FIND_DATAW FirstFind; + ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind)); + if (!FindHandle) + return windows_error(::GetLastError()); + + size_t FilenameLen = ::wcslen(FirstFind.cFileName); + while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || + (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && + FirstFind.cFileName[1] == L'.')) + if (!::FindNextFileW(FindHandle, &FirstFind)) { + error_code ec = windows_error(::GetLastError()); + // Check for end. + if (ec == windows_error::no_more_files) + return detail::directory_iterator_destruct(it); + return ec; + } else + FilenameLen = ::wcslen(FirstFind.cFileName); + + // Construct the current directory entry. + SmallString<128> directory_entry_name_utf8; + if (error_code ec = UTF16ToUTF8(FirstFind.cFileName, + ::wcslen(FirstFind.cFileName), + directory_entry_name_utf8)) + return ec; + + it.IterationHandle = intptr_t(FindHandle.take()); + SmallString<128> directory_entry_path(path); + path::append(directory_entry_path, directory_entry_name_utf8.str()); + it.CurrentEntry = directory_entry(directory_entry_path.str()); + + return error_code::success(); +} + +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 error_code::success(); +} + +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 detail::directory_iterator_destruct(it); + return ec; + } + + size_t FilenameLen = ::wcslen(FindData.cFileName); + if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || + (FilenameLen == 2 && FindData.cFileName[0] == L'.' && + FindData.cFileName[1] == L'.')) + return directory_iterator_increment(it); + + SmallString<128> directory_entry_path_utf8; + if (error_code ec = UTF16ToUTF8(FindData.cFileName, + ::wcslen(FindData.cFileName), + directory_entry_path_utf8)) + return ec; + + it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); + return error_code::success(); +} + +} // end namespace fs +} // end namespace sys +} // end namespace llvm diff --git a/contrib/llvm/lib/Support/Windows/Process.inc b/contrib/llvm/lib/Support/Windows/Process.inc new file mode 100644 index 0000000..913b073 --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/Process.inc @@ -0,0 +1,223 @@ +//===- Win32/Process.cpp - Win32 Process Implementation ------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Process class. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include <psapi.h> +#include <malloc.h> +#include <io.h> +#include <direct.h> + +#ifdef __MINGW32__ + #if (HAVE_LIBPSAPI != 1) + #error "libpsapi.a should be present" + #endif +#else + #pragma comment(lib, "psapi.lib") +#endif + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +#ifdef __MINGW32__ +// This ban should be lifted when MinGW 1.0+ has defined this value. +# define _HEAPOK (-2) +#endif + +namespace llvm { +using namespace sys; + +// This function retrieves the page size using GetSystemInfo and is present +// solely so it can be called once in Process::GetPageSize to initialize the +// static variable PageSize. +inline unsigned GetPageSizeOnce() { + // NOTE: A 32-bit application running under WOW64 is supposed to use + // GetNativeSystemInfo. However, this interface is not present prior + // to Windows XP so to use it requires dynamic linking. It is not clear + // how this affects the reported page size, if at all. One could argue + // that LLVM ought to run as 64-bits on a 64-bit system, anyway. + SYSTEM_INFO info; + GetSystemInfo(&info); + return static_cast<unsigned>(info.dwPageSize); +} + +unsigned +Process::GetPageSize() { + static const unsigned PageSize = GetPageSizeOnce(); + return PageSize; +} + +size_t +Process::GetMallocUsage() +{ + _HEAPINFO hinfo; + hinfo._pentry = NULL; + + size_t size = 0; + + while (_heapwalk(&hinfo) == _HEAPOK) + size += hinfo._size; + + return size; +} + +size_t +Process::GetTotalMemoryUsage() +{ + PROCESS_MEMORY_COUNTERS pmc; + GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); + return pmc.PagefileUsage; +} + +void +Process::GetTimeUsage( + TimeValue& elapsed, TimeValue& user_time, TimeValue& sys_time) +{ + elapsed = TimeValue::now(); + + uint64_t ProcCreate, ProcExit, KernelTime, UserTime; + GetProcessTimes(GetCurrentProcess(), (FILETIME*)&ProcCreate, + (FILETIME*)&ProcExit, (FILETIME*)&KernelTime, + (FILETIME*)&UserTime); + + // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond) + user_time.seconds( UserTime / 10000000 ); + user_time.nanoseconds( unsigned(UserTime % 10000000) * 100 ); + sys_time.seconds( KernelTime / 10000000 ); + sys_time.nanoseconds( unsigned(KernelTime % 10000000) * 100 ); +} + +int Process::GetCurrentUserId() +{ + return 65536; +} + +int Process::GetCurrentGroupId() +{ + return 65536; +} + +// Some LLVM programs such as bugpoint produce core files as a normal part of +// their operation. To prevent the disk from filling up, this configuration item +// does what's necessary to prevent their generation. +void Process::PreventCoreFiles() { + // Windows doesn't do core files, but it does do modal pop-up message + // boxes. As this method is used by bugpoint, preventing these pop-ups + // is the moral equivalent of suppressing core files. + SetErrorMode(SEM_FAILCRITICALERRORS | + SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); +} + +bool Process::StandardInIsUserInput() { + return FileDescriptorIsDisplayed(0); +} + +bool Process::StandardOutIsDisplayed() { + return FileDescriptorIsDisplayed(1); +} + +bool Process::StandardErrIsDisplayed() { + return FileDescriptorIsDisplayed(2); +} + +bool Process::FileDescriptorIsDisplayed(int fd) { + DWORD Mode; // Unused + return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0); +} + +unsigned Process::StandardOutColumns() { + unsigned Columns = 0; + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) + Columns = csbi.dwSize.X; + return Columns; +} + +unsigned Process::StandardErrColumns() { + unsigned Columns = 0; + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)) + Columns = csbi.dwSize.X; + return Columns; +} + +// It always has colors. +bool Process::StandardErrHasColors() { + return StandardErrIsDisplayed(); +} + +bool Process::StandardOutHasColors() { + return StandardOutIsDisplayed(); +} + +namespace { +class DefaultColors +{ + private: + WORD defaultColor; + public: + DefaultColors() + :defaultColor(GetCurrentColor()) {} + static unsigned GetCurrentColor() { + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) + return csbi.wAttributes; + return 0; + } + WORD operator()() const { return defaultColor; } +}; + +DefaultColors defaultColors; +} + +bool Process::ColorNeedsFlush() { + return true; +} + +const char *Process::OutputBold(bool bg) { + WORD colors = DefaultColors::GetCurrentColor(); + if (bg) + colors |= BACKGROUND_INTENSITY; + else + colors |= FOREGROUND_INTENSITY; + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); + return 0; +} + +const char *Process::OutputColor(char code, bool bold, bool bg) { + WORD colors; + if (bg) { + colors = ((code&1) ? BACKGROUND_RED : 0) | + ((code&2) ? BACKGROUND_GREEN : 0 ) | + ((code&4) ? BACKGROUND_BLUE : 0); + if (bold) + colors |= BACKGROUND_INTENSITY; + } else { + colors = ((code&1) ? FOREGROUND_RED : 0) | + ((code&2) ? FOREGROUND_GREEN : 0 ) | + ((code&4) ? FOREGROUND_BLUE : 0); + if (bold) + colors |= FOREGROUND_INTENSITY; + } + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); + return 0; +} + +const char *Process::ResetColor() { + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors()); + return 0; +} + +} diff --git a/contrib/llvm/lib/Support/Windows/Program.inc b/contrib/llvm/lib/Support/Windows/Program.inc new file mode 100644 index 0000000..80ccaa6 --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/Program.inc @@ -0,0 +1,421 @@ +//===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Program class. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include <cstdio> +#include <malloc.h> +#include <io.h> +#include <fcntl.h> + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +namespace { + struct Win32ProcessInfo { + HANDLE hProcess; + DWORD dwProcessId; + }; +} + +namespace llvm { +using namespace sys; + +Program::Program() : Data_(0) {} + +Program::~Program() { + if (Data_) { + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + CloseHandle(wpi->hProcess); + delete wpi; + Data_ = 0; + } +} + +unsigned Program::GetPid() const { + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + return wpi->dwProcessId; +} + +// This function just uses the PATH environment variable to find the program. +Path +Program::FindProgramByName(const std::string& progName) { + + // Check some degenerate cases + if (progName.length() == 0) // no program + return Path(); + Path temp; + if (!temp.set(progName)) // invalid name + return Path(); + // Return paths with slashes verbatim. + if (progName.find('\\') != std::string::npos || + progName.find('/') != std::string::npos) + return temp; + + // At this point, the file name is valid and does not contain slashes. + // Let Windows search for it. + char buffer[MAX_PATH]; + char *dummy = NULL; + DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH, + buffer, &dummy); + + // See if it wasn't found. + if (len == 0) + return Path(); + + // See if we got the entire path. + if (len < MAX_PATH) + return Path(buffer); + + // Buffer was too small; grow and retry. + while (true) { + char *b = reinterpret_cast<char *>(_alloca(len+1)); + DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy); + + // It is unlikely the search failed, but it's always possible some file + // was added or removed since the last search, so be paranoid... + if (len2 == 0) + return Path(); + else if (len2 <= len) + return Path(b); + + len = len2; + } +} + +static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) { + HANDLE h; + if (path == 0) { + DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), + GetCurrentProcess(), &h, + 0, TRUE, DUPLICATE_SAME_ACCESS); + return h; + } + + const char *fname; + if (path->isEmpty()) + fname = "NUL"; + else + fname = path->c_str(); + + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = 0; + sa.bInheritHandle = TRUE; + + h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ, + &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) { + MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " + + (fd ? "input: " : "output: ")); + } + + return h; +} + +/// ArgNeedsQuotes - Check whether argument needs to be quoted when calling +/// CreateProcess. +static bool ArgNeedsQuotes(const char *Str) { + return Str[0] == '\0' || strpbrk(Str, "\t \"&\'()*<>\\`^|") != 0; +} + + +/// ArgLenWithQuotes - Check whether argument needs to be quoted when calling +/// CreateProcess and returns length of quoted arg with escaped quotes +static unsigned int ArgLenWithQuotes(const char *Str) { + unsigned int len = ArgNeedsQuotes(Str) ? 2 : 0; + + while (*Str != '\0') { + if (*Str == '\"') + ++len; + + ++len; + ++Str; + } + + return len; +} + + +bool +Program::Execute(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned memoryLimit, + std::string* ErrMsg) { + if (Data_) { + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + CloseHandle(wpi->hProcess); + delete wpi; + Data_ = 0; + } + + if (!path.canExecute()) { + if (ErrMsg) + *ErrMsg = "program not executable"; + return false; + } + + // Windows wants a command line, not an array of args, to pass to the new + // process. We have to concatenate them all, while quoting the args that + // have embedded spaces (or are empty). + + // First, determine the length of the command line. + unsigned len = 0; + for (unsigned i = 0; args[i]; i++) { + len += ArgLenWithQuotes(args[i]) + 1; + } + + // Now build the command line. + char *command = reinterpret_cast<char *>(_alloca(len+1)); + char *p = command; + + for (unsigned i = 0; args[i]; i++) { + const char *arg = args[i]; + + bool needsQuoting = ArgNeedsQuotes(arg); + if (needsQuoting) + *p++ = '"'; + + while (*arg != '\0') { + if (*arg == '\"') + *p++ = '\\'; + + *p++ = *arg++; + } + + if (needsQuoting) + *p++ = '"'; + *p++ = ' '; + } + + *p = 0; + + // The pointer to the environment block for the new process. + char *envblock = 0; + + if (envp) { + // An environment block consists of a null-terminated block of + // null-terminated strings. Convert the array of environment variables to + // an environment block by concatenating them. + + // First, determine the length of the environment block. + len = 0; + for (unsigned i = 0; envp[i]; i++) + len += strlen(envp[i]) + 1; + + // Now build the environment block. + envblock = reinterpret_cast<char *>(_alloca(len+1)); + p = envblock; + + for (unsigned i = 0; envp[i]; i++) { + const char *ev = envp[i]; + size_t len = strlen(ev) + 1; + memcpy(p, ev, len); + p += len; + } + + *p = 0; + } + + // Create a child process. + STARTUPINFO si; + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.hStdInput = INVALID_HANDLE_VALUE; + si.hStdOutput = INVALID_HANDLE_VALUE; + si.hStdError = INVALID_HANDLE_VALUE; + + if (redirects) { + si.dwFlags = STARTF_USESTDHANDLES; + + si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg); + if (si.hStdInput == INVALID_HANDLE_VALUE) { + MakeErrMsg(ErrMsg, "can't redirect stdin"); + return false; + } + si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg); + if (si.hStdOutput == INVALID_HANDLE_VALUE) { + CloseHandle(si.hStdInput); + MakeErrMsg(ErrMsg, "can't redirect stdout"); + return false; + } + if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { + // If stdout and stderr should go to the same place, redirect stderr + // to the handle already open for stdout. + DuplicateHandle(GetCurrentProcess(), si.hStdOutput, + GetCurrentProcess(), &si.hStdError, + 0, TRUE, DUPLICATE_SAME_ACCESS); + } else { + // Just redirect stderr + si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); + if (si.hStdError == INVALID_HANDLE_VALUE) { + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + MakeErrMsg(ErrMsg, "can't redirect stderr"); + return false; + } + } + } + + PROCESS_INFORMATION pi; + memset(&pi, 0, sizeof(pi)); + + fflush(stdout); + fflush(stderr); + BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, TRUE, 0, + envblock, NULL, &si, &pi); + DWORD err = GetLastError(); + + // Regardless of whether the process got created or not, we are done with + // the handles we created for it to inherit. + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + + // Now return an error if the process didn't get created. + if (!rc) { + SetLastError(err); + MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + + path.str() + "'"); + return false; + } + Win32ProcessInfo* wpi = new Win32ProcessInfo; + wpi->hProcess = pi.hProcess; + wpi->dwProcessId = pi.dwProcessId; + Data_ = wpi; + + // Make sure these get closed no matter what. + ScopedCommonHandle hThread(pi.hThread); + + // Assign the process to a job if a memory limit is defined. + ScopedJobHandle hJob; + if (memoryLimit != 0) { + hJob = CreateJobObject(0, 0); + bool success = false; + if (hJob) { + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; + memset(&jeli, 0, sizeof(jeli)); + jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; + jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576; + if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, + &jeli, sizeof(jeli))) { + if (AssignProcessToJobObject(hJob, pi.hProcess)) + success = true; + } + } + if (!success) { + SetLastError(GetLastError()); + MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); + TerminateProcess(pi.hProcess, 1); + WaitForSingleObject(pi.hProcess, INFINITE); + return false; + } + } + + return true; +} + +int +Program::Wait(const Path &path, + unsigned secondsToWait, + std::string* ErrMsg) { + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return -1; + } + + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + HANDLE hProcess = wpi->hProcess; + + // Wait for the process to terminate. + DWORD millisecondsToWait = INFINITE; + if (secondsToWait > 0) + millisecondsToWait = secondsToWait * 1000; + + if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) { + if (!TerminateProcess(hProcess, 1)) { + MakeErrMsg(ErrMsg, "Failed to terminate timed-out program."); + // -2 indicates a crash or timeout as opposed to failure to execute. + return -2; + } + WaitForSingleObject(hProcess, INFINITE); + } + + // Get its exit status. + DWORD status; + BOOL rc = GetExitCodeProcess(hProcess, &status); + DWORD err = GetLastError(); + + if (!rc) { + SetLastError(err); + MakeErrMsg(ErrMsg, "Failed getting status for program."); + // -2 indicates a crash or timeout as opposed to failure to execute. + return -2; + } + + 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 +Program::Kill(std::string* ErrMsg) { + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return true; + } + + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + HANDLE hProcess = wpi->hProcess; + if (TerminateProcess(hProcess, 1) == 0) { + MakeErrMsg(ErrMsg, "The process couldn't be killed!"); + return true; + } + + return false; +} + +error_code Program::ChangeStdinToBinary(){ + int result = _setmode( _fileno(stdin), _O_BINARY ); + if (result == -1) + return error_code(errno, generic_category()); + return make_error_code(errc::success); +} + +error_code Program::ChangeStdoutToBinary(){ + int result = _setmode( _fileno(stdout), _O_BINARY ); + if (result == -1) + return error_code(errno, generic_category()); + return make_error_code(errc::success); +} + +error_code Program::ChangeStderrToBinary(){ + int result = _setmode( _fileno(stderr), _O_BINARY ); + if (result == -1) + return error_code(errno, generic_category()); + return make_error_code(errc::success); +} + +} diff --git a/contrib/llvm/lib/Support/Windows/RWMutex.inc b/contrib/llvm/lib/Support/Windows/RWMutex.inc new file mode 100644 index 0000000..26b9bba --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/RWMutex.inc @@ -0,0 +1,134 @@ +//= llvm/Support/Win32/Mutex.inc - Win32 Reader/Writer Mutual Exclusion Lock =// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 specific (non-pthread) RWMutex class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" + +namespace llvm { +using namespace sys; + +// Windows has slim read-writer lock support on Vista and higher, so we +// will attempt to load the APIs. If they exist, we will use them, and +// if not, we will fall back on critical sections. When we drop support +// for XP, we can stop lazy-loading these APIs and just use them directly. +#if defined(__MINGW32__) + // Taken from WinNT.h + typedef struct _RTL_SRWLOCK { + PVOID Ptr; + } RTL_SRWLOCK, *PRTL_SRWLOCK; + + // Taken from WinBase.h + typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK; +#endif + +static VOID (WINAPI *fpInitializeSRWLock)(PSRWLOCK lock) = NULL; +static VOID (WINAPI *fpAcquireSRWLockExclusive)(PSRWLOCK lock) = NULL; +static VOID (WINAPI *fpAcquireSRWLockShared)(PSRWLOCK lock) = NULL; +static VOID (WINAPI *fpReleaseSRWLockExclusive)(PSRWLOCK lock) = NULL; +static VOID (WINAPI *fpReleaseSRWLockShared)(PSRWLOCK lock) = NULL; + +static bool sHasSRW = false; + +static bool loadSRW() { + static bool sChecked = false; + if (!sChecked) { + sChecked = true; + + HMODULE hLib = ::LoadLibrary(TEXT("Kernel32")); + if (hLib) { + fpInitializeSRWLock = + (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, + "InitializeSRWLock"); + fpAcquireSRWLockExclusive = + (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, + "AcquireSRWLockExclusive"); + fpAcquireSRWLockShared = + (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, + "AcquireSRWLockShared"); + fpReleaseSRWLockExclusive = + (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, + "ReleaseSRWLockExclusive"); + fpReleaseSRWLockShared = + (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, + "ReleaseSRWLockShared"); + ::FreeLibrary(hLib); + + if (fpInitializeSRWLock != NULL) { + sHasSRW = true; + } + } + } + return sHasSRW; +} + +RWMutexImpl::RWMutexImpl() { + if (loadSRW()) { + data_ = calloc(1, sizeof(SRWLOCK)); + fpInitializeSRWLock(static_cast<PSRWLOCK>(data_)); + } else { + data_ = calloc(1, sizeof(CRITICAL_SECTION)); + InitializeCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); + } +} + +RWMutexImpl::~RWMutexImpl() { + if (sHasSRW) { + // Nothing to do in the case of slim reader/writers + } else { + DeleteCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); + free(data_); + } +} + +bool RWMutexImpl::reader_acquire() { + if (sHasSRW) { + fpAcquireSRWLockShared(static_cast<PSRWLOCK>(data_)); + } else { + EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); + } + return true; +} + +bool RWMutexImpl::reader_release() { + if (sHasSRW) { + fpReleaseSRWLockShared(static_cast<PSRWLOCK>(data_)); + } else { + LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); + } + return true; +} + +bool RWMutexImpl::writer_acquire() { + if (sHasSRW) { + fpAcquireSRWLockExclusive(static_cast<PSRWLOCK>(data_)); + } else { + EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); + } + return true; +} + +bool RWMutexImpl::writer_release() { + if (sHasSRW) { + fpReleaseSRWLockExclusive(static_cast<PSRWLOCK>(data_)); + } else { + LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); + } + return true; +} + + +} diff --git a/contrib/llvm/lib/Support/Windows/Signals.inc b/contrib/llvm/lib/Support/Windows/Signals.inc new file mode 100644 index 0000000..38308f6 --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/Signals.inc @@ -0,0 +1,488 @@ +//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Signals class. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include <stdio.h> +#include <vector> +#include <algorithm> + +#ifdef __MINGW32__ + #include <imagehlp.h> +#else + #include <dbghelp.h> +#endif +#include <psapi.h> + +#ifdef _MSC_VER + #pragma comment(lib, "psapi.lib") + #pragma comment(lib, "dbghelp.lib") +#elif __MINGW32__ + #if ((HAVE_LIBIMAGEHLP != 1) || (HAVE_LIBPSAPI != 1)) + #error "libimagehlp.a & libpsapi.a should be present" + #endif + // The version of g++ that comes with MinGW does *not* properly understand + // the ll format specifier for printf. However, MinGW passes the format + // specifiers on to the MSVCRT entirely, and the CRT understands the ll + // specifier. So these warnings are spurious in this case. Since we compile + // with -Wall, this will generate these warnings which should be ignored. So + // we will turn off the warnings for this just file. However, MinGW also does + // not support push and pop for diagnostics, so we have to manually turn it + // back on at the end of the file. + #pragma GCC diagnostic ignored "-Wformat" + #pragma GCC diagnostic ignored "-Wformat-extra-args" + + #if !defined(__MINGW64_VERSION_MAJOR) + // MinGW.org does not have updated support for the 64-bit versions of the + // DebugHlp APIs. So we will have to load them manually. The structures and + // method signatures were pulled from DbgHelp.h in the Windows Platform SDK, + // and adjusted for brevity. + typedef struct _IMAGEHLP_LINE64 { + DWORD SizeOfStruct; + PVOID Key; + DWORD LineNumber; + PCHAR FileName; + DWORD64 Address; + } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; + + typedef struct _IMAGEHLP_SYMBOL64 { + DWORD SizeOfStruct; + DWORD64 Address; + DWORD Size; + DWORD Flags; + DWORD MaxNameLength; + CHAR Name[1]; + } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; + + typedef struct _tagADDRESS64 { + DWORD64 Offset; + WORD Segment; + ADDRESS_MODE Mode; + } ADDRESS64, *LPADDRESS64; + + typedef struct _KDHELP64 { + DWORD64 Thread; + DWORD ThCallbackStack; + DWORD ThCallbackBStore; + DWORD NextCallback; + DWORD FramePointer; + DWORD64 KiCallUserMode; + DWORD64 KeUserCallbackDispatcher; + DWORD64 SystemRangeStart; + DWORD64 KiUserExceptionDispatcher; + DWORD64 StackBase; + DWORD64 StackLimit; + DWORD64 Reserved[5]; + } KDHELP64, *PKDHELP64; + + typedef struct _tagSTACKFRAME64 { + ADDRESS64 AddrPC; + ADDRESS64 AddrReturn; + ADDRESS64 AddrFrame; + ADDRESS64 AddrStack; + ADDRESS64 AddrBStore; + PVOID FuncTableEntry; + DWORD64 Params[4]; + BOOL Far; + BOOL Virtual; + DWORD64 Reserved[3]; + KDHELP64 KdHelp; + } STACKFRAME64, *LPSTACKFRAME64; + +typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, + DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, + LPDWORD lpNumberOfBytesRead); + +typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess, + DWORD64 AddrBase); + +typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, + DWORD64 Address); + +typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, + HANDLE hThread, LPADDRESS64 lpaddr); + +typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, + PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, + PFUNCTION_TABLE_ACCESS_ROUTINE64, + PGET_MODULE_BASE_ROUTINE64, + PTRANSLATE_ADDRESS_ROUTINE64); +static fpStackWalk64 StackWalk64; + +typedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64); +static fpSymGetModuleBase64 SymGetModuleBase64; + +typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, + PDWORD64, PIMAGEHLP_SYMBOL64); +static fpSymGetSymFromAddr64 SymGetSymFromAddr64; + +typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, + PDWORD, PIMAGEHLP_LINE64); +static fpSymGetLineFromAddr64 SymGetLineFromAddr64; + +typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64); +static fpSymFunctionTableAccess64 SymFunctionTableAccess64; + +static bool load64BitDebugHelp(void) { + HMODULE hLib = ::LoadLibrary("Dbghelp.dll"); + if (hLib) { + StackWalk64 = (fpStackWalk64) + ::GetProcAddress(hLib, "StackWalk64"); + SymGetModuleBase64 = (fpSymGetModuleBase64) + ::GetProcAddress(hLib, "SymGetModuleBase64"); + SymGetSymFromAddr64 = (fpSymGetSymFromAddr64) + ::GetProcAddress(hLib, "SymGetSymFromAddr64"); + SymGetLineFromAddr64 = (fpSymGetLineFromAddr64) + ::GetProcAddress(hLib, "SymGetLineFromAddr64"); + SymFunctionTableAccess64 = (fpSymFunctionTableAccess64) + ::GetProcAddress(hLib, "SymFunctionTableAccess64"); + } + return StackWalk64 != NULL; +} + #endif // !defined(__MINGW64_VERSION_MAJOR) +#endif // __MINGW32__ + +// Forward declare. +static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); +static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); + +// InterruptFunction - The function to call if ctrl-c is pressed. +static void (*InterruptFunction)() = 0; + +static std::vector<llvm::sys::Path> *FilesToRemove = NULL; +static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0; +static bool RegisteredUnhandledExceptionFilter = false; +static bool CleanupExecuted = false; +static bool ExitOnUnhandledExceptions = false; +static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; + +// Windows creates a new thread to execute the console handler when an event +// (such as CTRL/C) occurs. This causes concurrency issues with the above +// globals which this critical section addresses. +static CRITICAL_SECTION CriticalSection; + +namespace llvm { + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +#ifdef _MSC_VER +/// CRTReportHook - Function called on a CRT debugging event. +static int CRTReportHook(int ReportType, char *Message, int *Return) { + // Don't cause a DebugBreak() on return. + if (Return) + *Return = 0; + + switch (ReportType) { + default: + case _CRT_ASSERT: + fprintf(stderr, "CRT assert: %s\n", Message); + // FIXME: Is there a way to just crash? Perhaps throw to the unhandled + // exception code? Perhaps SetErrorMode() handles this. + _exit(3); + break; + case _CRT_ERROR: + fprintf(stderr, "CRT error: %s\n", Message); + // FIXME: Is there a way to just crash? Perhaps throw to the unhandled + // exception code? Perhaps SetErrorMode() handles this. + _exit(3); + break; + case _CRT_WARN: + fprintf(stderr, "CRT warn: %s\n", Message); + break; + } + + // Don't call _CrtDbgReport. + return TRUE; +} +#endif + +static void RegisterHandler() { +#if __MINGW32__ && !defined(__MINGW64_VERSION_MAJOR) + // On MinGW.org, we need to load up the symbols explicitly, because the + // Win32 framework they include does not have support for the 64-bit + // versions of the APIs we need. If we cannot load up the APIs (which + // would be unexpected as they should exist on every version of Windows + // we support), we will bail out since there would be nothing to report. + if (!load64BitDebugHelp()) { + assert(false && "These APIs should always be available"); + return; + } +#endif + + if (RegisteredUnhandledExceptionFilter) { + EnterCriticalSection(&CriticalSection); + return; + } + + // Now's the time to create the critical section. This is the first time + // through here, and there's only one thread. + InitializeCriticalSection(&CriticalSection); + + // Enter it immediately. Now if someone hits CTRL/C, the console handler + // can't proceed until the globals are updated. + EnterCriticalSection(&CriticalSection); + + RegisteredUnhandledExceptionFilter = true; + OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); + SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); + + // Environment variable to disable any kind of crash dialog. + if (getenv("LLVM_DISABLE_CRASH_REPORT")) { +#ifdef _MSC_VER + _CrtSetReportHook(CRTReportHook); +#endif + SetErrorMode(SEM_FAILCRITICALERRORS | + SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); + ExitOnUnhandledExceptions = true; + } + + // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or + // else multi-threading problems will ensue. +} + +// RemoveFileOnSignal - The public API +bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { + RegisterHandler(); + + if (CleanupExecuted) { + if (ErrMsg) + *ErrMsg = "Process terminating -- cannot register for removal"; + return true; + } + + if (FilesToRemove == NULL) + FilesToRemove = new std::vector<sys::Path>; + + FilesToRemove->push_back(Filename); + + LeaveCriticalSection(&CriticalSection); + return false; +} + +// DontRemoveFileOnSignal - The public API +void sys::DontRemoveFileOnSignal(const sys::Path &Filename) { + if (FilesToRemove == NULL) + return; + + RegisterHandler(); + + FilesToRemove->push_back(Filename); + std::vector<sys::Path>::reverse_iterator I = + std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename); + if (I != FilesToRemove->rend()) + FilesToRemove->erase(I.base()-1); + + LeaveCriticalSection(&CriticalSection); +} + +/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or +/// SIGSEGV) is delivered to the process, print a stack trace and then exit. +void sys::PrintStackTraceOnErrorSignal() { + RegisterHandler(); + LeaveCriticalSection(&CriticalSection); +} + + +void sys::SetInterruptFunction(void (*IF)()) { + RegisterHandler(); + InterruptFunction = IF; + LeaveCriticalSection(&CriticalSection); +} + + +/// AddSignalHandler - Add a function to be called when a signal is delivered +/// to the process. The handler can have a cookie passed to it to identify +/// what instance of the handler it is. +void sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { + if (CallBacksToRun == 0) + CallBacksToRun = new std::vector<std::pair<void(*)(void*), void*> >(); + CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); + RegisterHandler(); + LeaveCriticalSection(&CriticalSection); +} +} + +static void Cleanup() { + EnterCriticalSection(&CriticalSection); + + // Prevent other thread from registering new files and directories for + // removal, should we be executing because of the console handler callback. + CleanupExecuted = true; + + // FIXME: open files cannot be deleted. + + if (FilesToRemove != NULL) + while (!FilesToRemove->empty()) { + FilesToRemove->back().eraseFromDisk(); + FilesToRemove->pop_back(); + } + + if (CallBacksToRun) + for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i) + (*CallBacksToRun)[i].first((*CallBacksToRun)[i].second); + + LeaveCriticalSection(&CriticalSection); +} + +void llvm::sys::RunInterruptHandlers() { + Cleanup(); +} + +static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { + Cleanup(); + + // Initialize the STACKFRAME structure. + STACKFRAME64 StackFrame; + memset(&StackFrame, 0, sizeof(StackFrame)); + + DWORD machineType; +#if defined(_M_X64) + machineType = IMAGE_FILE_MACHINE_AMD64; + StackFrame.AddrPC.Offset = ep->ContextRecord->Rip; + StackFrame.AddrPC.Mode = AddrModeFlat; + StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp; + StackFrame.AddrStack.Mode = AddrModeFlat; + StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp; + StackFrame.AddrFrame.Mode = AddrModeFlat; +#elif defined(_M_IX86) + machineType = IMAGE_FILE_MACHINE_I386; + StackFrame.AddrPC.Offset = ep->ContextRecord->Eip; + StackFrame.AddrPC.Mode = AddrModeFlat; + StackFrame.AddrStack.Offset = ep->ContextRecord->Esp; + StackFrame.AddrStack.Mode = AddrModeFlat; + StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp; + StackFrame.AddrFrame.Mode = AddrModeFlat; +#endif + + HANDLE hProcess = GetCurrentProcess(); + HANDLE hThread = GetCurrentThread(); + + // Initialize the symbol handler. + SymSetOptions(SYMOPT_DEFERRED_LOADS|SYMOPT_LOAD_LINES); + SymInitialize(hProcess, NULL, TRUE); + + while (true) { + if (!StackWalk64(machineType, hProcess, hThread, &StackFrame, + ep->ContextRecord, NULL, SymFunctionTableAccess64, + SymGetModuleBase64, NULL)) { + break; + } + + if (StackFrame.AddrFrame.Offset == 0) + break; + + // Print the PC in hexadecimal. + DWORD64 PC = StackFrame.AddrPC.Offset; +#if defined(_M_X64) + fprintf(stderr, "0x%016llX", PC); +#elif defined(_M_IX86) + fprintf(stderr, "0x%08lX", static_cast<DWORD>(PC)); +#endif + + // Print the parameters. Assume there are four. +#if defined(_M_X64) + fprintf(stderr, " (0x%016llX 0x%016llX 0x%016llX 0x%016llX)", + StackFrame.Params[0], + StackFrame.Params[1], + StackFrame.Params[2], + StackFrame.Params[3]); +#elif defined(_M_IX86) + fprintf(stderr, " (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", + static_cast<DWORD>(StackFrame.Params[0]), + static_cast<DWORD>(StackFrame.Params[1]), + static_cast<DWORD>(StackFrame.Params[2]), + static_cast<DWORD>(StackFrame.Params[3])); +#endif + // Verify the PC belongs to a module in this process. + if (!SymGetModuleBase64(hProcess, PC)) { + fputs(" <unknown module>\n", stderr); + continue; + } + + // Print the symbol name. + char buffer[512]; + IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer); + memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); + symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); + + DWORD64 dwDisp; + if (!SymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { + fputc('\n', stderr); + continue; + } + + buffer[511] = 0; + if (dwDisp > 0) + fprintf(stderr, ", %s() + 0x%llX bytes(s)", symbol->Name, dwDisp); + else + fprintf(stderr, ", %s", symbol->Name); + + // Print the source file and line number information. + IMAGEHLP_LINE64 line; + DWORD dwLineDisp; + memset(&line, 0, sizeof(line)); + line.SizeOfStruct = sizeof(line); + if (SymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { + fprintf(stderr, ", %s, line %lu", line.FileName, line.LineNumber); + if (dwLineDisp > 0) + fprintf(stderr, " + 0x%lX byte(s)", dwLineDisp); + } + + fputc('\n', stderr); + } + + if (ExitOnUnhandledExceptions) + _exit(ep->ExceptionRecord->ExceptionCode); + + // Allow dialog box to pop up allowing choice to start debugger. + if (OldFilter) + return (*OldFilter)(ep); + else + return EXCEPTION_CONTINUE_SEARCH; +} + +static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { + // We are running in our very own thread, courtesy of Windows. + EnterCriticalSection(&CriticalSection); + Cleanup(); + + // If an interrupt function has been set, go and run one it; otherwise, + // the process dies. + void (*IF)() = InterruptFunction; + InterruptFunction = 0; // Don't run it on another CTRL-C. + + if (IF) { + // Note: if the interrupt function throws an exception, there is nothing + // to catch it in this thread so it will kill the process. + IF(); // Run it now. + LeaveCriticalSection(&CriticalSection); + return TRUE; // Don't kill the process. + } + + // Allow normal processing to take place; i.e., the process dies. + LeaveCriticalSection(&CriticalSection); + return FALSE; +} + +#if __MINGW32__ + // We turned these warnings off for this file so that MinGW-g++ doesn't + // complain about the ll format specifiers used. Now we are turning the + // warnings back on. If MinGW starts to support diagnostic stacks, we can + // replace this with a pop. + #pragma GCC diagnostic warning "-Wformat" + #pragma GCC diagnostic warning "-Wformat-extra-args" +#endif diff --git a/contrib/llvm/lib/Support/Windows/ThreadLocal.inc b/contrib/llvm/lib/Support/Windows/ThreadLocal.inc new file mode 100644 index 0000000..512462d --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/ThreadLocal.inc @@ -0,0 +1,54 @@ +//= llvm/Support/Win32/ThreadLocal.inc - Win32 Thread Local Data -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 specific (non-pthread) ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include "llvm/Support/ThreadLocal.h" + +namespace llvm { +using namespace sys; + +ThreadLocalImpl::ThreadLocalImpl() { + DWORD* tls = new DWORD; + *tls = TlsAlloc(); + assert(*tls != TLS_OUT_OF_INDEXES); + data = tls; +} + +ThreadLocalImpl::~ThreadLocalImpl() { + DWORD* tls = static_cast<DWORD*>(data); + TlsFree(*tls); + delete tls; +} + +const void* ThreadLocalImpl::getInstance() { + DWORD* tls = static_cast<DWORD*>(data); + return TlsGetValue(*tls); +} + +void ThreadLocalImpl::setInstance(const void* d){ + DWORD* tls = static_cast<DWORD*>(data); + int errorcode = TlsSetValue(*tls, const_cast<void*>(d)); + assert(errorcode != 0); + (void)errorcode; +} + +void ThreadLocalImpl::removeInstance() { + setInstance(0); +} + +} diff --git a/contrib/llvm/lib/Support/Windows/TimeValue.inc b/contrib/llvm/lib/Support/Windows/TimeValue.inc new file mode 100644 index 0000000..1227552 --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/TimeValue.inc @@ -0,0 +1,51 @@ +//===- Win32/TimeValue.cpp - Win32 TimeValue Implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 implementation of the TimeValue class. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include <time.h> + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code. +//===----------------------------------------------------------------------===// + +TimeValue TimeValue::now() { + uint64_t ft; + GetSystemTimeAsFileTime(reinterpret_cast<FILETIME *>(&ft)); + + TimeValue t(0, 0); + t.fromWin32Time(ft); + return t; +} + +std::string TimeValue::str() const { +#ifdef __MINGW32__ + // This ban may be lifted by either: + // (i) a future MinGW version other than 1.0 inherents the __time64_t type, or + // (ii) configure tests for either the time_t or __time64_t type. + time_t ourTime = time_t(this->toEpochTime()); + struct tm *lt = ::localtime(&ourTime); +#else + __time64_t ourTime = this->toEpochTime(); + struct tm *lt = ::_localtime64(&ourTime); +#endif + + char buffer[25]; + strftime(buffer, 25, "%a %b %d %H:%M:%S %Y", lt); + return std::string(buffer); +} + + +} diff --git a/contrib/llvm/lib/Support/Windows/Windows.h b/contrib/llvm/lib/Support/Windows/Windows.h new file mode 100644 index 0000000..5c1da0d --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/Windows.h @@ -0,0 +1,150 @@ +//===- Win32/Win32.h - Common Win32 Include File ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines things specific to Win32 implementations. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +// mingw-w64 tends to define it as 0x0502 in its headers. +#undef _WIN32_WINNT + +// Require at least Windows XP(5.1) API. +#define _WIN32_WINNT 0x0501 +#define _WIN32_IE 0x0600 // MinGW at it again. +#define WIN32_LEAN_AND_MEAN + +#include "llvm/Config/config.h" // Get build system configuration settings +#include <windows.h> +#include <wincrypt.h> +#include <shlobj.h> +#include <cassert> +#include <string> + +inline bool MakeErrMsg(std::string* ErrMsg, const std::string& prefix) { + if (!ErrMsg) + return true; + char *buffer = NULL; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, + NULL, GetLastError(), 0, (LPSTR)&buffer, 1, NULL); + *ErrMsg = prefix + buffer; + LocalFree(buffer); + return true; +} + +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: + ScopedHandle() + : Handle(HandleTraits::GetInvalid()) {} + + explicit ScopedHandle(handle_type h) + : Handle(h) {} + + ~ScopedHandle() { + if (HandleTraits::IsValid(Handle)) + HandleTraits::Close(Handle); + } + + handle_type take() { + handle_type t = Handle; + Handle = HandleTraits::GetInvalid(); + return t; + } + + 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; + } +}; + +struct CommonHandleTraits { + typedef HANDLE handle_type; + + static handle_type GetInvalid() { + return INVALID_HANDLE_VALUE; + } + + static void Close(handle_type h) { + ::CloseHandle(h); + } + + static bool IsValid(handle_type h) { + return h != GetInvalid(); + } +}; + +struct JobHandleTraits : CommonHandleTraits { + static handle_type GetInvalid() { + return NULL; + } +}; + +struct CryptContextTraits : CommonHandleTraits { + typedef HCRYPTPROV handle_type; + + static handle_type GetInvalid() { + return 0; + } + + static void Close(handle_type h) { + ::CryptReleaseContext(h, 0); + } + + static bool IsValid(handle_type h) { + return h != GetInvalid(); + } +}; + +struct FindHandleTraits : CommonHandleTraits { + static void Close(handle_type h) { + ::FindClose(h); + } +}; + +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> +class SmallVectorImpl; + +template <class T> +typename SmallVectorImpl<T>::const_pointer +c_str(SmallVectorImpl<T> &str) { + str.push_back(0); + str.pop_back(); + return str.data(); +} +} // end namespace llvm. diff --git a/contrib/llvm/lib/Support/Windows/explicit_symbols.inc b/contrib/llvm/lib/Support/Windows/explicit_symbols.inc new file mode 100644 index 0000000..379645d --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/explicit_symbols.inc @@ -0,0 +1,66 @@ +/* in libgcc.a */ + +#ifdef HAVE__ALLOCA + EXPLICIT_SYMBOL(_alloca) + EXPLICIT_SYMBOL2(alloca, _alloca) +#endif +#ifdef HAVE___ALLOCA + EXPLICIT_SYMBOL(__alloca) +#endif +#ifdef HAVE___CHKSTK + EXPLICIT_SYMBOL(__chkstk) +#endif +#ifdef HAVE____CHKSTK + EXPLICIT_SYMBOL(___chkstk) +#endif +#ifdef HAVE___MAIN + EXPLICIT_SYMBOL(__main) // FIXME: Don't call it. +#endif + +#ifdef HAVE___ASHLDI3 + EXPLICIT_SYMBOL(__ashldi3) +#endif +#ifdef HAVE___ASHRDI3 + EXPLICIT_SYMBOL(__ashrdi3) +#endif +#ifdef HAVE___CMPDI2 // FIXME: unused + EXPLICIT_SYMBOL(__cmpdi2) +#endif +#ifdef HAVE___DIVDI3 + EXPLICIT_SYMBOL(__divdi3) +#endif +#ifdef HAVE___FIXDFDI + EXPLICIT_SYMBOL(__fixdfdi) +#endif +#ifdef HAVE___FIXSFDI + EXPLICIT_SYMBOL(__fixsfdi) +#endif +#ifdef HAVE___FIXUNSDFDI + EXPLICIT_SYMBOL(__fixunsdfdi) +#endif +#ifdef HAVE___FIXUNSSFDI + EXPLICIT_SYMBOL(__fixunssfdi) +#endif +#ifdef HAVE___FLOATDIDF + EXPLICIT_SYMBOL(__floatdidf) +#endif +#ifdef HAVE___FLOATDISF + EXPLICIT_SYMBOL(__floatdisf) +#endif +#ifdef HAVE___LSHRDI3 + EXPLICIT_SYMBOL(__lshrdi3) +#endif +#ifdef HAVE___MODDI3 + EXPLICIT_SYMBOL(__moddi3) +#endif +#ifdef HAVE___UDIVDI3 + EXPLICIT_SYMBOL(__udivdi3) +#endif +#ifdef HAVE___UMODDI3 + EXPLICIT_SYMBOL(__umoddi3) +#endif + +/* msvcrt */ +#if defined(_MSC_VER) + EXPLICIT_SYMBOL2(alloca, _alloca_probe) +#endif diff --git a/contrib/llvm/lib/Support/Windows/system_error.inc b/contrib/llvm/lib/Support/Windows/system_error.inc new file mode 100644 index 0000000..37ec81d --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/system_error.inc @@ -0,0 +1,142 @@ +//===- llvm/Support/Win32/system_error.inc - Windows error_code --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Windows specific implementation of the error_code +// and error_condition classes. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Windows code that +//=== is guaranteed to work on *all* Windows variants. +//===----------------------------------------------------------------------===// + +#include <windows.h> +#include <winerror.h> + +using namespace llvm; + +std::string +_system_error_category::message(int ev) const { + LPVOID lpMsgBuf = 0; + DWORD retval = ::FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + ev, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPSTR) &lpMsgBuf, + 0, + NULL); + if (retval == 0) { + ::LocalFree(lpMsgBuf); + return std::string("Unknown error"); + } + + std::string str( static_cast<LPCSTR>(lpMsgBuf) ); + ::LocalFree(lpMsgBuf); + + while (str.size() + && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r')) + str.erase( str.size()-1 ); + if (str.size() && str[str.size()-1] == '.') + str.erase( str.size()-1 ); + return str; +} + +// I'd rather not double the line count of the following. +#define MAP_ERR_TO_COND(x, y) case x: return make_error_condition(errc::y) + +error_condition +_system_error_category::default_error_condition(int ev) const { + switch (ev) { + MAP_ERR_TO_COND(0, success); + // Windows system -> posix_errno decode table ---------------------------// + // see WinError.h comments for descriptions of errors + MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied); + MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists); + MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device); + MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long); + MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_CANNOT_MAKE, permission_denied); + MAP_ERR_TO_COND(ERROR_CANTOPEN, io_error); + MAP_ERR_TO_COND(ERROR_CANTREAD, io_error); + MAP_ERR_TO_COND(ERROR_CANTWRITE, io_error); + MAP_ERR_TO_COND(ERROR_CURRENT_DIRECTORY, permission_denied); + MAP_ERR_TO_COND(ERROR_DEV_NOT_EXIST, no_such_device); + MAP_ERR_TO_COND(ERROR_DEVICE_IN_USE, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_DIR_NOT_EMPTY, directory_not_empty); + MAP_ERR_TO_COND(ERROR_DIRECTORY, invalid_argument); + MAP_ERR_TO_COND(ERROR_DISK_FULL, no_space_on_device); + MAP_ERR_TO_COND(ERROR_FILE_EXISTS, file_exists); + MAP_ERR_TO_COND(ERROR_FILE_NOT_FOUND, no_such_file_or_directory); + MAP_ERR_TO_COND(ERROR_HANDLE_DISK_FULL, no_space_on_device); + MAP_ERR_TO_COND(ERROR_HANDLE_EOF, value_too_large); + MAP_ERR_TO_COND(ERROR_INVALID_ACCESS, permission_denied); + MAP_ERR_TO_COND(ERROR_INVALID_DRIVE, no_such_device); + MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported); + MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument); + MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument); + MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available); + MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available); + MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument); + MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied); + MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory); + MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again); + MAP_ERR_TO_COND(ERROR_NOT_SAME_DEVICE, cross_device_link); + MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error); + MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_OPERATION_ABORTED, operation_canceled); + MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory); + MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory); + MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory); + MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error); + MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again); + MAP_ERR_TO_COND(ERROR_SEEK, io_error); + MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied); + MAP_ERR_TO_COND(ERROR_TOO_MANY_OPEN_FILES, too_many_files_open); + MAP_ERR_TO_COND(ERROR_WRITE_FAULT, io_error); + MAP_ERR_TO_COND(ERROR_WRITE_PROTECT, permission_denied); + MAP_ERR_TO_COND(ERROR_SEM_TIMEOUT, timed_out); + MAP_ERR_TO_COND(WSAEACCES, permission_denied); + MAP_ERR_TO_COND(WSAEADDRINUSE, address_in_use); + MAP_ERR_TO_COND(WSAEADDRNOTAVAIL, address_not_available); + MAP_ERR_TO_COND(WSAEAFNOSUPPORT, address_family_not_supported); + MAP_ERR_TO_COND(WSAEALREADY, connection_already_in_progress); + MAP_ERR_TO_COND(WSAEBADF, bad_file_descriptor); + MAP_ERR_TO_COND(WSAECONNABORTED, connection_aborted); + MAP_ERR_TO_COND(WSAECONNREFUSED, connection_refused); + MAP_ERR_TO_COND(WSAECONNRESET, connection_reset); + MAP_ERR_TO_COND(WSAEDESTADDRREQ, destination_address_required); + MAP_ERR_TO_COND(WSAEFAULT, bad_address); + MAP_ERR_TO_COND(WSAEHOSTUNREACH, host_unreachable); + MAP_ERR_TO_COND(WSAEINPROGRESS, operation_in_progress); + MAP_ERR_TO_COND(WSAEINTR, interrupted); + MAP_ERR_TO_COND(WSAEINVAL, invalid_argument); + MAP_ERR_TO_COND(WSAEISCONN, already_connected); + MAP_ERR_TO_COND(WSAEMFILE, too_many_files_open); + MAP_ERR_TO_COND(WSAEMSGSIZE, message_size); + MAP_ERR_TO_COND(WSAENAMETOOLONG, filename_too_long); + MAP_ERR_TO_COND(WSAENETDOWN, network_down); + MAP_ERR_TO_COND(WSAENETRESET, network_reset); + MAP_ERR_TO_COND(WSAENETUNREACH, network_unreachable); + MAP_ERR_TO_COND(WSAENOBUFS, no_buffer_space); + MAP_ERR_TO_COND(WSAENOPROTOOPT, no_protocol_option); + MAP_ERR_TO_COND(WSAENOTCONN, not_connected); + MAP_ERR_TO_COND(WSAENOTSOCK, not_a_socket); + MAP_ERR_TO_COND(WSAEOPNOTSUPP, operation_not_supported); + MAP_ERR_TO_COND(WSAEPROTONOSUPPORT, protocol_not_supported); + MAP_ERR_TO_COND(WSAEPROTOTYPE, wrong_protocol_type); + MAP_ERR_TO_COND(WSAETIMEDOUT, timed_out); + MAP_ERR_TO_COND(WSAEWOULDBLOCK, operation_would_block); + default: return error_condition(ev, system_category()); + } +} diff --git a/contrib/llvm/lib/Support/YAMLParser.cpp b/contrib/llvm/lib/Support/YAMLParser.cpp new file mode 100644 index 0000000..330519f --- /dev/null +++ b/contrib/llvm/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/contrib/llvm/lib/Support/circular_raw_ostream.cpp b/contrib/llvm/lib/Support/circular_raw_ostream.cpp new file mode 100644 index 0000000..ca0d30d --- /dev/null +++ b/contrib/llvm/lib/Support/circular_raw_ostream.cpp @@ -0,0 +1,45 @@ +//===- circular_raw_ostream.cpp - Implement circular_raw_ostream ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This implements support for circular buffered streams. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/circular_raw_ostream.h" +#include <algorithm> +using namespace llvm; + +void circular_raw_ostream::write_impl(const char *Ptr, size_t Size) { + if (BufferSize == 0) { + TheStream->write(Ptr, Size); + return; + } + + // Write into the buffer, wrapping if necessary. + while (Size != 0) { + unsigned Bytes = + std::min(unsigned(Size), unsigned(BufferSize - (Cur - BufferArray))); + memcpy(Cur, Ptr, Bytes); + Size -= Bytes; + Cur += Bytes; + if (Cur == BufferArray + BufferSize) { + // Reset the output pointer to the start of the buffer. + Cur = BufferArray; + Filled = true; + } + } +} + +void circular_raw_ostream::flushBufferWithBanner() { + if (BufferSize != 0) { + // Write out the buffer + TheStream->write(Banner, std::strlen(Banner)); + flushBuffer(); + } +} diff --git a/contrib/llvm/lib/Support/raw_os_ostream.cpp b/contrib/llvm/lib/Support/raw_os_ostream.cpp new file mode 100644 index 0000000..44f2325 --- /dev/null +++ b/contrib/llvm/lib/Support/raw_os_ostream.cpp @@ -0,0 +1,30 @@ +//===--- raw_os_ostream.cpp - Implement the raw_os_ostream class ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This implements support adapting raw_ostream to std::ostream. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/raw_os_ostream.h" +#include <ostream> +using namespace llvm; + +//===----------------------------------------------------------------------===// +// raw_os_ostream +//===----------------------------------------------------------------------===// + +raw_os_ostream::~raw_os_ostream() { + flush(); +} + +void raw_os_ostream::write_impl(const char *Ptr, size_t Size) { + OS.write(Ptr, Size); +} + +uint64_t raw_os_ostream::current_pos() const { return OS.tellp(); } diff --git a/contrib/llvm/lib/Support/raw_ostream.cpp b/contrib/llvm/lib/Support/raw_ostream.cpp new file mode 100644 index 0000000..72d3986 --- /dev/null +++ b/contrib/llvm/lib/Support/raw_ostream.cpp @@ -0,0 +1,765 @@ +//===--- raw_ostream.cpp - Implement the raw_ostream classes --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This implements support for bulk buffered stream output. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/Process.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/SmallVector.h" +#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> +#include <sys/stat.h> +#include <sys/types.h> + +#if defined(HAVE_UNISTD_H) +# include <unistd.h> +#endif +#if defined(HAVE_FCNTL_H) +# include <fcntl.h> +#endif +#if defined(HAVE_SYS_UIO_H) && defined(HAVE_WRITEV) +# include <sys/uio.h> +#endif + +#if defined(__CYGWIN__) +#include <io.h> +#endif + +#if defined(_MSC_VER) +#include <io.h> +#include <fcntl.h> +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +# define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif +#endif + +using namespace llvm; + +raw_ostream::~raw_ostream() { + // raw_ostream's subclasses should take care to flush the buffer + // in their destructors. + assert(OutBufCur == OutBufStart && + "raw_ostream destructor called with non-empty buffer!"); + + if (BufferMode == InternalBuffer) + delete [] OutBufStart; +} + +// An out of line virtual method to provide a home for the class vtable. +void raw_ostream::handle() {} + +size_t raw_ostream::preferred_buffer_size() const { + // BUFSIZ is intended to be a reasonable default. + return BUFSIZ; +} + +void raw_ostream::SetBuffered() { + // Ask the subclass to determine an appropriate buffer size. + if (size_t Size = preferred_buffer_size()) + SetBufferSize(Size); + else + // It may return 0, meaning this stream should be unbuffered. + SetUnbuffered(); +} + +void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size, + BufferKind Mode) { + assert(((Mode == Unbuffered && BufferStart == 0 && Size == 0) || + (Mode != Unbuffered && BufferStart && Size)) && + "stream must be unbuffered or have at least one byte"); + // Make sure the current buffer is free of content (we can't flush here; the + // child buffer management logic will be in write_impl). + assert(GetNumBytesInBuffer() == 0 && "Current buffer is non-empty!"); + + if (BufferMode == InternalBuffer) + delete [] OutBufStart; + OutBufStart = BufferStart; + OutBufEnd = OutBufStart+Size; + OutBufCur = OutBufStart; + BufferMode = Mode; + + assert(OutBufStart <= OutBufEnd && "Invalid size!"); +} + +raw_ostream &raw_ostream::operator<<(unsigned long N) { + // Zero is a special case. + if (N == 0) + return *this << '0'; + + char NumberBuffer[20]; + char *EndPtr = NumberBuffer+sizeof(NumberBuffer); + char *CurPtr = EndPtr; + + while (N) { + *--CurPtr = '0' + char(N % 10); + N /= 10; + } + return write(CurPtr, EndPtr-CurPtr); +} + +raw_ostream &raw_ostream::operator<<(long N) { + if (N < 0) { + *this << '-'; + // Avoid undefined behavior on LONG_MIN with a cast. + N = -(unsigned long)N; + } + + return this->operator<<(static_cast<unsigned long>(N)); +} + +raw_ostream &raw_ostream::operator<<(unsigned long long N) { + // Output using 32-bit div/mod when possible. + if (N == static_cast<unsigned long>(N)) + return this->operator<<(static_cast<unsigned long>(N)); + + char NumberBuffer[20]; + char *EndPtr = NumberBuffer+sizeof(NumberBuffer); + char *CurPtr = EndPtr; + + while (N) { + *--CurPtr = '0' + char(N % 10); + N /= 10; + } + return write(CurPtr, EndPtr-CurPtr); +} + +raw_ostream &raw_ostream::operator<<(long long N) { + if (N < 0) { + *this << '-'; + // Avoid undefined behavior on INT64_MIN with a cast. + N = -(unsigned long long)N; + } + + return this->operator<<(static_cast<unsigned long long>(N)); +} + +raw_ostream &raw_ostream::write_hex(unsigned long long N) { + // Zero is a special case. + if (N == 0) + return *this << '0'; + + char NumberBuffer[20]; + char *EndPtr = NumberBuffer+sizeof(NumberBuffer); + char *CurPtr = EndPtr; + + while (N) { + uintptr_t x = N % 16; + *--CurPtr = (x < 10 ? '0' + x : 'a' + x - 10); + N /= 16; + } + + return write(CurPtr, EndPtr-CurPtr); +} + +raw_ostream &raw_ostream::write_escaped(StringRef Str, + bool UseHexEscapes) { + for (unsigned i = 0, e = Str.size(); i != e; ++i) { + unsigned char c = Str[i]; + + switch (c) { + case '\\': + *this << '\\' << '\\'; + break; + case '\t': + *this << '\\' << 't'; + break; + case '\n': + *this << '\\' << 'n'; + break; + case '"': + *this << '\\' << '"'; + break; + default: + if (std::isprint(c)) { + *this << c; + break; + } + + // Write out the escaped representation. + if (UseHexEscapes) { + *this << '\\' << 'x'; + *this << hexdigit((c >> 4 & 0xF)); + *this << hexdigit((c >> 0) & 0xF); + } else { + // Always use a full 3-character octal escape. + *this << '\\'; + *this << char('0' + ((c >> 6) & 7)); + *this << char('0' + ((c >> 3) & 7)); + *this << char('0' + ((c >> 0) & 7)); + } + } + } + + return *this; +} + +raw_ostream &raw_ostream::operator<<(const void *P) { + *this << '0' << 'x'; + + return write_hex((uintptr_t) P); +} + +raw_ostream &raw_ostream::operator<<(double N) { +#ifdef _WIN32 + // On MSVCRT and compatible, output of %e is incompatible to Posix + // by default. Number of exponent digits should be at least 2. "%+03d" + // FIXME: Implement our formatter to here or Support/Format.h! + int fpcl = _fpclass(N); + + // negative zero + if (fpcl == _FPCLASS_NZ) + return *this << "-0.000000e+00"; + + char buf[16]; + unsigned len; + len = snprintf(buf, sizeof(buf), "%e", N); + if (len <= sizeof(buf) - 2) { + if (len >= 5 && buf[len - 5] == 'e' && buf[len - 3] == '0') { + int cs = buf[len - 4]; + if (cs == '+' || cs == '-') { + int c1 = buf[len - 2]; + int c0 = buf[len - 1]; + if (isdigit(c1) && isdigit(c0)) { + // Trim leading '0': "...e+012" -> "...e+12\0" + buf[len - 3] = c1; + buf[len - 2] = c0; + buf[--len] = 0; + } + } + } + return this->operator<<(buf); + } +#endif + return this->operator<<(format("%e", N)); +} + + + +void raw_ostream::flush_nonempty() { + assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty."); + size_t Length = OutBufCur - OutBufStart; + OutBufCur = OutBufStart; + write_impl(OutBufStart, Length); +} + +raw_ostream &raw_ostream::write(unsigned char C) { + // Group exceptional cases into a single branch. + if (BUILTIN_EXPECT(OutBufCur >= OutBufEnd, false)) { + if (BUILTIN_EXPECT(!OutBufStart, false)) { + if (BufferMode == Unbuffered) { + write_impl(reinterpret_cast<char*>(&C), 1); + return *this; + } + // Set up a buffer and start over. + SetBuffered(); + return write(C); + } + + flush_nonempty(); + } + + *OutBufCur++ = C; + return *this; +} + +raw_ostream &raw_ostream::write(const char *Ptr, size_t Size) { + // Group exceptional cases into a single branch. + if (BUILTIN_EXPECT(size_t(OutBufEnd - OutBufCur) < Size, false)) { + if (BUILTIN_EXPECT(!OutBufStart, false)) { + if (BufferMode == Unbuffered) { + write_impl(Ptr, Size); + return *this; + } + // Set up a buffer and start over. + SetBuffered(); + return write(Ptr, Size); + } + + size_t NumBytes = OutBufEnd - OutBufCur; + + // If the buffer is empty at this point we have a string that is larger + // than the buffer. Directly write the chunk that is a multiple of the + // preferred buffer size and put the remainder in the buffer. + if (BUILTIN_EXPECT(OutBufCur == OutBufStart, false)) { + size_t BytesToWrite = Size - (Size % NumBytes); + write_impl(Ptr, BytesToWrite); + copy_to_buffer(Ptr + BytesToWrite, Size - BytesToWrite); + return *this; + } + + // We don't have enough space in the buffer to fit the string in. Insert as + // much as possible, flush and start over with the remainder. + copy_to_buffer(Ptr, NumBytes); + flush_nonempty(); + return write(Ptr + NumBytes, Size - NumBytes); + } + + copy_to_buffer(Ptr, Size); + + return *this; +} + +void raw_ostream::copy_to_buffer(const char *Ptr, size_t Size) { + assert(Size <= size_t(OutBufEnd - OutBufCur) && "Buffer overrun!"); + + // Handle short strings specially, memcpy isn't very good at very short + // strings. + switch (Size) { + case 4: OutBufCur[3] = Ptr[3]; // FALL THROUGH + case 3: OutBufCur[2] = Ptr[2]; // FALL THROUGH + case 2: OutBufCur[1] = Ptr[1]; // FALL THROUGH + case 1: OutBufCur[0] = Ptr[0]; // FALL THROUGH + case 0: break; + default: + memcpy(OutBufCur, Ptr, Size); + break; + } + + OutBufCur += Size; +} + +// Formatted output. +raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) { + // If we have more than a few bytes left in our output buffer, try + // formatting directly onto its end. + size_t NextBufferSize = 127; + size_t BufferBytesLeft = OutBufEnd - OutBufCur; + if (BufferBytesLeft > 3) { + size_t BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft); + + // Common case is that we have plenty of space. + if (BytesUsed <= BufferBytesLeft) { + OutBufCur += BytesUsed; + return *this; + } + + // Otherwise, we overflowed and the return value tells us the size to try + // again with. + NextBufferSize = BytesUsed; + } + + // If we got here, we didn't have enough space in the output buffer for the + // string. Try printing into a SmallVector that is resized to have enough + // space. Iterate until we win. + SmallVector<char, 128> V; + + while (1) { + V.resize(NextBufferSize); + + // Try formatting into the SmallVector. + size_t BytesUsed = Fmt.print(V.data(), NextBufferSize); + + // If BytesUsed fit into the vector, we win. + if (BytesUsed <= NextBufferSize) + return write(V.data(), BytesUsed); + + // Otherwise, try again with a new size. + assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?"); + NextBufferSize = BytesUsed; + } +} + +/// indent - Insert 'NumSpaces' spaces. +raw_ostream &raw_ostream::indent(unsigned NumSpaces) { + static const char Spaces[] = " " + " " + " "; + + // Usually the indentation is small, handle it with a fastpath. + if (NumSpaces < array_lengthof(Spaces)) + return write(Spaces, NumSpaces); + + while (NumSpaces) { + unsigned NumToWrite = std::min(NumSpaces, + (unsigned)array_lengthof(Spaces)-1); + write(Spaces, NumToWrite); + NumSpaces -= NumToWrite; + } + return *this; +} + + +//===----------------------------------------------------------------------===// +// Formatted Output +//===----------------------------------------------------------------------===// + +// Out of line virtual method. +void format_object_base::home() { +} + +//===----------------------------------------------------------------------===// +// raw_fd_ostream +//===----------------------------------------------------------------------===// + +/// raw_fd_ostream - Open the specified file for writing. If an error +/// occurs, information about the error is put into ErrorInfo, and the +/// stream should be immediately destroyed; the string will be empty +/// if no error occurred. +raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo, + unsigned Flags) + : Error(false), UseAtomicWrites(false), pos(0) +{ + assert(Filename != 0 && "Filename is null"); + // Verify that we don't have both "append" and "excl". + assert((!(Flags & F_Excl) || !(Flags & F_Append)) && + "Cannot specify both 'excl' and 'append' file creation flags!"); + + ErrorInfo.clear(); + + // Handle "-" as stdout. Note that when we do this, we consider ourself + // the owner of stdout. This means that we can do things like close the + // file descriptor when we're done and set the "binary" flag globally. + if (Filename[0] == '-' && Filename[1] == 0) { + FD = STDOUT_FILENO; + // If user requested binary then put stdout into binary mode if + // possible. + if (Flags & F_Binary) + sys::Program::ChangeStdoutToBinary(); + // Close stdout when we're done, to detect any output errors. + ShouldClose = true; + return; + } + + int OpenFlags = O_WRONLY|O_CREAT; +#ifdef O_BINARY + if (Flags & F_Binary) + OpenFlags |= O_BINARY; +#endif + + if (Flags & F_Append) + OpenFlags |= O_APPEND; + else + OpenFlags |= O_TRUNC; + if (Flags & F_Excl) + OpenFlags |= O_EXCL; + + while ((FD = open(Filename, OpenFlags, 0664)) < 0) { + if (errno != EINTR) { + ErrorInfo = "Error opening output file '" + std::string(Filename) + "'"; + ShouldClose = false; + return; + } + } + + // Ok, we successfully opened the file, so it'll need to be closed. + ShouldClose = true; +} + +/// raw_fd_ostream ctor - FD is the file descriptor that this writes to. If +/// ShouldClose is true, this closes the file when the stream is destroyed. +raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered) + : raw_ostream(unbuffered), FD(fd), + ShouldClose(shouldClose), Error(false), UseAtomicWrites(false) { +#ifdef O_BINARY + // Setting STDOUT and STDERR to binary mode is necessary in Win32 + // to avoid undesirable linefeed conversion. + if (fd == STDOUT_FILENO || fd == STDERR_FILENO) + setmode(fd, O_BINARY); +#endif + + // Get the starting position. + off_t loc = ::lseek(FD, 0, SEEK_CUR); + if (loc == (off_t)-1) + pos = 0; + else + pos = static_cast<uint64_t>(loc); +} + +raw_fd_ostream::~raw_fd_ostream() { + if (FD >= 0) { + flush(); + if (ShouldClose) + while (::close(FD) != 0) + if (errno != EINTR) { + error_detected(); + break; + } + } + +#ifdef __MINGW32__ + // On mingw, global dtors should not call exit(). + // report_fatal_error() invokes exit(). We know report_fatal_error() + // might not write messages to stderr when any errors were detected + // on FD == 2. + if (FD == 2) return; +#endif + + // If there are any pending errors, report them now. Clients wishing + // to avoid report_fatal_error calls should check for errors with + // has_error() and clear the error flag with clear_error() before + // destructing raw_ostream objects which may have errors. + if (has_error()) + report_fatal_error("IO failure on output stream."); +} + + +void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) { + assert(FD >= 0 && "File already closed."); + pos += Size; + + do { + ssize_t ret; + + // Check whether we should attempt to use atomic writes. + if (BUILTIN_EXPECT(!UseAtomicWrites, true)) { + ret = ::write(FD, Ptr, Size); + } else { + // Use ::writev() where available. +#if defined(HAVE_WRITEV) + struct iovec IOV = { (void*) Ptr, Size }; + ret = ::writev(FD, &IOV, 1); +#else + ret = ::write(FD, Ptr, Size); +#endif + } + + if (ret < 0) { + // If it's a recoverable error, swallow it and retry the write. + // + // Ideally we wouldn't ever see EAGAIN or EWOULDBLOCK here, since + // raw_ostream isn't designed to do non-blocking I/O. However, some + // programs, such as old versions of bjam, have mistakenly used + // O_NONBLOCK. For compatibility, emulate blocking semantics by + // spinning until the write succeeds. If you don't want spinning, + // don't use O_NONBLOCK file descriptors with raw_ostream. + if (errno == EINTR || errno == EAGAIN +#ifdef EWOULDBLOCK + || errno == EWOULDBLOCK +#endif + ) + continue; + + // Otherwise it's a non-recoverable error. Note it and quit. + error_detected(); + break; + } + + // The write may have written some or all of the data. Update the + // size and buffer pointer to reflect the remainder that needs + // to be written. If there are no bytes left, we're done. + Ptr += ret; + Size -= ret; + } while (Size > 0); +} + +void raw_fd_ostream::close() { + assert(ShouldClose); + ShouldClose = false; + flush(); + while (::close(FD) != 0) + if (errno != EINTR) { + error_detected(); + break; + } + FD = -1; +} + +uint64_t raw_fd_ostream::seek(uint64_t off) { + flush(); + pos = ::lseek(FD, off, SEEK_SET); + if (pos != off) + error_detected(); + return pos; +} + +size_t raw_fd_ostream::preferred_buffer_size() const { +#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__minix) + // Windows and Minix have no st_blksize. + assert(FD >= 0 && "File not yet open!"); + struct stat statbuf; + if (fstat(FD, &statbuf) != 0) + return 0; + + // If this is a terminal, don't use buffering. Line buffering + // would be a more traditional thing to do, but it's not worth + // the complexity. + if (S_ISCHR(statbuf.st_mode) && isatty(FD)) + return 0; + // Return the preferred block size. + return statbuf.st_blksize; +#else + return raw_ostream::preferred_buffer_size(); +#endif +} + +raw_ostream &raw_fd_ostream::changeColor(enum Colors colors, bool bold, + bool bg) { + if (sys::Process::ColorNeedsFlush()) + flush(); + const char *colorcode = + (colors == SAVEDCOLOR) ? sys::Process::OutputBold(bg) + : sys::Process::OutputColor(colors, bold, bg); + if (colorcode) { + size_t len = strlen(colorcode); + write(colorcode, len); + // don't account colors towards output characters + pos -= len; + } + return *this; +} + +raw_ostream &raw_fd_ostream::resetColor() { + if (sys::Process::ColorNeedsFlush()) + flush(); + const char *colorcode = sys::Process::ResetColor(); + if (colorcode) { + size_t len = strlen(colorcode); + write(colorcode, len); + // don't account colors towards output characters + pos -= len; + } + return *this; +} + +bool raw_fd_ostream::is_displayed() const { + return sys::Process::FileDescriptorIsDisplayed(FD); +} + +//===----------------------------------------------------------------------===// +// outs(), errs(), nulls() +//===----------------------------------------------------------------------===// + +/// outs() - This returns a reference to a raw_ostream for standard output. +/// Use it like: outs() << "foo" << "bar"; +raw_ostream &llvm::outs() { + // Set buffer settings to model stdout behavior. + // Delete the file descriptor when the program exists, forcing error + // detection. If you don't want this behavior, don't use outs(). + static raw_fd_ostream S(STDOUT_FILENO, true); + return S; +} + +/// errs() - This returns a reference to a raw_ostream for standard error. +/// Use it like: errs() << "foo" << "bar"; +raw_ostream &llvm::errs() { + // Set standard error to be unbuffered by default. + static raw_fd_ostream S(STDERR_FILENO, false, true); + return S; +} + +/// nulls() - This returns a reference to a raw_ostream which discards output. +raw_ostream &llvm::nulls() { + static raw_null_ostream S; + return S; +} + + +//===----------------------------------------------------------------------===// +// raw_string_ostream +//===----------------------------------------------------------------------===// + +raw_string_ostream::~raw_string_ostream() { + flush(); +} + +void raw_string_ostream::write_impl(const char *Ptr, size_t Size) { + OS.append(Ptr, Size); +} + +//===----------------------------------------------------------------------===// +// raw_svector_ostream +//===----------------------------------------------------------------------===// + +// The raw_svector_ostream implementation uses the SmallVector itself as the +// buffer for the raw_ostream. We guarantee that the raw_ostream buffer is +// always pointing past the end of the vector, but within the vector +// capacity. This allows raw_ostream to write directly into the correct place, +// and we only need to set the vector size when the data is flushed. + +raw_svector_ostream::raw_svector_ostream(SmallVectorImpl<char> &O) : OS(O) { + // Set up the initial external buffer. We make sure that the buffer has at + // least 128 bytes free; raw_ostream itself only requires 64, but we want to + // make sure that we don't grow the buffer unnecessarily on destruction (when + // the data is flushed). See the FIXME below. + OS.reserve(OS.size() + 128); + SetBuffer(OS.end(), OS.capacity() - OS.size()); +} + +raw_svector_ostream::~raw_svector_ostream() { + // FIXME: Prevent resizing during this flush(). + flush(); +} + +/// resync - This is called when the SmallVector we're appending to is changed +/// outside of the raw_svector_ostream's control. It is only safe to do this +/// if the raw_svector_ostream has previously been flushed. +void raw_svector_ostream::resync() { + assert(GetNumBytesInBuffer() == 0 && "Didn't flush before mutating vector"); + + if (OS.capacity() - OS.size() < 64) + OS.reserve(OS.capacity() * 2); + SetBuffer(OS.end(), OS.capacity() - OS.size()); +} + +void raw_svector_ostream::write_impl(const char *Ptr, size_t Size) { + // If we're writing bytes from the end of the buffer into the smallvector, we + // don't need to copy the bytes, just commit the bytes because they are + // already in the right place. + if (Ptr == OS.end()) { + assert(OS.size() + Size <= OS.capacity() && "Invalid write_impl() call!"); + OS.set_size(OS.size() + Size); + } else { + assert(GetNumBytesInBuffer() == 0 && + "Should be writing from buffer if some bytes in it"); + // Otherwise, do copy the bytes. + OS.append(Ptr, Ptr+Size); + } + + // Grow the vector if necessary. + if (OS.capacity() - OS.size() < 64) + OS.reserve(OS.capacity() * 2); + + // Update the buffer position. + SetBuffer(OS.end(), OS.capacity() - OS.size()); +} + +uint64_t raw_svector_ostream::current_pos() const { + return OS.size(); +} + +StringRef raw_svector_ostream::str() { + flush(); + return StringRef(OS.begin(), OS.size()); +} + +//===----------------------------------------------------------------------===// +// raw_null_ostream +//===----------------------------------------------------------------------===// + +raw_null_ostream::~raw_null_ostream() { +#ifndef NDEBUG + // ~raw_ostream asserts that the buffer is empty. This isn't necessary + // with raw_null_ostream, but it's better to have raw_null_ostream follow + // the rules than to change the rules just for raw_null_ostream. + flush(); +#endif +} + +void raw_null_ostream::write_impl(const char *Ptr, size_t Size) { +} + +uint64_t raw_null_ostream::current_pos() const { + return 0; +} diff --git a/contrib/llvm/lib/Support/regcclass.h b/contrib/llvm/lib/Support/regcclass.h new file mode 100644 index 0000000..2cea3e4 --- /dev/null +++ b/contrib/llvm/lib/Support/regcclass.h @@ -0,0 +1,70 @@ +/*- + * This code is derived from OpenBSD's libc/regex, original license follows: + * + * This code is derived from OpenBSD's libc/regex, original license follows: + * + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cclass.h 8.3 (Berkeley) 3/20/94 + */ + +/* character-class table */ +static struct cclass { + const char *name; + const char *chars; + const char *multis; +} cclasses[] = { + { "alnum", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789", ""} , + { "alpha", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", + ""} , + { "blank", " \t", ""} , + { "cntrl", "\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\ +\25\26\27\30\31\32\33\34\35\36\37\177", ""} , + { "digit", "0123456789", ""} , + { "graph", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + ""} , + { "lower", "abcdefghijklmnopqrstuvwxyz", + ""} , + { "print", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ", + ""} , + { "punct", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + ""} , + { "space", "\t\n\v\f\r ", ""} , + { "upper", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + ""} , + { "xdigit", "0123456789ABCDEFabcdef", + ""} , + { NULL, 0, "" } +}; diff --git a/contrib/llvm/lib/Support/regcname.h b/contrib/llvm/lib/Support/regcname.h new file mode 100644 index 0000000..3c0bb24 --- /dev/null +++ b/contrib/llvm/lib/Support/regcname.h @@ -0,0 +1,139 @@ +/*- + * This code is derived from OpenBSD's libc/regex, original license follows: + * + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cname.h 8.3 (Berkeley) 3/20/94 + */ + +/* character-name table */ +static struct cname { + const char *name; + char code; +} cnames[] = { + { "NUL", '\0' }, + { "SOH", '\001' }, + { "STX", '\002' }, + { "ETX", '\003' }, + { "EOT", '\004' }, + { "ENQ", '\005' }, + { "ACK", '\006' }, + { "BEL", '\007' }, + { "alert", '\007' }, + { "BS", '\010' }, + { "backspace", '\b' }, + { "HT", '\011' }, + { "tab", '\t' }, + { "LF", '\012' }, + { "newline", '\n' }, + { "VT", '\013' }, + { "vertical-tab", '\v' }, + { "FF", '\014' }, + { "form-feed", '\f' }, + { "CR", '\015' }, + { "carriage-return", '\r' }, + { "SO", '\016' }, + { "SI", '\017' }, + { "DLE", '\020' }, + { "DC1", '\021' }, + { "DC2", '\022' }, + { "DC3", '\023' }, + { "DC4", '\024' }, + { "NAK", '\025' }, + { "SYN", '\026' }, + { "ETB", '\027' }, + { "CAN", '\030' }, + { "EM", '\031' }, + { "SUB", '\032' }, + { "ESC", '\033' }, + { "IS4", '\034' }, + { "FS", '\034' }, + { "IS3", '\035' }, + { "GS", '\035' }, + { "IS2", '\036' }, + { "RS", '\036' }, + { "IS1", '\037' }, + { "US", '\037' }, + { "space", ' ' }, + { "exclamation-mark", '!' }, + { "quotation-mark", '"' }, + { "number-sign", '#' }, + { "dollar-sign", '$' }, + { "percent-sign", '%' }, + { "ampersand", '&' }, + { "apostrophe", '\'' }, + { "left-parenthesis", '(' }, + { "right-parenthesis", ')' }, + { "asterisk", '*' }, + { "plus-sign", '+' }, + { "comma", ',' }, + { "hyphen", '-' }, + { "hyphen-minus", '-' }, + { "period", '.' }, + { "full-stop", '.' }, + { "slash", '/' }, + { "solidus", '/' }, + { "zero", '0' }, + { "one", '1' }, + { "two", '2' }, + { "three", '3' }, + { "four", '4' }, + { "five", '5' }, + { "six", '6' }, + { "seven", '7' }, + { "eight", '8' }, + { "nine", '9' }, + { "colon", ':' }, + { "semicolon", ';' }, + { "less-than-sign", '<' }, + { "equals-sign", '=' }, + { "greater-than-sign", '>' }, + { "question-mark", '?' }, + { "commercial-at", '@' }, + { "left-square-bracket", '[' }, + { "backslash", '\\' }, + { "reverse-solidus", '\\' }, + { "right-square-bracket", ']' }, + { "circumflex", '^' }, + { "circumflex-accent", '^' }, + { "underscore", '_' }, + { "low-line", '_' }, + { "grave-accent", '`' }, + { "left-brace", '{' }, + { "left-curly-bracket", '{' }, + { "vertical-line", '|' }, + { "right-brace", '}' }, + { "right-curly-bracket", '}' }, + { "tilde", '~' }, + { "DEL", '\177' }, + { NULL, 0 } +}; diff --git a/contrib/llvm/lib/Support/regcomp.c b/contrib/llvm/lib/Support/regcomp.c new file mode 100644 index 0000000..46c91a9 --- /dev/null +++ b/contrib/llvm/lib/Support/regcomp.c @@ -0,0 +1,1525 @@ +/*- + * This code is derived from OpenBSD's libc/regex, original license follows: + * + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regcomp.c 8.5 (Berkeley) 3/20/94 + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <limits.h> +#include <stdlib.h> +#include "regex_impl.h" + +#include "regutils.h" +#include "regex2.h" + +#include "regcclass.h" +#include "regcname.h" + +/* + * parse structure, passed up and down to avoid global variables and + * other clumsinesses + */ +struct parse { + char *next; /* next character in RE */ + char *end; /* end of string (-> NUL normally) */ + int error; /* has an error been seen? */ + sop *strip; /* malloced strip */ + sopno ssize; /* malloced strip size (allocated) */ + sopno slen; /* malloced strip length (used) */ + int ncsalloc; /* number of csets allocated */ + struct re_guts *g; +# define NPAREN 10 /* we need to remember () 1-9 for back refs */ + sopno pbegin[NPAREN]; /* -> ( ([0] unused) */ + sopno pend[NPAREN]; /* -> ) ([0] unused) */ +}; + +static void p_ere(struct parse *, int); +static void p_ere_exp(struct parse *); +static void p_str(struct parse *); +static void p_bre(struct parse *, int, int); +static int p_simp_re(struct parse *, int); +static int p_count(struct parse *); +static void p_bracket(struct parse *); +static void p_b_term(struct parse *, cset *); +static void p_b_cclass(struct parse *, cset *); +static void p_b_eclass(struct parse *, cset *); +static char p_b_symbol(struct parse *); +static char p_b_coll_elem(struct parse *, int); +static char othercase(int); +static void bothcases(struct parse *, int); +static void ordinary(struct parse *, int); +static void nonnewline(struct parse *); +static void repeat(struct parse *, sopno, int, int); +static int seterr(struct parse *, int); +static cset *allocset(struct parse *); +static void freeset(struct parse *, cset *); +static int freezeset(struct parse *, cset *); +static int firstch(struct parse *, cset *); +static int nch(struct parse *, cset *); +static void mcadd(struct parse *, cset *, const char *); +static void mcinvert(struct parse *, cset *); +static void mccase(struct parse *, cset *); +static int isinsets(struct re_guts *, int); +static int samesets(struct re_guts *, int, int); +static void categorize(struct parse *, struct re_guts *); +static sopno dupl(struct parse *, sopno, sopno); +static void doemit(struct parse *, sop, size_t); +static void doinsert(struct parse *, sop, size_t, sopno); +static void dofwd(struct parse *, sopno, sop); +static void enlarge(struct parse *, sopno); +static void stripsnug(struct parse *, struct re_guts *); +static void findmust(struct parse *, struct re_guts *); +static sopno pluscount(struct parse *, struct re_guts *); + +static char nuls[10]; /* place to point scanner in event of error */ + +/* + * macros for use with parse structure + * BEWARE: these know that the parse structure is named `p' !!! + */ +#define PEEK() (*p->next) +#define PEEK2() (*(p->next+1)) +#define MORE() (p->next < p->end) +#define MORE2() (p->next+1 < p->end) +#define SEE(c) (MORE() && PEEK() == (c)) +#define SEETWO(a, b) (MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b)) +#define EAT(c) ((SEE(c)) ? (NEXT(), 1) : 0) +#define EATTWO(a, b) ((SEETWO(a, b)) ? (NEXT2(), 1) : 0) +#define NEXT() (p->next++) +#define NEXT2() (p->next += 2) +#define NEXTn(n) (p->next += (n)) +#define GETNEXT() (*p->next++) +#define SETERROR(e) seterr(p, (e)) +#define REQUIRE(co, e) (void)((co) || SETERROR(e)) +#define MUSTSEE(c, e) (REQUIRE(MORE() && PEEK() == (c), e)) +#define MUSTEAT(c, e) (REQUIRE(MORE() && GETNEXT() == (c), e)) +#define MUSTNOTSEE(c, e) (REQUIRE(!MORE() || PEEK() != (c), e)) +#define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd)) +#define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos) +#define AHEAD(pos) dofwd(p, pos, HERE()-(pos)) +#define ASTERN(sop, pos) EMIT(sop, HERE()-pos) +#define HERE() (p->slen) +#define THERE() (p->slen - 1) +#define THERETHERE() (p->slen - 2) +#define DROP(n) (p->slen -= (n)) + +#ifdef _POSIX2_RE_DUP_MAX +#define DUPMAX _POSIX2_RE_DUP_MAX +#else +#define DUPMAX 255 +#endif +#define INFINITY (DUPMAX + 1) + +#ifndef NDEBUG +static int never = 0; /* for use in asserts; shuts lint up */ +#else +#define never 0 /* some <assert.h>s have bugs too */ +#endif + +/* + - llvm_regcomp - interface for parser and compilation + */ +int /* 0 success, otherwise REG_something */ +llvm_regcomp(llvm_regex_t *preg, const char *pattern, int cflags) +{ + struct parse pa; + struct re_guts *g; + struct parse *p = &pa; + int i; + size_t len; +#ifdef REDEBUG +# define GOODFLAGS(f) (f) +#else +# define GOODFLAGS(f) ((f)&~REG_DUMP) +#endif + + cflags = GOODFLAGS(cflags); + if ((cflags®_EXTENDED) && (cflags®_NOSPEC)) + return(REG_INVARG); + + if (cflags®_PEND) { + if (preg->re_endp < pattern) + return(REG_INVARG); + len = preg->re_endp - pattern; + } else + len = strlen((const char *)pattern); + + /* do the mallocs early so failure handling is easy */ + g = (struct re_guts *)malloc(sizeof(struct re_guts) + + (NC-1)*sizeof(cat_t)); + if (g == NULL) + return(REG_ESPACE); + p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */ + p->strip = (sop *)calloc(p->ssize, sizeof(sop)); + p->slen = 0; + if (p->strip == NULL) { + free((char *)g); + return(REG_ESPACE); + } + + /* set things up */ + p->g = g; + p->next = (char *)pattern; /* convenience; we do not modify it */ + p->end = p->next + len; + p->error = 0; + p->ncsalloc = 0; + for (i = 0; i < NPAREN; i++) { + p->pbegin[i] = 0; + p->pend[i] = 0; + } + g->csetsize = NC; + g->sets = NULL; + g->setbits = NULL; + g->ncsets = 0; + g->cflags = cflags; + g->iflags = 0; + g->nbol = 0; + g->neol = 0; + g->must = NULL; + g->mlen = 0; + g->nsub = 0; + g->ncategories = 1; /* category 0 is "everything else" */ + g->categories = &g->catspace[-(CHAR_MIN)]; + (void) memset((char *)g->catspace, 0, NC*sizeof(cat_t)); + g->backrefs = 0; + + /* do it */ + EMIT(OEND, 0); + g->firststate = THERE(); + if (cflags®_EXTENDED) + p_ere(p, OUT); + else if (cflags®_NOSPEC) + p_str(p); + else + p_bre(p, OUT, OUT); + EMIT(OEND, 0); + g->laststate = THERE(); + + /* tidy up loose ends and fill things in */ + categorize(p, g); + stripsnug(p, g); + findmust(p, g); + g->nplus = pluscount(p, g); + g->magic = MAGIC2; + preg->re_nsub = g->nsub; + preg->re_g = g; + preg->re_magic = MAGIC1; +#ifndef REDEBUG + /* not debugging, so can't rely on the assert() in llvm_regexec() */ + if (g->iflags®EX_BAD) + SETERROR(REG_ASSERT); +#endif + + /* win or lose, we're done */ + if (p->error != 0) /* lose */ + llvm_regfree(preg); + return(p->error); +} + +/* + - p_ere - ERE parser top level, concatenation and alternation + */ +static void +p_ere(struct parse *p, int stop) /* character this ERE should end at */ +{ + char c; + sopno prevback = 0; + sopno prevfwd = 0; + sopno conc; + int first = 1; /* is this the first alternative? */ + + for (;;) { + /* do a bunch of concatenated expressions */ + conc = HERE(); + while (MORE() && (c = PEEK()) != '|' && c != stop) + p_ere_exp(p); + REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */ + + if (!EAT('|')) + break; /* NOTE BREAK OUT */ + + if (first) { + INSERT(OCH_, conc); /* offset is wrong */ + prevfwd = conc; + prevback = conc; + first = 0; + } + ASTERN(OOR1, prevback); + prevback = THERE(); + AHEAD(prevfwd); /* fix previous offset */ + prevfwd = HERE(); + EMIT(OOR2, 0); /* offset is very wrong */ + } + + if (!first) { /* tail-end fixups */ + AHEAD(prevfwd); + ASTERN(O_CH, prevback); + } + + assert(!MORE() || SEE(stop)); +} + +/* + - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op + */ +static void +p_ere_exp(struct parse *p) +{ + char c; + sopno pos; + int count; + int count2; + sopno subno; + int wascaret = 0; + + assert(MORE()); /* caller should have ensured this */ + c = GETNEXT(); + + pos = HERE(); + switch (c) { + case '(': + REQUIRE(MORE(), REG_EPAREN); + p->g->nsub++; + subno = p->g->nsub; + if (subno < NPAREN) + p->pbegin[subno] = HERE(); + EMIT(OLPAREN, subno); + if (!SEE(')')) + p_ere(p, ')'); + if (subno < NPAREN) { + p->pend[subno] = HERE(); + assert(p->pend[subno] != 0); + } + EMIT(ORPAREN, subno); + MUSTEAT(')', REG_EPAREN); + break; +#ifndef POSIX_MISTAKE + case ')': /* happens only if no current unmatched ( */ + /* + * You may ask, why the ifndef? Because I didn't notice + * this until slightly too late for 1003.2, and none of the + * other 1003.2 regular-expression reviewers noticed it at + * all. So an unmatched ) is legal POSIX, at least until + * we can get it fixed. + */ + SETERROR(REG_EPAREN); + break; +#endif + case '^': + EMIT(OBOL, 0); + p->g->iflags |= USEBOL; + p->g->nbol++; + wascaret = 1; + break; + case '$': + EMIT(OEOL, 0); + p->g->iflags |= USEEOL; + p->g->neol++; + break; + case '|': + SETERROR(REG_EMPTY); + break; + case '*': + case '+': + case '?': + SETERROR(REG_BADRPT); + break; + case '.': + if (p->g->cflags®_NEWLINE) + nonnewline(p); + else + EMIT(OANY, 0); + break; + case '[': + p_bracket(p); + break; + case '\\': + REQUIRE(MORE(), REG_EESCAPE); + c = GETNEXT(); + ordinary(p, c); + break; + case '{': /* okay as ordinary except if digit follows */ + REQUIRE(!MORE() || !isdigit((uch)PEEK()), REG_BADRPT); + /* FALLTHROUGH */ + default: + ordinary(p, c); + break; + } + + if (!MORE()) + return; + c = PEEK(); + /* we call { a repetition if followed by a digit */ + if (!( c == '*' || c == '+' || c == '?' || + (c == '{' && MORE2() && isdigit((uch)PEEK2())) )) + return; /* no repetition, we're done */ + NEXT(); + + REQUIRE(!wascaret, REG_BADRPT); + switch (c) { + case '*': /* implemented as +? */ + /* this case does not require the (y|) trick, noKLUDGE */ + INSERT(OPLUS_, pos); + ASTERN(O_PLUS, pos); + INSERT(OQUEST_, pos); + ASTERN(O_QUEST, pos); + break; + case '+': + INSERT(OPLUS_, pos); + ASTERN(O_PLUS, pos); + break; + case '?': + /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ + INSERT(OCH_, pos); /* offset slightly wrong */ + ASTERN(OOR1, pos); /* this one's right */ + AHEAD(pos); /* fix the OCH_ */ + EMIT(OOR2, 0); /* offset very wrong... */ + AHEAD(THERE()); /* ...so fix it */ + ASTERN(O_CH, THERETHERE()); + break; + case '{': + count = p_count(p); + if (EAT(',')) { + if (isdigit((uch)PEEK())) { + count2 = p_count(p); + REQUIRE(count <= count2, REG_BADBR); + } else /* single number with comma */ + count2 = INFINITY; + } else /* just a single number */ + count2 = count; + repeat(p, pos, count, count2); + if (!EAT('}')) { /* error heuristics */ + while (MORE() && PEEK() != '}') + NEXT(); + REQUIRE(MORE(), REG_EBRACE); + SETERROR(REG_BADBR); + } + break; + } + + if (!MORE()) + return; + c = PEEK(); + if (!( c == '*' || c == '+' || c == '?' || + (c == '{' && MORE2() && isdigit((uch)PEEK2())) ) ) + return; + SETERROR(REG_BADRPT); +} + +/* + - p_str - string (no metacharacters) "parser" + */ +static void +p_str(struct parse *p) +{ + REQUIRE(MORE(), REG_EMPTY); + while (MORE()) + ordinary(p, GETNEXT()); +} + +/* + - p_bre - BRE parser top level, anchoring and concatenation + * Giving end1 as OUT essentially eliminates the end1/end2 check. + * + * This implementation is a bit of a kludge, in that a trailing $ is first + * taken as an ordinary character and then revised to be an anchor. The + * only undesirable side effect is that '$' gets included as a character + * category in such cases. This is fairly harmless; not worth fixing. + * The amount of lookahead needed to avoid this kludge is excessive. + */ +static void +p_bre(struct parse *p, + int end1, /* first terminating character */ + int end2) /* second terminating character */ +{ + sopno start = HERE(); + int first = 1; /* first subexpression? */ + int wasdollar = 0; + + if (EAT('^')) { + EMIT(OBOL, 0); + p->g->iflags |= USEBOL; + p->g->nbol++; + } + while (MORE() && !SEETWO(end1, end2)) { + wasdollar = p_simp_re(p, first); + first = 0; + } + if (wasdollar) { /* oops, that was a trailing anchor */ + DROP(1); + EMIT(OEOL, 0); + p->g->iflags |= USEEOL; + p->g->neol++; + } + + REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */ +} + +/* + - p_simp_re - parse a simple RE, an atom possibly followed by a repetition + */ +static int /* was the simple RE an unbackslashed $? */ +p_simp_re(struct parse *p, + int starordinary) /* is a leading * an ordinary character? */ +{ + int c; + int count; + int count2; + sopno pos; + int i; + sopno subno; +# define BACKSL (1<<CHAR_BIT) + + pos = HERE(); /* repetion op, if any, covers from here */ + + assert(MORE()); /* caller should have ensured this */ + c = GETNEXT(); + if (c == '\\') { + REQUIRE(MORE(), REG_EESCAPE); + c = BACKSL | GETNEXT(); + } + switch (c) { + case '.': + if (p->g->cflags®_NEWLINE) + nonnewline(p); + else + EMIT(OANY, 0); + break; + case '[': + p_bracket(p); + break; + case BACKSL|'{': + SETERROR(REG_BADRPT); + break; + case BACKSL|'(': + p->g->nsub++; + subno = p->g->nsub; + if (subno < NPAREN) + p->pbegin[subno] = HERE(); + EMIT(OLPAREN, subno); + /* the MORE here is an error heuristic */ + if (MORE() && !SEETWO('\\', ')')) + p_bre(p, '\\', ')'); + if (subno < NPAREN) { + p->pend[subno] = HERE(); + assert(p->pend[subno] != 0); + } + EMIT(ORPAREN, subno); + REQUIRE(EATTWO('\\', ')'), REG_EPAREN); + break; + case BACKSL|')': /* should not get here -- must be user */ + case BACKSL|'}': + SETERROR(REG_EPAREN); + break; + case BACKSL|'1': + case BACKSL|'2': + case BACKSL|'3': + case BACKSL|'4': + case BACKSL|'5': + case BACKSL|'6': + case BACKSL|'7': + case BACKSL|'8': + case BACKSL|'9': + i = (c&~BACKSL) - '0'; + assert(i < NPAREN); + if (p->pend[i] != 0) { + assert(i <= p->g->nsub); + EMIT(OBACK_, i); + assert(p->pbegin[i] != 0); + assert(OP(p->strip[p->pbegin[i]]) == OLPAREN); + assert(OP(p->strip[p->pend[i]]) == ORPAREN); + (void) dupl(p, p->pbegin[i]+1, p->pend[i]); + EMIT(O_BACK, i); + } else + SETERROR(REG_ESUBREG); + p->g->backrefs = 1; + break; + case '*': + REQUIRE(starordinary, REG_BADRPT); + /* FALLTHROUGH */ + default: + ordinary(p, (char)c); + break; + } + + if (EAT('*')) { /* implemented as +? */ + /* this case does not require the (y|) trick, noKLUDGE */ + INSERT(OPLUS_, pos); + ASTERN(O_PLUS, pos); + INSERT(OQUEST_, pos); + ASTERN(O_QUEST, pos); + } else if (EATTWO('\\', '{')) { + count = p_count(p); + if (EAT(',')) { + if (MORE() && isdigit((uch)PEEK())) { + count2 = p_count(p); + REQUIRE(count <= count2, REG_BADBR); + } else /* single number with comma */ + count2 = INFINITY; + } else /* just a single number */ + count2 = count; + repeat(p, pos, count, count2); + if (!EATTWO('\\', '}')) { /* error heuristics */ + while (MORE() && !SEETWO('\\', '}')) + NEXT(); + REQUIRE(MORE(), REG_EBRACE); + SETERROR(REG_BADBR); + } + } else if (c == '$') /* $ (but not \$) ends it */ + return(1); + + return(0); +} + +/* + - p_count - parse a repetition count + */ +static int /* the value */ +p_count(struct parse *p) +{ + int count = 0; + int ndigits = 0; + + while (MORE() && isdigit((uch)PEEK()) && count <= DUPMAX) { + count = count*10 + (GETNEXT() - '0'); + ndigits++; + } + + REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR); + return(count); +} + +/* + - p_bracket - parse a bracketed character list + * + * Note a significant property of this code: if the allocset() did SETERROR, + * no set operations are done. + */ +static void +p_bracket(struct parse *p) +{ + cset *cs; + int invert = 0; + + /* Dept of Truly Sickening Special-Case Kludges */ + if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) { + EMIT(OBOW, 0); + NEXTn(6); + return; + } + if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) { + EMIT(OEOW, 0); + NEXTn(6); + return; + } + + if ((cs = allocset(p)) == NULL) { + /* allocset did set error status in p */ + return; + } + + if (EAT('^')) + invert++; /* make note to invert set at end */ + if (EAT(']')) + CHadd(cs, ']'); + else if (EAT('-')) + CHadd(cs, '-'); + while (MORE() && PEEK() != ']' && !SEETWO('-', ']')) + p_b_term(p, cs); + if (EAT('-')) + CHadd(cs, '-'); + MUSTEAT(']', REG_EBRACK); + + if (p->error != 0) { /* don't mess things up further */ + freeset(p, cs); + return; + } + + if (p->g->cflags®_ICASE) { + int i; + int ci; + + for (i = p->g->csetsize - 1; i >= 0; i--) + if (CHIN(cs, i) && isalpha(i)) { + ci = othercase(i); + if (ci != i) + CHadd(cs, ci); + } + if (cs->multis != NULL) + mccase(p, cs); + } + if (invert) { + int i; + + for (i = p->g->csetsize - 1; i >= 0; i--) + if (CHIN(cs, i)) + CHsub(cs, i); + else + CHadd(cs, i); + if (p->g->cflags®_NEWLINE) + CHsub(cs, '\n'); + if (cs->multis != NULL) + mcinvert(p, cs); + } + + assert(cs->multis == NULL); /* xxx */ + + if (nch(p, cs) == 1) { /* optimize singleton sets */ + ordinary(p, firstch(p, cs)); + freeset(p, cs); + } else + EMIT(OANYOF, freezeset(p, cs)); +} + +/* + - p_b_term - parse one term of a bracketed character list + */ +static void +p_b_term(struct parse *p, cset *cs) +{ + char c; + char start, finish; + int i; + + /* classify what we've got */ + switch ((MORE()) ? PEEK() : '\0') { + case '[': + c = (MORE2()) ? PEEK2() : '\0'; + break; + case '-': + SETERROR(REG_ERANGE); + return; /* NOTE RETURN */ + break; + default: + c = '\0'; + break; + } + + switch (c) { + case ':': /* character class */ + NEXT2(); + REQUIRE(MORE(), REG_EBRACK); + c = PEEK(); + REQUIRE(c != '-' && c != ']', REG_ECTYPE); + p_b_cclass(p, cs); + REQUIRE(MORE(), REG_EBRACK); + REQUIRE(EATTWO(':', ']'), REG_ECTYPE); + break; + case '=': /* equivalence class */ + NEXT2(); + REQUIRE(MORE(), REG_EBRACK); + c = PEEK(); + REQUIRE(c != '-' && c != ']', REG_ECOLLATE); + p_b_eclass(p, cs); + REQUIRE(MORE(), REG_EBRACK); + REQUIRE(EATTWO('=', ']'), REG_ECOLLATE); + break; + default: /* symbol, ordinary character, or range */ +/* xxx revision needed for multichar stuff */ + start = p_b_symbol(p); + if (SEE('-') && MORE2() && PEEK2() != ']') { + /* range */ + NEXT(); + if (EAT('-')) + finish = '-'; + else + finish = p_b_symbol(p); + } else + finish = start; +/* xxx what about signed chars here... */ + REQUIRE(start <= finish, REG_ERANGE); + for (i = start; i <= finish; i++) + CHadd(cs, i); + break; + } +} + +/* + - p_b_cclass - parse a character-class name and deal with it + */ +static void +p_b_cclass(struct parse *p, cset *cs) +{ + char *sp = p->next; + struct cclass *cp; + size_t len; + const char *u; + char c; + + while (MORE() && isalpha((uch)PEEK())) + NEXT(); + len = p->next - sp; + for (cp = cclasses; cp->name != NULL; cp++) + if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0') + break; + if (cp->name == NULL) { + /* oops, didn't find it */ + SETERROR(REG_ECTYPE); + return; + } + + u = cp->chars; + while ((c = *u++) != '\0') + CHadd(cs, c); + for (u = cp->multis; *u != '\0'; u += strlen(u) + 1) + MCadd(p, cs, u); +} + +/* + - p_b_eclass - parse an equivalence-class name and deal with it + * + * This implementation is incomplete. xxx + */ +static void +p_b_eclass(struct parse *p, cset *cs) +{ + char c; + + c = p_b_coll_elem(p, '='); + CHadd(cs, c); +} + +/* + - p_b_symbol - parse a character or [..]ed multicharacter collating symbol + */ +static char /* value of symbol */ +p_b_symbol(struct parse *p) +{ + char value; + + REQUIRE(MORE(), REG_EBRACK); + if (!EATTWO('[', '.')) + return(GETNEXT()); + + /* collating symbol */ + value = p_b_coll_elem(p, '.'); + REQUIRE(EATTWO('.', ']'), REG_ECOLLATE); + return(value); +} + +/* + - p_b_coll_elem - parse a collating-element name and look it up + */ +static char /* value of collating element */ +p_b_coll_elem(struct parse *p, + int endc) /* name ended by endc,']' */ +{ + char *sp = p->next; + struct cname *cp; + int len; + + while (MORE() && !SEETWO(endc, ']')) + NEXT(); + if (!MORE()) { + SETERROR(REG_EBRACK); + return(0); + } + len = p->next - sp; + for (cp = cnames; cp->name != NULL; cp++) + if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0') + return(cp->code); /* known name */ + if (len == 1) + return(*sp); /* single character */ + SETERROR(REG_ECOLLATE); /* neither */ + return(0); +} + +/* + - othercase - return the case counterpart of an alphabetic + */ +static char /* if no counterpart, return ch */ +othercase(int ch) +{ + ch = (uch)ch; + assert(isalpha(ch)); + if (isupper(ch)) + return ((uch)tolower(ch)); + else if (islower(ch)) + return ((uch)toupper(ch)); + else /* peculiar, but could happen */ + return(ch); +} + +/* + - bothcases - emit a dualcase version of a two-case character + * + * Boy, is this implementation ever a kludge... + */ +static void +bothcases(struct parse *p, int ch) +{ + char *oldnext = p->next; + char *oldend = p->end; + char bracket[3]; + + ch = (uch)ch; + assert(othercase(ch) != ch); /* p_bracket() would recurse */ + p->next = bracket; + p->end = bracket+2; + bracket[0] = ch; + bracket[1] = ']'; + bracket[2] = '\0'; + p_bracket(p); + assert(p->next == bracket+2); + p->next = oldnext; + p->end = oldend; +} + +/* + - ordinary - emit an ordinary character + */ +static void +ordinary(struct parse *p, int ch) +{ + cat_t *cap = p->g->categories; + + if ((p->g->cflags®_ICASE) && isalpha((uch)ch) && othercase(ch) != ch) + bothcases(p, ch); + else { + EMIT(OCHAR, (uch)ch); + if (cap[ch] == 0) + cap[ch] = p->g->ncategories++; + } +} + +/* + - nonnewline - emit REG_NEWLINE version of OANY + * + * Boy, is this implementation ever a kludge... + */ +static void +nonnewline(struct parse *p) +{ + char *oldnext = p->next; + char *oldend = p->end; + char bracket[4]; + + p->next = bracket; + p->end = bracket+3; + bracket[0] = '^'; + bracket[1] = '\n'; + bracket[2] = ']'; + bracket[3] = '\0'; + p_bracket(p); + assert(p->next == bracket+3); + p->next = oldnext; + p->end = oldend; +} + +/* + - repeat - generate code for a bounded repetition, recursively if needed + */ +static void +repeat(struct parse *p, + sopno start, /* operand from here to end of strip */ + int from, /* repeated from this number */ + int to) /* to this number of times (maybe INFINITY) */ +{ + sopno finish = HERE(); +# define N 2 +# define INF 3 +# define REP(f, t) ((f)*8 + (t)) +# define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N) + sopno copy; + + if (p->error != 0) /* head off possible runaway recursion */ + return; + + assert(from <= to); + + switch (REP(MAP(from), MAP(to))) { + case REP(0, 0): /* must be user doing this */ + DROP(finish-start); /* drop the operand */ + break; + case REP(0, 1): /* as x{1,1}? */ + case REP(0, N): /* as x{1,n}? */ + case REP(0, INF): /* as x{1,}? */ + /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ + INSERT(OCH_, start); /* offset is wrong... */ + repeat(p, start+1, 1, to); + ASTERN(OOR1, start); + AHEAD(start); /* ... fix it */ + EMIT(OOR2, 0); + AHEAD(THERE()); + ASTERN(O_CH, THERETHERE()); + break; + case REP(1, 1): /* trivial case */ + /* done */ + break; + case REP(1, N): /* as x?x{1,n-1} */ + /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ + INSERT(OCH_, start); + ASTERN(OOR1, start); + AHEAD(start); + EMIT(OOR2, 0); /* offset very wrong... */ + AHEAD(THERE()); /* ...so fix it */ + ASTERN(O_CH, THERETHERE()); + copy = dupl(p, start+1, finish+1); + assert(copy == finish+4); + repeat(p, copy, 1, to-1); + break; + case REP(1, INF): /* as x+ */ + INSERT(OPLUS_, start); + ASTERN(O_PLUS, start); + break; + case REP(N, N): /* as xx{m-1,n-1} */ + copy = dupl(p, start, finish); + repeat(p, copy, from-1, to-1); + break; + case REP(N, INF): /* as xx{n-1,INF} */ + copy = dupl(p, start, finish); + repeat(p, copy, from-1, to); + break; + default: /* "can't happen" */ + SETERROR(REG_ASSERT); /* just in case */ + break; + } +} + +/* + - seterr - set an error condition + */ +static int /* useless but makes type checking happy */ +seterr(struct parse *p, int e) +{ + if (p->error == 0) /* keep earliest error condition */ + p->error = e; + p->next = nuls; /* try to bring things to a halt */ + p->end = nuls; + return(0); /* make the return value well-defined */ +} + +/* + - allocset - allocate a set of characters for [] + */ +static cset * +allocset(struct parse *p) +{ + int no = p->g->ncsets++; + size_t nc; + size_t nbytes; + cset *cs; + size_t css = (size_t)p->g->csetsize; + int i; + + if (no >= p->ncsalloc) { /* need another column of space */ + void *ptr; + + p->ncsalloc += CHAR_BIT; + nc = p->ncsalloc; + assert(nc % CHAR_BIT == 0); + nbytes = nc / CHAR_BIT * css; + + ptr = (cset *)realloc((char *)p->g->sets, nc * sizeof(cset)); + if (ptr == NULL) + goto nomem; + p->g->sets = ptr; + + ptr = (uch *)realloc((char *)p->g->setbits, nbytes); + if (ptr == NULL) + goto nomem; + p->g->setbits = ptr; + + for (i = 0; i < no; i++) + p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT); + + (void) memset((char *)p->g->setbits + (nbytes - css), 0, css); + } + /* XXX should not happen */ + if (p->g->sets == NULL || p->g->setbits == NULL) + goto nomem; + + cs = &p->g->sets[no]; + cs->ptr = p->g->setbits + css*((no)/CHAR_BIT); + cs->mask = 1 << ((no) % CHAR_BIT); + cs->hash = 0; + cs->smultis = 0; + cs->multis = NULL; + + return(cs); +nomem: + free(p->g->sets); + p->g->sets = NULL; + free(p->g->setbits); + p->g->setbits = NULL; + + SETERROR(REG_ESPACE); + /* caller's responsibility not to do set ops */ + return(NULL); +} + +/* + - freeset - free a now-unused set + */ +static void +freeset(struct parse *p, cset *cs) +{ + size_t i; + cset *top = &p->g->sets[p->g->ncsets]; + size_t css = (size_t)p->g->csetsize; + + for (i = 0; i < css; i++) + CHsub(cs, i); + if (cs == top-1) /* recover only the easy case */ + p->g->ncsets--; +} + +/* + - freezeset - final processing on a set of characters + * + * The main task here is merging identical sets. This is usually a waste + * of time (although the hash code minimizes the overhead), but can win + * big if REG_ICASE is being used. REG_ICASE, by the way, is why the hash + * is done using addition rather than xor -- all ASCII [aA] sets xor to + * the same value! + */ +static int /* set number */ +freezeset(struct parse *p, cset *cs) +{ + uch h = cs->hash; + size_t i; + cset *top = &p->g->sets[p->g->ncsets]; + cset *cs2; + size_t css = (size_t)p->g->csetsize; + + /* look for an earlier one which is the same */ + for (cs2 = &p->g->sets[0]; cs2 < top; cs2++) + if (cs2->hash == h && cs2 != cs) { + /* maybe */ + for (i = 0; i < css; i++) + if (!!CHIN(cs2, i) != !!CHIN(cs, i)) + break; /* no */ + if (i == css) + break; /* yes */ + } + + if (cs2 < top) { /* found one */ + freeset(p, cs); + cs = cs2; + } + + return((int)(cs - p->g->sets)); +} + +/* + - firstch - return first character in a set (which must have at least one) + */ +static int /* character; there is no "none" value */ +firstch(struct parse *p, cset *cs) +{ + size_t i; + size_t css = (size_t)p->g->csetsize; + + for (i = 0; i < css; i++) + if (CHIN(cs, i)) + return((char)i); + assert(never); + return(0); /* arbitrary */ +} + +/* + - nch - number of characters in a set + */ +static int +nch(struct parse *p, cset *cs) +{ + size_t i; + size_t css = (size_t)p->g->csetsize; + int n = 0; + + for (i = 0; i < css; i++) + if (CHIN(cs, i)) + n++; + return(n); +} + +/* + - mcadd - add a collating element to a cset + */ +static void +mcadd( struct parse *p, cset *cs, const char *cp) +{ + size_t oldend = cs->smultis; + void *np; + + cs->smultis += strlen(cp) + 1; + np = realloc(cs->multis, cs->smultis); + if (np == NULL) { + if (cs->multis) + free(cs->multis); + cs->multis = NULL; + SETERROR(REG_ESPACE); + return; + } + cs->multis = np; + + llvm_strlcpy(cs->multis + oldend - 1, cp, cs->smultis - oldend + 1); +} + +/* + - mcinvert - invert the list of collating elements in a cset + * + * This would have to know the set of possibilities. Implementation + * is deferred. + */ +/* ARGSUSED */ +static void +mcinvert(struct parse *p, cset *cs) +{ + assert(cs->multis == NULL); /* xxx */ +} + +/* + - mccase - add case counterparts of the list of collating elements in a cset + * + * This would have to know the set of possibilities. Implementation + * is deferred. + */ +/* ARGSUSED */ +static void +mccase(struct parse *p, cset *cs) +{ + assert(cs->multis == NULL); /* xxx */ +} + +/* + - isinsets - is this character in any sets? + */ +static int /* predicate */ +isinsets(struct re_guts *g, int c) +{ + uch *col; + int i; + int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT; + unsigned uc = (uch)c; + + for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize) + if (col[uc] != 0) + return(1); + return(0); +} + +/* + - samesets - are these two characters in exactly the same sets? + */ +static int /* predicate */ +samesets(struct re_guts *g, int c1, int c2) +{ + uch *col; + int i; + int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT; + unsigned uc1 = (uch)c1; + unsigned uc2 = (uch)c2; + + for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize) + if (col[uc1] != col[uc2]) + return(0); + return(1); +} + +/* + - categorize - sort out character categories + */ +static void +categorize(struct parse *p, struct re_guts *g) +{ + cat_t *cats = g->categories; + int c; + int c2; + cat_t cat; + + /* avoid making error situations worse */ + if (p->error != 0) + return; + + for (c = CHAR_MIN; c <= CHAR_MAX; c++) + if (cats[c] == 0 && isinsets(g, c)) { + cat = g->ncategories++; + cats[c] = cat; + for (c2 = c+1; c2 <= CHAR_MAX; c2++) + if (cats[c2] == 0 && samesets(g, c, c2)) + cats[c2] = cat; + } +} + +/* + - dupl - emit a duplicate of a bunch of sops + */ +static sopno /* start of duplicate */ +dupl(struct parse *p, + sopno start, /* from here */ + sopno finish) /* to this less one */ +{ + sopno ret = HERE(); + sopno len = finish - start; + + assert(finish >= start); + if (len == 0) + return(ret); + enlarge(p, p->ssize + len); /* this many unexpected additions */ + assert(p->ssize >= p->slen + len); + (void) memmove((char *)(p->strip + p->slen), + (char *)(p->strip + start), (size_t)len*sizeof(sop)); + p->slen += len; + return(ret); +} + +/* + - doemit - emit a strip operator + * + * It might seem better to implement this as a macro with a function as + * hard-case backup, but it's just too big and messy unless there are + * some changes to the data structures. Maybe later. + */ +static void +doemit(struct parse *p, sop op, size_t opnd) +{ + /* avoid making error situations worse */ + if (p->error != 0) + return; + + /* deal with oversize operands ("can't happen", more or less) */ + assert(opnd < 1<<OPSHIFT); + + /* deal with undersized strip */ + if (p->slen >= p->ssize) + enlarge(p, (p->ssize+1) / 2 * 3); /* +50% */ + assert(p->slen < p->ssize); + + /* finally, it's all reduced to the easy case */ + p->strip[p->slen++] = SOP(op, opnd); +} + +/* + - doinsert - insert a sop into the strip + */ +static void +doinsert(struct parse *p, sop op, size_t opnd, sopno pos) +{ + sopno sn; + sop s; + int i; + + /* avoid making error situations worse */ + if (p->error != 0) + return; + + sn = HERE(); + EMIT(op, opnd); /* do checks, ensure space */ + assert(HERE() == sn+1); + s = p->strip[sn]; + + /* adjust paren pointers */ + assert(pos > 0); + for (i = 1; i < NPAREN; i++) { + if (p->pbegin[i] >= pos) { + p->pbegin[i]++; + } + if (p->pend[i] >= pos) { + p->pend[i]++; + } + } + + memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos], + (HERE()-pos-1)*sizeof(sop)); + p->strip[pos] = s; +} + +/* + - dofwd - complete a forward reference + */ +static void +dofwd(struct parse *p, sopno pos, sop value) +{ + /* avoid making error situations worse */ + if (p->error != 0) + return; + + assert(value < 1<<OPSHIFT); + p->strip[pos] = OP(p->strip[pos]) | value; +} + +/* + - enlarge - enlarge the strip + */ +static void +enlarge(struct parse *p, sopno size) +{ + sop *sp; + + if (p->ssize >= size) + return; + + sp = (sop *)realloc(p->strip, size*sizeof(sop)); + if (sp == NULL) { + SETERROR(REG_ESPACE); + return; + } + p->strip = sp; + p->ssize = size; +} + +/* + - stripsnug - compact the strip + */ +static void +stripsnug(struct parse *p, struct re_guts *g) +{ + g->nstates = p->slen; + g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop)); + if (g->strip == NULL) { + SETERROR(REG_ESPACE); + g->strip = p->strip; + } +} + +/* + - findmust - fill in must and mlen with longest mandatory literal string + * + * This algorithm could do fancy things like analyzing the operands of | + * for common subsequences. Someday. This code is simple and finds most + * of the interesting cases. + * + * Note that must and mlen got initialized during setup. + */ +static void +findmust(struct parse *p, struct re_guts *g) +{ + sop *scan; + sop *start = 0; /* start initialized in the default case, after that */ + sop *newstart = 0; /* newstart was initialized in the OCHAR case */ + sopno newlen; + sop s; + char *cp; + sopno i; + + /* avoid making error situations worse */ + if (p->error != 0) + return; + + /* find the longest OCHAR sequence in strip */ + newlen = 0; + scan = g->strip + 1; + do { + s = *scan++; + switch (OP(s)) { + case OCHAR: /* sequence member */ + if (newlen == 0) /* new sequence */ + newstart = scan - 1; + newlen++; + break; + case OPLUS_: /* things that don't break one */ + case OLPAREN: + case ORPAREN: + break; + case OQUEST_: /* things that must be skipped */ + case OCH_: + scan--; + do { + scan += OPND(s); + s = *scan; + /* assert() interferes w debug printouts */ + if (OP(s) != O_QUEST && OP(s) != O_CH && + OP(s) != OOR2) { + g->iflags |= REGEX_BAD; + return; + } + } while (OP(s) != O_QUEST && OP(s) != O_CH); + /* fallthrough */ + default: /* things that break a sequence */ + if (newlen > g->mlen) { /* ends one */ + start = newstart; + g->mlen = newlen; + } + newlen = 0; + break; + } + } while (OP(s) != OEND); + + if (g->mlen == 0) /* there isn't one */ + return; + + /* turn it into a character string */ + g->must = malloc((size_t)g->mlen + 1); + if (g->must == NULL) { /* argh; just forget it */ + g->mlen = 0; + return; + } + cp = g->must; + scan = start; + for (i = g->mlen; i > 0; i--) { + while (OP(s = *scan++) != OCHAR) + continue; + assert(cp < g->must + g->mlen); + *cp++ = (char)OPND(s); + } + assert(cp == g->must + g->mlen); + *cp++ = '\0'; /* just on general principles */ +} + +/* + - pluscount - count + nesting + */ +static sopno /* nesting depth */ +pluscount(struct parse *p, struct re_guts *g) +{ + sop *scan; + sop s; + sopno plusnest = 0; + sopno maxnest = 0; + + if (p->error != 0) + return(0); /* there may not be an OEND */ + + scan = g->strip + 1; + do { + s = *scan++; + switch (OP(s)) { + case OPLUS_: + plusnest++; + break; + case O_PLUS: + if (plusnest > maxnest) + maxnest = plusnest; + plusnest--; + break; + } + } while (OP(s) != OEND); + if (plusnest != 0) + g->iflags |= REGEX_BAD; + return(maxnest); +} diff --git a/contrib/llvm/lib/Support/regengine.inc b/contrib/llvm/lib/Support/regengine.inc new file mode 100644 index 0000000..7e41f96 --- /dev/null +++ b/contrib/llvm/lib/Support/regengine.inc @@ -0,0 +1,1034 @@ +/*- + * This code is derived from OpenBSD's libc/regex, original license follows: + * + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)engine.c 8.5 (Berkeley) 3/20/94 + */ + +/* + * The matching engine and friends. This file is #included by regexec.c + * after suitable #defines of a variety of macros used herein, so that + * different state representations can be used without duplicating masses + * of code. + */ + +#ifdef SNAMES +#define matcher smatcher +#define fast sfast +#define slow sslow +#define dissect sdissect +#define backref sbackref +#define step sstep +#define print sprint +#define at sat +#define match smat +#define nope snope +#endif +#ifdef LNAMES +#define matcher lmatcher +#define fast lfast +#define slow lslow +#define dissect ldissect +#define backref lbackref +#define step lstep +#define print lprint +#define at lat +#define match lmat +#define nope lnope +#endif + +/* another structure passed up and down to avoid zillions of parameters */ +struct match { + struct re_guts *g; + int eflags; + llvm_regmatch_t *pmatch; /* [nsub+1] (0 element unused) */ + const char *offp; /* offsets work from here */ + const char *beginp; /* start of string -- virtual NUL precedes */ + const char *endp; /* end of string -- virtual NUL here */ + const char *coldp; /* can be no match starting before here */ + const char **lastpos; /* [nplus+1] */ + STATEVARS; + states st; /* current states */ + states fresh; /* states for a fresh start */ + states tmp; /* temporary */ + states empty; /* empty set of states */ +}; + +static int matcher(struct re_guts *, const char *, size_t, + llvm_regmatch_t[], int); +static const char *dissect(struct match *, const char *, const char *, sopno, + sopno); +static const char *backref(struct match *, const char *, const char *, sopno, + sopno, sopno, int); +static const char *fast(struct match *, const char *, const char *, sopno, sopno); +static const char *slow(struct match *, const char *, const char *, sopno, sopno); +static states step(struct re_guts *, sopno, sopno, states, int, states); +#define MAX_RECURSION 100 +#define BOL (OUT+1) +#define EOL (BOL+1) +#define BOLEOL (BOL+2) +#define NOTHING (BOL+3) +#define BOW (BOL+4) +#define EOW (BOL+5) +#define CODEMAX (BOL+5) /* highest code used */ +#define NONCHAR(c) ((c) > CHAR_MAX) +#define NNONCHAR (CODEMAX-CHAR_MAX) +#ifdef REDEBUG +static void print(struct match *, char *, states, int, FILE *); +#endif +#ifdef REDEBUG +static void at(struct match *, char *, char *, char *, sopno, sopno); +#endif +#ifdef REDEBUG +static char *pchar(int); +#endif + +#ifdef REDEBUG +#define SP(t, s, c) print(m, t, s, c, stdout) +#define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2) +#define NOTE(str) { if (m->eflags®_TRACE) (void)printf("=%s\n", (str)); } +static int nope = 0; +#else +#define SP(t, s, c) /* nothing */ +#define AT(t, p1, p2, s1, s2) /* nothing */ +#define NOTE(s) /* nothing */ +#endif + +/* + - matcher - the actual matching engine + */ +static int /* 0 success, REG_NOMATCH failure */ +matcher(struct re_guts *g, const char *string, size_t nmatch, + llvm_regmatch_t pmatch[], + int eflags) +{ + const char *endp; + size_t i; + struct match mv; + struct match *m = &mv; + const char *dp; + const sopno gf = g->firststate+1; /* +1 for OEND */ + const sopno gl = g->laststate; + const char *start; + const char *stop; + + /* simplify the situation where possible */ + if (g->cflags®_NOSUB) + nmatch = 0; + if (eflags®_STARTEND) { + start = string + pmatch[0].rm_so; + stop = string + pmatch[0].rm_eo; + } else { + start = string; + stop = start + strlen(start); + } + if (stop < start) + return(REG_INVARG); + + /* prescreening; this does wonders for this rather slow code */ + if (g->must != NULL) { + for (dp = start; dp < stop; dp++) + if (*dp == g->must[0] && stop - dp >= g->mlen && + memcmp(dp, g->must, (size_t)g->mlen) == 0) + break; + if (dp == stop) /* we didn't find g->must */ + return(REG_NOMATCH); + } + + /* match struct setup */ + m->g = g; + m->eflags = eflags; + m->pmatch = NULL; + m->lastpos = NULL; + m->offp = string; + m->beginp = start; + m->endp = stop; + STATESETUP(m, 4); + SETUP(m->st); + SETUP(m->fresh); + SETUP(m->tmp); + SETUP(m->empty); + CLEAR(m->empty); + + /* this loop does only one repetition except for backrefs */ + for (;;) { + endp = fast(m, start, stop, gf, gl); + if (endp == NULL) { /* a miss */ + free(m->pmatch); + free((void*)m->lastpos); + STATETEARDOWN(m); + return(REG_NOMATCH); + } + if (nmatch == 0 && !g->backrefs) + break; /* no further info needed */ + + /* where? */ + assert(m->coldp != NULL); + for (;;) { + NOTE("finding start"); + endp = slow(m, m->coldp, stop, gf, gl); + if (endp != NULL) + break; + assert(m->coldp < m->endp); + m->coldp++; + } + if (nmatch == 1 && !g->backrefs) + break; /* no further info needed */ + + /* oh my, he wants the subexpressions... */ + if (m->pmatch == NULL) + m->pmatch = (llvm_regmatch_t *)malloc((m->g->nsub + 1) * + sizeof(llvm_regmatch_t)); + if (m->pmatch == NULL) { + STATETEARDOWN(m); + return(REG_ESPACE); + } + for (i = 1; i <= m->g->nsub; i++) + m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1; + if (!g->backrefs && !(m->eflags®_BACKR)) { + NOTE("dissecting"); + dp = dissect(m, m->coldp, endp, gf, gl); + } else { + if (g->nplus > 0 && m->lastpos == NULL) + m->lastpos = (const char **)malloc((g->nplus+1) * + sizeof(char *)); + if (g->nplus > 0 && m->lastpos == NULL) { + free(m->pmatch); + STATETEARDOWN(m); + return(REG_ESPACE); + } + NOTE("backref dissect"); + dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0); + } + if (dp != NULL) + break; + + /* uh-oh... we couldn't find a subexpression-level match */ + assert(g->backrefs); /* must be back references doing it */ + assert(g->nplus == 0 || m->lastpos != NULL); + for (;;) { + if (dp != NULL || endp <= m->coldp) + break; /* defeat */ + NOTE("backoff"); + endp = slow(m, m->coldp, endp-1, gf, gl); + if (endp == NULL) + break; /* defeat */ + /* try it on a shorter possibility */ +#ifndef NDEBUG + for (i = 1; i <= m->g->nsub; i++) { + assert(m->pmatch[i].rm_so == -1); + assert(m->pmatch[i].rm_eo == -1); + } +#endif + NOTE("backoff dissect"); + dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0); + } + assert(dp == NULL || dp == endp); + if (dp != NULL) /* found a shorter one */ + break; + + /* despite initial appearances, there is no match here */ + NOTE("false alarm"); + if (m->coldp == stop) + break; + start = m->coldp + 1; /* recycle starting later */ + } + + /* fill in the details if requested */ + if (nmatch > 0) { + pmatch[0].rm_so = m->coldp - m->offp; + pmatch[0].rm_eo = endp - m->offp; + } + if (nmatch > 1) { + assert(m->pmatch != NULL); + for (i = 1; i < nmatch; i++) + if (i <= m->g->nsub) + pmatch[i] = m->pmatch[i]; + else { + pmatch[i].rm_so = -1; + pmatch[i].rm_eo = -1; + } + } + + if (m->pmatch != NULL) + free((char *)m->pmatch); + if (m->lastpos != NULL) + free((char *)m->lastpos); + STATETEARDOWN(m); + return(0); +} + +/* + - dissect - figure out what matched what, no back references + */ +static const char * /* == stop (success) always */ +dissect(struct match *m, const char *start, const char *stop, sopno startst, + sopno stopst) +{ + int i; + sopno ss; /* start sop of current subRE */ + sopno es; /* end sop of current subRE */ + const char *sp; /* start of string matched by it */ + const char *stp; /* string matched by it cannot pass here */ + const char *rest; /* start of rest of string */ + const char *tail; /* string unmatched by rest of RE */ + sopno ssub; /* start sop of subsubRE */ + sopno esub; /* end sop of subsubRE */ + const char *ssp; /* start of string matched by subsubRE */ + const char *sep; /* end of string matched by subsubRE */ + const char *oldssp; /* previous ssp */ + + AT("diss", start, stop, startst, stopst); + sp = start; + for (ss = startst; ss < stopst; ss = es) { + /* identify end of subRE */ + es = ss; + switch (OP(m->g->strip[es])) { + case OPLUS_: + case OQUEST_: + es += OPND(m->g->strip[es]); + break; + case OCH_: + while (OP(m->g->strip[es]) != O_CH) + es += OPND(m->g->strip[es]); + break; + } + es++; + + /* figure out what it matched */ + switch (OP(m->g->strip[ss])) { + case OEND: + assert(nope); + break; + case OCHAR: + sp++; + break; + case OBOL: + case OEOL: + case OBOW: + case OEOW: + break; + case OANY: + case OANYOF: + sp++; + break; + case OBACK_: + case O_BACK: + assert(nope); + break; + /* cases where length of match is hard to find */ + case OQUEST_: + stp = stop; + for (;;) { + /* how long could this one be? */ + rest = slow(m, sp, stp, ss, es); + assert(rest != NULL); /* it did match */ + /* could the rest match the rest? */ + tail = slow(m, rest, stop, es, stopst); + if (tail == stop) + break; /* yes! */ + /* no -- try a shorter match for this one */ + stp = rest - 1; + assert(stp >= sp); /* it did work */ + } + ssub = ss + 1; + esub = es - 1; + /* did innards match? */ + if (slow(m, sp, rest, ssub, esub) != NULL) { + const char *dp = dissect(m, sp, rest, ssub, esub); + (void)dp; /* avoid warning if assertions off */ + assert(dp == rest); + } else /* no */ + assert(sp == rest); + sp = rest; + break; + case OPLUS_: + stp = stop; + for (;;) { + /* how long could this one be? */ + rest = slow(m, sp, stp, ss, es); + assert(rest != NULL); /* it did match */ + /* could the rest match the rest? */ + tail = slow(m, rest, stop, es, stopst); + if (tail == stop) + break; /* yes! */ + /* no -- try a shorter match for this one */ + stp = rest - 1; + assert(stp >= sp); /* it did work */ + } + ssub = ss + 1; + esub = es - 1; + ssp = sp; + oldssp = ssp; + for (;;) { /* find last match of innards */ + sep = slow(m, ssp, rest, ssub, esub); + if (sep == NULL || sep == ssp) + break; /* failed or matched null */ + oldssp = ssp; /* on to next try */ + ssp = sep; + } + if (sep == NULL) { + /* last successful match */ + sep = ssp; + ssp = oldssp; + } + assert(sep == rest); /* must exhaust substring */ + assert(slow(m, ssp, sep, ssub, esub) == rest); + { + const char *dp = dissect(m, ssp, sep, ssub, esub); + (void)dp; /* avoid warning if assertions off */ + assert(dp == sep); + } + sp = rest; + break; + case OCH_: + stp = stop; + for (;;) { + /* how long could this one be? */ + rest = slow(m, sp, stp, ss, es); + assert(rest != NULL); /* it did match */ + /* could the rest match the rest? */ + tail = slow(m, rest, stop, es, stopst); + if (tail == stop) + break; /* yes! */ + /* no -- try a shorter match for this one */ + stp = rest - 1; + assert(stp >= sp); /* it did work */ + } + ssub = ss + 1; + esub = ss + OPND(m->g->strip[ss]) - 1; + assert(OP(m->g->strip[esub]) == OOR1); + for (;;) { /* find first matching branch */ + if (slow(m, sp, rest, ssub, esub) == rest) + break; /* it matched all of it */ + /* that one missed, try next one */ + assert(OP(m->g->strip[esub]) == OOR1); + esub++; + assert(OP(m->g->strip[esub]) == OOR2); + ssub = esub + 1; + esub += OPND(m->g->strip[esub]); + if (OP(m->g->strip[esub]) == OOR2) + esub--; + else + assert(OP(m->g->strip[esub]) == O_CH); + } + { + const char *dp = dissect(m, sp, rest, ssub, esub); + (void)dp; /* avoid warning if assertions off */ + assert(dp == rest); + } + sp = rest; + break; + case O_PLUS: + case O_QUEST: + case OOR1: + case OOR2: + case O_CH: + assert(nope); + break; + case OLPAREN: + i = OPND(m->g->strip[ss]); + assert(0 < i && i <= m->g->nsub); + m->pmatch[i].rm_so = sp - m->offp; + break; + case ORPAREN: + i = OPND(m->g->strip[ss]); + assert(0 < i && i <= m->g->nsub); + m->pmatch[i].rm_eo = sp - m->offp; + break; + default: /* uh oh */ + assert(nope); + break; + } + } + + assert(sp == stop); + return(sp); +} + +/* + - backref - figure out what matched what, figuring in back references + */ +static const char * /* == stop (success) or NULL (failure) */ +backref(struct match *m, const char *start, const char *stop, sopno startst, + sopno stopst, sopno lev, int rec) /* PLUS nesting level */ +{ + int i; + sopno ss; /* start sop of current subRE */ + const char *sp; /* start of string matched by it */ + sopno ssub; /* start sop of subsubRE */ + sopno esub; /* end sop of subsubRE */ + const char *ssp; /* start of string matched by subsubRE */ + const char *dp; + size_t len; + int hard; + sop s; + llvm_regoff_t offsave; + cset *cs; + + AT("back", start, stop, startst, stopst); + sp = start; + + /* get as far as we can with easy stuff */ + hard = 0; + for (ss = startst; !hard && ss < stopst; ss++) + switch (OP(s = m->g->strip[ss])) { + case OCHAR: + if (sp == stop || *sp++ != (char)OPND(s)) + return(NULL); + break; + case OANY: + if (sp == stop) + return(NULL); + sp++; + break; + case OANYOF: + cs = &m->g->sets[OPND(s)]; + if (sp == stop || !CHIN(cs, *sp++)) + return(NULL); + break; + case OBOL: + if ( (sp == m->beginp && !(m->eflags®_NOTBOL)) || + (sp < m->endp && *(sp-1) == '\n' && + (m->g->cflags®_NEWLINE)) ) + { /* yes */ } + else + return(NULL); + break; + case OEOL: + if ( (sp == m->endp && !(m->eflags®_NOTEOL)) || + (sp < m->endp && *sp == '\n' && + (m->g->cflags®_NEWLINE)) ) + { /* yes */ } + else + return(NULL); + break; + case OBOW: + if (( (sp == m->beginp && !(m->eflags®_NOTBOL)) || + (sp < m->endp && *(sp-1) == '\n' && + (m->g->cflags®_NEWLINE)) || + (sp > m->beginp && + !ISWORD(*(sp-1))) ) && + (sp < m->endp && ISWORD(*sp)) ) + { /* yes */ } + else + return(NULL); + break; + case OEOW: + if (( (sp == m->endp && !(m->eflags®_NOTEOL)) || + (sp < m->endp && *sp == '\n' && + (m->g->cflags®_NEWLINE)) || + (sp < m->endp && !ISWORD(*sp)) ) && + (sp > m->beginp && ISWORD(*(sp-1))) ) + { /* yes */ } + else + return(NULL); + break; + case O_QUEST: + break; + case OOR1: /* matches null but needs to skip */ + ss++; + s = m->g->strip[ss]; + do { + assert(OP(s) == OOR2); + ss += OPND(s); + } while (OP(s = m->g->strip[ss]) != O_CH); + /* note that the ss++ gets us past the O_CH */ + break; + default: /* have to make a choice */ + hard = 1; + break; + } + if (!hard) { /* that was it! */ + if (sp != stop) + return(NULL); + return(sp); + } + ss--; /* adjust for the for's final increment */ + + /* the hard stuff */ + AT("hard", sp, stop, ss, stopst); + s = m->g->strip[ss]; + switch (OP(s)) { + case OBACK_: /* the vilest depths */ + i = OPND(s); + assert(0 < i && i <= m->g->nsub); + if (m->pmatch[i].rm_eo == -1) + return(NULL); + assert(m->pmatch[i].rm_so != -1); + len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so; + if (len == 0 && rec++ > MAX_RECURSION) + return(NULL); + assert(stop - m->beginp >= len); + if (sp > stop - len) + return(NULL); /* not enough left to match */ + ssp = m->offp + m->pmatch[i].rm_so; + if (memcmp(sp, ssp, len) != 0) + return(NULL); + while (m->g->strip[ss] != SOP(O_BACK, i)) + ss++; + return(backref(m, sp+len, stop, ss+1, stopst, lev, rec)); + break; + case OQUEST_: /* to null or not */ + dp = backref(m, sp, stop, ss+1, stopst, lev, rec); + if (dp != NULL) + return(dp); /* not */ + return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev, rec)); + break; + case OPLUS_: + assert(m->lastpos != NULL); + assert(lev+1 <= m->g->nplus); + m->lastpos[lev+1] = sp; + return(backref(m, sp, stop, ss+1, stopst, lev+1, rec)); + break; + case O_PLUS: + if (sp == m->lastpos[lev]) /* last pass matched null */ + return(backref(m, sp, stop, ss+1, stopst, lev-1, rec)); + /* try another pass */ + m->lastpos[lev] = sp; + dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev, rec); + if (dp == NULL) + return(backref(m, sp, stop, ss+1, stopst, lev-1, rec)); + else + return(dp); + break; + case OCH_: /* find the right one, if any */ + ssub = ss + 1; + esub = ss + OPND(s) - 1; + assert(OP(m->g->strip[esub]) == OOR1); + for (;;) { /* find first matching branch */ + dp = backref(m, sp, stop, ssub, esub, lev, rec); + if (dp != NULL) + return(dp); + /* that one missed, try next one */ + if (OP(m->g->strip[esub]) == O_CH) + return(NULL); /* there is none */ + esub++; + assert(OP(m->g->strip[esub]) == OOR2); + ssub = esub + 1; + esub += OPND(m->g->strip[esub]); + if (OP(m->g->strip[esub]) == OOR2) + esub--; + else + assert(OP(m->g->strip[esub]) == O_CH); + } + break; + case OLPAREN: /* must undo assignment if rest fails */ + i = OPND(s); + assert(0 < i && i <= m->g->nsub); + offsave = m->pmatch[i].rm_so; + m->pmatch[i].rm_so = sp - m->offp; + dp = backref(m, sp, stop, ss+1, stopst, lev, rec); + if (dp != NULL) + return(dp); + m->pmatch[i].rm_so = offsave; + return(NULL); + break; + case ORPAREN: /* must undo assignment if rest fails */ + i = OPND(s); + assert(0 < i && i <= m->g->nsub); + offsave = m->pmatch[i].rm_eo; + m->pmatch[i].rm_eo = sp - m->offp; + dp = backref(m, sp, stop, ss+1, stopst, lev, rec); + if (dp != NULL) + return(dp); + m->pmatch[i].rm_eo = offsave; + return(NULL); + break; + default: /* uh oh */ + assert(nope); + break; + } + + /* "can't happen" */ + assert(nope); + /* NOTREACHED */ + return NULL; +} + +/* + - fast - step through the string at top speed + */ +static const char * /* where tentative match ended, or NULL */ +fast(struct match *m, const char *start, const char *stop, sopno startst, + sopno stopst) +{ + states st = m->st; + states fresh = m->fresh; + states tmp = m->tmp; + const char *p = start; + int c = (start == m->beginp) ? OUT : *(start-1); + int lastc; /* previous c */ + int flagch; + int i; + const char *coldp; /* last p after which no match was underway */ + + CLEAR(st); + SET1(st, startst); + st = step(m->g, startst, stopst, st, NOTHING, st); + ASSIGN(fresh, st); + SP("start", st, *p); + coldp = NULL; + for (;;) { + /* next character */ + lastc = c; + c = (p == m->endp) ? OUT : *p; + if (EQ(st, fresh)) + coldp = p; + + /* is there an EOL and/or BOL between lastc and c? */ + flagch = '\0'; + i = 0; + if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || + (lastc == OUT && !(m->eflags®_NOTBOL)) ) { + flagch = BOL; + i = m->g->nbol; + } + if ( (c == '\n' && m->g->cflags®_NEWLINE) || + (c == OUT && !(m->eflags®_NOTEOL)) ) { + flagch = (flagch == BOL) ? BOLEOL : EOL; + i += m->g->neol; + } + if (i != 0) { + for (; i > 0; i--) + st = step(m->g, startst, stopst, st, flagch, st); + SP("boleol", st, c); + } + + /* how about a word boundary? */ + if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) && + (c != OUT && ISWORD(c)) ) { + flagch = BOW; + } + if ( (lastc != OUT && ISWORD(lastc)) && + (flagch == EOL || (c != OUT && !ISWORD(c))) ) { + flagch = EOW; + } + if (flagch == BOW || flagch == EOW) { + st = step(m->g, startst, stopst, st, flagch, st); + SP("boweow", st, c); + } + + /* are we done? */ + if (ISSET(st, stopst) || p == stop) + break; /* NOTE BREAK OUT */ + + /* no, we must deal with this character */ + ASSIGN(tmp, st); + ASSIGN(st, fresh); + assert(c != OUT); + st = step(m->g, startst, stopst, tmp, c, st); + SP("aft", st, c); + assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st)); + p++; + } + + assert(coldp != NULL); + m->coldp = coldp; + if (ISSET(st, stopst)) + return(p+1); + else + return(NULL); +} + +/* + - slow - step through the string more deliberately + */ +static const char * /* where it ended */ +slow(struct match *m, const char *start, const char *stop, sopno startst, + sopno stopst) +{ + states st = m->st; + states empty = m->empty; + states tmp = m->tmp; + const char *p = start; + int c = (start == m->beginp) ? OUT : *(start-1); + int lastc; /* previous c */ + int flagch; + int i; + const char *matchp; /* last p at which a match ended */ + + AT("slow", start, stop, startst, stopst); + CLEAR(st); + SET1(st, startst); + SP("sstart", st, *p); + st = step(m->g, startst, stopst, st, NOTHING, st); + matchp = NULL; + for (;;) { + /* next character */ + lastc = c; + c = (p == m->endp) ? OUT : *p; + + /* is there an EOL and/or BOL between lastc and c? */ + flagch = '\0'; + i = 0; + if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || + (lastc == OUT && !(m->eflags®_NOTBOL)) ) { + flagch = BOL; + i = m->g->nbol; + } + if ( (c == '\n' && m->g->cflags®_NEWLINE) || + (c == OUT && !(m->eflags®_NOTEOL)) ) { + flagch = (flagch == BOL) ? BOLEOL : EOL; + i += m->g->neol; + } + if (i != 0) { + for (; i > 0; i--) + st = step(m->g, startst, stopst, st, flagch, st); + SP("sboleol", st, c); + } + + /* how about a word boundary? */ + if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) && + (c != OUT && ISWORD(c)) ) { + flagch = BOW; + } + if ( (lastc != OUT && ISWORD(lastc)) && + (flagch == EOL || (c != OUT && !ISWORD(c))) ) { + flagch = EOW; + } + if (flagch == BOW || flagch == EOW) { + st = step(m->g, startst, stopst, st, flagch, st); + SP("sboweow", st, c); + } + + /* are we done? */ + if (ISSET(st, stopst)) + matchp = p; + if (EQ(st, empty) || p == stop) + break; /* NOTE BREAK OUT */ + + /* no, we must deal with this character */ + ASSIGN(tmp, st); + ASSIGN(st, empty); + assert(c != OUT); + st = step(m->g, startst, stopst, tmp, c, st); + SP("saft", st, c); + assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st)); + p++; + } + + return(matchp); +} + + +/* + - step - map set of states reachable before char to set reachable after + */ +static states +step(struct re_guts *g, + sopno start, /* start state within strip */ + sopno stop, /* state after stop state within strip */ + states bef, /* states reachable before */ + int ch, /* character or NONCHAR code */ + states aft) /* states already known reachable after */ +{ + cset *cs; + sop s; + sopno pc; + onestate here; /* note, macros know this name */ + sopno look; + int i; + + for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) { + s = g->strip[pc]; + switch (OP(s)) { + case OEND: + assert(pc == stop-1); + break; + case OCHAR: + /* only characters can match */ + assert(!NONCHAR(ch) || ch != (char)OPND(s)); + if (ch == (char)OPND(s)) + FWD(aft, bef, 1); + break; + case OBOL: + if (ch == BOL || ch == BOLEOL) + FWD(aft, bef, 1); + break; + case OEOL: + if (ch == EOL || ch == BOLEOL) + FWD(aft, bef, 1); + break; + case OBOW: + if (ch == BOW) + FWD(aft, bef, 1); + break; + case OEOW: + if (ch == EOW) + FWD(aft, bef, 1); + break; + case OANY: + if (!NONCHAR(ch)) + FWD(aft, bef, 1); + break; + case OANYOF: + cs = &g->sets[OPND(s)]; + if (!NONCHAR(ch) && CHIN(cs, ch)) + FWD(aft, bef, 1); + break; + case OBACK_: /* ignored here */ + case O_BACK: + FWD(aft, aft, 1); + break; + case OPLUS_: /* forward, this is just an empty */ + FWD(aft, aft, 1); + break; + case O_PLUS: /* both forward and back */ + FWD(aft, aft, 1); + i = ISSETBACK(aft, OPND(s)); + BACK(aft, aft, OPND(s)); + if (!i && ISSETBACK(aft, OPND(s))) { + /* oho, must reconsider loop body */ + pc -= OPND(s) + 1; + INIT(here, pc); + } + break; + case OQUEST_: /* two branches, both forward */ + FWD(aft, aft, 1); + FWD(aft, aft, OPND(s)); + break; + case O_QUEST: /* just an empty */ + FWD(aft, aft, 1); + break; + case OLPAREN: /* not significant here */ + case ORPAREN: + FWD(aft, aft, 1); + break; + case OCH_: /* mark the first two branches */ + FWD(aft, aft, 1); + assert(OP(g->strip[pc+OPND(s)]) == OOR2); + FWD(aft, aft, OPND(s)); + break; + case OOR1: /* done a branch, find the O_CH */ + if (ISSTATEIN(aft, here)) { + for (look = 1; + OP(s = g->strip[pc+look]) != O_CH; + look += OPND(s)) + assert(OP(s) == OOR2); + FWD(aft, aft, look); + } + break; + case OOR2: /* propagate OCH_'s marking */ + FWD(aft, aft, 1); + if (OP(g->strip[pc+OPND(s)]) != O_CH) { + assert(OP(g->strip[pc+OPND(s)]) == OOR2); + FWD(aft, aft, OPND(s)); + } + break; + case O_CH: /* just empty */ + FWD(aft, aft, 1); + break; + default: /* ooooops... */ + assert(nope); + break; + } + } + + return(aft); +} + +#ifdef REDEBUG +/* + - print - print a set of states + */ +static void +print(struct match *m, char *caption, states st, int ch, FILE *d) +{ + struct re_guts *g = m->g; + int i; + int first = 1; + + if (!(m->eflags®_TRACE)) + return; + + (void)fprintf(d, "%s", caption); + if (ch != '\0') + (void)fprintf(d, " %s", pchar(ch)); + for (i = 0; i < g->nstates; i++) + if (ISSET(st, i)) { + (void)fprintf(d, "%s%d", (first) ? "\t" : ", ", i); + first = 0; + } + (void)fprintf(d, "\n"); +} + +/* + - at - print current situation + */ +static void +at(struct match *m, char *title, char *start, char *stop, sopno startst, + sopno stopst) +{ + if (!(m->eflags®_TRACE)) + return; + + (void)printf("%s %s-", title, pchar(*start)); + (void)printf("%s ", pchar(*stop)); + (void)printf("%ld-%ld\n", (long)startst, (long)stopst); +} + +#ifndef PCHARDONE +#define PCHARDONE /* never again */ +/* + - pchar - make a character printable + * + * Is this identical to regchar() over in debug.c? Well, yes. But a + * duplicate here avoids having a debugging-capable regexec.o tied to + * a matching debug.o, and this is convenient. It all disappears in + * the non-debug compilation anyway, so it doesn't matter much. + */ +static char * /* -> representation */ +pchar(int ch) +{ + static char pbuf[10]; + + if (isprint(ch) || ch == ' ') + (void)snprintf(pbuf, sizeof pbuf, "%c", ch); + else + (void)snprintf(pbuf, sizeof pbuf, "\\%o", ch); + return(pbuf); +} +#endif +#endif + +#undef matcher +#undef fast +#undef slow +#undef dissect +#undef backref +#undef step +#undef print +#undef at +#undef match +#undef nope diff --git a/contrib/llvm/lib/Support/regerror.c b/contrib/llvm/lib/Support/regerror.c new file mode 100644 index 0000000..1d67c9a --- /dev/null +++ b/contrib/llvm/lib/Support/regerror.c @@ -0,0 +1,135 @@ +/*- + * This code is derived from OpenBSD's libc/regex, original license follows: + * + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regerror.c 8.4 (Berkeley) 3/20/94 + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <limits.h> +#include <stdlib.h> +#include "regex_impl.h" + +#include "regutils.h" + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + +static const char *regatoi(const llvm_regex_t *, char *, int); + +static struct rerr { + int code; + const char *name; + const char *explain; +} rerrs[] = { + { REG_NOMATCH, "REG_NOMATCH", "llvm_regexec() failed to match" }, + { REG_BADPAT, "REG_BADPAT", "invalid regular expression" }, + { REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element" }, + { REG_ECTYPE, "REG_ECTYPE", "invalid character class" }, + { REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)" }, + { REG_ESUBREG, "REG_ESUBREG", "invalid backreference number" }, + { REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced" }, + { REG_EPAREN, "REG_EPAREN", "parentheses not balanced" }, + { REG_EBRACE, "REG_EBRACE", "braces not balanced" }, + { REG_BADBR, "REG_BADBR", "invalid repetition count(s)" }, + { REG_ERANGE, "REG_ERANGE", "invalid character range" }, + { REG_ESPACE, "REG_ESPACE", "out of memory" }, + { REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid" }, + { REG_EMPTY, "REG_EMPTY", "empty (sub)expression" }, + { REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug" }, + { REG_INVARG, "REG_INVARG", "invalid argument to regex routine" }, + { 0, "", "*** unknown regexp error code ***" } +}; + +/* + - llvm_regerror - the interface to error numbers + = extern size_t llvm_regerror(int, const llvm_regex_t *, char *, size_t); + */ +/* ARGSUSED */ +size_t +llvm_regerror(int errcode, const llvm_regex_t *preg, char *errbuf, size_t errbuf_size) +{ + struct rerr *r; + size_t len; + int target = errcode &~ REG_ITOA; + const char *s; + char convbuf[50]; + + if (errcode == REG_ATOI) + s = regatoi(preg, convbuf, sizeof convbuf); + else { + for (r = rerrs; r->code != 0; r++) + if (r->code == target) + break; + + if (errcode®_ITOA) { + if (r->code != 0) { + assert(strlen(r->name) < sizeof(convbuf)); + (void) llvm_strlcpy(convbuf, r->name, sizeof convbuf); + } else + (void)snprintf(convbuf, sizeof convbuf, + "REG_0x%x", target); + s = convbuf; + } else + s = r->explain; + } + + len = strlen(s) + 1; + if (errbuf_size > 0) { + llvm_strlcpy(errbuf, s, errbuf_size); + } + + return(len); +} + +/* + - regatoi - internal routine to implement REG_ATOI + */ +static const char * +regatoi(const llvm_regex_t *preg, char *localbuf, int localbufsize) +{ + struct rerr *r; + + for (r = rerrs; r->code != 0; r++) + if (strcmp(r->name, preg->re_endp) == 0) + break; + if (r->code == 0) + return("0"); + + (void)snprintf(localbuf, localbufsize, "%d", r->code); + return(localbuf); +} diff --git a/contrib/llvm/lib/Support/regex2.h b/contrib/llvm/lib/Support/regex2.h new file mode 100644 index 0000000..21659c3 --- /dev/null +++ b/contrib/llvm/lib/Support/regex2.h @@ -0,0 +1,157 @@ +/*- + * This code is derived from OpenBSD's libc/regex, original license follows: + * + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regex2.h 8.4 (Berkeley) 3/20/94 + */ + +/* + * internals of regex_t + */ +#define MAGIC1 ((('r'^0200)<<8) | 'e') + +/* + * The internal representation is a *strip*, a sequence of + * operators ending with an endmarker. (Some terminology etc. is a + * historical relic of earlier versions which used multiple strips.) + * Certain oddities in the representation are there to permit running + * the machinery backwards; in particular, any deviation from sequential + * flow must be marked at both its source and its destination. Some + * fine points: + * + * - OPLUS_ and O_PLUS are *inside* the loop they create. + * - OQUEST_ and O_QUEST are *outside* the bypass they create. + * - OCH_ and O_CH are *outside* the multi-way branch they create, while + * OOR1 and OOR2 are respectively the end and the beginning of one of + * the branches. Note that there is an implicit OOR2 following OCH_ + * and an implicit OOR1 preceding O_CH. + * + * In state representations, an operator's bit is on to signify a state + * immediately *preceding* "execution" of that operator. + */ +typedef unsigned long sop; /* strip operator */ +typedef long sopno; +#define OPRMASK 0xf8000000LU +#define OPDMASK 0x07ffffffLU +#define OPSHIFT ((unsigned)27) +#define OP(n) ((n)&OPRMASK) +#define OPND(n) ((n)&OPDMASK) +#define SOP(op, opnd) ((op)|(opnd)) +/* operators meaning operand */ +/* (back, fwd are offsets) */ +#define OEND (1LU<<OPSHIFT) /* endmarker - */ +#define OCHAR (2LU<<OPSHIFT) /* character unsigned char */ +#define OBOL (3LU<<OPSHIFT) /* left anchor - */ +#define OEOL (4LU<<OPSHIFT) /* right anchor - */ +#define OANY (5LU<<OPSHIFT) /* . - */ +#define OANYOF (6LU<<OPSHIFT) /* [...] set number */ +#define OBACK_ (7LU<<OPSHIFT) /* begin \d paren number */ +#define O_BACK (8LU<<OPSHIFT) /* end \d paren number */ +#define OPLUS_ (9LU<<OPSHIFT) /* + prefix fwd to suffix */ +#define O_PLUS (10LU<<OPSHIFT) /* + suffix back to prefix */ +#define OQUEST_ (11LU<<OPSHIFT) /* ? prefix fwd to suffix */ +#define O_QUEST (12LU<<OPSHIFT) /* ? suffix back to prefix */ +#define OLPAREN (13LU<<OPSHIFT) /* ( fwd to ) */ +#define ORPAREN (14LU<<OPSHIFT) /* ) back to ( */ +#define OCH_ (15LU<<OPSHIFT) /* begin choice fwd to OOR2 */ +#define OOR1 (16LU<<OPSHIFT) /* | pt. 1 back to OOR1 or OCH_ */ +#define OOR2 (17LU<<OPSHIFT) /* | pt. 2 fwd to OOR2 or O_CH */ +#define O_CH (18LU<<OPSHIFT) /* end choice back to OOR1 */ +#define OBOW (19LU<<OPSHIFT) /* begin word - */ +#define OEOW (20LU<<OPSHIFT) /* end word - */ + +/* + * Structure for [] character-set representation. Character sets are + * done as bit vectors, grouped 8 to a byte vector for compactness. + * The individual set therefore has both a pointer to the byte vector + * and a mask to pick out the relevant bit of each byte. A hash code + * simplifies testing whether two sets could be identical. + * + * This will get trickier for multicharacter collating elements. As + * preliminary hooks for dealing with such things, we also carry along + * a string of multi-character elements, and decide the size of the + * vectors at run time. + */ +typedef struct { + uch *ptr; /* -> uch [csetsize] */ + uch mask; /* bit within array */ + uch hash; /* hash code */ + size_t smultis; + char *multis; /* -> char[smulti] ab\0cd\0ef\0\0 */ +} cset; +/* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */ +#define CHadd(cs, c) ((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (c)) +#define CHsub(cs, c) ((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (c)) +#define CHIN(cs, c) ((cs)->ptr[(uch)(c)] & (cs)->mask) +#define MCadd(p, cs, cp) mcadd(p, cs, cp) /* llvm_regcomp() internal fns */ +#define MCsub(p, cs, cp) mcsub(p, cs, cp) +#define MCin(p, cs, cp) mcin(p, cs, cp) + +/* stuff for character categories */ +typedef unsigned char cat_t; + +/* + * main compiled-expression structure + */ +struct re_guts { + int magic; +# define MAGIC2 ((('R'^0200)<<8)|'E') + sop *strip; /* malloced area for strip */ + int csetsize; /* number of bits in a cset vector */ + int ncsets; /* number of csets in use */ + cset *sets; /* -> cset [ncsets] */ + uch *setbits; /* -> uch[csetsize][ncsets/CHAR_BIT] */ + int cflags; /* copy of llvm_regcomp() cflags argument */ + sopno nstates; /* = number of sops */ + sopno firststate; /* the initial OEND (normally 0) */ + sopno laststate; /* the final OEND */ + int iflags; /* internal flags */ +# define USEBOL 01 /* used ^ */ +# define USEEOL 02 /* used $ */ +# define REGEX_BAD 04 /* something wrong */ + int nbol; /* number of ^ used */ + int neol; /* number of $ used */ + int ncategories; /* how many character categories */ + cat_t *categories; /* ->catspace[-CHAR_MIN] */ + char *must; /* match must contain this string */ + int mlen; /* length of must */ + size_t nsub; /* copy of re_nsub */ + int backrefs; /* does it use back references? */ + sopno nplus; /* how deep does it nest +s? */ + /* catspace must be last */ + cat_t catspace[1]; /* actually [NC] */ +}; + +/* misc utilities */ +#define OUT (CHAR_MAX+1) /* a non-character value */ +#define ISWORD(c) (isalnum(c&0xff) || (c) == '_') diff --git a/contrib/llvm/lib/Support/regex_impl.h b/contrib/llvm/lib/Support/regex_impl.h new file mode 100644 index 0000000..f8296c9 --- /dev/null +++ b/contrib/llvm/lib/Support/regex_impl.h @@ -0,0 +1,108 @@ +/*- + * This code is derived from OpenBSD's libc/regex, original license follows: + * + * Copyright (c) 1992 Henry Spencer. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer of the University of Toronto. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regex.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _REGEX_H_ +#define _REGEX_H_ + +#include <sys/types.h> +typedef off_t llvm_regoff_t; +typedef struct { + llvm_regoff_t rm_so; /* start of match */ + llvm_regoff_t rm_eo; /* end of match */ +} llvm_regmatch_t; + +typedef struct llvm_regex { + int re_magic; + size_t re_nsub; /* number of parenthesized subexpressions */ + const char *re_endp; /* end pointer for REG_PEND */ + struct re_guts *re_g; /* none of your business :-) */ +} llvm_regex_t; + +/* llvm_regcomp() flags */ +#define REG_BASIC 0000 +#define REG_EXTENDED 0001 +#define REG_ICASE 0002 +#define REG_NOSUB 0004 +#define REG_NEWLINE 0010 +#define REG_NOSPEC 0020 +#define REG_PEND 0040 +#define REG_DUMP 0200 + +/* llvm_regerror() flags */ +#define REG_NOMATCH 1 +#define REG_BADPAT 2 +#define REG_ECOLLATE 3 +#define REG_ECTYPE 4 +#define REG_EESCAPE 5 +#define REG_ESUBREG 6 +#define REG_EBRACK 7 +#define REG_EPAREN 8 +#define REG_EBRACE 9 +#define REG_BADBR 10 +#define REG_ERANGE 11 +#define REG_ESPACE 12 +#define REG_BADRPT 13 +#define REG_EMPTY 14 +#define REG_ASSERT 15 +#define REG_INVARG 16 +#define REG_ATOI 255 /* convert name to number (!) */ +#define REG_ITOA 0400 /* convert number to name (!) */ + +/* llvm_regexec() flags */ +#define REG_NOTBOL 00001 +#define REG_NOTEOL 00002 +#define REG_STARTEND 00004 +#define REG_TRACE 00400 /* tracing of execution */ +#define REG_LARGE 01000 /* force large representation */ +#define REG_BACKR 02000 /* force use of backref code */ + +#ifdef __cplusplus +extern "C" { +#endif + +int llvm_regcomp(llvm_regex_t *, const char *, int); +size_t llvm_regerror(int, const llvm_regex_t *, char *, size_t); +int llvm_regexec(const llvm_regex_t *, const char *, size_t, + llvm_regmatch_t [], int); +void llvm_regfree(llvm_regex_t *); +size_t llvm_strlcpy(char *dst, const char *src, size_t siz); + +#ifdef __cplusplus +} +#endif + +#endif /* !_REGEX_H_ */ diff --git a/contrib/llvm/lib/Support/regexec.c b/contrib/llvm/lib/Support/regexec.c new file mode 100644 index 0000000..0078616 --- /dev/null +++ b/contrib/llvm/lib/Support/regexec.c @@ -0,0 +1,162 @@ +/*- + * This code is derived from OpenBSD's libc/regex, original license follows: + * + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regexec.c 8.3 (Berkeley) 3/20/94 + */ + +/* + * the outer shell of llvm_regexec() + * + * This file includes engine.inc *twice*, after muchos fiddling with the + * macros that code uses. This lets the same code operate on two different + * representations for state sets. + */ +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <ctype.h> +#include "regex_impl.h" + +#include "regutils.h" +#include "regex2.h" + +/* macros for manipulating states, small version */ +/* FIXME: 'states' is assumed as 'long' on small version. */ +#define states1 long /* for later use in llvm_regexec() decision */ +#define states states1 +#define CLEAR(v) ((v) = 0) +#define SET0(v, n) ((v) &= ~((unsigned long)1 << (n))) +#define SET1(v, n) ((v) |= (unsigned long)1 << (n)) +#define ISSET(v, n) (((v) & ((unsigned long)1 << (n))) != 0) +#define ASSIGN(d, s) ((d) = (s)) +#define EQ(a, b) ((a) == (b)) +#define STATEVARS long dummy /* dummy version */ +#define STATESETUP(m, n) /* nothing */ +#define STATETEARDOWN(m) /* nothing */ +#define SETUP(v) ((v) = 0) +#define onestate long +#define INIT(o, n) ((o) = (unsigned long)1 << (n)) +#define INC(o) ((o) <<= 1) +#define ISSTATEIN(v, o) (((v) & (o)) != 0) +/* some abbreviations; note that some of these know variable names! */ +/* do "if I'm here, I can also be there" etc without branches */ +#define FWD(dst, src, n) ((dst) |= ((unsigned long)(src)&(here)) << (n)) +#define BACK(dst, src, n) ((dst) |= ((unsigned long)(src)&(here)) >> (n)) +#define ISSETBACK(v, n) (((v) & ((unsigned long)here >> (n))) != 0) +/* function names */ +#define SNAMES /* engine.inc looks after details */ + +#include "regengine.inc" + +/* now undo things */ +#undef states +#undef CLEAR +#undef SET0 +#undef SET1 +#undef ISSET +#undef ASSIGN +#undef EQ +#undef STATEVARS +#undef STATESETUP +#undef STATETEARDOWN +#undef SETUP +#undef onestate +#undef INIT +#undef INC +#undef ISSTATEIN +#undef FWD +#undef BACK +#undef ISSETBACK +#undef SNAMES + +/* macros for manipulating states, large version */ +#define states char * +#define CLEAR(v) memset(v, 0, m->g->nstates) +#define SET0(v, n) ((v)[n] = 0) +#define SET1(v, n) ((v)[n] = 1) +#define ISSET(v, n) ((v)[n]) +#define ASSIGN(d, s) memmove(d, s, m->g->nstates) +#define EQ(a, b) (memcmp(a, b, m->g->nstates) == 0) +#define STATEVARS long vn; char *space +#define STATESETUP(m, nv) { (m)->space = malloc((nv)*(m)->g->nstates); \ + if ((m)->space == NULL) return(REG_ESPACE); \ + (m)->vn = 0; } +#define STATETEARDOWN(m) { free((m)->space); } +#define SETUP(v) ((v) = &m->space[m->vn++ * m->g->nstates]) +#define onestate long +#define INIT(o, n) ((o) = (n)) +#define INC(o) ((o)++) +#define ISSTATEIN(v, o) ((v)[o]) +/* some abbreviations; note that some of these know variable names! */ +/* do "if I'm here, I can also be there" etc without branches */ +#define FWD(dst, src, n) ((dst)[here+(n)] |= (src)[here]) +#define BACK(dst, src, n) ((dst)[here-(n)] |= (src)[here]) +#define ISSETBACK(v, n) ((v)[here - (n)]) +/* function names */ +#define LNAMES /* flag */ + +#include "regengine.inc" + +/* + - llvm_regexec - interface for matching + * + * We put this here so we can exploit knowledge of the state representation + * when choosing which matcher to call. Also, by this point the matchers + * have been prototyped. + */ +int /* 0 success, REG_NOMATCH failure */ +llvm_regexec(const llvm_regex_t *preg, const char *string, size_t nmatch, + llvm_regmatch_t pmatch[], int eflags) +{ + struct re_guts *g = preg->re_g; +#ifdef REDEBUG +# define GOODFLAGS(f) (f) +#else +# define GOODFLAGS(f) ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND)) +#endif + + if (preg->re_magic != MAGIC1 || g->magic != MAGIC2) + return(REG_BADPAT); + assert(!(g->iflags®EX_BAD)); + if (g->iflags®EX_BAD) /* backstop for no-debug case */ + return(REG_BADPAT); + eflags = GOODFLAGS(eflags); + + if (g->nstates <= (long)(CHAR_BIT*sizeof(states1)) && !(eflags®_LARGE)) + return(smatcher(g, string, nmatch, pmatch, eflags)); + else + return(lmatcher(g, string, nmatch, pmatch, eflags)); +} diff --git a/contrib/llvm/lib/Support/regfree.c b/contrib/llvm/lib/Support/regfree.c new file mode 100644 index 0000000..dc2b4af --- /dev/null +++ b/contrib/llvm/lib/Support/regfree.c @@ -0,0 +1,72 @@ +/*- + * This code is derived from OpenBSD's libc/regex, original license follows: + * + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regfree.c 8.3 (Berkeley) 3/20/94 + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include "regex_impl.h" + +#include "regutils.h" +#include "regex2.h" + +/* + - llvm_regfree - free everything + */ +void +llvm_regfree(llvm_regex_t *preg) +{ + struct re_guts *g; + + if (preg->re_magic != MAGIC1) /* oops */ + return; /* nice to complain, but hard */ + + g = preg->re_g; + if (g == NULL || g->magic != MAGIC2) /* oops again */ + return; + preg->re_magic = 0; /* mark it invalid */ + g->magic = 0; /* mark it invalid */ + + if (g->strip != NULL) + free((char *)g->strip); + if (g->sets != NULL) + free((char *)g->sets); + if (g->setbits != NULL) + free((char *)g->setbits); + if (g->must != NULL) + free(g->must); + free((char *)g); +} diff --git a/contrib/llvm/lib/Support/regstrlcpy.c b/contrib/llvm/lib/Support/regstrlcpy.c new file mode 100644 index 0000000..8b68afd --- /dev/null +++ b/contrib/llvm/lib/Support/regstrlcpy.c @@ -0,0 +1,52 @@ +/* + * This code is derived from OpenBSD's libc, original license follows: + * + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <string.h> + +#include "regex_impl.h" +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +llvm_strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0) { + while (--n != 0) { + if ((*d++ = *s++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} diff --git a/contrib/llvm/lib/Support/regutils.h b/contrib/llvm/lib/Support/regutils.h new file mode 100644 index 0000000..d0ee100 --- /dev/null +++ b/contrib/llvm/lib/Support/regutils.h @@ -0,0 +1,53 @@ +/*- + * This code is derived from OpenBSD's libc/regex, original license follows: + * + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)utils.h 8.3 (Berkeley) 3/20/94 + */ + +/* utility definitions */ +#define NC (CHAR_MAX - CHAR_MIN + 1) +typedef unsigned char uch; + +/* switch off assertions (if not already off) if no REDEBUG */ +#ifndef REDEBUG +#ifndef NDEBUG +#define NDEBUG /* no assertions please */ +#endif +#endif +#include <assert.h> + +/* for old systems with bcopy() but no memmove() */ +#ifdef USEBCOPY +#define memmove(d, s, c) bcopy(s, d, c) +#endif diff --git a/contrib/llvm/lib/Support/system_error.cpp b/contrib/llvm/lib/Support/system_error.cpp new file mode 100644 index 0000000..56898de --- /dev/null +++ b/contrib/llvm/lib/Support/system_error.cpp @@ -0,0 +1,130 @@ +//===---------------------- system_error.cpp ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This was lifted from libc++ and modified for C++03. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/system_error.h" +#include "llvm/Support/Errno.h" +#include <string> +#include <cstring> + +namespace llvm { + +// class error_category + +error_category::error_category() { +} + +error_category::~error_category() { +} + +error_condition +error_category::default_error_condition(int ev) const { + return error_condition(ev, *this); +} + +bool +error_category::equivalent(int code, const error_condition& condition) const { + return default_error_condition(code) == condition; +} + +bool +error_category::equivalent(const error_code& code, int condition) const { + return *this == code.category() && code.value() == condition; +} + +std::string +_do_message::message(int ev) const { + return std::string(sys::StrError(ev)); +} + +class _generic_error_category : public _do_message { +public: + virtual const char* name() const; + virtual std::string message(int ev) const; +}; + +const char* +_generic_error_category::name() const { + return "generic"; +} + +std::string +_generic_error_category::message(int ev) const { +#ifdef ELAST + if (ev > ELAST) + return std::string("unspecified generic_category error"); +#endif // ELAST + return _do_message::message(ev); +} + +const error_category& +generic_category() { + static _generic_error_category s; + return s; +} + +class _system_error_category : public _do_message { +public: + virtual const char* name() const; + virtual std::string message(int ev) const; + virtual error_condition default_error_condition(int ev) const; +}; + +const char* +_system_error_category::name() const { + return "system"; +} + +// std::string _system_error_category::message(int ev) const { +// Is in Platform/system_error.inc + +// error_condition _system_error_category::default_error_condition(int ev) const +// Is in Platform/system_error.inc + +const error_category& +system_category() { + static _system_error_category s; + return s; +} + +const error_category& +posix_category() { +#ifdef LLVM_ON_WIN32 + return generic_category(); +#else + return system_category(); +#endif +} + +// error_condition + +std::string +error_condition::message() const { + return _cat_->message(_val_); +} + +// error_code + +std::string +error_code::message() const { + return _cat_->message(_val_); +} + +} // end namespace llvm + +// Include the truly platform-specific parts of this class. +#if defined(LLVM_ON_UNIX) +#include "Unix/system_error.inc" +#endif +#if defined(LLVM_ON_WIN32) +#include "Windows/system_error.inc" +#endif |