diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2013-04-08 18:41:23 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2013-04-08 18:41:23 +0000 |
commit | 4a16efa3e43e35f0cc9efe3a67f620f0017c3d36 (patch) | |
tree | 06099edc18d30894081a822b756f117cbe0b8207 /lib/Support | |
parent | 482e7bddf617ae804dc47133cb07eb4aa81e45de (diff) | |
download | src-test2-f7d92b5cb9ddb3fef35c44a9b066c5f16b6a40c8.tar.gz src-test2-f7d92b5cb9ddb3fef35c44a9b066c5f16b6a40c8.zip |
Diffstat (limited to 'lib/Support')
61 files changed, 2599 insertions, 526 deletions
diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index 7e8b4a3d0d29..6182e3415005 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -16,11 +16,12 @@ #include "llvm/ADT/APSInt.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" -#include <limits.h> #include <cstring> +#include <limits.h> using namespace llvm; @@ -101,26 +102,6 @@ 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; -} - /* Return the value of a decimal exponent of the form [+-]ddddddd. @@ -697,6 +678,13 @@ APFloat::operator=(const APFloat &rhs) } bool +APFloat::isDenormal() const { + return isNormal() && (exponent == semantics->minExponent) && + (APInt::tcExtractBit(significandParts(), + semantics->precision - 1) == 0); +} + +bool APFloat::bitwiseIsEqual(const APFloat &rhs) const { if (this == &rhs) return true; @@ -1925,6 +1913,12 @@ APFloat::convert(const fltSemantics &toSemantics, *losesInfo = (fs != opOK); } else if (category == fcNaN) { *losesInfo = lostFraction != lfExactlyZero || X86SpecialNan; + + // For x87 extended precision, we want to make a NaN, not a special NaN if + // the input wasn't special either. + if (!X86SpecialNan && semantics == &APFloat::x87DoubleExtended) + APInt::tcSetBit(significandParts(), semantics->precision - 1); + // 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 @@ -2761,9 +2755,11 @@ APFloat::convertPPCDoubleDoubleAPFloatToAPInt() const // normalize against the "double" minExponent first, and only *then* // truncate the mantissa. The result of that second conversion // may be inexact, but should never underflow. - APFloat extended(*this); + // Declare fltSemantics before APFloat that uses it (and + // saves pointer to it) to ensure correct destruction order. fltSemantics extendedSemantics = *semantics; extendedSemantics.minExponent = IEEEdouble.minExponent; + APFloat extended(*this); fs = extended.convert(extendedSemantics, rmNearestTiesToEven, &losesInfo); assert(fs == opOK && !losesInfo); (void)fs; @@ -3023,7 +3019,7 @@ APFloat::initFromPPCDoubleDoubleAPInt(const APInt &api) // Unless we have a special case, add in second double. if (category == fcNormal) { - APFloat v(APInt(64, i2)); + APFloat v(IEEEdouble, APInt(64, i2)); fs = v.convert(PPCDoubleDouble, rmNearestTiesToEven, &losesInfo); assert(fs == opOK && !losesInfo); (void)fs; @@ -3176,27 +3172,43 @@ APFloat::initFromHalfAPInt(const APInt & api) /// isIEEE argument distinguishes between PPC128 and IEEE128 (not meaningful /// when the size is anything else). void -APFloat::initFromAPInt(const APInt& api, bool isIEEE) +APFloat::initFromAPInt(const fltSemantics* Sem, const APInt& api) { - if (api.getBitWidth() == 16) + if (Sem == &IEEEhalf) return initFromHalfAPInt(api); - else if (api.getBitWidth() == 32) + if (Sem == &IEEEsingle) return initFromFloatAPInt(api); - else if (api.getBitWidth()==64) + if (Sem == &IEEEdouble) return initFromDoubleAPInt(api); - else if (api.getBitWidth()==80) + if (Sem == &x87DoubleExtended) return initFromF80LongDoubleAPInt(api); - else if (api.getBitWidth()==128) - return (isIEEE ? - initFromQuadrupleAPInt(api) : initFromPPCDoubleDoubleAPInt(api)); - else - llvm_unreachable(0); + if (Sem == &IEEEquad) + return initFromQuadrupleAPInt(api); + if (Sem == &PPCDoubleDouble) + return initFromPPCDoubleDoubleAPInt(api); + + llvm_unreachable(0); } APFloat APFloat::getAllOnesValue(unsigned BitWidth, bool isIEEE) { - return APFloat(APInt::getAllOnesValue(BitWidth), isIEEE); + switch (BitWidth) { + case 16: + return APFloat(IEEEhalf, APInt::getAllOnesValue(BitWidth)); + case 32: + return APFloat(IEEEsingle, APInt::getAllOnesValue(BitWidth)); + case 64: + return APFloat(IEEEdouble, APInt::getAllOnesValue(BitWidth)); + case 80: + return APFloat(x87DoubleExtended, APInt::getAllOnesValue(BitWidth)); + case 128: + if (isIEEE) + return APFloat(IEEEquad, APInt::getAllOnesValue(BitWidth)); + return APFloat(PPCDoubleDouble, APInt::getAllOnesValue(BitWidth)); + default: + llvm_unreachable("Unknown floating bit width"); + } } APFloat APFloat::getLargest(const fltSemantics &Sem, bool Negative) { @@ -3254,16 +3266,16 @@ APFloat APFloat::getSmallestNormalized(const fltSemantics &Sem, bool Negative) { return Val; } -APFloat::APFloat(const APInt& api, bool isIEEE) { - initFromAPInt(api, isIEEE); +APFloat::APFloat(const fltSemantics &Sem, const APInt &API) { + initFromAPInt(&Sem, API); } APFloat::APFloat(float f) { - initFromAPInt(APInt::floatToBits(f)); + initFromAPInt(&IEEEsingle, APInt::floatToBits(f)); } APFloat::APFloat(double d) { - initFromAPInt(APInt::doubleToBits(d)); + initFromAPInt(&IEEEdouble, APInt::doubleToBits(d)); } namespace { @@ -3299,10 +3311,8 @@ namespace { 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); + // Truncate the significand down to its active bit count. + significand = significand.trunc(significand.getActiveBits()); } @@ -3439,7 +3449,7 @@ void APFloat::toString(SmallVectorImpl<char> &Str, AdjustToPrecision(significand, exp, FormatPrecision); - llvm::SmallVector<char, 256> buffer; + SmallVector<char, 256> buffer; // Fill the buffer. unsigned precision = significand.getBitWidth(); diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index 38cfaed9d217..e8534753b46e 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -23,9 +23,9 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include <cmath> -#include <limits> -#include <cstring> #include <cstdlib> +#include <cstring> +#include <limits> using namespace llvm; /// A utility function for allocating memory, checking for allocation failures, @@ -559,12 +559,12 @@ bool APInt::slt(const APInt& RHS) const { if (lhsNeg) { // Sign bit is set so perform two's complement to make it positive lhs.flipAllBits(); - lhs++; + ++lhs; } if (rhsNeg) { // Sign bit is set so perform two's complement to make it positive rhs.flipAllBits(); - rhs++; + ++rhs; } // Now we have unsigned values to compare so do the comparison if necessary @@ -1876,6 +1876,17 @@ APInt APInt::udiv(const APInt& RHS) const { return Quotient; } +APInt APInt::sdiv(const APInt &RHS) const { + if (isNegative()) { + if (RHS.isNegative()) + return (-(*this)).udiv(-RHS); + return -((-(*this)).udiv(RHS)); + } + if (RHS.isNegative()) + return -(this->udiv(-RHS)); + return this->udiv(RHS); +} + APInt APInt::urem(const APInt& RHS) const { assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); if (isSingleWord()) { @@ -1913,6 +1924,17 @@ APInt APInt::urem(const APInt& RHS) const { return Remainder; } +APInt APInt::srem(const APInt &RHS) const { + if (isNegative()) { + if (RHS.isNegative()) + return -((-(*this)).urem(-RHS)); + return -((-(*this)).urem(RHS)); + } + if (RHS.isNegative()) + return this->urem(-RHS); + return this->urem(RHS); +} + void APInt::udivrem(const APInt &LHS, const APInt &RHS, APInt &Quotient, APInt &Remainder) { // Get some size facts about the dividend and divisor @@ -1953,6 +1975,24 @@ void APInt::udivrem(const APInt &LHS, const APInt &RHS, divide(LHS, lhsWords, RHS, rhsWords, &Quotient, &Remainder); } +void APInt::sdivrem(const APInt &LHS, const APInt &RHS, + APInt &Quotient, APInt &Remainder) { + if (LHS.isNegative()) { + if (RHS.isNegative()) + APInt::udivrem(-LHS, -RHS, Quotient, Remainder); + else { + APInt::udivrem(-LHS, RHS, Quotient, Remainder); + Quotient = -Quotient; + } + Remainder = -Remainder; + } else if (RHS.isNegative()) { + APInt::udivrem(LHS, -RHS, Quotient, Remainder); + Quotient = -Quotient; + } else { + APInt::udivrem(LHS, RHS, Quotient, Remainder); + } +} + APInt APInt::sadd_ov(const APInt &RHS, bool &Overflow) const { APInt Res = *this+RHS; Overflow = isNonNegative() == RHS.isNonNegative() && @@ -2076,7 +2116,7 @@ void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) { } // If its negative, put it in two's complement form if (isNeg) { - (*this)--; + --(*this); this->flipAllBits(); } } @@ -2157,7 +2197,7 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, // Flip the bits and add one to turn it into the equivalent positive // value and put a '-' in the result. Tmp.flipAllBits(); - Tmp++; + ++Tmp; Str.push_back('-'); } diff --git a/lib/Support/Allocator.cpp b/lib/Support/Allocator.cpp index b8978302e746..3c4191b805a3 100644 --- a/lib/Support/Allocator.cpp +++ b/lib/Support/Allocator.cpp @@ -12,10 +12,11 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Allocator.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/Memory.h" #include "llvm/Support/Recycler.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Memory.h" #include <cstring> namespace llvm { @@ -82,6 +83,7 @@ void BumpPtrAllocator::Reset() { CurSlab->NextPtr = 0; CurPtr = (char*)(CurSlab + 1); End = ((char*)CurSlab) + CurSlab->Size; + BytesAllocated = 0; } /// Allocate - Allocate space at the specified alignment. @@ -102,6 +104,10 @@ void *BumpPtrAllocator::Allocate(size_t Size, size_t Alignment) { // Check if we can hold it. if (Ptr + Size <= End) { CurPtr = Ptr + Size; + // Update the allocation point of this memory block in MemorySanitizer. + // Without this, MemorySanitizer messages for values originated from here + // will point to the allocation of the entire slab. + __msan_allocated_memory(Ptr, Size); return Ptr; } @@ -117,6 +123,7 @@ void *BumpPtrAllocator::Allocate(size_t Size, size_t Alignment) { Ptr = AlignPtr((char*)(NewSlab + 1), Alignment); assert((uintptr_t)Ptr + Size <= (uintptr_t)NewSlab + NewSlab->Size); + __msan_allocated_memory(Ptr, Size); return Ptr; } @@ -125,6 +132,7 @@ void *BumpPtrAllocator::Allocate(size_t Size, size_t Alignment) { Ptr = AlignPtr(CurPtr, Alignment); CurPtr = Ptr + Size; assert(CurPtr <= End && "Unable to allocate memory!"); + __msan_allocated_memory(Ptr, Size); return Ptr; } diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt index 6af0f4a6c938..3746a810114f 100644 --- a/lib/Support/CMakeLists.txt +++ b/lib/Support/CMakeLists.txt @@ -8,6 +8,8 @@ add_llvm_library(LLVMSupport circular_raw_ostream.cpp CommandLine.cpp ConstantRange.cpp + ConvertUTF.c + ConvertUTFWrapper.cpp CrashRecoveryContext.cpp DataExtractor.cpp DataStream.cpp @@ -50,6 +52,7 @@ add_llvm_library(LLVMSupport Triple.cpp Twine.cpp YAMLParser.cpp + YAMLTraits.cpp raw_os_ostream.cpp raw_ostream.cpp regcomp.c @@ -80,6 +83,7 @@ add_llvm_library(LLVMSupport Threading.cpp TimeValue.cpp Valgrind.cpp + Watchdog.cpp Unix/Host.inc Unix/Memory.inc Unix/Mutex.inc @@ -92,6 +96,7 @@ add_llvm_library(LLVMSupport Unix/system_error.inc Unix/ThreadLocal.inc Unix/TimeValue.inc + Unix/Watchdog.inc Windows/DynamicLibrary.inc Windows/Host.inc Windows/Memory.inc @@ -105,4 +110,5 @@ add_llvm_library(LLVMSupport Windows/system_error.inc Windows/ThreadLocal.inc Windows/TimeValue.inc + Windows/Watchdog.inc ) diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index fc4f1891d95f..560d7eb289c6 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -17,20 +17,20 @@ //===----------------------------------------------------------------------===// #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 "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" #include <cerrno> #include <cstdlib> using namespace llvm; @@ -1222,14 +1222,10 @@ sortOpts(StringMap<Option*> &OptMap, namespace { class HelpPrinter { - size_t MaxArgLen; - const Option *EmptyArg; const bool ShowHidden; public: - explicit HelpPrinter(bool showHidden) : ShowHidden(showHidden) { - EmptyArg = 0; - } + explicit HelpPrinter(bool showHidden) : ShowHidden(showHidden) {} void operator=(bool Value) { if (Value == false) return; @@ -1266,7 +1262,7 @@ public: outs() << "\n\n"; // Compute the maximum argument length... - MaxArgLen = 0; + size_t MaxArgLen = 0; for (size_t i = 0, e = Opts.size(); i != e; ++i) MaxArgLen = std::max(MaxArgLen, Opts[i].second->getOptionWidth()); diff --git a/lib/Support/ConstantRange.cpp b/lib/Support/ConstantRange.cpp index 720ef36c4640..5c5895026b67 100644 --- a/lib/Support/ConstantRange.cpp +++ b/lib/Support/ConstantRange.cpp @@ -21,7 +21,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/InstrTypes.h" +#include "llvm/IR/InstrTypes.h" #include "llvm/Support/ConstantRange.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/Support/ConvertUTF.c b/lib/Support/ConvertUTF.c new file mode 100644 index 000000000000..23f17ca25aea --- /dev/null +++ b/lib/Support/ConvertUTF.c @@ -0,0 +1,571 @@ +/*===--- ConvertUTF.c - Universal Character Names conversions ---------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + *===------------------------------------------------------------------------=*/ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Source code file. + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Sept 2001: fixed const & error conditions per + mods suggested by S. Parent & A. Lillich. + June 2002: Tim Dodd added detection and handling of incomplete + source sequences, enhanced error detection, added casts + to eliminate compiler warnings. + July 2003: slight mods to back out aggressive FFFE detection. + Jan 2004: updated switches in from-UTF8 conversions. + Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. + + See the header file "ConvertUTF.h" for complete documentation. + +------------------------------------------------------------------------ */ + + +#include "llvm/Support/ConvertUTF.h" +#ifdef CVTUTF_DEBUG +#include <stdio.h> +#endif + +static const int halfShift = 10; /* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF32 halfMask = 0x3FFUL; + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF +#define false 0 +#define true 1 + +/* --------------------------------------------------------------------- */ + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. + */ +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. + */ +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... etc.). Remember that sequencs + * for *legal* UTF-8 will be 4 or fewer bytes total. + */ +static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* --------------------------------------------------------------------- */ + +/* The interface converts a whole buffer to avoid function-call overhead. + * Constants have been gathered. Loops & conditionals have been removed as + * much as possible for efficiency, in favor of drop-through switches. + * (See "Note A" at the bottom of the file for equivalent code.) + * If your compiler supports it, the "isLegalUTF8" call can be turned + * into an inline function. + */ + + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + if (target >= targetEnd) { + result = targetExhausted; break; + } + ch = *source++; + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_LEGAL_UTF32) { + if (flags == strictConversion) { + result = sourceIllegal; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + --source; /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF32* target = *targetStart; + UTF32 ch, ch2; + while (source < sourceEnd) { + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + if (target >= targetEnd) { + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; break; + } + *target++ = ch; + } + *sourceStart = source; + *targetStart = target; +#ifdef CVTUTF_DEBUG +if (result == sourceIllegal) { + fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); + fflush(stderr); +} +#endif + return result; +} +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + UTF32 ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + ch = *source++; + if (flags == strictConversion ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + } + + target += bytesToWrite; + if (target > targetEnd) { + --source; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * If not calling this from ConvertUTF8to*, then the length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns false. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ + +static Boolean isLegalUTF8(const UTF8 *source, int length) { + UTF8 a; + const UTF8 *srcptr = source+length; + switch (length) { + default: return false; + /* Everything else falls through when "true"... */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 2: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xED: if (a > 0x9F) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; + } + + case 1: if (*source >= 0x80 && *source < 0xC2) return false; + } + if (*source > 0xF4) return false; + return true; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 sequence is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { + int length = trailingBytesForUTF8[*source]+1; + if (length > sourceEnd - source) { + return false; + } + return isLegalUTF8(source, length); +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return the total number of bytes in a codepoint + * represented in UTF-8, given the value of the first byte. + */ +unsigned getNumBytesForUTF8(UTF8 first) { + return trailingBytesForUTF8[first] + 1; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 string is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd) { + while (*source != sourceEnd) { + int length = trailingBytesForUTF8[**source] + 1; + if (length > sourceEnd - *source || !isLegalUTF8(*source, length)) + return false; + *source += length; + } + return true; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (extraBytesToRead >= sourceEnd - source) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (!isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF32 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF32* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (extraBytesToRead >= sourceEnd - source) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (!isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; + case 4: ch += *source++; ch <<= 6; + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up the source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_LEGAL_UTF32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = ch; + } + } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- + + Note A. + The fall-through switches in UTF-8 reading code save a + temp variable, some decrements & conditionals. The switches + are equivalent to the following loop: + { + int tmpBytesToRead = extraBytesToRead+1; + do { + ch += *source++; + --tmpBytesToRead; + if (tmpBytesToRead) ch <<= 6; + } while (tmpBytesToRead > 0); + } + In UTF-8 writing code, the switches on "bytesToWrite" are + similarly unrolled loops. + + --------------------------------------------------------------------- */ diff --git a/lib/Support/ConvertUTFWrapper.cpp b/lib/Support/ConvertUTFWrapper.cpp new file mode 100644 index 000000000000..458fbb0b496a --- /dev/null +++ b/lib/Support/ConvertUTFWrapper.cpp @@ -0,0 +1,76 @@ +//===-- ConvertUTFWrapper.cpp - Wrap ConvertUTF.h with clang data types -----=== +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ConvertUTF.h" + +namespace llvm { + +bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source, + char *&ResultPtr, const UTF8 *&ErrorPtr) { + assert(WideCharWidth == 1 || WideCharWidth == 2 || WideCharWidth == 4); + ConversionResult result = conversionOK; + // Copy the character span over. + if (WideCharWidth == 1) { + const UTF8 *Pos = reinterpret_cast<const UTF8*>(Source.begin()); + if (!isLegalUTF8String(&Pos, reinterpret_cast<const UTF8*>(Source.end()))) { + result = sourceIllegal; + ErrorPtr = Pos; + } else { + memcpy(ResultPtr, Source.data(), Source.size()); + ResultPtr += Source.size(); + } + } else if (WideCharWidth == 2) { + const UTF8 *sourceStart = (const UTF8*)Source.data(); + // FIXME: Make the type of the result buffer correct instead of + // using reinterpret_cast. + UTF16 *targetStart = reinterpret_cast<UTF16*>(ResultPtr); + ConversionFlags flags = strictConversion; + result = ConvertUTF8toUTF16( + &sourceStart, sourceStart + Source.size(), + &targetStart, targetStart + 2*Source.size(), flags); + if (result == conversionOK) + ResultPtr = reinterpret_cast<char*>(targetStart); + else + ErrorPtr = sourceStart; + } else if (WideCharWidth == 4) { + const UTF8 *sourceStart = (const UTF8*)Source.data(); + // FIXME: Make the type of the result buffer correct instead of + // using reinterpret_cast. + UTF32 *targetStart = reinterpret_cast<UTF32*>(ResultPtr); + ConversionFlags flags = strictConversion; + result = ConvertUTF8toUTF32( + &sourceStart, sourceStart + Source.size(), + &targetStart, targetStart + 4*Source.size(), flags); + if (result == conversionOK) + ResultPtr = reinterpret_cast<char*>(targetStart); + else + ErrorPtr = sourceStart; + } + assert((result != targetExhausted) + && "ConvertUTF8toUTFXX exhausted target buffer"); + return result == conversionOK; +} + +bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) { + const UTF32 *SourceStart = &Source; + const UTF32 *SourceEnd = SourceStart + 1; + UTF8 *TargetStart = reinterpret_cast<UTF8 *>(ResultPtr); + UTF8 *TargetEnd = TargetStart + 4; + ConversionResult CR = ConvertUTF32toUTF8(&SourceStart, SourceEnd, + &TargetStart, TargetEnd, + strictConversion); + if (CR != conversionOK) + return false; + + ResultPtr = reinterpret_cast<char*>(TargetStart); + return true; +} + +} // end namespace llvm + diff --git a/lib/Support/CrashRecoveryContext.cpp b/lib/Support/CrashRecoveryContext.cpp index e175056279cc..182c362cc755 100644 --- a/lib/Support/CrashRecoveryContext.cpp +++ b/lib/Support/CrashRecoveryContext.cpp @@ -10,11 +10,11 @@ #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/ADT/SmallString.h" #include "llvm/Config/config.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/ThreadLocal.h" -#include "llvm/Support/ErrorHandling.h" -#include <setjmp.h> #include <cstdio> +#include <setjmp.h> using namespace llvm; namespace { diff --git a/lib/Support/DataStream.cpp b/lib/Support/DataStream.cpp index 3a38e2a66b43..0a02281c2549 100644 --- a/lib/Support/DataStream.cpp +++ b/lib/Support/DataStream.cpp @@ -15,13 +15,13 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "Data-stream" -#include "llvm/ADT/Statistic.h" #include "llvm/Support/DataStream.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Support/Program.h" #include "llvm/Support/system_error.h" -#include <string> #include <cerrno> #include <cstdio> +#include <string> #if !defined(_MSC_VER) && !defined(__MINGW32__) #include <unistd.h> #else diff --git a/lib/Support/Debug.cpp b/lib/Support/Debug.cpp index c8e8900749bb..d9cb8a9da815 100644 --- a/lib/Support/Debug.cpp +++ b/lib/Support/Debug.cpp @@ -23,10 +23,10 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/circular_raw_ostream.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/circular_raw_ostream.h" using namespace llvm; @@ -44,7 +44,7 @@ Debug("debug", cl::desc("Enable debug output"), cl::Hidden, //until program termination. static cl::opt<unsigned> DebugBufferSize("debug-buffer-size", - cl::desc("Buffer the last N characters of debug output" + cl::desc("Buffer the last N characters of debug output " "until program termination. " "[default 0 -- immediate print-out]"), cl::Hidden, diff --git a/lib/Support/Disassembler.cpp b/lib/Support/Disassembler.cpp index c6d73bcad3e4..b3244fab7df7 100644 --- a/lib/Support/Disassembler.cpp +++ b/lib/Support/Disassembler.cpp @@ -12,13 +12,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Config/config.h" #include "llvm/Support/Disassembler.h" - +#include "llvm/Config/config.h" #include <cassert> #include <iomanip> -#include <string> #include <sstream> +#include <string> #if USE_UDIS86 #include <udis86.h> diff --git a/lib/Support/Dwarf.cpp b/lib/Support/Dwarf.cpp index 5c59a3ef8ef3..0f91c11ac260 100644 --- a/lib/Support/Dwarf.cpp +++ b/lib/Support/Dwarf.cpp @@ -80,8 +80,6 @@ const char *llvm::dwarf::TagString(unsigned Tag) { 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"; @@ -248,6 +246,14 @@ const char *llvm::dwarf::AttributeString(unsigned Attribute) { 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"; + + // DWARF5 Fission Extension Attribute + case DW_AT_GNU_dwo_name: return "DW_AT_GNU_dwo_name"; + case DW_AT_GNU_dwo_id: return "DW_AT_GNU_dwo_id"; + case DW_AT_GNU_ranges_base: return "DW_AT_GNU_ranges_base"; + case DW_AT_GNU_addr_base: return "DW_AT_GNU_addr_base"; + case DW_AT_GNU_pubnames: return "DW_AT_GNU_pubnames"; + case DW_AT_GNU_pubtypes: return "DW_AT_GNU_pubtypes"; } return 0; } @@ -281,6 +287,10 @@ const char *llvm::dwarf::FormEncodingString(unsigned Encoding) { 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"; + + // DWARF5 Fission Extension Forms + case DW_FORM_GNU_addr_index: return "DW_FORM_GNU_addr_index"; + case DW_FORM_GNU_str_index: return "DW_FORM_GNU_str_index"; } return 0; } @@ -445,6 +455,10 @@ const char *llvm::dwarf::OperationEncodingString(unsigned Encoding) { 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"; + + // DWARF5 Fission Proposal Op Extensions + case DW_OP_GNU_addr_index: return "DW_OP_GNU_addr_index"; + case DW_OP_GNU_const_index: return "DW_OP_GNU_const_index"; } return 0; } @@ -674,6 +688,7 @@ const char *llvm::dwarf::MacinfoString(unsigned Encoding) { /// encodings. const char *llvm::dwarf::CallFrameString(unsigned Encoding) { switch (Encoding) { + case DW_CFA_nop: return "DW_CFA_nop"; 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"; diff --git a/lib/Support/DynamicLibrary.cpp b/lib/Support/DynamicLibrary.cpp index 45fec361c1a6..f14cb45d9dc0 100644 --- a/lib/Support/DynamicLibrary.cpp +++ b/lib/Support/DynamicLibrary.cpp @@ -13,11 +13,11 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/Mutex.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Config/config.h" +#include "llvm/Support/Mutex.h" #include <cstdio> #include <cstring> @@ -46,7 +46,7 @@ void llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName, void *symbolValue) { SmartScopedLock<true> lock(getMutex()); if (ExplicitSymbols == 0) - ExplicitSymbols = new llvm::StringMap<void*>(); + ExplicitSymbols = new StringMap<void*>(); (*ExplicitSymbols)[symbolName] = symbolValue; } diff --git a/lib/Support/ErrorHandling.cpp b/lib/Support/ErrorHandling.cpp index e6cc57db8243..f4b591e777eb 100644 --- a/lib/Support/ErrorHandling.cpp +++ b/lib/Support/ErrorHandling.cpp @@ -12,14 +12,14 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Support/ErrorHandling.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Twine.h" +#include "llvm/Config/config.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 "llvm/Support/raw_ostream.h" #include <cassert> #include <cstdlib> @@ -49,21 +49,21 @@ 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 char *Reason, bool GenCrashDiag) { + report_fatal_error(Twine(Reason), GenCrashDiag); } -void llvm::report_fatal_error(const std::string &Reason) { - report_fatal_error(Twine(Reason)); +void llvm::report_fatal_error(const std::string &Reason, bool GenCrashDiag) { + report_fatal_error(Twine(Reason), GenCrashDiag); } -void llvm::report_fatal_error(StringRef Reason) { - report_fatal_error(Twine(Reason)); +void llvm::report_fatal_error(StringRef Reason, bool GenCrashDiag) { + report_fatal_error(Twine(Reason), GenCrashDiag); } -void llvm::report_fatal_error(const Twine &Reason) { +void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) { if (ErrorHandler) { - ErrorHandler(ErrorHandlerUserData, Reason.str()); + ErrorHandler(ErrorHandlerUserData, Reason.str(), GenCrashDiag); } 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 diff --git a/lib/Support/FileOutputBuffer.cpp b/lib/Support/FileOutputBuffer.cpp index 7dc9587caae2..1ee69b60234f 100644 --- a/lib/Support/FileOutputBuffer.cpp +++ b/lib/Support/FileOutputBuffer.cpp @@ -12,37 +12,28 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/FileOutputBuffer.h" - #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" +using llvm::sys::fs::mapped_file_region; namespace llvm { - - -FileOutputBuffer::FileOutputBuffer(uint8_t *Start, uint8_t *End, - StringRef Path, StringRef TmpPath) - : BufferStart(Start), BufferEnd(End) { - FinalPath.assign(Path); - TempPath.assign(TmpPath); +FileOutputBuffer::FileOutputBuffer(mapped_file_region * R, + StringRef Path, StringRef TmpPath) + : Region(R) + , FinalPath(Path) + , TempPath(TmpPath) { } - FileOutputBuffer::~FileOutputBuffer() { - // If not already commited, delete buffer and remove temp file. - if ( BufferStart != NULL ) { - sys::fs::unmap_file_pages((void*)BufferStart, getBufferSize()); - bool Existed; - sys::fs::remove(Twine(TempPath), Existed); - } + bool Existed; + sys::fs::remove(Twine(TempPath), Existed); } - -error_code FileOutputBuffer::create(StringRef FilePath, - size_t Size, +error_code FileOutputBuffer::create(StringRef FilePath, + size_t Size, OwningPtr<FileOutputBuffer> &Result, unsigned Flags) { // If file already exists, it must be a regular file (to be mappable). @@ -70,34 +61,27 @@ error_code FileOutputBuffer::create(StringRef FilePath, EC = sys::fs::remove(FilePath, Existed); if (EC) return EC; - + // Create new file in same directory but with random name. SmallString<128> TempFilePath; int FD; - EC = sys::fs::unique_file(Twine(FilePath) + ".tmp%%%%%%%", - FD, TempFilePath, false, 0644); + EC = sys::fs::unique_file(Twine(FilePath) + ".tmp%%%%%%%", + FD, TempFilePath, false, 0644); if (EC) return EC; - - // The unique_file() interface leaks lower layers and returns a file - // descriptor. There is no way to directly close it, so use this hack - // to hand it off to raw_fd_ostream to close for us. - { - raw_fd_ostream Dummy(FD, /*shouldClose=*/true); - } - - // Resize file to requested initial size - EC = sys::fs::resize_file(Twine(TempFilePath), Size); + + OwningPtr<mapped_file_region> MappedFile(new mapped_file_region( + FD, true, mapped_file_region::readwrite, Size, 0, EC)); if (EC) return EC; - + // If requested, make the output file executable. if ( Flags & F_executable ) { sys::fs::file_status Stat2; EC = sys::fs::status(Twine(TempFilePath), Stat2); if (EC) return EC; - + sys::fs::perms new_perms = Stat2.permissions(); if ( new_perms & sys::fs::owner_read ) new_perms |= sys::fs::owner_exe; @@ -111,38 +95,25 @@ error_code FileOutputBuffer::create(StringRef FilePath, return EC; } - // Memory map new file. - void *Base; - EC = sys::fs::map_file_pages(Twine(TempFilePath), 0, Size, true, Base); - if (EC) - return EC; - - // Create FileOutputBuffer object to own mapped range. - uint8_t *Start = reinterpret_cast<uint8_t*>(Base); - Result.reset(new FileOutputBuffer(Start, Start+Size, FilePath, TempFilePath)); - - return error_code::success(); -} + Result.reset(new FileOutputBuffer(MappedFile.get(), FilePath, TempFilePath)); + if (Result) + MappedFile.take(); + return error_code::success(); +} error_code FileOutputBuffer::commit(int64_t NewSmallerSize) { // Unmap buffer, letting OS flush dirty pages to file on disk. - void *Start = reinterpret_cast<void*>(BufferStart); - error_code EC = sys::fs::unmap_file_pages(Start, getBufferSize()); - if (EC) - return EC; - + Region.reset(0); + // If requested, resize file as part of commit. if ( NewSmallerSize != -1 ) { - EC = sys::fs::resize_file(Twine(TempPath), NewSmallerSize); + error_code EC = sys::fs::resize_file(Twine(TempPath), NewSmallerSize); if (EC) return EC; } - + // Rename file to final name. return sys::fs::rename(Twine(TempPath), Twine(FinalPath)); } - - } // namespace - diff --git a/lib/Support/FileUtilities.cpp b/lib/Support/FileUtilities.cpp index f9e9cf036608..4d7b2391f01e 100644 --- a/lib/Support/FileUtilities.cpp +++ b/lib/Support/FileUtilities.cpp @@ -13,15 +13,15 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/FileUtilities.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/SmallString.h" +#include <cctype> #include <cstdlib> #include <cstring> -#include <cctype> using namespace llvm; static bool isSignedChar(char C) { @@ -87,9 +87,9 @@ static bool CompareNumbers(const char *&F1P, const char *&F2P, // 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) + while (isspace(static_cast<unsigned char>(*F1P)) && F1P != F1End) ++F1P; - while (isspace(*F2P) && F2P != F2End) + while (isspace(static_cast<unsigned char>(*F2P)) && F2P != F2End) ++F2P; // If we stop on numbers, compare their difference. diff --git a/lib/Support/FoldingSet.cpp b/lib/Support/FoldingSet.cpp index 4d489a88e55d..36e33b5aafa3 100644 --- a/lib/Support/FoldingSet.cpp +++ b/lib/Support/FoldingSet.cpp @@ -8,9 +8,7 @@ //===----------------------------------------------------------------------===// // // 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. +// nodes in a graph. // //===----------------------------------------------------------------------===// @@ -18,8 +16,8 @@ #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 "llvm/Support/MathExtras.h" #include <cassert> #include <cstring> using namespace llvm; @@ -150,7 +148,7 @@ unsigned FoldingSetNodeID::ComputeHash() const { /// operator== - Used to compare two nodes to each other. /// -bool FoldingSetNodeID::operator==(const FoldingSetNodeID &RHS)const{ +bool FoldingSetNodeID::operator==(const FoldingSetNodeID &RHS) const { return *this == FoldingSetNodeIDRef(RHS.Bits.data(), RHS.Bits.size()); } @@ -162,7 +160,7 @@ bool FoldingSetNodeID::operator==(FoldingSetNodeIDRef RHS) const { /// Used to compare the "ordering" of two nodes as defined by the /// profiled bits and their ordering defined by memcmp(). -bool FoldingSetNodeID::operator<(const FoldingSetNodeID &RHS)const{ +bool FoldingSetNodeID::operator<(const FoldingSetNodeID &RHS) const { return *this < FoldingSetNodeIDRef(RHS.Bits.data(), RHS.Bits.size()); } diff --git a/lib/Support/GraphWriter.cpp b/lib/Support/GraphWriter.cpp index f6aaf8381171..bff182f30e35 100644 --- a/lib/Support/GraphWriter.cpp +++ b/lib/Support/GraphWriter.cpp @@ -11,11 +11,11 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/CommandLine.h" #include "llvm/Support/GraphWriter.h" +#include "llvm/Config/config.h" +#include "llvm/Support/CommandLine.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, @@ -53,6 +53,17 @@ std::string llvm::DOT::EscapeString(const std::string &Label) { return Str; } +/// \brief Get a color string for this node number. Simply round-robin selects +/// from a reasonable number of colors. +StringRef llvm::DOT::getColorString(unsigned ColorNumber) { + static const int NumColors = 20; + static const char* Colors[NumColors] = { + "aaaaaa", "aa0000", "00aa00", "aa5500", "0055ff", "aa00aa", "00aaaa", + "555555", "ff5555", "55ff55", "ffff55", "5555ff", "ff55ff", "55ffff", + "ffaaaa", "aaffaa", "ffffaa", "aaaaff", "ffaaff", "aaffff"}; + return Colors[ColorNumber % NumColors]; +} + // Execute the graph viewer. Return true if successful. static bool LLVM_ATTRIBUTE_UNUSED ExecGraphViewer(const sys::Path &ExecPath, std::vector<const char*> &args, diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp index 34e32b817b36..73d98d148746 100644 --- a/lib/Support/Host.cpp +++ b/lib/Support/Host.cpp @@ -11,14 +11,15 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Support/Host.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Config/config.h" #include "llvm/Support/DataStream.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/Host.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Config/config.h" #include <string.h> // Include the platform-specific parts of this class. @@ -111,6 +112,21 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, #endif } +static bool OSHasAVXSupport() {
+#if defined(__GNUC__)
+ // Check xgetbv; this uses a .byte sequence instead of the instruction
+ // directly because older assemblers do not include support for xgetbv and
+ // there is no easy way to conditionally compile based on the assembler used.
+ int rEAX, rEDX;
+ __asm__ (".byte 0x0f, 0x01, 0xd0" : "=a" (rEAX), "=d" (rEDX) : "c" (0));
+#elif defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 160040219
+ unsigned long long rEAX = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
+#else
+ int rEAX = 0; // Ensures we return false
+#endif
+ return (rEAX & 6) == 6;
+} + static void DetectX86FamilyModel(unsigned EAX, unsigned &Family, unsigned &Model) { Family = (EAX >> 8) & 0xf; // Bits 8 - 11 @@ -133,6 +149,11 @@ std::string sys::getHostCPUName() { DetectX86FamilyModel(EAX, Family, Model); bool HasSSE3 = (ECX & 0x1); + // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV + // indicates that the AVX registers will be saved and restored on context + // switch, then we have full AVX support. + const unsigned AVXBits = (1 << 27) | (1 << 28); + bool HasAVX = ((ECX & AVXBits) == AVXBits) && OSHasAVXSupport(); GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); bool Em64T = (EDX >> 29) & 0x1; @@ -242,11 +263,15 @@ std::string sys::getHostCPUName() { case 42: // Intel Core i7 processor. All processors are manufactured // using the 32 nm process. case 45: - return "corei7-avx"; + // Not all Sandy Bridge processors support AVX (such as the Pentium + // versions instead of the i7 versions). + return HasAVX ? "corei7-avx" : "corei7"; // Ivy Bridge: case 58: - return "core-avx-i"; + // Not all Ivy Bridge processors support AVX (such as the Pentium + // versions instead of the i7 versions). + return HasAVX ? "core-avx-i" : "corei7"; case 28: // Most 45 nm Intel Atom processors case 38: // 45 nm Atom Lincroft @@ -330,7 +355,10 @@ std::string sys::getHostCPUName() { case 20: return "btver1"; case 21: - return "bdver1"; + if (Model <= 15) + return "bdver1"; + else if (Model <= 31) + return "bdver2"; default: return "generic"; } @@ -517,6 +545,75 @@ std::string sys::getHostCPUName() { } #endif +#if defined(__linux__) && defined(__arm__) +bool sys::getHostCPUFeatures(StringMap<bool> &Features) { + std::string Err; + DataStreamer *DS = getDataFileStreamer("/proc/cpuinfo", &Err); + if (!DS) { + DEBUG(dbgs() << "Unable to open /proc/cpuinfo: " << Err << "\n"); + return false; + } + + // Read 1024 bytes from /proc/cpuinfo, which should contain the Features line + // in all cases. + char buffer[1024]; + size_t CPUInfoSize = DS->GetBytes((unsigned char*) buffer, sizeof(buffer)); + delete DS; + + StringRef Str(buffer, CPUInfoSize); + + SmallVector<StringRef, 32> Lines; + Str.split(Lines, "\n"); + + // Look for the CPU implementer line. + StringRef Implementer; + for (unsigned I = 0, E = Lines.size(); I != E; ++I) + if (Lines[I].startswith("CPU implementer")) + Implementer = Lines[I].substr(15).ltrim("\t :"); + + if (Implementer == "0x41") { // ARM Ltd. + SmallVector<StringRef, 32> CPUFeatures; + + // Look for the CPU features. + for (unsigned I = 0, E = Lines.size(); I != E; ++I) + if (Lines[I].startswith("Features")) { + Lines[I].split(CPUFeatures, " "); + break; + } + + for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) { + StringRef LLVMFeatureStr = StringSwitch<StringRef>(CPUFeatures[I]) + .Case("half", "fp16") + .Case("neon", "neon") + .Case("vfpv3", "vfp3") + .Case("vfpv3d16", "d16") + .Case("vfpv4", "vfp4") + .Case("idiva", "hwdiv-arm") + .Case("idivt", "hwdiv") + .Default(""); + + if (LLVMFeatureStr != "") + Features.GetOrCreateValue(LLVMFeatureStr).setValue(true); + } + + return true; + } + + return false; +} +#else bool sys::getHostCPUFeatures(StringMap<bool> &Features){ return false; } +#endif + +std::string sys::getProcessTriple() { + Triple PT(LLVM_HOSTTRIPLE); + + if (sizeof(void *) == 8 && PT.isArch32Bit()) + PT = PT.get64BitArchVariant(); + if (sizeof(void *) == 4 && PT.isArch64Bit()) + PT = PT.get32BitArchVariant(); + + return PT.str(); +} diff --git a/lib/Support/LocaleWindows.inc b/lib/Support/LocaleWindows.inc index 6827ac15a1ac..28e429c0cb7d 100644 --- a/lib/Support/LocaleWindows.inc +++ b/lib/Support/LocaleWindows.inc @@ -12,4 +12,4 @@ bool isPrint(int c) { } } -}
\ No newline at end of file +} diff --git a/lib/Support/LocaleXlocale.inc b/lib/Support/LocaleXlocale.inc index f595e7c582ca..389fe3d1d4fd 100644 --- a/lib/Support/LocaleXlocale.inc +++ b/lib/Support/LocaleXlocale.inc @@ -1,5 +1,5 @@ -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/ManagedStatic.h" #include <cassert> #include <xlocale.h> diff --git a/lib/Support/LockFileManager.cpp b/lib/Support/LockFileManager.cpp index 59bfcfcd254c..92d8b83cf94e 100644 --- a/lib/Support/LockFileManager.cpp +++ b/lib/Support/LockFileManager.cpp @@ -10,8 +10,8 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include <fstream> -#include <sys/types.h> #include <sys/stat.h> +#include <sys/types.h> #if LLVM_ON_WIN32 #include <windows.h> #endif @@ -31,7 +31,7 @@ LockFileManager::readLockFile(StringRef LockFileName) { // to read, so we just return. bool Exists = false; if (sys::fs::exists(LockFileName, Exists) || !Exists) - return Optional<std::pair<std::string, int> >(); + return None; // 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. @@ -45,7 +45,7 @@ LockFileManager::readLockFile(StringRef LockFileName) { // Delete the lock file. It's invalid anyway. bool Existed; sys::fs::remove(LockFileName, Existed); - return Optional<std::pair<std::string, int> >(); + return None; } bool LockFileManager::processStillExecuting(StringRef Hostname, int PID) { @@ -64,6 +64,7 @@ bool LockFileManager::processStillExecuting(StringRef Hostname, int PID) { LockFileManager::LockFileManager(StringRef FileName) { + this->FileName = FileName; LockFileName = FileName; LockFileName += ".lock"; @@ -175,6 +176,7 @@ void LockFileManager::waitForUnlock() { #endif // Don't wait more than an hour for the file to appear. const unsigned MaxSeconds = 3600; + bool LockFileGone = false; do { // Sleep for the designated interval, to allow the owning process time to // finish up and remove the lock file. @@ -185,10 +187,18 @@ void LockFileManager::waitForUnlock() { #else nanosleep(&Interval, NULL); #endif - // If the file no longer exists, we're done. + // If the lock file no longer exists, wait for the actual file. bool Exists = false; - if (!sys::fs::exists(LockFileName.str(), Exists) && !Exists) - return; + if (!LockFileGone) { + if (!sys::fs::exists(LockFileName.str(), Exists) && !Exists) { + LockFileGone = true; + Exists = false; + } + } + if (LockFileGone) { + if (!sys::fs::exists(FileName.str(), Exists) && Exists) + return; + } if (!processStillExecuting((*Owner).first, (*Owner).second)) return; diff --git a/lib/Support/Memory.cpp b/lib/Support/Memory.cpp index 12f083822fd4..f9a4903ad015 100644 --- a/lib/Support/Memory.cpp +++ b/lib/Support/Memory.cpp @@ -13,8 +13,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Memory.h" -#include "llvm/Support/Valgrind.h" #include "llvm/Config/config.h" +#include "llvm/Support/Valgrind.h" // Include the platform-specific parts of this class. #ifdef LLVM_ON_UNIX diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp index ec373e7f997c..7c5ab96a764a 100644 --- a/lib/Support/MemoryBuffer.cpp +++ b/lib/Support/MemoryBuffer.cpp @@ -15,26 +15,31 @@ #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/FileSystem.h" +#include "llvm/Support/MathExtras.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 <cerrno> #include <cstdio> #include <cstring> -#include <cerrno> #include <new> -#include <sys/types.h> #include <sys/stat.h> +#include <sys/types.h> #if !defined(_MSC_VER) && !defined(__MINGW32__) #include <unistd.h> #else #include <io.h> -#ifndef S_ISFIFO -#define S_ISFIFO(x) (0) +// Simplistic definitinos of these macros to allow files to be read with +// MapInFilePages. +#ifndef S_ISREG +#define S_ISREG(x) (1) +#endif +#ifndef S_ISBLK +#define S_ISBLK(x) (0) #endif #endif #include <fcntl.h> @@ -67,13 +72,17 @@ static void CopyStringRef(char *Memory, StringRef Data) { 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 { +struct NamedBufferAlloc { + StringRef Name; + NamedBufferAlloc(StringRef Name) : Name(Name) {} +}; +} + +void *operator new(size_t N, const NamedBufferAlloc &Alloc) { + char *Mem = static_cast<char *>(operator new(N + Alloc.Name.size() + 1)); + CopyStringRef(Mem + N, Alloc.Name); + return Mem; } namespace { @@ -100,8 +109,8 @@ public: MemoryBuffer *MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName, bool RequiresNullTerminator) { - return GetNamedBuffer<MemoryBufferMem>(InputData, BufferName, - RequiresNullTerminator); + return new (NamedBufferAlloc(BufferName)) + MemoryBufferMem(InputData, RequiresNullTerminator); } /// getMemBufferCopy - Open the specified memory range as a MemoryBuffer, @@ -178,24 +187,38 @@ error_code MemoryBuffer::getFileOrSTDIN(const char *Filename, //===----------------------------------------------------------------------===// 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) { } +/// \brief Memorry maps a file descriptor using sys::fs::mapped_file_region. +/// +/// This handles converting the offset into a legal offset on the platform. +class MemoryBufferMMapFile : public MemoryBuffer { + sys::fs::mapped_file_region MFR; + + static uint64_t getLegalMapOffset(uint64_t Offset) { + return Offset & ~(sys::fs::mapped_file_region::alignment() - 1); + } - ~MemoryBufferMMapFile() { - static int PageSize = sys::Process::GetPageSize(); + static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) { + return Len + (Offset - getLegalMapOffset(Offset)); + } - uintptr_t Start = reinterpret_cast<uintptr_t>(getBufferStart()); - size_t Size = getBufferSize(); - uintptr_t RealStart = Start & ~(PageSize - 1); - size_t RealSize = Size + (Start - RealStart); + const char *getStart(uint64_t Len, uint64_t Offset) { + return MFR.const_data() + (Offset - getLegalMapOffset(Offset)); + } - sys::Path::UnMapFilePages(reinterpret_cast<const char*>(RealStart), - RealSize); +public: + MemoryBufferMMapFile(bool RequiresNullTerminator, int FD, uint64_t Len, + uint64_t Offset, error_code EC) + : MFR(FD, false, sys::fs::mapped_file_region::readonly, + getLegalMapSize(Len, Offset), getLegalMapOffset(Offset), EC) { + if (!EC) { + const char *Start = getStart(Len, Offset); + init(Start, Start + Len, RequiresNullTerminator); + } + } + + virtual const char *getBufferIdentifier() const LLVM_OVERRIDE { + // The name is stored after the class itself. + return reinterpret_cast<const char *>(this + 1); } virtual BufferKind getBufferKind() const LLVM_OVERRIDE { @@ -239,6 +262,8 @@ error_code MemoryBuffer::getFile(const char *Filename, OwningPtr<MemoryBuffer> &result, int64_t FileSize, bool RequiresNullTerminator) { + // FIXME: Review if this check is unnecessary on windows as well. +#ifdef LLVM_ON_WIN32 // First check that the "file" is not a directory bool is_dir = false; error_code err = sys::fs::is_directory(Filename, is_dir); @@ -246,6 +271,7 @@ error_code MemoryBuffer::getFile(const char *Filename, return err; if (is_dir) return make_error_code(errc::is_a_directory); +#endif int OpenFlags = O_RDONLY; #ifdef O_BINARY @@ -309,7 +335,7 @@ error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, uint64_t FileSize, uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator) { - static int PageSize = sys::Process::GetPageSize(); + static int PageSize = sys::process::get_self()->page_size(); // Default is to map the full file. if (MapSize == uint64_t(-1)) { @@ -322,9 +348,10 @@ error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, return error_code(errno, posix_category()); } - // If this is a named pipe, we can't trust the size. Create the memory + // If this not a file or a block device (e.g. it's a named pipe + // or character device), we can't trust the size. Create the memory // buffer by copying off the stream. - if (S_ISFIFO(FileInfo.st_mode)) { + if (!S_ISREG(FileInfo.st_mode) && !S_ISBLK(FileInfo.st_mode)) { return getMemoryBufferForStream(FD, Filename, result); } @@ -335,17 +362,11 @@ error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, 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)); + error_code EC; + result.reset(new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile( + RequiresNullTerminator, FD, MapSize, Offset, EC)); + if (!EC) return error_code::success(); - } } MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename); diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp index db4a56b6928c..d0703754e04f 100644 --- a/lib/Support/Path.cpp +++ b/lib/Support/Path.cpp @@ -12,10 +12,9 @@ //===----------------------------------------------------------------------===// #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 "llvm/Support/FileSystem.h" #include <cassert> #include <cstring> #include <ostream> diff --git a/lib/Support/PathV2.cpp b/lib/Support/PathV2.cpp index 46571c049f12..58a6ea720e73 100644 --- a/lib/Support/PathV2.cpp +++ b/lib/Support/PathV2.cpp @@ -12,12 +12,15 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/PathV2.h" -#include "llvm/Support/FileSystem.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" #include <cctype> #include <cstdio> #include <cstring> +#ifdef __APPLE__ +#include <unistd.h> +#endif namespace { using llvm::StringRef; @@ -44,7 +47,8 @@ namespace { #ifdef LLVM_ON_WIN32 // C: - if (path.size() >= 2 && std::isalpha(path[0]) && path[1] == ':') + if (path.size() >= 2 && std::isalpha(static_cast<unsigned char>(path[0])) && + path[1] == ':') return path.substr(0, 2); #endif @@ -492,6 +496,27 @@ bool is_separator(char value) { void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result) { result.clear(); +#ifdef __APPLE__ + // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR. + int ConfName = erasedOnReboot? _CS_DARWIN_USER_TEMP_DIR + : _CS_DARWIN_USER_CACHE_DIR; + size_t ConfLen = confstr(ConfName, 0, 0); + if (ConfLen > 0) { + do { + result.resize(ConfLen); + ConfLen = confstr(ConfName, result.data(), result.size()); + } while (ConfLen > 0 && ConfLen != result.size()); + + if (ConfLen > 0) { + assert(result.back() == 0); + result.pop_back(); + return; + } + + result.clear(); + } +#endif + // Check whether the temporary directory is specified by an environment // variable. const char *EnvironmentVariable; diff --git a/lib/Support/PluginLoader.cpp b/lib/Support/PluginLoader.cpp index 2924cfa38897..358137f08f5f 100644 --- a/lib/Support/PluginLoader.cpp +++ b/lib/Support/PluginLoader.cpp @@ -12,11 +12,11 @@ //===----------------------------------------------------------------------===// #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/ManagedStatic.h" #include "llvm/Support/Mutex.h" +#include "llvm/Support/raw_ostream.h" #include <vector> using namespace llvm; diff --git a/lib/Support/PrettyStackTrace.cpp b/lib/Support/PrettyStackTrace.cpp index ef3307317c4a..23ee5ab105ae 100644 --- a/lib/Support/PrettyStackTrace.cpp +++ b/lib/Support/PrettyStackTrace.cpp @@ -12,12 +12,13 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Config/config.h" // Get autoconf configuration settings #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Config/config.h" // Get autoconf configuration settings #include "llvm/Support/Signals.h" #include "llvm/Support/ThreadLocal.h" -#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Watchdog.h" +#include "llvm/Support/raw_ostream.h" #ifdef HAVE_CRASHREPORTERCLIENT_H #include <CrashReporterClient.h> @@ -37,7 +38,10 @@ static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){ if (Entry->getNextEntry()) NextID = PrintStack(Entry->getNextEntry(), OS); OS << NextID << ".\t"; - Entry->print(OS); + { + sys::Watchdog W(5); + Entry->print(OS); + } return NextID+1; } diff --git a/lib/Support/Process.cpp b/lib/Support/Process.cpp index 88ca7c3f220f..2c0d37bb3299 100644 --- a/lib/Support/Process.cpp +++ b/lib/Support/Process.cpp @@ -11,10 +11,11 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/Process.h" #include "llvm/Config/config.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Process.h" -namespace llvm { +using namespace llvm; using namespace sys; //===----------------------------------------------------------------------===// @@ -22,8 +23,63 @@ using namespace sys; //=== independent code. //===----------------------------------------------------------------------===// +// Empty virtual destructor to anchor the vtable for the process class. +process::~process() {} + +self_process *process::get_self() { + // Use a function local static for thread safe initialization and allocate it + // as a raw pointer to ensure it is never destroyed. + static self_process *SP = new self_process(); + + return SP; } +#if defined(_MSC_VER) +// Visual Studio complains that the self_process destructor never exits. This +// doesn't make much sense, as that's the whole point of calling abort... Just +// silence this warning. +#pragma warning(push) +#pragma warning(disable:4722) +#endif + +// The destructor for the self_process subclass must never actually be +// executed. There should be at most one instance of this class, and that +// instance should live until the process terminates to avoid the potential for +// racy accesses during shutdown. +self_process::~self_process() { + llvm_unreachable("This destructor must never be executed!"); +} + +/// \brief A helper function to compute the elapsed wall-time since the program +/// started. +/// +/// Note that this routine actually computes the elapsed wall time since the +/// first time it was called. However, we arrange to have it called during the +/// startup of the process to get approximately correct results. +static TimeValue getElapsedWallTime() { + static TimeValue &StartTime = *new TimeValue(TimeValue::now()); + return TimeValue::now() - StartTime; +} + +/// \brief A special global variable to ensure we call \c getElapsedWallTime +/// during global initialization of the program. +/// +/// Note that this variable is never referenced elsewhere. Doing so could +/// create race conditions during program startup or shutdown. +static volatile TimeValue DummyTimeValue = getElapsedWallTime(); + +// Implement this routine by using the static helpers above. They're already +// portable. +TimeValue self_process::get_wall_time() const { + return getElapsedWallTime(); +} + + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + + // Include the platform-specific parts of this class. #ifdef LLVM_ON_UNIX #include "Unix/Process.inc" diff --git a/lib/Support/Program.cpp b/lib/Support/Program.cpp index 75bc282d9bd4..201d5c0d3056 100644 --- a/lib/Support/Program.cpp +++ b/lib/Support/Program.cpp @@ -29,12 +29,15 @@ Program::ExecuteAndWait(const Path& path, const Path** redirects, unsigned secondsToWait, unsigned memoryLimit, - std::string* ErrMsg) { + std::string* ErrMsg, + bool *ExecutionFailed) { Program prg; - if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg)) + if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg)) { + if (ExecutionFailed) *ExecutionFailed = false; return prg.Wait(path, secondsToWait, ErrMsg); - else - return -1; + } + if (ExecutionFailed) *ExecutionFailed = true; + return -1; } void diff --git a/lib/Support/Regex.cpp b/lib/Support/Regex.cpp index d293da07d684..efc8b90a0090 100644 --- a/lib/Support/Regex.cpp +++ b/lib/Support/Regex.cpp @@ -12,10 +12,10 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Regex.h" +#include "regex_impl.h" +#include "llvm/ADT/SmallVector.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; @@ -27,7 +27,9 @@ Regex::Regex(StringRef regex, unsigned Flags) { flags |= REG_ICASE; if (Flags & Newline) flags |= REG_NEWLINE; - error = llvm_regcomp(preg, regex.data(), flags|REG_EXTENDED|REG_PEND); + if (!(Flags & BasicRegex)) + flags |= REG_EXTENDED; + error = llvm_regcomp(preg, regex.data(), flags|REG_PEND); } Regex::~Regex() { diff --git a/lib/Support/SmallPtrSet.cpp b/lib/Support/SmallPtrSet.cpp index 3b53e9ff49fe..f0fed7792ce6 100644 --- a/lib/Support/SmallPtrSet.cpp +++ b/lib/Support/SmallPtrSet.cpp @@ -29,13 +29,9 @@ void SmallPtrSetImpl::shrink_and_clear() { NumElements = NumTombstones = 0; // Install the new array. Clear all the buckets to empty. - CurArray = (const void**)malloc(sizeof(void*) * (CurArraySize+1)); + CurArray = (const void**)malloc(sizeof(void*) * CurArraySize); 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) { @@ -139,15 +135,11 @@ void SmallPtrSetImpl::Grow(unsigned NewSize) { bool WasSmall = isSmall(); // Install the new array. Clear all the buckets to empty. - CurArray = (const void**)malloc(sizeof(void*) * (NewSize+1)); + CurArray = (const void**)malloc(sizeof(void*) * NewSize); 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. @@ -180,7 +172,7 @@ SmallPtrSetImpl::SmallPtrSetImpl(const void **SmallStorage, CurArray = SmallArray; // Otherwise, allocate new heap space (unless we were the same size) } else { - CurArray = (const void**)malloc(sizeof(void*) * (that.CurArraySize+1)); + CurArray = (const void**)malloc(sizeof(void*) * that.CurArraySize); assert(CurArray && "Failed to allocate memory?"); } @@ -188,7 +180,7 @@ SmallPtrSetImpl::SmallPtrSetImpl(const void **SmallStorage, CurArraySize = that.CurArraySize; // Copy over the contents from the other set - memcpy(CurArray, that.CurArray, sizeof(void*)*(CurArraySize+1)); + memcpy(CurArray, that.CurArray, sizeof(void*)*CurArraySize); NumElements = that.NumElements; NumTombstones = that.NumTombstones; @@ -200,7 +192,7 @@ 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()) @@ -209,9 +201,9 @@ void SmallPtrSetImpl::CopyFrom(const SmallPtrSetImpl &RHS) { // Otherwise, allocate new heap space (unless we were the same size) } else if (CurArraySize != RHS.CurArraySize) { if (isSmall()) - CurArray = (const void**)malloc(sizeof(void*) * (RHS.CurArraySize+1)); + CurArray = (const void**)malloc(sizeof(void*) * RHS.CurArraySize); else - CurArray = (const void**)realloc(CurArray, sizeof(void*)*(RHS.CurArraySize+1)); + CurArray = (const void**)realloc(CurArray, sizeof(void*)*RHS.CurArraySize); assert(CurArray && "Failed to allocate memory?"); } @@ -219,7 +211,7 @@ void SmallPtrSetImpl::CopyFrom(const SmallPtrSetImpl &RHS) { CurArraySize = RHS.CurArraySize; // Copy over the contents from the other set - memcpy(CurArray, RHS.CurArray, sizeof(void*)*(CurArraySize+1)); + memcpy(CurArray, RHS.CurArray, sizeof(void*)*CurArraySize); NumElements = RHS.NumElements; NumTombstones = RHS.NumTombstones; diff --git a/lib/Support/SourceMgr.cpp b/lib/Support/SourceMgr.cpp index e4e01be03802..fac3cad5cc25 100644 --- a/lib/Support/SourceMgr.cpp +++ b/lib/Support/SourceMgr.cpp @@ -13,14 +13,18 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/Twine.h" #include "llvm/Support/SourceMgr.h" -#include "llvm/Support/MemoryBuffer.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Locale.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" using namespace llvm; +static const size_t TabStop = 8; + namespace { struct LineNoCacheTy { int LastQueryBufferID; @@ -146,7 +150,8 @@ void SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const { /// prefixed to the message. SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg, - ArrayRef<SMRange> Ranges) const { + ArrayRef<SMRange> Ranges, + ArrayRef<SMFixIt> FixIts) const { // First thing to do: find the current buffer containing the specified // location to pull out the source line. @@ -193,6 +198,7 @@ SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind, R.End = SMLoc::getFromPointer(LineEnd); // Translate from SMLoc ranges to column ranges. + // FIXME: Handle multibyte characters. ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart, R.End.getPointer()-LineStart)); } @@ -202,13 +208,13 @@ SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind, return SMDiagnostic(*this, Loc, BufferID, LineAndCol.first, LineAndCol.second-1, Kind, Msg.str(), - LineStr, ColRanges); + LineStr, ColRanges, FixIts); } void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg, ArrayRef<SMRange> Ranges, - bool ShowColors) const { - SMDiagnostic Diagnostic = GetMessage(Loc, Kind, Msg, Ranges); + ArrayRef<SMFixIt> FixIts, bool ShowColors) const { + SMDiagnostic Diagnostic = GetMessage(Loc, Kind, Msg, Ranges, FixIts); // Report the message with the diagnostic handler if present. if (DiagHandler) { @@ -231,15 +237,108 @@ void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind, // SMDiagnostic Implementation //===----------------------------------------------------------------------===// -SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, const std::string &FN, +SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN, int Line, int Col, SourceMgr::DiagKind Kind, - const std::string &Msg, - const std::string &LineStr, - ArrayRef<std::pair<unsigned,unsigned> > Ranges) + StringRef Msg, StringRef LineStr, + ArrayRef<std::pair<unsigned,unsigned> > Ranges, + ArrayRef<SMFixIt> Hints) : SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Kind(Kind), - Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()) { + Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()), + FixIts(Hints.begin(), Hints.end()) { + std::sort(FixIts.begin(), FixIts.end()); } +static void buildFixItLine(std::string &CaretLine, std::string &FixItLine, + ArrayRef<SMFixIt> FixIts, ArrayRef<char> SourceLine){ + if (FixIts.empty()) + return; + + const char *LineStart = SourceLine.begin(); + const char *LineEnd = SourceLine.end(); + + size_t PrevHintEndCol = 0; + + for (ArrayRef<SMFixIt>::iterator I = FixIts.begin(), E = FixIts.end(); + I != E; ++I) { + // If the fixit contains a newline or tab, ignore it. + if (I->getText().find_first_of("\n\r\t") != StringRef::npos) + continue; + + SMRange R = I->getRange(); + + // If the line doesn't contain any part of the range, then ignore it. + if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart) + continue; + + // Translate from SMLoc to column. + // Ignore pieces of the range that go onto other lines. + // FIXME: Handle multibyte characters in the source line. + unsigned FirstCol; + if (R.Start.getPointer() < LineStart) + FirstCol = 0; + else + FirstCol = R.Start.getPointer() - LineStart; + + // If we inserted a long previous hint, push this one forwards, and add + // an extra space to show that this is not part of the previous + // completion. This is sort of the best we can do when two hints appear + // to overlap. + // + // Note that if this hint is located immediately after the previous + // hint, no space will be added, since the location is more important. + unsigned HintCol = FirstCol; + if (HintCol < PrevHintEndCol) + HintCol = PrevHintEndCol + 1; + + // FIXME: This assertion is intended to catch unintended use of multibyte + // characters in fixits. If we decide to do this, we'll have to track + // separate byte widths for the source and fixit lines. + assert((size_t)llvm::sys::locale::columnWidth(I->getText()) == + I->getText().size()); + + // This relies on one byte per column in our fixit hints. + unsigned LastColumnModified = HintCol + I->getText().size(); + if (LastColumnModified > FixItLine.size()) + FixItLine.resize(LastColumnModified, ' '); + + std::copy(I->getText().begin(), I->getText().end(), + FixItLine.begin() + HintCol); + + PrevHintEndCol = LastColumnModified; + + // For replacements, mark the removal range with '~'. + // FIXME: Handle multibyte characters in the source line. + unsigned LastCol; + if (R.End.getPointer() >= LineEnd) + LastCol = LineEnd - LineStart; + else + LastCol = R.End.getPointer() - LineStart; + + std::fill(&CaretLine[FirstCol], &CaretLine[LastCol], '~'); + } +} + +static void printSourceLine(raw_ostream &S, StringRef LineContents) { + // 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 % TabStop) != 0); + } + S << '\n'; +} + +static bool isNonASCII(char c) { + return c & 0x80; +} void SMDiagnostic::print(const char *ProgName, raw_ostream &S, bool ShowColors) const { @@ -297,43 +396,48 @@ void SMDiagnostic::print(const char *ProgName, raw_ostream &S, if (LineNo == -1 || ColumnNo == -1) return; + // FIXME: If there are multibyte or multi-column characters in the source, all + // our ranges will be wrong. To do this properly, we'll need a byte-to-column + // map like Clang's TextDiagnostic. For now, we'll just handle tabs by + // expanding them later, and bail out rather than show incorrect ranges and + // misaligned fixits for any other odd characters. + if (std::find_if(LineContents.begin(), LineContents.end(), isNonASCII) != + LineContents.end()) { + printSourceLine(S, LineContents); + return; + } + size_t NumColumns = LineContents.size(); + // Build the line with the caret and ranges. - std::string CaretLine(LineContents.size()+1, ' '); + std::string CaretLine(NumColumns+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] = '~'; + std::fill(&CaretLine[R.first], + &CaretLine[std::min((size_t)R.second, CaretLine.size())], + '~'); } - + + // Add any fix-its. + // FIXME: Find the beginning of the line properly for multibyte characters. + std::string FixItInsertionLine; + buildFixItLine(CaretLine, FixItInsertionLine, FixIts, + makeArrayRef(Loc.getPointer() - ColumnNo, + LineContents.size())); + // Finally, plop on the caret. - if (unsigned(ColumnNo) <= LineContents.size()) + if (unsigned(ColumnNo) <= NumColumns) CaretLine[ColumnNo] = '^'; else - CaretLine[LineContents.size()] = '^'; + CaretLine[NumColumns] = '^'; // ... 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'; + printSourceLine(S, LineContents); if (ShowColors) S.changeColor(raw_ostream::GREEN, true); @@ -350,11 +454,36 @@ void SMDiagnostic::print(const char *ProgName, raw_ostream &S, do { S << CaretLine[i]; ++OutCol; - } while (OutCol & 7); + } while ((OutCol % TabStop) != 0); } + S << '\n'; if (ShowColors) S.resetColor(); + + // Print out the replacement line, matching tabs in the source line. + if (FixItInsertionLine.empty()) + return; + for (size_t i = 0, e = FixItInsertionLine.size(), OutCol = 0; i != e; ++i) { + if (i >= LineContents.size() || LineContents[i] != '\t') { + S << FixItInsertionLine[i]; + ++OutCol; + continue; + } + + // Okay, we have a tab. Insert the appropriate number of characters. + do { + S << FixItInsertionLine[i]; + // FIXME: This is trying not to break up replacements, but then to re-sync + // with the tabs between replacements. This will fail, though, if two + // fix-it replacements are exactly adjacent, or if a fix-it contains a + // space. Really we should be precomputing column widths, which we'll + // need anyway for multibyte chars. + if (FixItInsertionLine[i] != ' ') + ++i; + ++OutCol; + } while (((OutCol % TabStop) != 0) && i != e); + } S << '\n'; } diff --git a/lib/Support/Statistic.cpp b/lib/Support/Statistic.cpp index d8a6ad35ba9c..9c28176b730e 100644 --- a/lib/Support/Statistic.cpp +++ b/lib/Support/Statistic.cpp @@ -22,13 +22,13 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringExtras.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 "llvm/Support/raw_ostream.h" #include <algorithm> #include <cstring> using namespace llvm; @@ -40,7 +40,9 @@ namespace llvm { extern raw_ostream *CreateInfoOutputFile(); } /// what they did. /// static cl::opt<bool> -Enabled("stats", cl::desc("Enable statistics output from program")); +Enabled( + "stats", + cl::desc("Enable statistics output from program (available with Asserts)")); namespace { @@ -142,6 +144,7 @@ void llvm::PrintStatistics(raw_ostream &OS) { } void llvm::PrintStatistics() { +#if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS) StatisticInfo &Stats = *StatInfo; // Statistics not enabled? @@ -151,4 +154,17 @@ void llvm::PrintStatistics() { raw_ostream &OutStream = *CreateInfoOutputFile(); PrintStatistics(OutStream); delete &OutStream; // Close the file. +#else + // Check if the -stats option is set instead of checking + // !Stats.Stats.empty(). In release builds, Statistics operators + // do nothing, so stats are never Registered. + if (Enabled) { + // Get the stream to write to. + raw_ostream &OutStream = *CreateInfoOutputFile(); + OutStream << "Statistics are disabled. " + << "Build with asserts or with -DLLVM_ENABLE_STATS\n"; + OutStream.flush(); + delete &OutStream; // Close the file. + } +#endif } diff --git a/lib/Support/StringRef.cpp b/lib/Support/StringRef.cpp index f8e920846259..d7a0bfa41005 100644 --- a/lib/Support/StringRef.cpp +++ b/lib/Support/StringRef.cpp @@ -9,10 +9,9 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/APInt.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/edit_distance.h" - #include <bitset> using namespace llvm; diff --git a/lib/Support/Threading.cpp b/lib/Support/Threading.cpp index 7483225fdfb0..13fba2ea2584 100644 --- a/lib/Support/Threading.cpp +++ b/lib/Support/Threading.cpp @@ -12,9 +12,9 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Threading.h" +#include "llvm/Config/config.h" #include "llvm/Support/Atomic.h" #include "llvm/Support/Mutex.h" -#include "llvm/Config/config.h" #include <cassert> using namespace llvm; diff --git a/lib/Support/TimeValue.cpp b/lib/Support/TimeValue.cpp index 1a0f7bc36394..bd8af174bcd0 100644 --- a/lib/Support/TimeValue.cpp +++ b/lib/Support/TimeValue.cpp @@ -17,11 +17,16 @@ namespace llvm { using namespace sys; +const TimeValue::SecondsType + TimeValue::PosixZeroTimeSeconds = -946684800; +const TimeValue::SecondsType + TimeValue::Win32ZeroTimeSeconds = -12591158400ULL; + 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 ); +const TimeValue TimeValue::PosixZeroTime = TimeValue ( PosixZeroTimeSeconds,0 ); +const TimeValue TimeValue::Win32ZeroTime = TimeValue ( Win32ZeroTimeSeconds,0 ); void TimeValue::normalize( void ) { diff --git a/lib/Support/Timer.cpp b/lib/Support/Timer.cpp index 598e8ad6a1a5..896d869aa1e7 100644 --- a/lib/Support/Timer.cpp +++ b/lib/Support/Timer.cpp @@ -12,15 +12,15 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Timer.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringMap.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/ManagedStatic.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/Process.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/StringMap.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; // CreateInfoOutputFile - Return a file stream to print our output on. diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp index c058c05595f1..d2508ac1ef3a 100644 --- a/lib/Support/Triple.cpp +++ b/lib/Support/Triple.cpp @@ -8,9 +8,9 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/Triple.h" +#include "llvm/ADT/STLExtras.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; @@ -19,8 +19,8 @@ const char *Triple::getArchTypeName(ArchType Kind) { switch (Kind) { case UnknownArch: return "unknown"; + case aarch64: return "aarch64"; case arm: return "arm"; - case cellspu: return "cellspu"; case hexagon: return "hexagon"; case mips: return "mips"; case mipsel: return "mipsel"; @@ -54,11 +54,11 @@ const char *Triple::getArchTypePrefix(ArchType Kind) { default: return 0; + case aarch64: return "aarch64"; + case arm: case thumb: return "arm"; - case cellspu: return "spu"; - case ppc64: case ppc: return "ppc"; @@ -128,7 +128,7 @@ const char *Triple::getOSTypeName(OSType Kind) { case Haiku: return "haiku"; case Minix: return "minix"; case RTEMS: return "rtems"; - case NativeClient: return "nacl"; + case NaCl: return "nacl"; case CNK: return "cnk"; case Bitrig: return "bitrig"; case AIX: return "aix"; @@ -143,6 +143,7 @@ const char *Triple::getEnvironmentTypeName(EnvironmentType Kind) { case GNU: return "gnu"; case GNUEABIHF: return "gnueabihf"; case GNUEABI: return "gnueabi"; + case GNUX32: return "gnux32"; case EABI: return "eabi"; case MachO: return "macho"; case Android: return "android"; @@ -154,8 +155,8 @@ const char *Triple::getEnvironmentTypeName(EnvironmentType Kind) { Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { return StringSwitch<Triple::ArchType>(Name) + .Case("aarch64", aarch64) .Case("arm", arm) - .Case("cellspu", cellspu) .Case("mips", mips) .Case("mipsel", mipsel) .Case("mips64", mips64) @@ -218,13 +219,13 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Case("powerpc", Triple::ppc) .Cases("powerpc64", "ppu", Triple::ppc64) .Case("mblaze", Triple::mblaze) + .Case("aarch64", Triple::aarch64) .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) @@ -277,7 +278,7 @@ static Triple::OSType parseOS(StringRef OSName) { .StartsWith("haiku", Triple::Haiku) .StartsWith("minix", Triple::Minix) .StartsWith("rtems", Triple::RTEMS) - .StartsWith("nacl", Triple::NativeClient) + .StartsWith("nacl", Triple::NaCl) .StartsWith("cnk", Triple::CNK) .StartsWith("bitrig", Triple::Bitrig) .StartsWith("aix", Triple::AIX) @@ -289,6 +290,7 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { .StartsWith("eabi", Triple::EABI) .StartsWith("gnueabihf", Triple::GNUEABIHF) .StartsWith("gnueabi", Triple::GNUEABI) + .StartsWith("gnux32", Triple::GNUX32) .StartsWith("gnu", Triple::GNU) .StartsWith("macho", Triple::MachO) .StartsWith("android", Triple::Android) @@ -663,7 +665,6 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::amdil: case llvm::Triple::arm: - case llvm::Triple::cellspu: case llvm::Triple::hexagon: case llvm::Triple::le32: case llvm::Triple::mblaze: @@ -680,6 +681,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::spir: return 32; + case llvm::Triple::aarch64: case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::nvptx64: @@ -708,6 +710,7 @@ Triple Triple::get32BitArchVariant() const { Triple T(*this); switch (getArch()) { case Triple::UnknownArch: + case Triple::aarch64: case Triple::msp430: T.setArch(UnknownArch); break; @@ -715,7 +718,6 @@ Triple Triple::get32BitArchVariant() const { case Triple::amdil: case Triple::spir: case Triple::arm: - case Triple::cellspu: case Triple::hexagon: case Triple::le32: case Triple::mblaze: @@ -749,7 +751,6 @@ Triple Triple::get64BitArchVariant() const { case Triple::UnknownArch: case Triple::amdil: case Triple::arm: - case Triple::cellspu: case Triple::hexagon: case Triple::le32: case Triple::mblaze: @@ -761,6 +762,7 @@ Triple Triple::get64BitArchVariant() const { T.setArch(UnknownArch); break; + case Triple::aarch64: case Triple::spir64: case Triple::mips64: case Triple::mips64el: diff --git a/lib/Support/Unix/Memory.inc b/lib/Support/Unix/Memory.inc index 9a8abd27f158..e9b26bdb80f2 100644 --- a/lib/Support/Unix/Memory.inc +++ b/lib/Support/Unix/Memory.inc @@ -51,7 +51,18 @@ int getPosixProtectionFlags(unsigned Flags) { llvm::sys::Memory::MF_EXEC: return PROT_READ | PROT_WRITE | PROT_EXEC; case llvm::sys::Memory::MF_EXEC: +#if defined(__FreeBSD__) + // On PowerPC, having an executable page that has no read permission + // can have unintended consequences. The function InvalidateInstruction- + // Cache uses instructions dcbf and icbi, both of which are treated by + // the processor as loads. If the page has no read permissions, + // executing these instructions will result in a segmentation fault. + // Somehow, this problem is not present on Linux, but it does happen + // on FreeBSD. + return PROT_READ | PROT_EXEC; +#else return PROT_EXEC; +#endif default: llvm_unreachable("Illegal memory protection flag specified!"); } @@ -73,7 +84,7 @@ Memory::allocateMappedMemory(size_t NumBytes, if (NumBytes == 0) return MemoryBlock(); - static const size_t PageSize = Process::GetPageSize(); + static const size_t PageSize = process::get_self()->page_size(); const size_t NumPages = (NumBytes+PageSize-1)/PageSize; int fd = -1; @@ -166,8 +177,8 @@ 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; + size_t PageSize = process::get_self()->page_size(); + size_t NumPages = (NumBytes+PageSize-1)/PageSize; int fd = -1; #ifdef NEED_DEV_ZERO_FOR_MMAP @@ -191,10 +202,10 @@ Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, NearBlock->size() : 0; #if defined(__APPLE__) && defined(__arm__) - void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_EXEC, + 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, + void *pa = ::mmap(start, PageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC, flags, fd, 0); #endif if (pa == MAP_FAILED) { @@ -207,7 +218,7 @@ Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, #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_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"); @@ -215,7 +226,7 @@ Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, } kr = vm_protect(mach_task_self(), (vm_address_t)pa, - (vm_size_t)(pageSize*NumPages), 0, + (vm_size_t)(PageSize*NumPages), 0, VM_PROT_READ | VM_PROT_WRITE); if (KERN_SUCCESS != kr) { MakeErrMsg(ErrMsg, "vm_protect RW failed"); @@ -225,7 +236,7 @@ Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, MemoryBlock result; result.Address = pa; - result.Size = NumPages*pageSize; + result.Size = NumPages*PageSize; return result; } @@ -321,7 +332,16 @@ void Memory::InvalidateInstructionCache(const void *Addr, __clear_cache(const_cast<char *>(Start), const_cast<char *>(End)); # elif defined(__mips__) const char *Start = static_cast<const char *>(Addr); +# if defined(ANDROID) + // The declaration of "cacheflush" in Android bionic: + // extern int cacheflush(long start, long end, long flags); + const char *End = Start + Len; + long LStart = reinterpret_cast<long>(const_cast<char *>(Start)); + long LEnd = reinterpret_cast<long>(const_cast<char *>(End)); + cacheflush(LStart, LEnd, BCACHE); +# else cacheflush(const_cast<char *>(Start), Len, BCACHE); +# endif # endif #endif // end apple diff --git a/lib/Support/Unix/PathV2.inc b/lib/Support/Unix/PathV2.inc index d04f590f87ed..a3dfd4b0a32d 100644 --- a/lib/Support/Unix/PathV2.inc +++ b/lib/Support/Unix/PathV2.inc @@ -417,16 +417,24 @@ retry_random_path: RandomPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; } + // Make sure we don't fall into an infinite loop by constantly trying + // to create the parent path. + bool TriedToCreateParent = false; + // Try to open + create the file. rety_open_create: int RandomFD = ::open(RandomPath.c_str(), O_RDWR | O_CREAT | O_EXCL, mode); if (RandomFD == -1) { + int SavedErrno = errno; // If the file existed, try again, otherwise, error. - if (errno == errc::file_exists) + if (SavedErrno == 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()); + // If path prefix doesn't exist, try to create it. + if (SavedErrno == errc::no_such_file_or_directory && + !exists(path::parent_path(RandomPath)) && + !TriedToCreateParent) { + TriedToCreateParent = true; + StringRef p(RandomPath); SmallString<64> dir_to_create; for (path::const_iterator i = path::begin(p), e = --path::end(p); i != e; ++i) { @@ -439,13 +447,15 @@ rety_open_create: (*i)[1] == '/' && (*i)[2] != '/') return make_error_code(errc::no_such_file_or_directory); - if (::mkdir(dir_to_create.c_str(), 0700) == -1) + if (::mkdir(dir_to_create.c_str(), 0700) == -1 && + errno != errc::file_exists) return error_code(errno, system_category()); } } goto rety_open_create; } - return error_code(errno, system_category()); + + return error_code(SavedErrno, system_category()); } // Make the path absolute. @@ -465,12 +475,14 @@ rety_open_create: return error_code::success(); } -error_code mapped_file_region::init(int fd, uint64_t offset) { - AutoFD FD(fd); +error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { + AutoFD ScopedFD(FD); + if (!CloseFD) + ScopedFD.take(); // Figure out how large the file is. struct stat FileInfo; - if (fstat(fd, &FileInfo) == -1) + if (fstat(FD, &FileInfo) == -1) return error_code(errno, system_category()); uint64_t FileSize = FileInfo.st_size; @@ -478,7 +490,7 @@ error_code mapped_file_region::init(int fd, uint64_t offset) { Size = FileSize; else if (FileSize < Size) { // We need to grow the file. - if (ftruncate(fd, Size) == -1) + if (ftruncate(FD, Size) == -1) return error_code(errno, system_category()); } @@ -487,7 +499,7 @@ error_code mapped_file_region::init(int fd, uint64_t offset) { #ifdef MAP_FILE flags |= MAP_FILE; #endif - Mapping = ::mmap(0, Size, prot, flags, fd, offset); + Mapping = ::mmap(0, Size, prot, flags, FD, Offset); if (Mapping == MAP_FAILED) return error_code(errno, system_category()); return error_code::success(); @@ -516,12 +528,13 @@ mapped_file_region::mapped_file_region(const Twine &path, return; } - ec = init(ofd, offset); + ec = init(ofd, true, offset); if (ec) Mapping = 0; } mapped_file_region::mapped_file_region(int fd, + bool closefd, mapmode mode, uint64_t length, uint64_t offset, @@ -535,7 +548,7 @@ mapped_file_region::mapped_file_region(int fd, return; } - ec = init(fd, offset); + ec = init(fd, closefd, offset); if (ec) Mapping = 0; } @@ -545,7 +558,7 @@ mapped_file_region::~mapped_file_region() { ::munmap(Mapping, Size); } -#if LLVM_USE_RVALUE_REFERENCES +#if LLVM_HAS_RVALUE_REFERENCES mapped_file_region::mapped_file_region(mapped_file_region &&other) : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) { other.Mapping = 0; @@ -574,7 +587,7 @@ const char *mapped_file_region::const_data() const { } int mapped_file_region::alignment() { - return Process::GetPageSize(); + return process::get_self()->page_size(); } error_code detail::directory_iterator_construct(detail::DirIterState &it, diff --git a/lib/Support/Unix/Process.inc b/lib/Support/Unix/Process.inc index 5204147ce316..9a4454f1c650 100644 --- a/lib/Support/Unix/Process.inc +++ b/lib/Support/Unix/Process.inc @@ -44,9 +44,49 @@ using namespace llvm; using namespace sys; -unsigned -Process::GetPageSize() -{ + +process::id_type self_process::get_id() { + return getpid(); +} + +static std::pair<TimeValue, TimeValue> getRUsageTimes() { +#if defined(HAVE_GETRUSAGE) + struct rusage RU; + ::getrusage(RUSAGE_SELF, &RU); + return std::make_pair( + TimeValue( + static_cast<TimeValue::SecondsType>(RU.ru_utime.tv_sec), + static_cast<TimeValue::NanoSecondsType>( + RU.ru_utime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND)), + TimeValue( + static_cast<TimeValue::SecondsType>(RU.ru_stime.tv_sec), + static_cast<TimeValue::NanoSecondsType>( + RU.ru_stime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND))); +#else +#warning Cannot get usage times on this platform + return std::make_pair(TimeValue(), TimeValue()); +#endif +} + +TimeValue self_process::get_user_time() const { +#if _POSIX_TIMERS > 0 && _POSIX_CPUTIME > 0 + // Try to get a high resolution CPU timer. + struct timespec TS; + if (::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &TS) == 0) + return TimeValue(static_cast<TimeValue::SecondsType>(TS.tv_sec), + static_cast<TimeValue::NanoSecondsType>(TS.tv_nsec)); +#endif + + // Otherwise fall back to rusage based timing. + return getRUsageTimes().first; +} + +TimeValue self_process::get_system_time() const { + // We can only collect system time by inspecting the results of getrusage. + return getRUsageTimes().second; +} + +static unsigned getPageSize() { #if defined(__CYGWIN__) // On Cygwin, getpagesize() returns 64k but the page size for the purposes of // memory protection and mmap() is 4k. @@ -62,6 +102,12 @@ Process::GetPageSize() return static_cast<unsigned>(page_size); } +// This constructor guaranteed to be run exactly once on a single thread, and +// sets up various process invariants that can be queried cheaply from then on. +self_process::self_process() : PageSize(getPageSize()) { +} + + size_t Process::GetMallocUsage() { #if defined(HAVE_MALLINFO) struct mallinfo mi; @@ -86,49 +132,10 @@ size_t Process::GetMallocUsage() { #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) -{ +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 + llvm::tie(user_time, sys_time) = getRUsageTimes(); } int Process::GetCurrentUserId() { @@ -217,6 +224,8 @@ static unsigned getColumns(int FileID) { #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) // Try to determine the width of the terminal. struct winsize ws; + // Zero-fill ws to avoid a false positive from MemorySanitizer. + memset(&ws, 0, sizeof(ws)); if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) Columns = ws.ws_col; #endif @@ -318,7 +327,7 @@ static unsigned GetRandomNumberSeed() { // Otherwise, swizzle the current time and the process ID to form a reasonable // seed. - TimeValue Now = llvm::TimeValue::now(); + TimeValue Now = TimeValue::now(); return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid()); } #endif diff --git a/lib/Support/Unix/Program.inc b/lib/Support/Unix/Program.inc index e5990d06ecc2..117151c91d8b 100644 --- a/lib/Support/Unix/Program.inc +++ b/lib/Support/Unix/Program.inc @@ -16,9 +16,10 @@ //=== is guaranteed to work on *all* UNIX variants. //===----------------------------------------------------------------------===// -#include <llvm/Config/config.h> -#include "llvm/Support/FileSystem.h" #include "Unix.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/FileSystem.h" +#include <llvm/Config/config.h> #if HAVE_SYS_STAT_H #include <sys/stat.h> #endif @@ -47,11 +48,6 @@ 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) { @@ -169,12 +165,16 @@ static void SetMemoryLimits (unsigned size) setrlimit (RLIMIT_RSS, &r); #endif #ifdef RLIMIT_AS // e.g. NetBSD doesn't have it. + // Don't set virtual memory limit if built with any Sanitizer. They need 80Tb + // of virtual memory for shadow memory mapping. +#if !LLVM_MEMORY_SANITIZER_BUILD && !LLVM_ADDRESS_SANITIZER_BUILD // Virtual memory. getrlimit (RLIMIT_AS, &r); r.rlim_cur = limit; setrlimit (RLIMIT_AS, &r); #endif #endif +#endif } bool @@ -394,24 +394,6 @@ Program::Wait(const sys::Path &path, #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); diff --git a/lib/Support/Unix/Signals.inc b/lib/Support/Unix/Signals.inc index 9e94068c9c36..66338f17d88f 100644 --- a/lib/Support/Unix/Signals.inc +++ b/lib/Support/Unix/Signals.inc @@ -15,9 +15,9 @@ #include "Unix.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Mutex.h" +#include <algorithm> #include <string> #include <vector> -#include <algorithm> #if HAVE_EXECINFO_H # include <execinfo.h> // For backtrace(). #endif @@ -47,17 +47,19 @@ static void (*InterruptFunction)() = 0; static std::vector<std::string> FilesToRemove; static std::vector<std::pair<void(*)(void*), void*> > CallBacksToRun; -// IntSigs - Signals that may interrupt the program at any time. +// IntSigs - Signals that represent requested termination. There's no bug +// or failure, or if there is, it's not our direct responsibility. For whatever +// reason, our continued execution is no longer desirable. static const int IntSigs[] = { - SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2 + SIGHUP, SIGINT, 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. +// KillSigs - Signals that represent that we have a bug, and our prompt +// termination has been ordered. static const int KillSigs[] = { - SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV + SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGQUIT #ifdef SIGSYS , SIGSYS #endif @@ -254,7 +256,7 @@ void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { // // On glibc systems we have the 'backtrace' function, which works nicely, but // doesn't demangle symbols. -static void PrintStackTrace(void *) { +void llvm::sys::PrintStackTrace(FILE *FD) { #if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) static void* StackTrace[256]; // Use backtrace() to output a backtrace on Linux systems with glibc. @@ -278,26 +280,30 @@ static void PrintStackTrace(void *) { Dl_info dlinfo; dladdr(StackTrace[i], &dlinfo); - fprintf(stderr, "%-2d", i); + fprintf(FD, "%-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); + if (name == NULL) fprintf(FD, " %-*s", width, dlinfo.dli_fname); + else fprintf(FD, " %-*s", width, name+1); - fprintf(stderr, " %#0*lx", + fprintf(FD, " %#0*lx", (int)(sizeof(void*) * 2) + 2, (unsigned long)StackTrace[i]); if (dlinfo.dli_sname != NULL) { int res; - fputc(' ', stderr); + fputc(' ', FD); char* d = abi::__cxa_demangle(dlinfo.dli_sname, NULL, NULL, &res); - if (d == NULL) fputs(dlinfo.dli_sname, stderr); - else fputs(d, stderr); + if (d == NULL) fputs(dlinfo.dli_sname, FD); + else fputs(d, FD); free(d); - fprintf(stderr, " + %tu",(char*)StackTrace[i]-(char*)dlinfo.dli_saddr); + // FIXME: When we move to C++11, use %t length modifier. It's not in + // C++03 and causes gcc to issue warnings. Losing the upper 32 bits of + // the stack offset for a stack dump isn't likely to cause any problems. + fprintf(FD, " + %u",(unsigned)((char*)StackTrace[i]- + (char*)dlinfo.dli_saddr)); } - fputc('\n', stderr); + fputc('\n', FD); } #else backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); @@ -305,10 +311,14 @@ static void PrintStackTrace(void *) { #endif } +static void PrintStackTraceSignalHandler(void *) { + PrintStackTrace(stderr); +} + /// PrintStackTraceOnErrorSignal - When an error signal (such as SIGABRT or /// SIGSEGV) is delivered to the process, print a stack trace and then exit. void llvm::sys::PrintStackTraceOnErrorSignal() { - AddSignalHandler(PrintStackTrace, 0); + AddSignalHandler(PrintStackTraceSignalHandler, 0); #if defined(__APPLE__) // Environment variable to disable any kind of crash dialog. diff --git a/lib/Support/Unix/TimeValue.inc b/lib/Support/Unix/TimeValue.inc index 5cf5a9d44ed6..df8558bf8bed 100644 --- a/lib/Support/Unix/TimeValue.inc +++ b/lib/Support/Unix/TimeValue.inc @@ -48,7 +48,8 @@ TimeValue TimeValue::now() { } return TimeValue( - static_cast<TimeValue::SecondsType>( the_time.tv_sec + PosixZeroTime.seconds_ ), + static_cast<TimeValue::SecondsType>( the_time.tv_sec + + PosixZeroTimeSeconds ), static_cast<TimeValue::NanoSecondsType>( the_time.tv_usec * NANOSECONDS_PER_MICROSECOND ) ); } diff --git a/lib/Support/Unix/Unix.h b/lib/Support/Unix/Unix.h index 361f297d3642..051f56f96922 100644 --- a/lib/Support/Unix/Unix.h +++ b/lib/Support/Unix/Unix.h @@ -21,12 +21,12 @@ #include "llvm/Config/config.h" // Get autoconf configuration settings #include "llvm/Support/Errno.h" -#include <cstdlib> +#include <algorithm> +#include <cerrno> #include <cstdio> +#include <cstdlib> #include <cstring> -#include <cerrno> #include <string> -#include <algorithm> #ifdef HAVE_UNISTD_H #include <unistd.h> diff --git a/lib/Support/Unix/Watchdog.inc b/lib/Support/Unix/Watchdog.inc new file mode 100644 index 000000000000..5d89c0e51b11 --- /dev/null +++ b/lib/Support/Unix/Watchdog.inc @@ -0,0 +1,32 @@ +//===--- Unix/Watchdog.inc - Unix Watchdog 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 Watchdog class. +// +//===----------------------------------------------------------------------===// + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +namespace llvm { + namespace sys { + Watchdog::Watchdog(unsigned int seconds) { +#ifdef HAVE_UNISTD_H + alarm(seconds); +#endif + } + + Watchdog::~Watchdog() { +#ifdef HAVE_UNISTD_H + alarm(0); +#endif + } + } +} diff --git a/lib/Support/Watchdog.cpp b/lib/Support/Watchdog.cpp new file mode 100644 index 000000000000..724aa001f16e --- /dev/null +++ b/lib/Support/Watchdog.cpp @@ -0,0 +1,23 @@ +//===---- Watchdog.cpp - Implement Watchdog ---------------------*- 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 Watchdog class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Watchdog.h" +#include "llvm/Config/config.h" + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Watchdog.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Watchdog.inc" +#endif diff --git a/lib/Support/Windows/Memory.inc b/lib/Support/Windows/Memory.inc index cb80f2817c02..4c5aebd5e71a 100644 --- a/lib/Support/Windows/Memory.inc +++ b/lib/Support/Windows/Memory.inc @@ -15,6 +15,8 @@ #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Process.h" + +// The Windows.h header must be the last one included. #include "Windows.h" namespace { diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc index 2280b3417145..f4898e619abf 100644 --- a/lib/Support/Windows/Path.inc +++ b/lib/Support/Windows/Path.inc @@ -17,8 +17,8 @@ //===----------------------------------------------------------------------===// #include "Windows.h" -#include <malloc.h> #include <cstdio> +#include <malloc.h> // We need to undo a macro defined in Windows.h, otherwise we won't compile: #undef CopyFile @@ -82,7 +82,7 @@ Path::isValid() const { pos = path.rfind(':',len); size_t rootslash = 0; if (pos != std::string::npos) { - if (pos != 1 || !isalpha(path[0]) || len < 3) + if (pos != 1 || !isalpha(static_cast<unsigned char>(path[0])) || len < 3) return false; rootslash = 2; } diff --git a/lib/Support/Windows/PathV2.inc b/lib/Support/Windows/PathV2.inc index 3dfac66b77ce..23f3d14f91f0 100644 --- a/lib/Support/Windows/PathV2.inc +++ b/lib/Support/Windows/PathV2.inc @@ -328,7 +328,7 @@ error_code resize_file(const Twine &path, uint64_t size) { path_utf16)) return ec; - int fd = ::_wopen(path_utf16.begin(), O_BINARY, S_IREAD | S_IWRITE); + int fd = ::_wopen(path_utf16.begin(), O_BINARY | _O_RDWR, S_IWRITE); if (fd == -1) return error_code(errno, generic_category()); #ifdef HAVE__CHSIZE_S @@ -593,6 +593,10 @@ retry_random_path: random_path_utf16.push_back(0); random_path_utf16.pop_back(); + // Make sure we don't fall into an infinite loop by constantly trying + // to create the parent path. + bool TriedToCreateParent = false; + // Try to create + open the path. retry_create_file: HANDLE TempFileHandle = ::CreateFileW(random_path_utf16.begin(), @@ -610,7 +614,9 @@ retry_create_file: if (ec == windows_error::file_exists) goto retry_random_path; // Check for non-existing parent directories. - if (ec == windows_error::path_not_found) { + if (ec == windows_error::path_not_found && !TriedToCreateParent) { + TriedToCreateParent = true; + // Create the directories using result_path as temp storage. if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), random_path_utf16.size(), result_path)) @@ -705,13 +711,14 @@ error_code get_magic(const Twine &path, uint32_t len, return error_code::success(); } -error_code mapped_file_region::init(int FD, uint64_t Offset) { +error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { FileDescriptor = FD; // Make sure that the requested size fits within SIZE_T. if (Size > std::numeric_limits<SIZE_T>::max()) { - if (FileDescriptor) - _close(FileDescriptor); - else + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); + } else ::CloseHandle(FileHandle); return make_error_code(errc::invalid_argument); } @@ -732,9 +739,10 @@ error_code mapped_file_region::init(int FD, uint64_t Offset) { 0); if (FileMappingHandle == NULL) { error_code ec = windows_error(GetLastError()); - if (FileDescriptor) - _close(FileDescriptor); - else + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); + } else ::CloseHandle(FileHandle); return ec; } @@ -754,9 +762,10 @@ error_code mapped_file_region::init(int FD, uint64_t Offset) { if (Mapping == NULL) { error_code ec = windows_error(GetLastError()); ::CloseHandle(FileMappingHandle); - if (FileDescriptor) - _close(FileDescriptor); - else + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); + } else ::CloseHandle(FileHandle); return ec; } @@ -768,14 +777,24 @@ error_code mapped_file_region::init(int FD, uint64_t Offset) { error_code ec = windows_error(GetLastError()); ::UnmapViewOfFile(Mapping); ::CloseHandle(FileMappingHandle); - if (FileDescriptor) - _close(FileDescriptor); - else + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); + } else ::CloseHandle(FileHandle); return ec; } Size = mbi.RegionSize; } + + // Close all the handles except for the view. It will keep the other handles + // alive. + ::CloseHandle(FileMappingHandle); + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); // Also closes FileHandle. + } else + ::CloseHandle(FileHandle); return error_code::success(); } @@ -815,7 +834,7 @@ mapped_file_region::mapped_file_region(const Twine &path, } FileDescriptor = 0; - ec = init(FileDescriptor, offset); + ec = init(FileDescriptor, true, offset); if (ec) { Mapping = FileMappingHandle = 0; FileHandle = INVALID_HANDLE_VALUE; @@ -824,6 +843,7 @@ mapped_file_region::mapped_file_region(const Twine &path, } mapped_file_region::mapped_file_region(int fd, + bool closefd, mapmode mode, uint64_t length, uint64_t offset, @@ -836,13 +856,14 @@ mapped_file_region::mapped_file_region(int fd, , FileMappingHandle() { FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd)); if (FileHandle == INVALID_HANDLE_VALUE) { - _close(FileDescriptor); + if (closefd) + _close(FileDescriptor); FileDescriptor = 0; ec = make_error_code(errc::bad_file_descriptor); return; } - ec = init(FileDescriptor, offset); + ec = init(FileDescriptor, closefd, offset); if (ec) { Mapping = FileMappingHandle = 0; FileHandle = INVALID_HANDLE_VALUE; @@ -853,15 +874,9 @@ mapped_file_region::mapped_file_region(int fd, mapped_file_region::~mapped_file_region() { if (Mapping) ::UnmapViewOfFile(Mapping); - if (FileMappingHandle) - ::CloseHandle(FileMappingHandle); - if (FileDescriptor) - _close(FileDescriptor); - else if (FileHandle != INVALID_HANDLE_VALUE) - ::CloseHandle(FileHandle); } -#if LLVM_USE_RVALUE_REFERENCES +#if LLVM_HAS_RVALUE_REFERENCES mapped_file_region::mapped_file_region(mapped_file_region &&other) : Mode(other.Mode) , Size(other.Size) diff --git a/lib/Support/Windows/Process.inc b/lib/Support/Windows/Process.inc index e29eb6dff6d7..ad9412852f10 100644 --- a/lib/Support/Windows/Process.inc +++ b/lib/Support/Windows/Process.inc @@ -12,10 +12,10 @@ //===----------------------------------------------------------------------===// #include "Windows.h" -#include <psapi.h> -#include <malloc.h> -#include <io.h> #include <direct.h> +#include <io.h> +#include <malloc.h> +#include <psapi.h> #ifdef __MINGW32__ #if (HAVE_LIBPSAPI != 1) @@ -35,13 +35,47 @@ # define _HEAPOK (-2) #endif -namespace llvm { +using namespace llvm; using namespace sys; + +process::id_type self_process::get_id() { + return GetCurrentProcess(); +} + +static TimeValue getTimeValueFromFILETIME(FILETIME Time) { + ULARGE_INTEGER TimeInteger; + TimeInteger.LowPart = Time.dwLowDateTime; + TimeInteger.HighPart = Time.dwHighDateTime; + + // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond) + return TimeValue( + static_cast<TimeValue::SecondsType>(TimeInteger.QuadPart / 10000000), + static_cast<TimeValue::NanoSecondsType>( + (TimeInteger.QuadPart % 10000000) * 100)); +} + +TimeValue self_process::get_user_time() const { + FILETIME ProcCreate, ProcExit, KernelTime, UserTime; + if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime, + &UserTime) == 0) + return TimeValue(); + + return getTimeValueFromFILETIME(UserTime); +} + +TimeValue self_process::get_system_time() const { + FILETIME ProcCreate, ProcExit, KernelTime, UserTime; + if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime, + &UserTime) == 0) + return TimeValue(); + + return getTimeValueFromFILETIME(KernelTime); +} + // 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() { +// solely so it can be called once to initialize the self_process member below. +static unsigned getPageSize() { // 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 @@ -52,12 +86,12 @@ inline unsigned GetPageSizeOnce() { return static_cast<unsigned>(info.dwPageSize); } -unsigned -Process::GetPageSize() { - static const unsigned PageSize = GetPageSizeOnce(); - return PageSize; +// This constructor guaranteed to be run exactly once on a single thread, and +// sets up various process invariants that can be queried cheaply from then on. +self_process::self_process() : PageSize(getPageSize()) { } + size_t Process::GetMallocUsage() { @@ -72,30 +106,17 @@ Process::GetMallocUsage() 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) -{ +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 ProcCreate, ProcExit, KernelTime, UserTime; + if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime, + &UserTime) == 0) + return; - // 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 ); + user_time = getTimeValueFromFILETIME(UserTime); + sys_time = getTimeValueFromFILETIME(KernelTime); } int Process::GetCurrentUserId() @@ -255,5 +276,3 @@ const char *Process::ResetColor() { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors()); return 0; } - -} diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc index 80ccaa6ea6b1..691d6d455501 100644 --- a/lib/Support/Windows/Program.inc +++ b/lib/Support/Windows/Program.inc @@ -13,9 +13,9 @@ #include "Windows.h" #include <cstdio> -#include <malloc.h> -#include <io.h> #include <fcntl.h> +#include <io.h> +#include <malloc.h> //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only Win32 specific code @@ -43,11 +43,6 @@ Program::~Program() { } } -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) { @@ -380,23 +375,6 @@ Program::Wait(const Path &path, 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) diff --git a/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc index 38308f6abd85..3dd6660b031d 100644 --- a/lib/Support/Windows/Signals.inc +++ b/lib/Support/Windows/Signals.inc @@ -12,9 +12,9 @@ //===----------------------------------------------------------------------===// #include "Windows.h" +#include <algorithm> #include <stdio.h> #include <vector> -#include <algorithm> #ifdef __MINGW32__ #include <imagehlp.h> @@ -295,6 +295,10 @@ void sys::PrintStackTraceOnErrorSignal() { LeaveCriticalSection(&CriticalSection); } +void llvm::sys::PrintStackTrace(FILE *) { + // FIXME: Implement. +} + void sys::SetInterruptFunction(void (*IF)()) { RegisterHandler(); diff --git a/lib/Support/Windows/Watchdog.inc b/lib/Support/Windows/Watchdog.inc new file mode 100644 index 000000000000..fab2bdf2a941 --- /dev/null +++ b/lib/Support/Windows/Watchdog.inc @@ -0,0 +1,24 @@ +//===--- Windows/Watchdog.inc - Windows Watchdog 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 Windows implementation of the Watchdog class. +// +//===----------------------------------------------------------------------===// + +// TODO: implement. +// Currently this is only used by PrettyStackTrace which is also unimplemented +// on Windows. Roughly, a Windows implementation would use CreateWaitableTimer +// and a second thread to run the TimerAPCProc. + +namespace llvm { + namespace sys { + Watchdog::Watchdog(unsigned int seconds) {} + Watchdog::~Watchdog() {} + } +} diff --git a/lib/Support/YAMLParser.cpp b/lib/Support/YAMLParser.cpp index 34df636a72a0..2cead20c0b21 100644 --- a/lib/Support/YAMLParser.cpp +++ b/lib/Support/YAMLParser.cpp @@ -12,16 +12,15 @@ //===----------------------------------------------------------------------===// #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/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace yaml; @@ -252,6 +251,7 @@ namespace yaml { class Scanner { public: Scanner(const StringRef Input, SourceMgr &SM); + Scanner(MemoryBuffer *Buffer, SourceMgr &SM_); /// @brief Parse the next token and return it without popping it. Token &peekNext(); @@ -708,6 +708,21 @@ Scanner::Scanner(StringRef Input, SourceMgr &sm) End = InputBuffer->getBufferEnd(); } +Scanner::Scanner(MemoryBuffer *Buffer, SourceMgr &SM_) + : SM(SM_) + , InputBuffer(Buffer) + , Current(InputBuffer->getBufferStart()) + , End(InputBuffer->getBufferEnd()) + , Indent(-1) + , Column(0) + , Line(0) + , FlowLevel(0) + , IsStartOfStream(true) + , IsSimpleKeyAllowed(true) + , Failed(false) { + SM.AddNewSourceBuffer(InputBuffer, SMLoc()); +} + Token &Scanner::peekNext() { // If the current token is a possible simple key, keep parsing until we // can confirm. @@ -1532,6 +1547,10 @@ Stream::Stream(StringRef Input, SourceMgr &SM) : scanner(new Scanner(Input, SM)) , CurrentDoc(0) {} +Stream::Stream(MemoryBuffer *InputBuffer, SourceMgr &SM) + : scanner(new Scanner(InputBuffer, SM)) + , CurrentDoc(0) {} + Stream::~Stream() {} bool Stream::failed() { return scanner->failed(); } diff --git a/lib/Support/YAMLTraits.cpp b/lib/Support/YAMLTraits.cpp new file mode 100644 index 000000000000..9da2aa7c841d --- /dev/null +++ b/lib/Support/YAMLTraits.cpp @@ -0,0 +1,827 @@ +//===- lib/Support/YAMLTraits.cpp -----------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/YAMLTraits.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/YAMLParser.h" +#include "llvm/Support/raw_ostream.h" +#include <cstring> +using namespace llvm; +using namespace yaml; + +//===----------------------------------------------------------------------===// +// IO +//===----------------------------------------------------------------------===// + +IO::IO(void *Context) : Ctxt(Context) { +} + +IO::~IO() { +} + +void *IO::getContext() { + return Ctxt; +} + +void IO::setContext(void *Context) { + Ctxt = Context; +} + +//===----------------------------------------------------------------------===// +// Input +//===----------------------------------------------------------------------===// + +Input::Input(StringRef InputContent, void *Ctxt) + : IO(Ctxt), + Strm(new Stream(InputContent, SrcMgr)), + CurrentNode(NULL) { + DocIterator = Strm->begin(); +} + +Input::~Input() { + +} + +error_code Input::error() { + return EC; +} + +void Input::setDiagHandler(SourceMgr::DiagHandlerTy Handler, void *Ctxt) { + SrcMgr.setDiagHandler(Handler, Ctxt); +} + +bool Input::outputting() { + return false; +} + +bool Input::setCurrentDocument() { + if (DocIterator != Strm->end()) { + Node *N = DocIterator->getRoot(); + if (isa<NullNode>(N)) { + // Empty files are allowed and ignored + ++DocIterator; + return setCurrentDocument(); + } + TopNode.reset(this->createHNodes(N)); + CurrentNode = TopNode.get(); + return true; + } + return false; +} + +void Input::nextDocument() { + ++DocIterator; +} + +void Input::beginMapping() { + if (EC) + return; + MapHNode *MN = dyn_cast<MapHNode>(CurrentNode); + if (MN) { + MN->ValidKeys.clear(); + } +} + +bool Input::preflightKey(const char *Key, bool Required, bool, bool &UseDefault, + void *&SaveInfo) { + UseDefault = false; + if (EC) + return false; + MapHNode *MN = dyn_cast<MapHNode>(CurrentNode); + if (!MN) { + setError(CurrentNode, "not a mapping"); + return false; + } + MN->ValidKeys.push_back(Key); + HNode *Value = MN->Mapping[Key]; + if (!Value) { + if (Required) + setError(CurrentNode, Twine("missing required key '") + Key + "'"); + else + UseDefault = true; + return false; + } + SaveInfo = CurrentNode; + CurrentNode = Value; + return true; +} + +void Input::postflightKey(void *saveInfo) { + CurrentNode = reinterpret_cast<HNode *>(saveInfo); +} + +void Input::endMapping() { + if (EC) + return; + MapHNode *MN = dyn_cast<MapHNode>(CurrentNode); + if (!MN) + return; + for (MapHNode::NameToNode::iterator i = MN->Mapping.begin(), + End = MN->Mapping.end(); i != End; ++i) { + if (!MN->isValidKey(i->first)) { + setError(i->second, Twine("unknown key '") + i->first + "'"); + break; + } + } +} + +unsigned Input::beginSequence() { + if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) { + return SQ->Entries.size(); + } + return 0; +} + +void Input::endSequence() { +} + +bool Input::preflightElement(unsigned Index, void *&SaveInfo) { + if (EC) + return false; + if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) { + SaveInfo = CurrentNode; + CurrentNode = SQ->Entries[Index]; + return true; + } + return false; +} + +void Input::postflightElement(void *SaveInfo) { + CurrentNode = reinterpret_cast<HNode *>(SaveInfo); +} + +unsigned Input::beginFlowSequence() { + if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) { + return SQ->Entries.size(); + } + return 0; +} + +bool Input::preflightFlowElement(unsigned index, void *&SaveInfo) { + if (EC) + return false; + if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) { + SaveInfo = CurrentNode; + CurrentNode = SQ->Entries[index]; + return true; + } + return false; +} + +void Input::postflightFlowElement(void *SaveInfo) { + CurrentNode = reinterpret_cast<HNode *>(SaveInfo); +} + +void Input::endFlowSequence() { +} + +void Input::beginEnumScalar() { + ScalarMatchFound = false; +} + +bool Input::matchEnumScalar(const char *Str, bool) { + if (ScalarMatchFound) + return false; + if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) { + if (SN->value().equals(Str)) { + ScalarMatchFound = true; + return true; + } + } + return false; +} + +void Input::endEnumScalar() { + if (!ScalarMatchFound) { + setError(CurrentNode, "unknown enumerated scalar"); + } +} + +bool Input::beginBitSetScalar(bool &DoClear) { + BitValuesUsed.clear(); + if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) { + BitValuesUsed.insert(BitValuesUsed.begin(), SQ->Entries.size(), false); + } else { + setError(CurrentNode, "expected sequence of bit values"); + } + DoClear = true; + return true; +} + +bool Input::bitSetMatch(const char *Str, bool) { + if (EC) + return false; + if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) { + unsigned Index = 0; + for (std::vector<HNode *>::iterator i = SQ->Entries.begin(), + End = SQ->Entries.end(); i != End; ++i) { + if (ScalarHNode *SN = dyn_cast<ScalarHNode>(*i)) { + if (SN->value().equals(Str)) { + BitValuesUsed[Index] = true; + return true; + } + } else { + setError(CurrentNode, "unexpected scalar in sequence of bit values"); + } + ++Index; + } + } else { + setError(CurrentNode, "expected sequence of bit values"); + } + return false; +} + +void Input::endBitSetScalar() { + if (EC) + return; + if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) { + assert(BitValuesUsed.size() == SQ->Entries.size()); + for (unsigned i = 0; i < SQ->Entries.size(); ++i) { + if (!BitValuesUsed[i]) { + setError(SQ->Entries[i], "unknown bit value"); + return; + } + } + } +} + +void Input::scalarString(StringRef &S) { + if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) { + S = SN->value(); + } else { + setError(CurrentNode, "unexpected scalar"); + } +} + +void Input::setError(HNode *hnode, const Twine &message) { + this->setError(hnode->_node, message); +} + +void Input::setError(Node *node, const Twine &message) { + Strm->printError(node, message); + EC = make_error_code(errc::invalid_argument); +} + +Input::HNode *Input::createHNodes(Node *N) { + SmallString<128> StringStorage; + if (ScalarNode *SN = dyn_cast<ScalarNode>(N)) { + StringRef KeyStr = SN->getValue(StringStorage); + if (!StringStorage.empty()) { + // Copy string to permanent storage + unsigned Len = StringStorage.size(); + char *Buf = StringAllocator.Allocate<char>(Len); + memcpy(Buf, &StringStorage[0], Len); + KeyStr = StringRef(Buf, Len); + } + return new ScalarHNode(N, KeyStr); + } else if (SequenceNode *SQ = dyn_cast<SequenceNode>(N)) { + SequenceHNode *SQHNode = new SequenceHNode(N); + for (SequenceNode::iterator i = SQ->begin(), End = SQ->end(); i != End; + ++i) { + HNode *Entry = this->createHNodes(i); + if (EC) + break; + SQHNode->Entries.push_back(Entry); + } + return SQHNode; + } else if (MappingNode *Map = dyn_cast<MappingNode>(N)) { + MapHNode *mapHNode = new MapHNode(N); + for (MappingNode::iterator i = Map->begin(), End = Map->end(); i != End; + ++i) { + ScalarNode *KeyScalar = dyn_cast<ScalarNode>(i->getKey()); + StringStorage.clear(); + StringRef KeyStr = KeyScalar->getValue(StringStorage); + if (!StringStorage.empty()) { + // Copy string to permanent storage + unsigned Len = StringStorage.size(); + char *Buf = StringAllocator.Allocate<char>(Len); + memcpy(Buf, &StringStorage[0], Len); + KeyStr = StringRef(Buf, Len); + } + HNode *ValueHNode = this->createHNodes(i->getValue()); + if (EC) + break; + mapHNode->Mapping[KeyStr] = ValueHNode; + } + return mapHNode; + } else if (isa<NullNode>(N)) { + return new EmptyHNode(N); + } else { + setError(N, "unknown node kind"); + return NULL; + } +} + +bool Input::MapHNode::isValidKey(StringRef Key) { + for (SmallVector<const char *, 6>::iterator i = ValidKeys.begin(), + End = ValidKeys.end(); i != End; ++i) { + if (Key.equals(*i)) + return true; + } + return false; +} + +void Input::setError(const Twine &Message) { + this->setError(CurrentNode, Message); +} + +Input::MapHNode::~MapHNode() { + for (MapHNode::NameToNode::iterator i = Mapping.begin(), End = Mapping.end(); + i != End; ++i) { + delete i->second; + } +} + +Input::SequenceHNode::~SequenceHNode() { + for (std::vector<HNode*>::iterator i = Entries.begin(), End = Entries.end(); + i != End; ++i) { + delete *i; + } +} + + + +//===----------------------------------------------------------------------===// +// Output +//===----------------------------------------------------------------------===// + +Output::Output(raw_ostream &yout, void *context) + : IO(context), + Out(yout), + Column(0), + ColumnAtFlowStart(0), + NeedBitValueComma(false), + NeedFlowSequenceComma(false), + EnumerationMatchFound(false), + NeedsNewLine(false) { +} + +Output::~Output() { +} + +bool Output::outputting() { + return true; +} + +void Output::beginMapping() { + StateStack.push_back(inMapFirstKey); + NeedsNewLine = true; +} + +void Output::endMapping() { + StateStack.pop_back(); +} + +bool Output::preflightKey(const char *Key, bool Required, bool SameAsDefault, + bool &UseDefault, void *&) { + UseDefault = false; + if (Required || !SameAsDefault) { + this->newLineCheck(); + this->paddedKey(Key); + return true; + } + return false; +} + +void Output::postflightKey(void *) { + if (StateStack.back() == inMapFirstKey) { + StateStack.pop_back(); + StateStack.push_back(inMapOtherKey); + } +} + +void Output::beginDocuments() { + this->outputUpToEndOfLine("---"); +} + +bool Output::preflightDocument(unsigned index) { + if (index > 0) + this->outputUpToEndOfLine("\n---"); + return true; +} + +void Output::postflightDocument() { +} + +void Output::endDocuments() { + output("\n...\n"); +} + +unsigned Output::beginSequence() { + StateStack.push_back(inSeq); + NeedsNewLine = true; + return 0; +} + +void Output::endSequence() { + StateStack.pop_back(); +} + +bool Output::preflightElement(unsigned, void *&) { + return true; +} + +void Output::postflightElement(void *) { +} + +unsigned Output::beginFlowSequence() { + StateStack.push_back(inFlowSeq); + this->newLineCheck(); + ColumnAtFlowStart = Column; + output("[ "); + NeedFlowSequenceComma = false; + return 0; +} + +void Output::endFlowSequence() { + StateStack.pop_back(); + this->outputUpToEndOfLine(" ]"); +} + +bool Output::preflightFlowElement(unsigned, void *&) { + if (NeedFlowSequenceComma) + output(", "); + if (Column > 70) { + output("\n"); + for (int i = 0; i < ColumnAtFlowStart; ++i) + output(" "); + Column = ColumnAtFlowStart; + output(" "); + } + return true; +} + +void Output::postflightFlowElement(void *) { + NeedFlowSequenceComma = true; +} + +void Output::beginEnumScalar() { + EnumerationMatchFound = false; +} + +bool Output::matchEnumScalar(const char *Str, bool Match) { + if (Match && !EnumerationMatchFound) { + this->newLineCheck(); + this->outputUpToEndOfLine(Str); + EnumerationMatchFound = true; + } + return false; +} + +void Output::endEnumScalar() { + if (!EnumerationMatchFound) + llvm_unreachable("bad runtime enum value"); +} + +bool Output::beginBitSetScalar(bool &DoClear) { + this->newLineCheck(); + output("[ "); + NeedBitValueComma = false; + DoClear = false; + return true; +} + +bool Output::bitSetMatch(const char *Str, bool Matches) { + if (Matches) { + if (NeedBitValueComma) + output(", "); + this->output(Str); + NeedBitValueComma = true; + } + return false; +} + +void Output::endBitSetScalar() { + this->outputUpToEndOfLine(" ]"); +} + +void Output::scalarString(StringRef &S) { + this->newLineCheck(); + if (S.find('\n') == StringRef::npos) { + // No embedded new-line chars, just print string. + this->outputUpToEndOfLine(S); + return; + } + unsigned i = 0; + unsigned j = 0; + unsigned End = S.size(); + output("'"); // Starting single quote. + const char *Base = S.data(); + while (j < End) { + // Escape a single quote by doubling it. + if (S[j] == '\'') { + output(StringRef(&Base[i], j - i + 1)); + output("'"); + i = j + 1; + } + ++j; + } + output(StringRef(&Base[i], j - i)); + this->outputUpToEndOfLine("'"); // Ending single quote. +} + +void Output::setError(const Twine &message) { +} + +void Output::output(StringRef s) { + Column += s.size(); + Out << s; +} + +void Output::outputUpToEndOfLine(StringRef s) { + this->output(s); + if (StateStack.empty() || StateStack.back() != inFlowSeq) + NeedsNewLine = true; +} + +void Output::outputNewLine() { + Out << "\n"; + Column = 0; +} + +// if seq at top, indent as if map, then add "- " +// if seq in middle, use "- " if firstKey, else use " " +// + +void Output::newLineCheck() { + if (!NeedsNewLine) + return; + NeedsNewLine = false; + + this->outputNewLine(); + + assert(StateStack.size() > 0); + unsigned Indent = StateStack.size() - 1; + bool OutputDash = false; + + if (StateStack.back() == inSeq) { + OutputDash = true; + } else if ((StateStack.size() > 1) && (StateStack.back() == inMapFirstKey) && + (StateStack[StateStack.size() - 2] == inSeq)) { + --Indent; + OutputDash = true; + } + + for (unsigned i = 0; i < Indent; ++i) { + output(" "); + } + if (OutputDash) { + output("- "); + } + +} + +void Output::paddedKey(StringRef key) { + output(key); + output(":"); + const char *spaces = " "; + if (key.size() < strlen(spaces)) + output(&spaces[key.size()]); + else + output(" "); +} + +//===----------------------------------------------------------------------===// +// traits for built-in types +//===----------------------------------------------------------------------===// + +void ScalarTraits<bool>::output(const bool &Val, void *, raw_ostream &Out) { + Out << (Val ? "true" : "false"); +} + +StringRef ScalarTraits<bool>::input(StringRef Scalar, void *, bool &Val) { + if (Scalar.equals("true")) { + Val = true; + return StringRef(); + } else if (Scalar.equals("false")) { + Val = false; + return StringRef(); + } + return "invalid boolean"; +} + +void ScalarTraits<StringRef>::output(const StringRef &Val, void *, + raw_ostream &Out) { + Out << Val; +} + +StringRef ScalarTraits<StringRef>::input(StringRef Scalar, void *, + StringRef &Val) { + Val = Scalar; + return StringRef(); +} + +void ScalarTraits<uint8_t>::output(const uint8_t &Val, void *, + raw_ostream &Out) { + // use temp uin32_t because ostream thinks uint8_t is a character + uint32_t Num = Val; + Out << Num; +} + +StringRef ScalarTraits<uint8_t>::input(StringRef Scalar, void *, uint8_t &Val) { + unsigned long long n; + if (getAsUnsignedInteger(Scalar, 0, n)) + return "invalid number"; + if (n > 0xFF) + return "out of range number"; + Val = n; + return StringRef(); +} + +void ScalarTraits<uint16_t>::output(const uint16_t &Val, void *, + raw_ostream &Out) { + Out << Val; +} + +StringRef ScalarTraits<uint16_t>::input(StringRef Scalar, void *, + uint16_t &Val) { + unsigned long long n; + if (getAsUnsignedInteger(Scalar, 0, n)) + return "invalid number"; + if (n > 0xFFFF) + return "out of range number"; + Val = n; + return StringRef(); +} + +void ScalarTraits<uint32_t>::output(const uint32_t &Val, void *, + raw_ostream &Out) { + Out << Val; +} + +StringRef ScalarTraits<uint32_t>::input(StringRef Scalar, void *, + uint32_t &Val) { + unsigned long long n; + if (getAsUnsignedInteger(Scalar, 0, n)) + return "invalid number"; + if (n > 0xFFFFFFFFUL) + return "out of range number"; + Val = n; + return StringRef(); +} + +void ScalarTraits<uint64_t>::output(const uint64_t &Val, void *, + raw_ostream &Out) { + Out << Val; +} + +StringRef ScalarTraits<uint64_t>::input(StringRef Scalar, void *, + uint64_t &Val) { + unsigned long long N; + if (getAsUnsignedInteger(Scalar, 0, N)) + return "invalid number"; + Val = N; + return StringRef(); +} + +void ScalarTraits<int8_t>::output(const int8_t &Val, void *, raw_ostream &Out) { + // use temp in32_t because ostream thinks int8_t is a character + int32_t Num = Val; + Out << Num; +} + +StringRef ScalarTraits<int8_t>::input(StringRef Scalar, void *, int8_t &Val) { + long long N; + if (getAsSignedInteger(Scalar, 0, N)) + return "invalid number"; + if ((N > 127) || (N < -128)) + return "out of range number"; + Val = N; + return StringRef(); +} + +void ScalarTraits<int16_t>::output(const int16_t &Val, void *, + raw_ostream &Out) { + Out << Val; +} + +StringRef ScalarTraits<int16_t>::input(StringRef Scalar, void *, int16_t &Val) { + long long N; + if (getAsSignedInteger(Scalar, 0, N)) + return "invalid number"; + if ((N > INT16_MAX) || (N < INT16_MIN)) + return "out of range number"; + Val = N; + return StringRef(); +} + +void ScalarTraits<int32_t>::output(const int32_t &Val, void *, + raw_ostream &Out) { + Out << Val; +} + +StringRef ScalarTraits<int32_t>::input(StringRef Scalar, void *, int32_t &Val) { + long long N; + if (getAsSignedInteger(Scalar, 0, N)) + return "invalid number"; + if ((N > INT32_MAX) || (N < INT32_MIN)) + return "out of range number"; + Val = N; + return StringRef(); +} + +void ScalarTraits<int64_t>::output(const int64_t &Val, void *, + raw_ostream &Out) { + Out << Val; +} + +StringRef ScalarTraits<int64_t>::input(StringRef Scalar, void *, int64_t &Val) { + long long N; + if (getAsSignedInteger(Scalar, 0, N)) + return "invalid number"; + Val = N; + return StringRef(); +} + +void ScalarTraits<double>::output(const double &Val, void *, raw_ostream &Out) { + Out << format("%g", Val); +} + +StringRef ScalarTraits<double>::input(StringRef Scalar, void *, double &Val) { + SmallString<32> buff(Scalar.begin(), Scalar.end()); + char *end; + Val = strtod(buff.c_str(), &end); + if (*end != '\0') + return "invalid floating point number"; + return StringRef(); +} + +void ScalarTraits<float>::output(const float &Val, void *, raw_ostream &Out) { + Out << format("%g", Val); +} + +StringRef ScalarTraits<float>::input(StringRef Scalar, void *, float &Val) { + SmallString<32> buff(Scalar.begin(), Scalar.end()); + char *end; + Val = strtod(buff.c_str(), &end); + if (*end != '\0') + return "invalid floating point number"; + return StringRef(); +} + +void ScalarTraits<Hex8>::output(const Hex8 &Val, void *, raw_ostream &Out) { + uint8_t Num = Val; + Out << format("0x%02X", Num); +} + +StringRef ScalarTraits<Hex8>::input(StringRef Scalar, void *, Hex8 &Val) { + unsigned long long n; + if (getAsUnsignedInteger(Scalar, 0, n)) + return "invalid hex8 number"; + if (n > 0xFF) + return "out of range hex8 number"; + Val = n; + return StringRef(); +} + +void ScalarTraits<Hex16>::output(const Hex16 &Val, void *, raw_ostream &Out) { + uint16_t Num = Val; + Out << format("0x%04X", Num); +} + +StringRef ScalarTraits<Hex16>::input(StringRef Scalar, void *, Hex16 &Val) { + unsigned long long n; + if (getAsUnsignedInteger(Scalar, 0, n)) + return "invalid hex16 number"; + if (n > 0xFFFF) + return "out of range hex16 number"; + Val = n; + return StringRef(); +} + +void ScalarTraits<Hex32>::output(const Hex32 &Val, void *, raw_ostream &Out) { + uint32_t Num = Val; + Out << format("0x%08X", Num); +} + +StringRef ScalarTraits<Hex32>::input(StringRef Scalar, void *, Hex32 &Val) { + unsigned long long n; + if (getAsUnsignedInteger(Scalar, 0, n)) + return "invalid hex32 number"; + if (n > 0xFFFFFFFFUL) + return "out of range hex32 number"; + Val = n; + return StringRef(); +} + +void ScalarTraits<Hex64>::output(const Hex64 &Val, void *, raw_ostream &Out) { + uint64_t Num = Val; + Out << format("0x%016llX", Num); +} + +StringRef ScalarTraits<Hex64>::input(StringRef Scalar, void *, Hex64 &Val) { + unsigned long long Num; + if (getAsUnsignedInteger(Scalar, 0, Num)) + return "invalid hex64 number"; + Val = Num; + return StringRef(); +} diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp index 7cd53648da35..a433088b1930 100644 --- a/lib/Support/raw_ostream.cpp +++ b/lib/Support/raw_ostream.cpp @@ -12,16 +12,16 @@ //===----------------------------------------------------------------------===// #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/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" #include "llvm/Support/system_error.h" -#include "llvm/ADT/STLExtras.h" #include <cctype> #include <cerrno> #include <sys/stat.h> @@ -241,7 +241,8 @@ raw_ostream &raw_ostream::operator<<(double N) { if (cs == '+' || cs == '-') { int c1 = buf[len - 2]; int c0 = buf[len - 1]; - if (isdigit(c1) && isdigit(c0)) { + if (isdigit(static_cast<unsigned char>(c1)) && + isdigit(static_cast<unsigned char>(c0))) { // Trim leading '0': "...e+012" -> "...e+12\0" buf[len - 3] = c1; buf[len - 2] = c0; @@ -305,7 +306,12 @@ raw_ostream &raw_ostream::write(const char *Ptr, size_t Size) { if (LLVM_UNLIKELY(OutBufCur == OutBufStart)) { size_t BytesToWrite = Size - (Size % NumBytes); write_impl(Ptr, BytesToWrite); - copy_to_buffer(Ptr + BytesToWrite, Size - BytesToWrite); + size_t BytesRemaining = Size - BytesToWrite; + if (BytesRemaining > size_t(OutBufEnd - OutBufCur)) { + // Too much left over to copy into our buffer. + return write(Ptr + BytesToWrite, BytesRemaining); + } + copy_to_buffer(Ptr + BytesToWrite, BytesRemaining); return *this; } @@ -511,7 +517,7 @@ raw_fd_ostream::~raw_fd_ostream() { // 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."); + report_fatal_error("IO failure on output stream.", /*GenCrashDiag=*/false); } diff --git a/lib/Support/regcomp.c b/lib/Support/regcomp.c index 46c91a9c497c..74d9186aaaa2 100644 --- a/lib/Support/regcomp.c +++ b/lib/Support/regcomp.c @@ -303,6 +303,7 @@ p_ere_exp(struct parse *p) sopno pos; int count; int count2; + int backrefnum; sopno subno; int wascaret = 0; @@ -370,7 +371,34 @@ p_ere_exp(struct parse *p) case '\\': REQUIRE(MORE(), REG_EESCAPE); c = GETNEXT(); - ordinary(p, c); + if (c >= '1' && c <= '9') { + /* \[0-9] is taken to be a back-reference to a previously specified + * matching group. backrefnum will hold the number. The matching + * group must exist (i.e. if \4 is found there must have been at + * least 4 matching groups specified in the pattern previously). + */ + backrefnum = c - '0'; + if (p->pend[backrefnum] == 0) { + SETERROR(REG_ESUBREG); + break; + } + + /* Make sure everything checks out and emit the sequence + * that marks a back-reference to the parse structure. + */ + assert(backrefnum <= p->g->nsub); + EMIT(OBACK_, backrefnum); + assert(p->pbegin[backrefnum] != 0); + assert(OP(p->strip[p->pbegin[backrefnum]]) != OLPAREN); + assert(OP(p->strip[p->pend[backrefnum]]) != ORPAREN); + (void) dupl(p, p->pbegin[backrefnum]+1, p->pend[backrefnum]); + EMIT(O_BACK, backrefnum); + p->g->backrefs = 1; + } else { + /* Other chars are simply themselves when escaped with a backslash. + */ + ordinary(p, c); + } break; case '{': /* okay as ordinary except if digit follows */ REQUIRE(!MORE() || !isdigit((uch)PEEK()), REG_BADRPT); diff --git a/lib/Support/system_error.cpp b/lib/Support/system_error.cpp index 2df223ca718a..b22745afc330 100644 --- a/lib/Support/system_error.cpp +++ b/lib/Support/system_error.cpp @@ -13,8 +13,8 @@ #include "llvm/Support/system_error.h" #include "llvm/Support/Errno.h" -#include <string> #include <cstring> +#include <string> namespace llvm { |