diff options
Diffstat (limited to 'lib/Support')
58 files changed, 2355 insertions, 1424 deletions
diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index 393ecf4784cb..4b0a0e5d4819 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -1248,10 +1248,10 @@ APFloat::roundAwayFromZero(roundingMode rounding_mode, return false; case rmTowardPositive: - return sign == false; + return !sign; case rmTowardNegative: - return sign == true; + return sign; } llvm_unreachable("Invalid rounding mode found"); } @@ -1430,7 +1430,7 @@ APFloat::addOrSubtractSignificand(const APFloat &rhs, bool subtract) /* Determine if the operation on the absolute values is effectively an addition or subtraction. */ - subtract ^= (sign ^ rhs.sign) ? true : false; + subtract ^= static_cast<bool>(sign ^ rhs.sign); /* Are we bigger exponent-wise than the RHS? */ bits = exponent - rhs.exponent; @@ -3920,7 +3920,7 @@ APFloat::makeZero(bool Negative) { APFloat llvm::scalbn(APFloat X, int Exp) { if (X.isInfinity() || X.isZero() || X.isNaN()) - return std::move(X); + return X; auto MaxExp = X.getSemantics().maxExponent; auto MinExp = X.getSemantics().minExponent; @@ -3932,5 +3932,5 @@ APFloat llvm::scalbn(APFloat X, int Exp) { return APFloat::getZero(X.getSemantics(), X.isNegative()); X.exponent += Exp; - return std::move(X); + return X; } diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index 0ddc2ab8af30..23f89bb66f9e 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -162,7 +162,7 @@ APInt& APInt::operator=(uint64_t RHS) { return clearUnusedBits(); } -/// Profile - This method 'profiles' an APInt for use with FoldingSet. +/// This method 'profiles' an APInt for use with FoldingSet. void APInt::Profile(FoldingSetNodeID& ID) const { ID.AddInteger(BitWidth); @@ -176,7 +176,7 @@ void APInt::Profile(FoldingSetNodeID& ID) const { ID.AddInteger(pVal[i]); } -/// add_1 - This function adds a single "digit" integer, y, to the multiple +/// This function adds a single "digit" integer, y, to the multiple /// "digit" integer array, x[]. x[] is modified to reflect the addition and /// 1 is returned if there is a carry out, otherwise 0 is returned. /// @returns the carry of the addition. @@ -202,7 +202,7 @@ APInt& APInt::operator++() { return clearUnusedBits(); } -/// sub_1 - This function subtracts a single "digit" (64-bit word), y, from +/// This function subtracts a single "digit" (64-bit word), y, from /// the multi-digit integer array, x[], propagating the borrowed 1 value until /// no further borrowing is neeeded or it runs out of "digits" in x. The result /// is 1 if "borrowing" exhausted the digits in x, or 0 if x was not exhausted. @@ -231,7 +231,7 @@ APInt& APInt::operator--() { return clearUnusedBits(); } -/// add - This function adds the integer array x to the integer array Y and +/// This function adds the integer array x to the integer array Y and /// places the result in dest. /// @returns the carry out from the addition /// @brief General addition of 64-bit integer arrays @@ -672,12 +672,20 @@ hash_code llvm::hash_value(const APInt &Arg) { return hash_combine_range(Arg.pVal, Arg.pVal + Arg.getNumWords()); } -/// HiBits - This function returns the high "numBits" bits of this APInt. +bool APInt::isSplat(unsigned SplatSizeInBits) const { + assert(getBitWidth() % SplatSizeInBits == 0 && + "SplatSizeInBits must divide width!"); + // We can check that all parts of an integer are equal by making use of a + // little trick: rotate and check if it's still the same value. + return *this == rotl(SplatSizeInBits); +} + +/// This function returns the high "numBits" bits of this APInt. APInt APInt::getHiBits(unsigned numBits) const { return APIntOps::lshr(*this, BitWidth - numBits); } -/// LoBits - This function returns the low "numBits" bits of this APInt. +/// This function returns the low "numBits" bits of this APInt. APInt APInt::getLoBits(unsigned numBits) const { return APIntOps::lshr(APIntOps::shl(*this, BitWidth - numBits), BitWidth - numBits); @@ -713,7 +721,7 @@ unsigned APInt::countLeadingZerosSlowCase() const { unsigned APInt::countLeadingOnes() const { if (isSingleWord()) - return CountLeadingOnes_64(VAL << (APINT_BITS_PER_WORD - BitWidth)); + return llvm::countLeadingOnes(VAL << (APINT_BITS_PER_WORD - BitWidth)); unsigned highWordBits = BitWidth % APINT_BITS_PER_WORD; unsigned shift; @@ -724,13 +732,13 @@ unsigned APInt::countLeadingOnes() const { shift = APINT_BITS_PER_WORD - highWordBits; } int i = getNumWords() - 1; - unsigned Count = CountLeadingOnes_64(pVal[i] << shift); + unsigned Count = llvm::countLeadingOnes(pVal[i] << shift); if (Count == highWordBits) { for (i--; i >= 0; --i) { if (pVal[i] == -1ULL) Count += APINT_BITS_PER_WORD; else { - Count += CountLeadingOnes_64(pVal[i]); + Count += llvm::countLeadingOnes(pVal[i]); break; } } @@ -756,14 +764,14 @@ unsigned APInt::countTrailingOnesSlowCase() const { for (; i < getNumWords() && pVal[i] == -1ULL; ++i) Count += APINT_BITS_PER_WORD; if (i < getNumWords()) - Count += CountTrailingOnes_64(pVal[i]); + Count += llvm::countTrailingOnes(pVal[i]); return std::min(Count, BitWidth); } unsigned APInt::countPopulationSlowCase() const { unsigned Count = 0; for (unsigned i = 0; i < getNumWords(); ++i) - Count += CountPopulation_64(pVal[i]); + Count += llvm::countPopulation(pVal[i]); return Count; } @@ -853,7 +861,7 @@ APInt llvm::APIntOps::RoundDoubleToAPInt(double Double, unsigned width) { return isNeg ? -Tmp : Tmp; } -/// RoundToDouble - This function converts this APInt to a double. +/// This function converts this APInt to a double. /// The layout for double is as following (IEEE Standard 754): /// -------------------------------------- /// | Sign Exponent Fraction Bias | @@ -1310,13 +1318,8 @@ APInt APInt::sqrt() const { // libc sqrt function which will probably use a hardware sqrt computation. // This should be faster than the algorithm below. if (magnitude < 52) { -#if HAVE_ROUND return APInt(BitWidth, uint64_t(::round(::sqrt(double(isSingleWord()?VAL:pVal[0]))))); -#else - return APInt(BitWidth, - uint64_t(::sqrt(double(isSingleWord()?VAL:pVal[0])) + 0.5)); -#endif } // Okay, all the short cuts are exhausted. We must compute it. The following @@ -1508,21 +1511,18 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, assert(u && "Must provide dividend"); assert(v && "Must provide divisor"); assert(q && "Must provide quotient"); - assert(u != v && u != q && v != q && "Must us different memory"); + assert(u != v && u != q && v != q && "Must use different memory"); assert(n>1 && "n must be > 1"); - // Knuth uses the value b as the base of the number system. In our case b - // is 2^31 so we just set it to -1u. - uint64_t b = uint64_t(1) << 32; + // b denotes the base of the number system. In our case b is 2^32. + LLVM_CONSTEXPR uint64_t b = uint64_t(1) << 32; -#if 0 DEBUG(dbgs() << "KnuthDiv: m=" << m << " n=" << n << '\n'); DEBUG(dbgs() << "KnuthDiv: original:"); DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); DEBUG(dbgs() << " by"); DEBUG(for (int i = n; i >0; i--) dbgs() << " " << v[i-1]); DEBUG(dbgs() << '\n'); -#endif // D1. [Normalize.] Set d = b / (v[n-1] + 1) and multiply all the digits of // u and v by d. Note that we have taken Knuth's advice here to use a power // of 2 value for d such that d * v[n-1] >= b/2 (b is the base). A power of @@ -1547,13 +1547,12 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, } } u[m+n] = u_carry; -#if 0 + DEBUG(dbgs() << "KnuthDiv: normal:"); DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); DEBUG(dbgs() << " by"); DEBUG(for (int i = n; i >0; i--) dbgs() << " " << v[i-1]); DEBUG(dbgs() << '\n'); -#endif // D2. [Initialize j.] Set j to m. This is the loop counter over the places. int j = m; @@ -1583,44 +1582,23 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, // (u[j+n]u[j+n-1]..u[j]) - qp * (v[n-1]...v[1]v[0]). This computation // consists of a simple multiplication by a one-place number, combined with // a subtraction. - bool isNeg = false; - for (unsigned i = 0; i < n; ++i) { - uint64_t u_tmp = uint64_t(u[j+i]) | (uint64_t(u[j+i+1]) << 32); - uint64_t subtrahend = uint64_t(qp) * uint64_t(v[i]); - bool borrow = subtrahend > u_tmp; - DEBUG(dbgs() << "KnuthDiv: u_tmp == " << u_tmp - << ", subtrahend == " << subtrahend - << ", borrow = " << borrow << '\n'); - - uint64_t result = u_tmp - subtrahend; - unsigned k = j + i; - u[k++] = (unsigned)(result & (b-1)); // subtract low word - u[k++] = (unsigned)(result >> 32); // subtract high word - while (borrow && k <= m+n) { // deal with borrow to the left - borrow = u[k] == 0; - u[k]--; - k++; - } - isNeg |= borrow; - DEBUG(dbgs() << "KnuthDiv: u[j+i] == " << u[j+i] << ", u[j+i+1] == " << - u[j+i+1] << '\n'); - } - DEBUG(dbgs() << "KnuthDiv: after subtraction:"); - DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); - DEBUG(dbgs() << '\n'); // The digits (u[j+n]...u[j]) should be kept positive; if the result of // this step is actually negative, (u[j+n]...u[j]) should be left as the // true value plus b**(n+1), namely as the b's complement of // the true value, and a "borrow" to the left should be remembered. - // - if (isNeg) { - bool carry = true; // true because b's complement is "complement + 1" - for (unsigned i = 0; i <= m+n; ++i) { - u[i] = ~u[i] + carry; // b's complement - carry = carry && u[i] == 0; - } + int64_t borrow = 0; + for (unsigned i = 0; i < n; ++i) { + uint64_t p = uint64_t(qp) * uint64_t(v[i]); + int64_t subres = int64_t(u[j+i]) - borrow - (unsigned)p; + u[j+i] = (unsigned)subres; + borrow = (p >> 32) - (subres >> 32); + DEBUG(dbgs() << "KnuthDiv: u[j+i] = " << u[j+i] + << ", borrow = " << borrow << '\n'); } - DEBUG(dbgs() << "KnuthDiv: after complement:"); + bool isNeg = u[j+n] < borrow; + u[j+n] -= (unsigned)borrow; + + DEBUG(dbgs() << "KnuthDiv: after subtraction:"); DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); DEBUG(dbgs() << '\n'); @@ -1644,7 +1622,7 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, u[j+n] += carry; } DEBUG(dbgs() << "KnuthDiv: after correction:"); - DEBUG(for (int i = m+n; i >=0; i--) dbgs() <<" " << u[i]); + DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); DEBUG(dbgs() << "\nKnuthDiv: digit result = " << q[j] << '\n'); // D7. [Loop on j.] Decrease j by one. Now if j >= 0, go back to D3. @@ -1677,9 +1655,7 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, } DEBUG(dbgs() << '\n'); } -#if 0 DEBUG(dbgs() << '\n'); -#endif } void APInt::divide(const APInt LHS, unsigned lhsWords, @@ -1803,6 +1779,8 @@ void APInt::divide(const APInt LHS, unsigned lhsWords, // The quotient is in Q. Reconstitute the quotient into Quotient's low // order words. + // This case is currently dead as all users of divide() handle trivial cases + // earlier. if (lhsWords == 1) { uint64_t tmp = uint64_t(Q[0]) | (uint64_t(Q[1]) << (APINT_BITS_PER_WORD / 2)); @@ -2281,9 +2259,8 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, std::reverse(Str.begin()+StartDig, Str.end()); } -/// toString - This returns the APInt as a std::string. Note that this is an -/// inefficient method. It is better to pass in a SmallVector/SmallString -/// to the methods above. +/// Returns the APInt as a std::string. Note that this is an inefficient method. +/// It is better to pass in a SmallVector/SmallString to the methods above. std::string APInt::toString(unsigned Radix = 10, bool Signed = true) const { SmallString<40> S; toString(S, Radix, Signed, /* formatAsCLiteral = */false); @@ -2296,13 +2273,13 @@ void APInt::dump() const { this->toStringUnsigned(U); this->toStringSigned(S); dbgs() << "APInt(" << BitWidth << "b, " - << U.str() << "u " << S.str() << "s)"; + << U << "u " << S << "s)"; } void APInt::print(raw_ostream &OS, bool isSigned) const { SmallString<40> S; this->toString(S, 10, isSigned, /* formatAsCLiteral = */false); - OS << S.str(); + OS << S; } // This implements a variety of operations on a representation of diff --git a/lib/Support/Allocator.cpp b/lib/Support/Allocator.cpp index 7c306b2370e6..f48edac0598c 100644 --- a/lib/Support/Allocator.cpp +++ b/lib/Support/Allocator.cpp @@ -12,12 +12,7 @@ //===----------------------------------------------------------------------===// #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 <cstring> namespace llvm { diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt index fa62591191db..79aae1584357 100644 --- a/lib/Support/CMakeLists.txt +++ b/lib/Support/CMakeLists.txt @@ -1,7 +1,7 @@ set(system_libs) if( NOT MSVC ) if( MINGW ) - set(system_libs ${system_libs} imagehlp psapi shell32) + set(system_libs ${system_libs} imagehlp psapi shell32 ole32) elseif( CMAKE_HOST_UNIX ) if( HAVE_LIBRT ) set(system_libs ${system_libs} rt) @@ -37,6 +37,7 @@ add_llvm_library(LLVMSupport BlockFrequency.cpp BranchProbability.cpp circular_raw_ostream.cpp + COM.cpp CommandLine.cpp Compression.cpp ConvertUTF.c @@ -58,8 +59,6 @@ add_llvm_library(LLVMSupport IntEqClasses.cpp IntervalMap.cpp IntrusiveRefCntPtr.cpp - IsInf.cpp - IsNAN.cpp LEB128.cpp LineIterator.cpp Locale.cpp @@ -86,6 +85,7 @@ add_llvm_library(LLVMSupport StringPool.cpp StringRef.cpp SystemUtils.cpp + TargetParser.cpp Timer.cpp ToolOutputFile.cpp Triple.cpp @@ -121,30 +121,10 @@ add_llvm_library(LLVMSupport Valgrind.cpp Watchdog.cpp - ADDITIONAL_HEADERS - Unix/Host.inc - Unix/Memory.inc - Unix/Mutex.inc - Unix/Path.inc - Unix/Process.inc - Unix/Program.inc - Unix/RWMutex.inc - Unix/Signals.inc - Unix/ThreadLocal.inc - Unix/TimeValue.inc - Unix/Watchdog.inc - Windows/DynamicLibrary.inc - Windows/Host.inc - Windows/Memory.inc - Windows/Mutex.inc - Windows/Path.inc - Windows/Process.inc - Windows/Program.inc - Windows/RWMutex.inc - Windows/Signals.inc - Windows/ThreadLocal.inc - Windows/TimeValue.inc - Windows/Watchdog.inc + ADDITIONAL_HEADER_DIRS + Unix + Windows + ${LLVM_MAIN_INCLUDE_DIR}/llvm/Support LINK_LIBS ${system_libs} ) diff --git a/lib/Support/COM.cpp b/lib/Support/COM.cpp new file mode 100644 index 000000000000..cf3a133fd9b4 --- /dev/null +++ b/lib/Support/COM.cpp @@ -0,0 +1,23 @@ +//===-- COM.cpp - Implement COM utility classes -----------------*- 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 utility classes related to COM. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/COM.h" + +#include "llvm/Config/config.h" + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/COM.inc" +#elif LLVM_ON_WIN32 +#include "Windows/COM.inc" +#endif diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index 40570cab7cc8..3cabc54a73aa 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm-c/Support.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" @@ -32,10 +33,8 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" -#include <cerrno> #include <cstdlib> #include <map> -#include <system_error> using namespace llvm; using namespace cl; @@ -83,129 +82,172 @@ void StringSaver::anchor() {} //===----------------------------------------------------------------------===// -// Globals for name and overview of program. Program name is not a string to -// avoid static ctor/dtor issues. -static char ProgramName[80] = "<premain>"; -static const char *ProgramOverview = nullptr; +namespace { -// This collects additional help to be printed. -static ManagedStatic<std::vector<const char *>> MoreHelp; +class CommandLineParser { +public: + // Globals for name and overview of program. Program name is not a string to + // avoid static ctor/dtor issues. + std::string ProgramName; + const char *ProgramOverview; -extrahelp::extrahelp(const char *Help) : morehelp(Help) { - MoreHelp->push_back(Help); -} + // This collects additional help to be printed. + std::vector<const char *> MoreHelp; -static bool OptionListChanged = false; + SmallVector<Option *, 4> PositionalOpts; + SmallVector<Option *, 4> SinkOpts; + StringMap<Option *> OptionsMap; -// MarkOptionsChanged - Internal helper function. -void cl::MarkOptionsChanged() { OptionListChanged = true; } + Option *ConsumeAfterOpt; // The ConsumeAfter option if it exists. -/// RegisteredOptionList - This is the list of the command line options that -/// have statically constructed themselves. -static Option *RegisteredOptionList = nullptr; + // This collects the different option categories that have been registered. + SmallPtrSet<OptionCategory *, 16> RegisteredOptionCategories; -void Option::addArgument() { - assert(!NextRegistered && "argument multiply registered!"); + CommandLineParser() : ProgramOverview(nullptr), ConsumeAfterOpt(nullptr) {} - NextRegistered = RegisteredOptionList; - RegisteredOptionList = this; - MarkOptionsChanged(); -} + void ParseCommandLineOptions(int argc, const char *const *argv, + const char *Overview); -void Option::removeArgument() { - if (RegisteredOptionList == this) { - RegisteredOptionList = NextRegistered; - MarkOptionsChanged(); - return; + void addLiteralOption(Option &Opt, const char *Name) { + if (!Opt.hasArgStr()) { + if (!OptionsMap.insert(std::make_pair(Name, &Opt)).second) { + errs() << ProgramName << ": CommandLine Error: Option '" << Name + << "' registered more than once!\n"; + report_fatal_error("inconsistency in registered CommandLine options"); + } + } } - Option *O = RegisteredOptionList; - for (; O->NextRegistered != this; O = O->NextRegistered) - ; - O->NextRegistered = NextRegistered; - MarkOptionsChanged(); -} - -// This collects the different option categories that have been registered. -typedef SmallPtrSet<OptionCategory *, 16> OptionCatSet; -static ManagedStatic<OptionCatSet> RegisteredOptionCategories; -// Initialise the general option category. -OptionCategory llvm::cl::GeneralCategory("General options"); - -void OptionCategory::registerCategory() { - assert(std::count_if(RegisteredOptionCategories->begin(), - RegisteredOptionCategories->end(), - [this](const OptionCategory *Category) { - return getName() == Category->getName(); - }) == 0 && - "Duplicate option categories"); - - RegisteredOptionCategories->insert(this); -} - -//===----------------------------------------------------------------------===// -// Basic, shared command line option processing machinery. -// - -/// GetOptionInfo - Scan the list of registered options, turning them into data -/// structures that are easier to handle. -static void GetOptionInfo(SmallVectorImpl<Option *> &PositionalOpts, - SmallVectorImpl<Option *> &SinkOpts, - StringMap<Option *> &OptionsMap) { - bool HadErrors = false; - SmallVector<const char *, 16> OptionNames; - Option *CAOpt = nullptr; // The ConsumeAfter option if it exists. - for (Option *O = RegisteredOptionList; O; O = O->getNextRegisteredOption()) { - // If this option wants to handle multiple option names, get the full set. - // This handles enum options like "-O1 -O2" etc. - O->getExtraOptionNames(OptionNames); - if (O->ArgStr[0]) - OptionNames.push_back(O->ArgStr); - - // Handle named options. - for (size_t i = 0, e = OptionNames.size(); i != e; ++i) { + void addOption(Option *O) { + bool HadErrors = false; + if (O->ArgStr[0]) { // Add argument to the argument map! - if (!OptionsMap.insert(std::make_pair(OptionNames[i], O)).second) { - errs() << ProgramName << ": CommandLine Error: Option '" - << OptionNames[i] << "' registered more than once!\n"; + if (!OptionsMap.insert(std::make_pair(O->ArgStr, O)).second) { + errs() << ProgramName << ": CommandLine Error: Option '" << O->ArgStr + << "' registered more than once!\n"; HadErrors = true; } } - OptionNames.clear(); - // Remember information about positional options. if (O->getFormattingFlag() == cl::Positional) PositionalOpts.push_back(O); else if (O->getMiscFlags() & cl::Sink) // Remember sink options SinkOpts.push_back(O); else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) { - if (CAOpt) { + if (ConsumeAfterOpt) { O->error("Cannot specify more than one option with cl::ConsumeAfter!"); HadErrors = true; } - CAOpt = O; + ConsumeAfterOpt = O; } + + // Fail hard if there were errors. These are strictly unrecoverable and + // indicate serious issues such as conflicting option names or an + // incorrectly + // linked LLVM distribution. + if (HadErrors) + report_fatal_error("inconsistency in registered CommandLine options"); } - if (CAOpt) - PositionalOpts.push_back(CAOpt); + void removeOption(Option *O) { + SmallVector<const char *, 16> OptionNames; + O->getExtraOptionNames(OptionNames); + if (O->ArgStr[0]) + OptionNames.push_back(O->ArgStr); + for (auto Name : OptionNames) + OptionsMap.erase(StringRef(Name)); - // Make sure that they are in order of registration not backwards. - std::reverse(PositionalOpts.begin(), PositionalOpts.end()); + if (O->getFormattingFlag() == cl::Positional) + for (auto Opt = PositionalOpts.begin(); Opt != PositionalOpts.end(); + ++Opt) { + if (*Opt == O) { + PositionalOpts.erase(Opt); + break; + } + } + else if (O->getMiscFlags() & cl::Sink) + for (auto Opt = SinkOpts.begin(); Opt != SinkOpts.end(); ++Opt) { + if (*Opt == O) { + SinkOpts.erase(Opt); + break; + } + } + else if (O == ConsumeAfterOpt) + ConsumeAfterOpt = nullptr; + } + + bool hasOptions() { + return (!OptionsMap.empty() || !PositionalOpts.empty() || + nullptr != ConsumeAfterOpt); + } + + void updateArgStr(Option *O, const char *NewName) { + if (!OptionsMap.insert(std::make_pair(NewName, O)).second) { + errs() << ProgramName << ": CommandLine Error: Option '" << O->ArgStr + << "' registered more than once!\n"; + report_fatal_error("inconsistency in registered CommandLine options"); + } + OptionsMap.erase(StringRef(O->ArgStr)); + } + + void printOptionValues(); + + void registerCategory(OptionCategory *cat) { + assert(std::count_if(RegisteredOptionCategories.begin(), + RegisteredOptionCategories.end(), + [cat](const OptionCategory *Category) { + return cat->getName() == Category->getName(); + }) == 0 && + "Duplicate option categories"); + + RegisteredOptionCategories.insert(cat); + } - // Fail hard if there were errors. These are strictly unrecoverable and - // indicate serious issues such as conflicting option names or an incorrectly - // linked LLVM distribution. - if (HadErrors) - report_fatal_error("inconsistency in registered CommandLine options"); +private: + Option *LookupOption(StringRef &Arg, StringRef &Value); +}; + +} // namespace + +static ManagedStatic<CommandLineParser> GlobalParser; + +void cl::AddLiteralOption(Option &O, const char *Name) { + GlobalParser->addLiteralOption(O, Name); } +extrahelp::extrahelp(const char *Help) : morehelp(Help) { + GlobalParser->MoreHelp.push_back(Help); +} + +void Option::addArgument() { + GlobalParser->addOption(this); + FullyInitialized = true; +} + +void Option::removeArgument() { GlobalParser->removeOption(this); } + +void Option::setArgStr(const char *S) { + if (FullyInitialized) + GlobalParser->updateArgStr(this, S); + ArgStr = S; +} + +// Initialise the general option category. +OptionCategory llvm::cl::GeneralCategory("General options"); + +void OptionCategory::registerCategory() { + GlobalParser->registerCategory(this); +} + +//===----------------------------------------------------------------------===// +// Basic, shared command line option processing machinery. +// + /// LookupOption - Lookup the option specified by the specified option on the /// command line. If there is a value specified (after an equal sign) return /// that as well. This assumes that leading dashes have already been stripped. -static Option *LookupOption(StringRef &Arg, StringRef &Value, - const StringMap<Option *> &OptionsMap) { +Option *CommandLineParser::LookupOption(StringRef &Arg, StringRef &Value) { // Reject all dashes. if (Arg.empty()) return nullptr; @@ -271,7 +313,7 @@ static Option *LookupNearestOption(StringRef Arg, if (RHS.empty() || !PermitValue) NearestString = OptionNames[i]; else - NearestString = std::string(OptionNames[i]) + "=" + RHS.str(); + NearestString = (Twine(OptionNames[i]) + "=" + RHS).str(); } } } @@ -655,6 +697,12 @@ void cl::TokenizeWindowsCommandLine(StringRef Src, StringSaver &Saver, NewArgv.push_back(nullptr); } +// It is called byte order marker but the UTF-8 BOM is actually not affected +// by the host system's endianness. +static bool hasUTF8ByteOrderMark(ArrayRef<char> S) { + return (S.size() >= 3 && S[0] == '\xef' && S[1] == '\xbb' && S[2] == '\xbf'); +} + static bool ExpandResponseFile(const char *FName, StringSaver &Saver, TokenizerCallback Tokenizer, SmallVectorImpl<const char *> &NewArgv, @@ -674,6 +722,11 @@ static bool ExpandResponseFile(const char *FName, StringSaver &Saver, return false; Str = StringRef(UTF8Buf); } + // If we see UTF-8 BOM sequence at the beginning of a file, we shall remove + // these bytes before parsing. + // Reference: http://en.wikipedia.org/wiki/UTF-8#Byte_order_mark + else if (hasUTF8ByteOrderMark(BufRef)) + Str = StringRef(BufRef.data() + 3, BufRef.size() - 3); // Tokenize the contents into NewArgv. Tokenizer(Str, Saver, NewArgv, MarkEOLs); @@ -731,7 +784,7 @@ class StrDupSaver : public StringSaver { std::vector<char *> Dups; public: - ~StrDupSaver() { + ~StrDupSaver() override { for (std::vector<char *>::iterator I = Dups.begin(), E = Dups.end(); I != E; ++I) { char *Dup = *I; @@ -777,28 +830,23 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, void cl::ParseCommandLineOptions(int argc, const char *const *argv, const char *Overview) { - // Process all registered options. - SmallVector<Option *, 4> PositionalOpts; - SmallVector<Option *, 4> SinkOpts; - StringMap<Option *> Opts; - GetOptionInfo(PositionalOpts, SinkOpts, Opts); + GlobalParser->ParseCommandLineOptions(argc, argv, Overview); +} - assert((!Opts.empty() || !PositionalOpts.empty()) && "No options specified!"); +void CommandLineParser::ParseCommandLineOptions(int argc, + const char *const *argv, + const char *Overview) { + assert(hasOptions() && "No options specified!"); // Expand response files. - SmallVector<const char *, 20> newArgv; - for (int i = 0; i != argc; ++i) - newArgv.push_back(argv[i]); + SmallVector<const char *, 20> newArgv(argv, argv + argc); StrDupSaver Saver; ExpandResponseFiles(Saver, TokenizeGNUCommandLine, newArgv); argv = &newArgv[0]; argc = static_cast<int>(newArgv.size()); // Copy the program name into ProgName, making sure not to overflow it. - StringRef ProgName = sys::path::filename(argv[0]); - size_t Len = std::min(ProgName.size(), size_t(79)); - memcpy(ProgramName, ProgName.data(), Len); - ProgramName[Len] = '\0'; + ProgramName = sys::path::filename(argv[0]); ProgramOverview = Overview; bool ErrorParsing = false; @@ -809,25 +857,22 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, // Determine whether or not there are an unlimited number of positionals bool HasUnlimitedPositionals = false; - Option *ConsumeAfterOpt = nullptr; + if (ConsumeAfterOpt) { + assert(PositionalOpts.size() > 0 && + "Cannot specify cl::ConsumeAfter without a positional argument!"); + } if (!PositionalOpts.empty()) { - if (PositionalOpts[0]->getNumOccurrencesFlag() == cl::ConsumeAfter) { - assert(PositionalOpts.size() > 1 && - "Cannot specify cl::ConsumeAfter without a positional argument!"); - ConsumeAfterOpt = PositionalOpts[0]; - } // Calculate how many positional values are _required_. bool UnboundedFound = false; - for (size_t i = ConsumeAfterOpt ? 1 : 0, e = PositionalOpts.size(); i != e; - ++i) { + for (size_t i = 0, e = PositionalOpts.size(); i != e; ++i) { Option *Opt = PositionalOpts[i]; if (RequiresValue(Opt)) ++NumPositionalRequired; else if (ConsumeAfterOpt) { // ConsumeAfter cannot be combined with "optional" positional options // unless there is only one positional argument... - if (PositionalOpts.size() > 2) + if (PositionalOpts.size() > 1) ErrorParsing |= Opt->error( "error - this positional option will never be matched, " "because it does not Require a value, and a " @@ -841,6 +886,9 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, "another positional argument will match an " "unbounded number of values, and this option" " does not require a value!"); + errs() << ProgramName << ": CommandLine Error: Option '" << Opt->ArgStr + << "' is all messed up!\n"; + errs() << PositionalOpts.size(); } UnboundedFound |= EatsUnboundedNumberOfValues(Opt); } @@ -866,17 +914,6 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, StringRef Value; StringRef ArgName = ""; - // If the option list changed, this means that some command line - // option has just been registered or deregistered. This can occur in - // response to things like -load, etc. If this happens, rescan the options. - if (OptionListChanged) { - PositionalOpts.clear(); - SinkOpts.clear(); - Opts.clear(); - GetOptionInfo(PositionalOpts, SinkOpts, Opts); - OptionListChanged = false; - } - // Check to see if this is a positional argument. This argument is // considered to be positional if it doesn't start with '-', if it is "-" // itself, or if we have seen "--" already. @@ -917,7 +954,7 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, while (!ArgName.empty() && ArgName[0] == '-') ArgName = ArgName.substr(1); - Handler = LookupOption(ArgName, Value, Opts); + Handler = LookupOption(ArgName, Value); if (!Handler || Handler->getFormattingFlag() != cl::Positional) { ProvidePositionalOption(ActivePositionalArg, argv[i], i); continue; // We are done! @@ -929,18 +966,18 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, while (!ArgName.empty() && ArgName[0] == '-') ArgName = ArgName.substr(1); - Handler = LookupOption(ArgName, Value, Opts); + Handler = LookupOption(ArgName, Value); // Check to see if this "option" is really a prefixed or grouped argument. if (!Handler) - Handler = - HandlePrefixedOrGroupedOption(ArgName, Value, ErrorParsing, Opts); + Handler = HandlePrefixedOrGroupedOption(ArgName, Value, ErrorParsing, + OptionsMap); // Otherwise, look for the closest available option to report to the user // in the upcoming error. if (!Handler && SinkOpts.empty()) NearestHandler = - LookupNearestOption(ArgName, Opts, NearestHandlerString); + LookupNearestOption(ArgName, OptionsMap, NearestHandlerString); } if (!Handler) { @@ -1037,8 +1074,8 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, // positional option and keep the rest for the consume after. The above // loop would have assigned no values to positional options in this case. // - if (PositionalOpts.size() == 2 && ValNo == 0 && !PositionalVals.empty()) { - ErrorParsing |= ProvidePositionalOption(PositionalOpts[1], + if (PositionalOpts.size() == 1 && ValNo == 0 && !PositionalVals.empty()) { + ErrorParsing |= ProvidePositionalOption(PositionalOpts[0], PositionalVals[ValNo].first, PositionalVals[ValNo].second); ValNo++; @@ -1053,7 +1090,7 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, } // Loop over args and make sure all required args are specified! - for (const auto &Opt : Opts) { + for (const auto &Opt : OptionsMap) { switch (Opt.second->getNumOccurrencesFlag()) { case Required: case OneOrMore: @@ -1076,9 +1113,7 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, // Free all of the memory allocated to the map. Command line options may only // be processed once! - Opts.clear(); - PositionalOpts.clear(); - MoreHelp->clear(); + MoreHelp.clear(); // If we had an error processing our arguments, don't let the program execute if (ErrorParsing) @@ -1095,7 +1130,7 @@ bool Option::error(const Twine &Message, StringRef ArgName) { if (ArgName.empty()) errs() << HelpStr; // Be nice for positional arguments else - errs() << ProgramName << ": for the -" << ArgName; + errs() << GlobalParser->ProgramName << ": for the -" << ArgName; errs() << " option: " << Message << "\n"; return true; @@ -1427,10 +1462,9 @@ void basic_parser_impl::printOptionNoValue(const Option &O, // -help and -help-hidden option implementation // -static int OptNameCompare(const void *LHS, const void *RHS) { - typedef std::pair<const char *, Option *> pair_ty; - - return strcmp(((const pair_ty *)LHS)->first, ((const pair_ty *)RHS)->first); +static int OptNameCompare(const std::pair<const char *, Option *> *LHS, + const std::pair<const char *, Option *> *RHS) { + return strcmp(LHS->first, RHS->first); } // Copy Options into a vector so we can sort them as we like. @@ -1458,7 +1492,7 @@ static void sortOpts(StringMap<Option *> &OptMap, } // Sort the options list alphabetically. - qsort(Opts.data(), Opts.size(), sizeof(Opts[0]), OptNameCompare); + array_pod_sort(Opts.begin(), Opts.end(), OptNameCompare); } namespace { @@ -1480,38 +1514,26 @@ public: // Invoke the printer. void operator=(bool Value) { - if (Value == false) + if (!Value) return; - // Get all the options. - SmallVector<Option *, 4> PositionalOpts; - SmallVector<Option *, 4> SinkOpts; - StringMap<Option *> OptMap; - GetOptionInfo(PositionalOpts, SinkOpts, OptMap); - StrOptionPairVector Opts; - sortOpts(OptMap, Opts, ShowHidden); - - if (ProgramOverview) - outs() << "OVERVIEW: " << ProgramOverview << "\n"; + sortOpts(GlobalParser->OptionsMap, Opts, ShowHidden); - outs() << "USAGE: " << ProgramName << " [options]"; + if (GlobalParser->ProgramOverview) + outs() << "OVERVIEW: " << GlobalParser->ProgramOverview << "\n"; - // Print out the positional options. - Option *CAOpt = nullptr; // The cl::ConsumeAfter option, if it exists... - if (!PositionalOpts.empty() && - PositionalOpts[0]->getNumOccurrencesFlag() == ConsumeAfter) - CAOpt = PositionalOpts[0]; + outs() << "USAGE: " << GlobalParser->ProgramName << " [options]"; - for (size_t i = CAOpt != nullptr, e = PositionalOpts.size(); i != e; ++i) { - if (PositionalOpts[i]->ArgStr[0]) - outs() << " --" << PositionalOpts[i]->ArgStr; - outs() << " " << PositionalOpts[i]->HelpStr; + for (auto Opt : GlobalParser->PositionalOpts) { + if (Opt->ArgStr[0]) + outs() << " --" << Opt->ArgStr; + outs() << " " << Opt->HelpStr; } // Print the consume after option info if it exists... - if (CAOpt) - outs() << " " << CAOpt->HelpStr; + if (GlobalParser->ConsumeAfterOpt) + outs() << " " << GlobalParser->ConsumeAfterOpt->HelpStr; outs() << "\n\n"; @@ -1524,11 +1546,9 @@ public: printOptions(Opts, MaxArgLen); // Print any extra help the user has declared. - for (std::vector<const char *>::iterator I = MoreHelp->begin(), - E = MoreHelp->end(); - I != E; ++I) - outs() << *I; - MoreHelp->clear(); + for (auto I : GlobalParser->MoreHelp) + outs() << I; + GlobalParser->MoreHelp.clear(); // Halt the program since help information was printed exit(0); @@ -1540,10 +1560,11 @@ public: explicit CategorizedHelpPrinter(bool showHidden) : HelpPrinter(showHidden) {} // Helper function for printOptions(). - // It shall return true if A's name should be lexographically - // ordered before B's name. It returns false otherwise. - static bool OptionCategoryCompare(OptionCategory *A, OptionCategory *B) { - return strcmp(A->getName(), B->getName()) < 0; + // It shall return a negative value if A's name should be lexicographically + // ordered before B's name. It returns a value greater equal zero otherwise. + static int OptionCategoryCompare(OptionCategory *const *A, + OptionCategory *const *B) { + return strcmp((*A)->getName(), (*B)->getName()); } // Make sure we inherit our base class's operator=() @@ -1556,16 +1577,16 @@ protected: // Collect registered option categories into vector in preparation for // sorting. - for (OptionCatSet::const_iterator I = RegisteredOptionCategories->begin(), - E = RegisteredOptionCategories->end(); + for (auto I = GlobalParser->RegisteredOptionCategories.begin(), + E = GlobalParser->RegisteredOptionCategories.end(); I != E; ++I) { SortedCategories.push_back(*I); } // Sort the different option categories alphabetically. assert(SortedCategories.size() > 0 && "No option categories registered!"); - std::sort(SortedCategories.begin(), SortedCategories.end(), - OptionCategoryCompare); + array_pod_sort(SortedCategories.begin(), SortedCategories.end(), + OptionCategoryCompare); // Create map to empty vectors. for (std::vector<OptionCategory *>::const_iterator @@ -1653,48 +1674,54 @@ static HelpPrinterWrapper WrappedNormalPrinter(UncategorizedNormalPrinter, static HelpPrinterWrapper WrappedHiddenPrinter(UncategorizedHiddenPrinter, CategorizedHiddenPrinter); +// Define a category for generic options that all tools should have. +static cl::OptionCategory GenericCategory("Generic Options"); + // Define uncategorized help printers. // -help-list is hidden by default because if Option categories are being used // then -help behaves the same as -help-list. static cl::opt<HelpPrinter, true, parser<bool>> HLOp( "help-list", cl::desc("Display list of available options (-help-list-hidden for more)"), - cl::location(UncategorizedNormalPrinter), cl::Hidden, cl::ValueDisallowed); + cl::location(UncategorizedNormalPrinter), cl::Hidden, cl::ValueDisallowed, + cl::cat(GenericCategory)); static cl::opt<HelpPrinter, true, parser<bool>> HLHOp("help-list-hidden", cl::desc("Display list of all available options"), cl::location(UncategorizedHiddenPrinter), cl::Hidden, - cl::ValueDisallowed); + cl::ValueDisallowed, cl::cat(GenericCategory)); // Define uncategorized/categorized help printers. These printers change their // behaviour at runtime depending on whether one or more Option categories have // been declared. static cl::opt<HelpPrinterWrapper, true, parser<bool>> HOp("help", cl::desc("Display available options (-help-hidden for more)"), - cl::location(WrappedNormalPrinter), cl::ValueDisallowed); + cl::location(WrappedNormalPrinter), cl::ValueDisallowed, + cl::cat(GenericCategory)); static cl::opt<HelpPrinterWrapper, true, parser<bool>> HHOp("help-hidden", cl::desc("Display all available options"), - cl::location(WrappedHiddenPrinter), cl::Hidden, cl::ValueDisallowed); + cl::location(WrappedHiddenPrinter), cl::Hidden, cl::ValueDisallowed, + cl::cat(GenericCategory)); static cl::opt<bool> PrintOptions( "print-options", cl::desc("Print non-default options after command line parsing"), - cl::Hidden, cl::init(false)); + cl::Hidden, cl::init(false), cl::cat(GenericCategory)); static cl::opt<bool> PrintAllOptions( "print-all-options", cl::desc("Print all option values after command line parsing"), cl::Hidden, - cl::init(false)); + cl::init(false), cl::cat(GenericCategory)); void HelpPrinterWrapper::operator=(bool Value) { - if (Value == false) + if (!Value) return; // Decide which printer to invoke. If more than one option category is // registered then it is useful to show the categorized help instead of // uncategorized help. - if (RegisteredOptionCategories->size() > 1) { + if (GlobalParser->RegisteredOptionCategories.size() > 1) { // unhide -help-list option so user can have uncategorized output if they // want it. HLOp.setHiddenFlag(NotHidden); @@ -1705,18 +1732,14 @@ void HelpPrinterWrapper::operator=(bool Value) { } // Print the value of each option. -void cl::PrintOptionValues() { +void cl::PrintOptionValues() { GlobalParser->printOptionValues(); } + +void CommandLineParser::printOptionValues() { if (!PrintOptions && !PrintAllOptions) return; - // Get all the options. - SmallVector<Option *, 4> PositionalOpts; - SmallVector<Option *, 4> SinkOpts; - StringMap<Option *> OptMap; - GetOptionInfo(PositionalOpts, SinkOpts, OptMap); - SmallVector<std::pair<const char *, Option *>, 128> Opts; - sortOpts(OptMap, Opts, /*ShowHidden*/ true); + sortOpts(OptionsMap, Opts, /*ShowHidden*/ true); // Compute the maximum argument length... size_t MaxArgLen = 0; @@ -1790,7 +1813,8 @@ static VersionPrinter VersionPrinterInstance; static cl::opt<VersionPrinter, true, parser<bool>> VersOp("version", cl::desc("Display the version of this program"), - cl::location(VersionPrinterInstance), cl::ValueDisallowed); + cl::location(VersionPrinterInstance), cl::ValueDisallowed, + cl::cat(GenericCategory)); // Utility function for printing the help message. void cl::PrintHelpMessage(bool Hidden, bool Categorized) { @@ -1823,13 +1847,27 @@ void cl::AddExtraVersionPrinter(void (*func)()) { ExtraVersionPrinters->push_back(func); } -void cl::getRegisteredOptions(StringMap<Option *> &Map) { - // Get all the options. - SmallVector<Option *, 4> PositionalOpts; // NOT USED - SmallVector<Option *, 4> SinkOpts; // NOT USED - assert(Map.size() == 0 && "StringMap must be empty"); - GetOptionInfo(PositionalOpts, SinkOpts, Map); - return; +StringMap<Option *> &cl::getRegisteredOptions() { + return GlobalParser->OptionsMap; +} + +void cl::HideUnrelatedOptions(cl::OptionCategory &Category) { + for (auto &I : GlobalParser->OptionsMap) { + if (I.second->Category != &Category && + I.second->Category != &GenericCategory) + I.second->setHiddenFlag(cl::ReallyHidden); + } +} + +void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories) { + auto CategoriesBegin = Categories.begin(); + auto CategoriesEnd = Categories.end(); + for (auto &I : GlobalParser->OptionsMap) { + if (std::find(CategoriesBegin, CategoriesEnd, I.second->Category) == + CategoriesEnd && + I.second->Category != &GenericCategory) + I.second->setHiddenFlag(cl::ReallyHidden); + } } void LLVMParseCommandLineOptions(int argc, const char *const *argv, diff --git a/lib/Support/Compression.cpp b/lib/Support/Compression.cpp index 17ae2957d12f..b54613e92b8b 100644 --- a/lib/Support/Compression.cpp +++ b/lib/Support/Compression.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Compression.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" diff --git a/lib/Support/ConvertUTFWrapper.cpp b/lib/Support/ConvertUTFWrapper.cpp index e45335ddcb6c..1bbef233b82f 100644 --- a/lib/Support/ConvertUTFWrapper.cpp +++ b/lib/Support/ConvertUTFWrapper.cpp @@ -109,8 +109,9 @@ bool convertUTF16ToUTF8String(ArrayRef<char> SrcBytes, std::string &Out) { if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_NATIVE) Src++; - // Just allocate enough space up front. We'll shrink it later. - Out.resize(SrcBytes.size() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT); + // Just allocate enough space up front. We'll shrink it later. Allocate + // enough that we can fit a null terminator without reallocating. + Out.resize(SrcBytes.size() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT + 1); UTF8 *Dst = reinterpret_cast<UTF8 *>(&Out[0]); UTF8 *DstEnd = Dst + Out.size(); @@ -124,6 +125,46 @@ bool convertUTF16ToUTF8String(ArrayRef<char> SrcBytes, std::string &Out) { } Out.resize(reinterpret_cast<char *>(Dst) - &Out[0]); + Out.push_back(0); + Out.pop_back(); + return true; +} + +bool convertUTF8ToUTF16String(StringRef SrcUTF8, + SmallVectorImpl<UTF16> &DstUTF16) { + assert(DstUTF16.empty()); + + // Avoid OOB by returning early on empty input. + if (SrcUTF8.empty()) { + DstUTF16.push_back(0); + DstUTF16.pop_back(); + return true; + } + + const UTF8 *Src = reinterpret_cast<const UTF8 *>(SrcUTF8.begin()); + const UTF8 *SrcEnd = reinterpret_cast<const UTF8 *>(SrcUTF8.end()); + + // Allocate the same number of UTF-16 code units as UTF-8 code units. Encoding + // as UTF-16 should always require the same amount or less code units than the + // UTF-8 encoding. Allocate one extra byte for the null terminator though, + // so that someone calling DstUTF16.data() gets a null terminated string. + // We resize down later so we don't have to worry that this over allocates. + DstUTF16.resize(SrcUTF8.size()+1); + UTF16 *Dst = &DstUTF16[0]; + UTF16 *DstEnd = Dst + DstUTF16.size(); + + ConversionResult CR = + ConvertUTF8toUTF16(&Src, SrcEnd, &Dst, DstEnd, strictConversion); + assert(CR != targetExhausted); + + if (CR != conversionOK) { + DstUTF16.clear(); + return false; + } + + DstUTF16.resize(Dst - &DstUTF16[0]); + DstUTF16.push_back(0); + DstUTF16.pop_back(); return true; } diff --git a/lib/Support/CrashRecoveryContext.cpp b/lib/Support/CrashRecoveryContext.cpp index 9b0e44339d84..aba0f1ddeee8 100644 --- a/lib/Support/CrashRecoveryContext.cpp +++ b/lib/Support/CrashRecoveryContext.cpp @@ -8,13 +8,11 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/CrashRecoveryContext.h" -#include "llvm/ADT/SmallString.h" #include "llvm/Config/config.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/ThreadLocal.h" -#include <cstdio> #include <setjmp.h> using namespace llvm; diff --git a/lib/Support/DAGDeltaAlgorithm.cpp b/lib/Support/DAGDeltaAlgorithm.cpp index 0d504ee86b43..f1a334bfc7be 100644 --- a/lib/Support/DAGDeltaAlgorithm.cpp +++ b/lib/Support/DAGDeltaAlgorithm.cpp @@ -63,9 +63,6 @@ private: DAGDeltaAlgorithm &DDA; - const changeset_ty &Changes; - const std::vector<edge_ty> &Dependencies; - std::vector<change_ty> Roots; /// Cache of failed test results. Successful test results are never cached @@ -139,9 +136,8 @@ private: } public: - DAGDeltaAlgorithmImpl(DAGDeltaAlgorithm &_DDA, - const changeset_ty &_Changes, - const std::vector<edge_ty> &_Dependencies); + DAGDeltaAlgorithmImpl(DAGDeltaAlgorithm &DDA, const changeset_ty &Changes, + const std::vector<edge_ty> &Dependencies); changeset_ty Run(); @@ -174,21 +170,17 @@ protected: } public: - DeltaActiveSetHelper(DAGDeltaAlgorithmImpl &_DDAI, - const changeset_ty &_Required) - : DDAI(_DDAI), Required(_Required) {} + DeltaActiveSetHelper(DAGDeltaAlgorithmImpl &DDAI, + const changeset_ty &Required) + : DDAI(DDAI), Required(Required) {} }; } -DAGDeltaAlgorithmImpl::DAGDeltaAlgorithmImpl(DAGDeltaAlgorithm &_DDA, - const changeset_ty &_Changes, - const std::vector<edge_ty> - &_Dependencies) - : DDA(_DDA), - Changes(_Changes), - Dependencies(_Dependencies) -{ +DAGDeltaAlgorithmImpl::DAGDeltaAlgorithmImpl( + DAGDeltaAlgorithm &DDA, const changeset_ty &Changes, + const std::vector<edge_ty> &Dependencies) + : DDA(DDA) { for (changeset_ty::const_iterator it = Changes.begin(), ie = Changes.end(); it != ie; ++it) { Predecessors.insert(std::make_pair(*it, std::vector<change_ty>())); diff --git a/lib/Support/DataStream.cpp b/lib/Support/DataStream.cpp index dbf6465189de..c24315526cff 100644 --- a/lib/Support/DataStream.cpp +++ b/lib/Support/DataStream.cpp @@ -18,8 +18,6 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Program.h" -#include <cerrno> -#include <cstdio> #include <string> #include <system_error> #if !defined(_MSC_VER) && !defined(__MINGW32__) @@ -56,9 +54,7 @@ class DataFileStreamer : public DataStreamer { int Fd; public: DataFileStreamer() : Fd(0) {} - virtual ~DataFileStreamer() { - close(Fd); - } + ~DataFileStreamer() override { close(Fd); } size_t GetBytes(unsigned char *buf, size_t len) override { NumStreamFetches++; return read(Fd, buf, len); diff --git a/lib/Support/Debug.cpp b/lib/Support/Debug.cpp index cb86ea6a600a..eb99242914c2 100644 --- a/lib/Support/Debug.cpp +++ b/lib/Support/Debug.cpp @@ -28,12 +28,49 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Signals.h" #include "llvm/Support/circular_raw_ostream.h" +#include "llvm/Support/raw_ostream.h" + +#undef isCurrentDebugType +#undef setCurrentDebugType using namespace llvm; +// Even though LLVM might be built with NDEBUG, define symbols that the code +// built without NDEBUG can depend on via the llvm/Support/Debug.h header. +namespace llvm { +/// Exported boolean set by the -debug option. +bool DebugFlag = false; + +static ManagedStatic<std::vector<std::string>> CurrentDebugType; + +/// Return true if the specified string is the debug type +/// specified on the command line, or if none was specified on the command line +/// with the -debug-only=X option. +bool isCurrentDebugType(const char *DebugType) { + if (CurrentDebugType->empty()) + return true; + // see if DebugType is in list. Note: do not use find() as that forces us to + // unnecessarily create an std::string instance. + for (auto d : *CurrentDebugType) { + if (d == DebugType) + return true; + } + return false; +} + +/// Set the current debug type, as if the -debug-only=X +/// option were specified. Note that DebugFlag also needs to be set to true for +/// debug output to be produced. +/// +void setCurrentDebugType(const char *Type) { + CurrentDebugType->clear(); + CurrentDebugType->push_back(Type); +} + +} // namespace llvm + // All Debug.h functionality is a no-op in NDEBUG mode. #ifndef NDEBUG -bool llvm::DebugFlag; // DebugFlag - Exported boolean set by the -debug option // -debug - Command line option to enable the DEBUG statements in the passes. // This flag may only be enabled in debug builds. @@ -51,8 +88,6 @@ DebugBufferSize("debug-buffer-size", cl::Hidden, cl::init(0)); -static ManagedStatic<std::vector<std::string> > CurrentDebugType; - namespace { struct DebugOnlyOpt { @@ -79,34 +114,9 @@ static void debug_user_sig_handler(void *Cookie) { // know that debug mode is enabled and dbgs() really is a // circular_raw_ostream. If NDEBUG is defined, then dbgs() == // errs() but this will never be invoked. - llvm::circular_raw_ostream *dbgout = - static_cast<llvm::circular_raw_ostream *>(&llvm::dbgs()); - dbgout->flushBufferWithBanner(); -} - -// isCurrentDebugType - Return true if the specified string is the debug type -// specified on the command line, or if none was specified on the command line -// with the -debug-only=X option. -// -bool llvm::isCurrentDebugType(const char *DebugType) { - if (CurrentDebugType->empty()) - return true; - // see if DebugType is in list. Note: do not use find() as that forces us to - // unnecessarily create an std::string instance. - for (auto d : *CurrentDebugType) { - if (d == DebugType) - return true; - } - return false; -} - -/// setCurrentDebugType - Set the current debug type, as if the -debug-only=X -/// option were specified. Note that DebugFlag also needs to be set to true for -/// debug output to be produced. -/// -void llvm::setCurrentDebugType(const char *Type) { - CurrentDebugType->clear(); - CurrentDebugType->push_back(Type); + llvm::circular_raw_ostream &dbgout = + static_cast<circular_raw_ostream &>(llvm::dbgs()); + dbgout.flushBufferWithBanner(); } /// dbgs - Return a circular-buffered debug stream. diff --git a/lib/Support/Dwarf.cpp b/lib/Support/Dwarf.cpp index 4b6337ecc52c..6229825a8ee2 100644 --- a/lib/Support/Dwarf.cpp +++ b/lib/Support/Dwarf.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Dwarf.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; @@ -19,87 +20,19 @@ using namespace dwarf; const char *llvm::dwarf::TagString(unsigned Tag) { switch (Tag) { - case DW_TAG_array_type: return "DW_TAG_array_type"; - case DW_TAG_class_type: return "DW_TAG_class_type"; - case DW_TAG_entry_point: return "DW_TAG_entry_point"; - case DW_TAG_enumeration_type: return "DW_TAG_enumeration_type"; - case DW_TAG_formal_parameter: return "DW_TAG_formal_parameter"; - case DW_TAG_imported_declaration: return "DW_TAG_imported_declaration"; - case DW_TAG_label: return "DW_TAG_label"; - case DW_TAG_lexical_block: return "DW_TAG_lexical_block"; - case DW_TAG_member: return "DW_TAG_member"; - case DW_TAG_pointer_type: return "DW_TAG_pointer_type"; - case DW_TAG_reference_type: return "DW_TAG_reference_type"; - case DW_TAG_compile_unit: return "DW_TAG_compile_unit"; - case DW_TAG_string_type: return "DW_TAG_string_type"; - case DW_TAG_structure_type: return "DW_TAG_structure_type"; - case DW_TAG_subroutine_type: return "DW_TAG_subroutine_type"; - case DW_TAG_typedef: return "DW_TAG_typedef"; - case DW_TAG_union_type: return "DW_TAG_union_type"; - case DW_TAG_unspecified_parameters: return "DW_TAG_unspecified_parameters"; - case DW_TAG_variant: return "DW_TAG_variant"; - case DW_TAG_common_block: return "DW_TAG_common_block"; - case DW_TAG_common_inclusion: return "DW_TAG_common_inclusion"; - case DW_TAG_inheritance: return "DW_TAG_inheritance"; - case DW_TAG_inlined_subroutine: return "DW_TAG_inlined_subroutine"; - case DW_TAG_module: return "DW_TAG_module"; - case DW_TAG_ptr_to_member_type: return "DW_TAG_ptr_to_member_type"; - case DW_TAG_set_type: return "DW_TAG_set_type"; - case DW_TAG_subrange_type: return "DW_TAG_subrange_type"; - case DW_TAG_with_stmt: return "DW_TAG_with_stmt"; - case DW_TAG_access_declaration: return "DW_TAG_access_declaration"; - case DW_TAG_base_type: return "DW_TAG_base_type"; - case DW_TAG_catch_block: return "DW_TAG_catch_block"; - case DW_TAG_const_type: return "DW_TAG_const_type"; - case DW_TAG_constant: return "DW_TAG_constant"; - case DW_TAG_enumerator: return "DW_TAG_enumerator"; - case DW_TAG_file_type: return "DW_TAG_file_type"; - case DW_TAG_friend: return "DW_TAG_friend"; - case DW_TAG_namelist: return "DW_TAG_namelist"; - case DW_TAG_namelist_item: return "DW_TAG_namelist_item"; - case DW_TAG_packed_type: return "DW_TAG_packed_type"; - case DW_TAG_subprogram: return "DW_TAG_subprogram"; - case DW_TAG_template_type_parameter: return "DW_TAG_template_type_parameter"; - case DW_TAG_template_value_parameter: return "DW_TAG_template_value_parameter"; - case DW_TAG_thrown_type: return "DW_TAG_thrown_type"; - case DW_TAG_try_block: return "DW_TAG_try_block"; - case DW_TAG_variant_part: return "DW_TAG_variant_part"; - case DW_TAG_variable: return "DW_TAG_variable"; - case DW_TAG_volatile_type: return "DW_TAG_volatile_type"; - case DW_TAG_dwarf_procedure: return "DW_TAG_dwarf_procedure"; - case DW_TAG_restrict_type: return "DW_TAG_restrict_type"; - case DW_TAG_interface_type: return "DW_TAG_interface_type"; - case DW_TAG_namespace: return "DW_TAG_namespace"; - case DW_TAG_imported_module: return "DW_TAG_imported_module"; - case DW_TAG_unspecified_type: return "DW_TAG_unspecified_type"; - case DW_TAG_partial_unit: return "DW_TAG_partial_unit"; - case DW_TAG_imported_unit: return "DW_TAG_imported_unit"; - case DW_TAG_condition: return "DW_TAG_condition"; - case DW_TAG_shared_type: return "DW_TAG_shared_type"; - case DW_TAG_lo_user: return "DW_TAG_lo_user"; - case DW_TAG_hi_user: return "DW_TAG_hi_user"; - case DW_TAG_auto_variable: return "DW_TAG_auto_variable"; - case DW_TAG_arg_variable: return "DW_TAG_arg_variable"; - case DW_TAG_expression: return "DW_TAG_expression"; - 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_coarray_type: return "DW_TAG_coarray_type"; - case DW_TAG_generic_subrange: return "DW_TAG_generic_subrange"; - case DW_TAG_dynamic_type: return "DW_TAG_dynamic_type"; - case DW_TAG_MIPS_loop: return "DW_TAG_MIPS_loop"; - case DW_TAG_type_unit: return "DW_TAG_type_unit"; - case DW_TAG_format_label: return "DW_TAG_format_label"; - case DW_TAG_function_template: return "DW_TAG_function_template"; - case DW_TAG_class_template: return "DW_TAG_class_template"; - case DW_TAG_GNU_template_template_param: - return "DW_TAG_GNU_template_template_param"; - case DW_TAG_GNU_template_parameter_pack: - return "DW_TAG_GNU_template_parameter_pack"; - case DW_TAG_GNU_formal_parameter_pack: - return "DW_TAG_GNU_formal_parameter_pack"; - case DW_TAG_APPLE_property: return "DW_TAG_APPLE_property"; + default: return nullptr; +#define HANDLE_DW_TAG(ID, NAME) \ + case DW_TAG_##NAME: \ + return "DW_TAG_" #NAME; +#include "llvm/Support/Dwarf.def" } - return nullptr; +} + +unsigned llvm::dwarf::getTag(StringRef TagString) { + return StringSwitch<unsigned>(TagString) +#define HANDLE_DW_TAG(ID, NAME) .Case("DW_TAG_" #NAME, DW_TAG_##NAME) +#include "llvm/Support/Dwarf.def" + .Default(DW_TAG_invalid); } const char *llvm::dwarf::ChildrenString(unsigned Children) { @@ -300,199 +233,46 @@ const char *llvm::dwarf::FormEncodingString(unsigned Encoding) { // 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"; + + // Alternate debug sections proposal (output of "dwz" tool). + case DW_FORM_GNU_ref_alt: return "DW_FORM_GNU_ref_alt"; + case DW_FORM_GNU_strp_alt: return "DW_FORM_GNU_strp_alt"; } return nullptr; } const char *llvm::dwarf::OperationEncodingString(unsigned Encoding) { switch (Encoding) { - case DW_OP_addr: return "DW_OP_addr"; - case DW_OP_deref: return "DW_OP_deref"; - case DW_OP_const1u: return "DW_OP_const1u"; - case DW_OP_const1s: return "DW_OP_const1s"; - case DW_OP_const2u: return "DW_OP_const2u"; - case DW_OP_const2s: return "DW_OP_const2s"; - case DW_OP_const4u: return "DW_OP_const4u"; - case DW_OP_const4s: return "DW_OP_const4s"; - case DW_OP_const8u: return "DW_OP_const8u"; - case DW_OP_const8s: return "DW_OP_const8s"; - case DW_OP_constu: return "DW_OP_constu"; - case DW_OP_consts: return "DW_OP_consts"; - case DW_OP_dup: return "DW_OP_dup"; - case DW_OP_drop: return "DW_OP_drop"; - case DW_OP_over: return "DW_OP_over"; - case DW_OP_pick: return "DW_OP_pick"; - case DW_OP_swap: return "DW_OP_swap"; - case DW_OP_rot: return "DW_OP_rot"; - case DW_OP_xderef: return "DW_OP_xderef"; - case DW_OP_abs: return "DW_OP_abs"; - case DW_OP_and: return "DW_OP_and"; - case DW_OP_div: return "DW_OP_div"; - case DW_OP_minus: return "DW_OP_minus"; - case DW_OP_mod: return "DW_OP_mod"; - case DW_OP_mul: return "DW_OP_mul"; - case DW_OP_neg: return "DW_OP_neg"; - case DW_OP_not: return "DW_OP_not"; - case DW_OP_or: return "DW_OP_or"; - case DW_OP_plus: return "DW_OP_plus"; - case DW_OP_plus_uconst: return "DW_OP_plus_uconst"; - case DW_OP_shl: return "DW_OP_shl"; - case DW_OP_shr: return "DW_OP_shr"; - case DW_OP_shra: return "DW_OP_shra"; - case DW_OP_xor: return "DW_OP_xor"; - case DW_OP_skip: return "DW_OP_skip"; - case DW_OP_bra: return "DW_OP_bra"; - case DW_OP_eq: return "DW_OP_eq"; - case DW_OP_ge: return "DW_OP_ge"; - case DW_OP_gt: return "DW_OP_gt"; - case DW_OP_le: return "DW_OP_le"; - case DW_OP_lt: return "DW_OP_lt"; - case DW_OP_ne: return "DW_OP_ne"; - case DW_OP_lit0: return "DW_OP_lit0"; - case DW_OP_lit1: return "DW_OP_lit1"; - case DW_OP_lit2: return "DW_OP_lit2"; - case DW_OP_lit3: return "DW_OP_lit3"; - case DW_OP_lit4: return "DW_OP_lit4"; - case DW_OP_lit5: return "DW_OP_lit5"; - case DW_OP_lit6: return "DW_OP_lit6"; - case DW_OP_lit7: return "DW_OP_lit7"; - case DW_OP_lit8: return "DW_OP_lit8"; - case DW_OP_lit9: return "DW_OP_lit9"; - case DW_OP_lit10: return "DW_OP_lit10"; - case DW_OP_lit11: return "DW_OP_lit11"; - case DW_OP_lit12: return "DW_OP_lit12"; - case DW_OP_lit13: return "DW_OP_lit13"; - case DW_OP_lit14: return "DW_OP_lit14"; - case DW_OP_lit15: return "DW_OP_lit15"; - case DW_OP_lit16: return "DW_OP_lit16"; - case DW_OP_lit17: return "DW_OP_lit17"; - case DW_OP_lit18: return "DW_OP_lit18"; - case DW_OP_lit19: return "DW_OP_lit19"; - case DW_OP_lit20: return "DW_OP_lit20"; - case DW_OP_lit21: return "DW_OP_lit21"; - case DW_OP_lit22: return "DW_OP_lit22"; - case DW_OP_lit23: return "DW_OP_lit23"; - case DW_OP_lit24: return "DW_OP_lit24"; - case DW_OP_lit25: return "DW_OP_lit25"; - case DW_OP_lit26: return "DW_OP_lit26"; - case DW_OP_lit27: return "DW_OP_lit27"; - case DW_OP_lit28: return "DW_OP_lit28"; - case DW_OP_lit29: return "DW_OP_lit29"; - case DW_OP_lit30: return "DW_OP_lit30"; - case DW_OP_lit31: return "DW_OP_lit31"; - case DW_OP_reg0: return "DW_OP_reg0"; - case DW_OP_reg1: return "DW_OP_reg1"; - case DW_OP_reg2: return "DW_OP_reg2"; - case DW_OP_reg3: return "DW_OP_reg3"; - case DW_OP_reg4: return "DW_OP_reg4"; - case DW_OP_reg5: return "DW_OP_reg5"; - case DW_OP_reg6: return "DW_OP_reg6"; - case DW_OP_reg7: return "DW_OP_reg7"; - case DW_OP_reg8: return "DW_OP_reg8"; - case DW_OP_reg9: return "DW_OP_reg9"; - case DW_OP_reg10: return "DW_OP_reg10"; - case DW_OP_reg11: return "DW_OP_reg11"; - case DW_OP_reg12: return "DW_OP_reg12"; - case DW_OP_reg13: return "DW_OP_reg13"; - case DW_OP_reg14: return "DW_OP_reg14"; - case DW_OP_reg15: return "DW_OP_reg15"; - case DW_OP_reg16: return "DW_OP_reg16"; - case DW_OP_reg17: return "DW_OP_reg17"; - case DW_OP_reg18: return "DW_OP_reg18"; - case DW_OP_reg19: return "DW_OP_reg19"; - case DW_OP_reg20: return "DW_OP_reg20"; - case DW_OP_reg21: return "DW_OP_reg21"; - case DW_OP_reg22: return "DW_OP_reg22"; - case DW_OP_reg23: return "DW_OP_reg23"; - case DW_OP_reg24: return "DW_OP_reg24"; - case DW_OP_reg25: return "DW_OP_reg25"; - case DW_OP_reg26: return "DW_OP_reg26"; - case DW_OP_reg27: return "DW_OP_reg27"; - case DW_OP_reg28: return "DW_OP_reg28"; - case DW_OP_reg29: return "DW_OP_reg29"; - case DW_OP_reg30: return "DW_OP_reg30"; - case DW_OP_reg31: return "DW_OP_reg31"; - case DW_OP_breg0: return "DW_OP_breg0"; - case DW_OP_breg1: return "DW_OP_breg1"; - case DW_OP_breg2: return "DW_OP_breg2"; - case DW_OP_breg3: return "DW_OP_breg3"; - case DW_OP_breg4: return "DW_OP_breg4"; - case DW_OP_breg5: return "DW_OP_breg5"; - case DW_OP_breg6: return "DW_OP_breg6"; - case DW_OP_breg7: return "DW_OP_breg7"; - case DW_OP_breg8: return "DW_OP_breg8"; - case DW_OP_breg9: return "DW_OP_breg9"; - case DW_OP_breg10: return "DW_OP_breg10"; - case DW_OP_breg11: return "DW_OP_breg11"; - case DW_OP_breg12: return "DW_OP_breg12"; - case DW_OP_breg13: return "DW_OP_breg13"; - case DW_OP_breg14: return "DW_OP_breg14"; - case DW_OP_breg15: return "DW_OP_breg15"; - case DW_OP_breg16: return "DW_OP_breg16"; - case DW_OP_breg17: return "DW_OP_breg17"; - case DW_OP_breg18: return "DW_OP_breg18"; - case DW_OP_breg19: return "DW_OP_breg19"; - case DW_OP_breg20: return "DW_OP_breg20"; - case DW_OP_breg21: return "DW_OP_breg21"; - case DW_OP_breg22: return "DW_OP_breg22"; - case DW_OP_breg23: return "DW_OP_breg23"; - case DW_OP_breg24: return "DW_OP_breg24"; - case DW_OP_breg25: return "DW_OP_breg25"; - case DW_OP_breg26: return "DW_OP_breg26"; - case DW_OP_breg27: return "DW_OP_breg27"; - case DW_OP_breg28: return "DW_OP_breg28"; - case DW_OP_breg29: return "DW_OP_breg29"; - case DW_OP_breg30: return "DW_OP_breg30"; - case DW_OP_breg31: return "DW_OP_breg31"; - case DW_OP_regx: return "DW_OP_regx"; - case DW_OP_fbreg: return "DW_OP_fbreg"; - case DW_OP_bregx: return "DW_OP_bregx"; - case DW_OP_piece: return "DW_OP_piece"; - case DW_OP_deref_size: return "DW_OP_deref_size"; - case DW_OP_xderef_size: return "DW_OP_xderef_size"; - case DW_OP_nop: return "DW_OP_nop"; - case DW_OP_push_object_address: return "DW_OP_push_object_address"; - case DW_OP_call2: return "DW_OP_call2"; - case DW_OP_call4: return "DW_OP_call4"; - case DW_OP_call_ref: return "DW_OP_call_ref"; - case DW_OP_form_tls_address: return "DW_OP_form_tls_address"; - case DW_OP_call_frame_cfa: return "DW_OP_call_frame_cfa"; - case DW_OP_bit_piece: return "DW_OP_bit_piece"; - case DW_OP_implicit_value: return "DW_OP_implicit_value"; - case DW_OP_stack_value: return "DW_OP_stack_value"; - - // GNU thread-local storage - case DW_OP_GNU_push_tls_address: return "DW_OP_GNU_push_tls_address"; - - // 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"; + default: return nullptr; +#define HANDLE_DW_OP(ID, NAME) \ + case DW_OP_##NAME: \ + return "DW_OP_" #NAME; +#include "llvm/Support/Dwarf.def" } - return nullptr; +} + +unsigned llvm::dwarf::getOperationEncoding(StringRef OperationEncodingString) { + return StringSwitch<unsigned>(OperationEncodingString) +#define HANDLE_DW_OP(ID, NAME) .Case("DW_OP_" #NAME, DW_OP_##NAME) +#include "llvm/Support/Dwarf.def" + .Default(0); } const char *llvm::dwarf::AttributeEncodingString(unsigned Encoding) { switch (Encoding) { - case DW_ATE_address: return "DW_ATE_address"; - case DW_ATE_boolean: return "DW_ATE_boolean"; - case DW_ATE_complex_float: return "DW_ATE_complex_float"; - case DW_ATE_float: return "DW_ATE_float"; - case DW_ATE_signed: return "DW_ATE_signed"; - case DW_ATE_signed_char: return "DW_ATE_signed_char"; - case DW_ATE_unsigned: return "DW_ATE_unsigned"; - case DW_ATE_unsigned_char: return "DW_ATE_unsigned_char"; - case DW_ATE_imaginary_float: return "DW_ATE_imaginary_float"; - case DW_ATE_UTF: return "DW_ATE_UTF"; - case DW_ATE_packed_decimal: return "DW_ATE_packed_decimal"; - case DW_ATE_numeric_string: return "DW_ATE_numeric_string"; - case DW_ATE_edited: return "DW_ATE_edited"; - case DW_ATE_signed_fixed: return "DW_ATE_signed_fixed"; - case DW_ATE_unsigned_fixed: return "DW_ATE_unsigned_fixed"; - case DW_ATE_decimal_float: return "DW_ATE_decimal_float"; - case DW_ATE_lo_user: return "DW_ATE_lo_user"; - case DW_ATE_hi_user: return "DW_ATE_hi_user"; + default: return nullptr; +#define HANDLE_DW_ATE(ID, NAME) \ + case DW_ATE_##NAME: \ + return "DW_ATE_" #NAME; +#include "llvm/Support/Dwarf.def" } - return nullptr; +} + +unsigned llvm::dwarf::getAttributeEncoding(StringRef EncodingString) { + return StringSwitch<unsigned>(EncodingString) +#define HANDLE_DW_ATE(ID, NAME) .Case("DW_ATE_" #NAME, DW_ATE_##NAME) +#include "llvm/Support/Dwarf.def" + .Default(0); } const char *llvm::dwarf::DecimalSignString(unsigned Sign) { @@ -538,47 +318,39 @@ const char *llvm::dwarf::VisibilityString(unsigned Visibility) { const char *llvm::dwarf::VirtualityString(unsigned Virtuality) { switch (Virtuality) { - case DW_VIRTUALITY_none: return "DW_VIRTUALITY_none"; - case DW_VIRTUALITY_virtual: return "DW_VIRTUALITY_virtual"; - case DW_VIRTUALITY_pure_virtual: return "DW_VIRTUALITY_pure_virtual"; + default: + return nullptr; +#define HANDLE_DW_VIRTUALITY(ID, NAME) \ + case DW_VIRTUALITY_##NAME: \ + return "DW_VIRTUALITY_" #NAME; +#include "llvm/Support/Dwarf.def" } - return nullptr; +} + +unsigned llvm::dwarf::getVirtuality(StringRef VirtualityString) { + return StringSwitch<unsigned>(VirtualityString) +#define HANDLE_DW_VIRTUALITY(ID, NAME) \ + .Case("DW_VIRTUALITY_" #NAME, DW_VIRTUALITY_##NAME) +#include "llvm/Support/Dwarf.def" + .Default(DW_VIRTUALITY_invalid); } const char *llvm::dwarf::LanguageString(unsigned Language) { switch (Language) { - case DW_LANG_C89: return "DW_LANG_C89"; - case DW_LANG_C: return "DW_LANG_C"; - case DW_LANG_Ada83: return "DW_LANG_Ada83"; - case DW_LANG_C_plus_plus: return "DW_LANG_C_plus_plus"; - case DW_LANG_Cobol74: return "DW_LANG_Cobol74"; - case DW_LANG_Cobol85: return "DW_LANG_Cobol85"; - case DW_LANG_Fortran77: return "DW_LANG_Fortran77"; - case DW_LANG_Fortran90: return "DW_LANG_Fortran90"; - case DW_LANG_Pascal83: return "DW_LANG_Pascal83"; - case DW_LANG_Modula2: return "DW_LANG_Modula2"; - case DW_LANG_Java: return "DW_LANG_Java"; - case DW_LANG_C99: return "DW_LANG_C99"; - case DW_LANG_Ada95: return "DW_LANG_Ada95"; - case DW_LANG_Fortran95: return "DW_LANG_Fortran95"; - case DW_LANG_PLI: return "DW_LANG_PLI"; - case DW_LANG_ObjC: return "DW_LANG_ObjC"; - case DW_LANG_ObjC_plus_plus: return "DW_LANG_ObjC_plus_plus"; - case DW_LANG_UPC: return "DW_LANG_UPC"; - case DW_LANG_D: return "DW_LANG_D"; - case DW_LANG_Python: return "DW_LANG_Python"; - case DW_LANG_OpenCL: return "DW_LANG_OpenCL"; - case DW_LANG_Go: return "DW_LANG_Go"; - case DW_LANG_Modula3: return "DW_LANG_Modula3"; - case DW_LANG_Haskell: return "DW_LANG_Haskell"; - case DW_LANG_C_plus_plus_03: return "DW_LANG_C_plus_plus_03"; - case DW_LANG_C_plus_plus_11: return "DW_LANG_C_plus_plus_11"; - case DW_LANG_OCaml: return "DW_LANG_OCaml"; - case DW_LANG_lo_user: return "DW_LANG_lo_user"; - case DW_LANG_Mips_Assembler: return "DW_LANG_Mips_Assembler"; - case DW_LANG_hi_user: return "DW_LANG_hi_user"; + default: + return nullptr; +#define HANDLE_DW_LANG(ID, NAME) \ + case DW_LANG_##NAME: \ + return "DW_LANG_" #NAME; +#include "llvm/Support/Dwarf.def" } - return nullptr; +} + +unsigned llvm::dwarf::getLanguage(StringRef LanguageString) { + return StringSwitch<unsigned>(LanguageString) +#define HANDLE_DW_LANG(ID, NAME) .Case("DW_LANG_" #NAME, DW_LANG_##NAME) +#include "llvm/Support/Dwarf.def" + .Default(0); } const char *llvm::dwarf::CaseString(unsigned Case) { diff --git a/lib/Support/FileOutputBuffer.cpp b/lib/Support/FileOutputBuffer.cpp index b176a8b45ab3..307ff09afedc 100644 --- a/lib/Support/FileOutputBuffer.cpp +++ b/lib/Support/FileOutputBuffer.cpp @@ -11,11 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/Errc.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Errc.h" #include <system_error> #if !defined(_MSC_VER) && !defined(__MINGW32__) @@ -77,9 +76,16 @@ FileOutputBuffer::create(StringRef FilePath, size_t Size, if (EC) return EC; +#ifndef LLVM_ON_WIN32 + // On Windows, CreateFileMapping (the mmap function on Windows) + // automatically extends the underlying file. We don't need to + // extend the file beforehand. _chsize (ftruncate on Windows) is + // pretty slow just like it writes specified amount of bytes, + // so we should avoid calling that. EC = sys::fs::resize_file(FD, Size); if (EC) return EC; +#endif auto MappedFile = llvm::make_unique<mapped_file_region>( FD, mapped_file_region::readwrite, Size, 0, EC); diff --git a/lib/Support/FoldingSet.cpp b/lib/Support/FoldingSet.cpp index 463511408759..b8538ffe1f9f 100644 --- a/lib/Support/FoldingSet.cpp +++ b/lib/Support/FoldingSet.cpp @@ -51,8 +51,8 @@ bool FoldingSetNodeIDRef::operator<(FoldingSetNodeIDRef RHS) const { /// void FoldingSetNodeID::AddPointer(const void *Ptr) { // Note: this adds pointers to the hash using sizes and endianness that - // depend on the host. It doesn't matter however, because hashing on - // pointer values in inherently unstable. Nothing should depend on the + // depend on the host. It doesn't matter, however, because hashing on + // pointer values is inherently unstable. Nothing should depend on the // ordering of nodes in the folding set. Bits.append(reinterpret_cast<unsigned *>(&Ptr), reinterpret_cast<unsigned *>(&Ptr+1)); @@ -101,6 +101,8 @@ void FoldingSetNodeID::AddString(StringRef String) { // Otherwise do it the hard way. // To be compatible with above bulk transfer, we need to take endianness // into account. + static_assert(sys::IsBigEndianHost || sys::IsLittleEndianHost, + "Unexpected host endianness"); if (sys::IsBigEndianHost) { for (Pos += 4; Pos <= Size; Pos += 4) { unsigned V = ((unsigned char)String[Pos - 4] << 24) | @@ -109,8 +111,7 @@ void FoldingSetNodeID::AddString(StringRef String) { (unsigned char)String[Pos - 1]; Bits.push_back(V); } - } else { - assert(sys::IsLittleEndianHost && "Unexpected host endianness"); + } else { // Little-endian host for (Pos += 4; Pos <= Size; Pos += 4) { unsigned V = ((unsigned char)String[Pos - 1] << 24) | ((unsigned char)String[Pos - 2] << 16) | @@ -222,6 +223,8 @@ static void **AllocateBuckets(unsigned NumBuckets) { //===----------------------------------------------------------------------===// // FoldingSetImpl Implementation +void FoldingSetImpl::anchor() {} + FoldingSetImpl::FoldingSetImpl(unsigned Log2InitSize) { assert(5 < Log2InitSize && Log2InitSize < 32 && "Initial hash table size out of range"); diff --git a/lib/Support/FormattedStream.cpp b/lib/Support/FormattedStream.cpp index 618ec2673a16..2ed71c7e4311 100644 --- a/lib/Support/FormattedStream.cpp +++ b/lib/Support/FormattedStream.cpp @@ -13,6 +13,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/raw_ostream.h" #include <algorithm> using namespace llvm; diff --git a/lib/Support/GraphWriter.cpp b/lib/Support/GraphWriter.cpp index 054df528474e..97aedc88473a 100644 --- a/lib/Support/GraphWriter.cpp +++ b/lib/Support/GraphWriter.cpp @@ -15,7 +15,6 @@ #include "llvm/Config/config.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" #include "llvm/Support/Program.h" using namespace llvm; @@ -93,11 +92,12 @@ static bool ExecGraphViewer(StringRef ExecPath, std::vector<const char *> &args, errs() << " done. \n"; } else { sys::ExecuteNoWait(ExecPath, args.data(), nullptr, nullptr, 0, &ErrMsg); - errs() << "Remember to erase graph file: " << Filename.str() << "\n"; + errs() << "Remember to erase graph file: " << Filename << "\n"; } return false; } +namespace { struct GraphSession { std::string LogBuffer; bool TryFindProgram(StringRef Names, std::string &ProgramPath) { @@ -114,6 +114,7 @@ struct GraphSession { return false; } }; +} // namespace static const char *getProgramName(GraphProgram::Name program) { switch (program) { @@ -139,6 +140,29 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait, std::string ViewerPath; GraphSession S; +#ifdef __APPLE__ + if (S.TryFindProgram("open", ViewerPath)) { + std::vector<const char *> args; + args.push_back(ViewerPath.c_str()); + if (wait) + args.push_back("-W"); + args.push_back(Filename.c_str()); + args.push_back(nullptr); + errs() << "Trying 'open' program... "; + if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg)) + return false; + } +#endif + if (S.TryFindProgram("xdg-open", ViewerPath)) { + std::vector<const char *> args; + args.push_back(ViewerPath.c_str()); + args.push_back(Filename.c_str()); + args.push_back(nullptr); + errs() << "Trying 'xdg-open' program... "; + if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg)) + return false; + } + // Graphviz if (S.TryFindProgram("Graphviz", ViewerPath)) { std::vector<const char *> args; diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp index 2abbc1440a25..1bd1fe2bea0e 100644 --- a/lib/Support/Host.cpp +++ b/lib/Support/Host.cpp @@ -137,18 +137,13 @@ static bool GetX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, "c" (subleaf)); return false; #elif defined(_MSC_VER) - // __cpuidex was added in MSVC++ 9.0 SP1 - #if (_MSC_VER > 1500) || (_MSC_VER == 1500 && _MSC_FULL_VER >= 150030729) - int registers[4]; - __cpuidex(registers, value, subleaf); - *rEAX = registers[0]; - *rEBX = registers[1]; - *rECX = registers[2]; - *rEDX = registers[3]; - return false; - #else - return true; - #endif + int registers[4]; + __cpuidex(registers, value, subleaf); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; + return false; #else return true; #endif @@ -187,19 +182,21 @@ static bool GetX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, #endif } -static bool OSHasAVXSupport() { +static bool GetX86XCR0(unsigned *rEAX, unsigned *rEDX) { #if defined(__GNUC__) // Check xgetbv; this uses a .byte sequence instead of the instruction // directly because older assemblers do not include support for xgetbv and // there is no easy way to conditionally compile based on the assembler used. - int rEAX, rEDX; - __asm__ (".byte 0x0f, 0x01, 0xd0" : "=a" (rEAX), "=d" (rEDX) : "c" (0)); + __asm__ (".byte 0x0f, 0x01, 0xd0" : "=a" (*rEAX), "=d" (*rEDX) : "c" (0)); + return false; #elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) - unsigned long long rEAX = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); + unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); + *rEAX = Result; + *rEDX = Result >> 32; + return false; #else - int rEAX = 0; // Ensures we return false + return true; #endif - return (rEAX & 6) == 6; } static void DetectX86FamilyModel(unsigned EAX, unsigned &Family, @@ -228,19 +225,30 @@ StringRef sys::getHostCPUName() { char c[12]; } text; - GetX86CpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1); - - unsigned MaxLeaf = EAX; - bool HasSSE3 = (ECX & 0x1); - bool HasSSE41 = (ECX & 0x80000); - // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV + unsigned MaxLeaf; + GetX86CpuIDAndInfo(0, &MaxLeaf, text.u+0, text.u+2, text.u+1); + + bool HasMMX = (EDX >> 23) & 1; + bool HasSSE = (EDX >> 25) & 1; + bool HasSSE2 = (EDX >> 26) & 1; + bool HasSSE3 = (ECX >> 0) & 1; + bool HasSSSE3 = (ECX >> 9) & 1; + bool HasSSE41 = (ECX >> 19) & 1; + bool HasSSE42 = (ECX >> 20) & 1; + bool HasMOVBE = (ECX >> 22) & 1; + // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV // indicates that the AVX registers will be saved and restored on context // switch, then we have full AVX support. const unsigned AVXBits = (1 << 27) | (1 << 28); - bool HasAVX = ((ECX & AVXBits) == AVXBits) && OSHasAVXSupport(); - bool HasAVX2 = HasAVX && MaxLeaf >= 0x7 && - !GetX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX) && - (EBX & 0x20); + bool HasAVX = ((ECX & AVXBits) == AVXBits) && !GetX86XCR0(&EAX, &EDX) && + ((EAX & 0x6) == 0x6); + bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); + bool HasLeaf7 = MaxLeaf >= 0x7 && + !GetX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); + bool HasADX = HasLeaf7 && ((EBX >> 19) & 1); + bool HasAVX2 = HasAVX && HasLeaf7 && (EBX & 0x20); + bool HasAVX512 = HasLeaf7 && HasAVX512Save && ((EBX >> 16) & 1); + GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); bool Em64T = (EDX >> 29) & 0x1; bool HasTBM = (ECX >> 21) & 0x1; @@ -303,6 +311,8 @@ StringRef sys::getHostCPUName() { case 9: // Intel Pentium M processor, Intel Celeron M processor model 09. case 13: // Intel Pentium M processor, Intel Celeron M processor, model // 0Dh. All processors are manufactured using the 90 nm process. + case 21: // Intel EP80579 Integrated Processor and Intel EP80579 + // Integrated Processor with Intel QuickAssist Technology return "pentium-m"; case 14: // Intel Core Duo processor, Intel Core Solo processor, model @@ -318,68 +328,85 @@ StringRef sys::getHostCPUName() { // manufactured using the 65 nm process return "core2"; - case 21: // Intel EP80579 Integrated Processor and Intel EP80579 - // Integrated Processor with Intel QuickAssist Technology - return "i686"; // FIXME: ??? - case 23: // Intel Core 2 Extreme processor, Intel Xeon processor, model // 17h. All processors are manufactured using the 45 nm process. // // 45nm: Penryn , Wolfdale, Yorkfield (XE) - // Not all Penryn processors support SSE 4.1 (such as the Pentium brand) - return HasSSE41 ? "penryn" : "core2"; + case 29: // Intel Xeon processor MP. All processors are manufactured using + // the 45 nm process. + return "penryn"; case 26: // Intel Core i7 processor and Intel Xeon processor. All // processors are manufactured using the 45 nm process. - case 29: // Intel Xeon processor MP. All processors are manufactured using - // the 45 nm process. case 30: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. // As found in a Summer 2010 model iMac. + case 46: // Nehalem EX + return "nehalem"; case 37: // Intel Core i7, laptop version. case 44: // Intel Core i7 processor and Intel Xeon processor. All // processors are manufactured using the 32 nm process. - case 46: // Nehalem EX case 47: // Westmere EX - return "corei7"; + return "westmere"; // SandyBridge: case 42: // Intel Core i7 processor. All processors are manufactured // using the 32 nm process. case 45: - // Not all Sandy Bridge processors support AVX (such as the Pentium - // versions instead of the i7 versions). - return HasAVX ? "corei7-avx" : "corei7"; + return "sandybridge"; // Ivy Bridge: case 58: case 62: // Ivy Bridge EP - // Not all Ivy Bridge processors support AVX (such as the Pentium - // versions instead of the i7 versions). - return HasAVX ? "core-avx-i" : "corei7"; + return "ivybridge"; // Haswell: case 60: case 63: case 69: case 70: - // Not all Haswell processors support AVX too (such as the Pentium - // versions instead of the i7 versions). - return HasAVX2 ? "core-avx2" : "corei7"; + return "haswell"; + + // Broadwell: + case 61: + return "broadwell"; case 28: // Most 45 nm Intel Atom processors case 38: // 45 nm Atom Lincroft case 39: // 32 nm Atom Medfield case 53: // 32 nm Atom Midview case 54: // 32 nm Atom Midview - return "atom"; + return "bonnell"; // Atom Silvermont codes from the Intel software optimization guide. case 55: case 74: case 77: - return "slm"; - - default: return (Em64T) ? "x86-64" : "i686"; + return "silvermont"; + + default: // Unknown family 6 CPU, try to guess. + if (HasAVX512) + return "knl"; + if (HasADX) + return "broadwell"; + if (HasAVX2) + return "haswell"; + if (HasAVX) + return "sandybridge"; + if (HasSSE42) + return HasMOVBE ? "silvermont" : "nehalem"; + if (HasSSE41) + return "penryn"; + if (HasSSSE3) + return HasMOVBE ? "bonnell" : "core2"; + if (Em64T) + return "x86-64"; + if (HasSSE2) + return "pentium-m"; + if (HasSSE) + return "pentium3"; + if (HasMMX) + return "pentium2"; + return "pentiumpro"; } case 15: { switch (Model) { @@ -655,6 +682,28 @@ StringRef sys::getHostCPUName() { StringRef Str(buffer, CPUInfoSize); SmallVector<StringRef, 32> Lines; Str.split(Lines, "\n"); + + // Look for the CPU features. + SmallVector<StringRef, 32> CPUFeatures; + for (unsigned I = 0, E = Lines.size(); I != E; ++I) + if (Lines[I].startswith("features")) { + size_t Pos = Lines[I].find(":"); + if (Pos != StringRef::npos) { + Lines[I].drop_front(Pos + 1).split(CPUFeatures, " "); + break; + } + } + + // We need to check for the presence of vector support independently of + // the machine type, since we may only use the vector register set when + // supported by the kernel (and hypervisor). + bool HaveVectorSupport = false; + for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) { + if (CPUFeatures[I] == "vx") + HaveVectorSupport = true; + } + + // Now check the processor machine type. for (unsigned I = 0, E = Lines.size(); I != E; ++I) { if (Lines[I].startswith("processor ")) { size_t Pos = Lines[I].find("machine = "); @@ -662,6 +711,8 @@ StringRef sys::getHostCPUName() { Pos += sizeof("machine = ") - 1; unsigned int Id; if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) { + if (Id >= 2964 && HaveVectorSupport) + return "z13"; if (Id >= 2827) return "zEC12"; if (Id >= 2817) @@ -680,7 +731,89 @@ StringRef sys::getHostCPUName() { } #endif -#if defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) +#if defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86)\ + || defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) +bool sys::getHostCPUFeatures(StringMap<bool> &Features) { + unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; + unsigned MaxLevel; + union { + unsigned u[3]; + char c[12]; + } text; + + if (GetX86CpuIDAndInfo(0, &MaxLevel, text.u+0, text.u+2, text.u+1) || + MaxLevel < 1) + return false; + + GetX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX); + + Features["cmov"] = (EDX >> 15) & 1; + Features["mmx"] = (EDX >> 23) & 1; + Features["sse"] = (EDX >> 25) & 1; + Features["sse2"] = (EDX >> 26) & 1; + Features["sse3"] = (ECX >> 0) & 1; + Features["ssse3"] = (ECX >> 9) & 1; + Features["sse4.1"] = (ECX >> 19) & 1; + Features["sse4.2"] = (ECX >> 20) & 1; + + Features["pclmul"] = (ECX >> 1) & 1; + Features["cx16"] = (ECX >> 13) & 1; + Features["movbe"] = (ECX >> 22) & 1; + Features["popcnt"] = (ECX >> 23) & 1; + Features["aes"] = (ECX >> 25) & 1; + Features["rdrnd"] = (ECX >> 30) & 1; + + // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV + // indicates that the AVX registers will be saved and restored on context + // switch, then we have full AVX support. + bool HasAVX = ((ECX >> 27) & 1) && ((ECX >> 28) & 1) && + !GetX86XCR0(&EAX, &EDX) && ((EAX & 0x6) == 0x6); + Features["avx"] = HasAVX; + Features["fma"] = HasAVX && (ECX >> 12) & 1; + Features["f16c"] = HasAVX && (ECX >> 29) & 1; + + // AVX512 requires additional context to be saved by the OS. + bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); + + unsigned MaxExtLevel; + GetX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); + + bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 && + !GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + Features["lzcnt"] = HasExtLeaf1 && ((ECX >> 5) & 1); + Features["sse4a"] = HasExtLeaf1 && ((ECX >> 6) & 1); + Features["prfchw"] = HasExtLeaf1 && ((ECX >> 8) & 1); + Features["xop"] = HasAVX && HasExtLeaf1 && ((ECX >> 11) & 1); + Features["fma4"] = HasAVX && HasExtLeaf1 && ((ECX >> 16) & 1); + Features["tbm"] = HasExtLeaf1 && ((ECX >> 21) & 1); + + bool HasLeaf7 = MaxLevel >= 7 && + !GetX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); + + // AVX2 is only supported if we have the OS save support from AVX. + Features["avx2"] = HasAVX && HasLeaf7 && (EBX >> 5) & 1; + + Features["fsgsbase"] = HasLeaf7 && ((EBX >> 0) & 1); + Features["bmi"] = HasLeaf7 && ((EBX >> 3) & 1); + Features["hle"] = HasLeaf7 && ((EBX >> 4) & 1); + Features["bmi2"] = HasLeaf7 && ((EBX >> 8) & 1); + Features["rtm"] = HasLeaf7 && ((EBX >> 11) & 1); + Features["rdseed"] = HasLeaf7 && ((EBX >> 18) & 1); + Features["adx"] = HasLeaf7 && ((EBX >> 19) & 1); + Features["sha"] = HasLeaf7 && ((EBX >> 29) & 1); + + // AVX512 is only supported if the OS supports the context save for it. + Features["avx512f"] = HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save; + Features["avx512dq"] = HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save; + Features["avx512pf"] = HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save; + Features["avx512er"] = HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save; + Features["avx512cd"] = HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save; + Features["avx512bw"] = HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save; + Features["avx512vl"] = HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save; + + return true; +} +#elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) bool sys::getHostCPUFeatures(StringMap<bool> &Features) { // Read 1024 bytes from /proc/cpuinfo, which should contain the Features line // in all cases. diff --git a/lib/Support/IsInf.cpp b/lib/Support/IsInf.cpp deleted file mode 100644 index d6da0c99e8d8..000000000000 --- a/lib/Support/IsInf.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//===-- IsInf.cpp - Platform-independent wrapper around C99 isinf() -------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Platform-independent wrapper around C99 isinf() -// -//===----------------------------------------------------------------------===// - -#include "llvm/Config/config.h" - -#if HAVE_ISINF_IN_MATH_H -# include <math.h> -#elif HAVE_ISINF_IN_CMATH -# include <cmath> -#elif HAVE_STD_ISINF_IN_CMATH -# include <cmath> -using std::isinf; -#elif HAVE_FINITE_IN_IEEEFP_H -// A handy workaround I found at http://www.unixguide.net/sun/faq ... -// apparently this has been a problem with Solaris for years. -# include <ieeefp.h> -static int isinf(double x) { return !finite(x) && x==x; } -#elif defined(_MSC_VER) -#include <float.h> -#define isinf(X) (!_finite(X)) -#elif defined(_AIX) && defined(__GNUC__) -// GCC's fixincludes seems to be removing the isinf() declaration from the -// system header /usr/include/math.h -# include <math.h> -static int isinf(double x) { return !finite(x) && x==x; } -#elif defined(__hpux) -// HP-UX is "special" -#include <math.h> -static int isinf(double x) { return ((x) == INFINITY) || ((x) == -INFINITY); } -#else -# error "Don't know how to get isinf()" -#endif - -namespace llvm { - -int IsInf(float f) { return isinf(f); } -int IsInf(double d) { return isinf(d); } - -} // end namespace llvm; diff --git a/lib/Support/IsNAN.cpp b/lib/Support/IsNAN.cpp deleted file mode 100644 index bdfdfbf3155d..000000000000 --- a/lib/Support/IsNAN.cpp +++ /dev/null @@ -1,33 +0,0 @@ -//===-- IsNAN.cpp ---------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Platform-independent wrapper around C99 isnan(). -// -//===----------------------------------------------------------------------===// - -#include "llvm/Config/config.h" - -#if HAVE_ISNAN_IN_MATH_H -# include <math.h> -#elif HAVE_ISNAN_IN_CMATH -# include <cmath> -#elif HAVE_STD_ISNAN_IN_CMATH -# include <cmath> -using std::isnan; -#elif defined(_MSC_VER) -#include <float.h> -#define isnan _isnan -#else -# error "Don't know how to get isnan()" -#endif - -namespace llvm { - int IsNAN(float f) { return isnan(f); } - int IsNAN(double d) { return isnan(d); } -} // end namespace llvm; diff --git a/lib/Support/LockFileManager.cpp b/lib/Support/LockFileManager.cpp index 5b82c367c0ad..d07c5f0f682f 100644 --- a/lib/Support/LockFileManager.cpp +++ b/lib/Support/LockFileManager.cpp @@ -7,12 +7,10 @@ // //===----------------------------------------------------------------------===// #include "llvm/Support/LockFileManager.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include <sys/stat.h> #include <sys/types.h> @@ -91,7 +89,7 @@ LockFileManager::LockFileManager(StringRef FileName) UniqueLockFileName += "-%%%%%%%%"; int UniqueLockFileID; if (std::error_code EC = sys::fs::createUniqueFile( - UniqueLockFileName.str(), UniqueLockFileID, UniqueLockFileName)) { + UniqueLockFileName, UniqueLockFileID, UniqueLockFileName)) { Error = EC; return; } @@ -116,7 +114,7 @@ LockFileManager::LockFileManager(StringRef FileName) // We failed to write out PID, so make up an excuse, remove the // unique lock file, and fail. Error = make_error_code(errc::no_space_on_device); - sys::fs::remove(UniqueLockFileName.c_str()); + sys::fs::remove(UniqueLockFileName); return; } } @@ -124,7 +122,7 @@ LockFileManager::LockFileManager(StringRef FileName) while (1) { // Create a link from the lock file name. If this succeeds, we're done. std::error_code EC = - sys::fs::create_link(UniqueLockFileName.str(), LockFileName.str()); + sys::fs::create_link(UniqueLockFileName, LockFileName); if (!EC) return; @@ -137,11 +135,11 @@ LockFileManager::LockFileManager(StringRef FileName) // from the lock file. if ((Owner = readLockFile(LockFileName))) { // Wipe out our unique lock file (it's useless now) - sys::fs::remove(UniqueLockFileName.str()); + sys::fs::remove(UniqueLockFileName); return; } - if (!sys::fs::exists(LockFileName.str())) { + if (!sys::fs::exists(LockFileName)) { // The previous owner released the lock file before we could read it. // Try to get ownership again. continue; @@ -149,7 +147,7 @@ LockFileManager::LockFileManager(StringRef FileName) // There is a lock file that nobody owns; try to clean it up and get // ownership. - if ((EC = sys::fs::remove(LockFileName.str()))) { + if ((EC = sys::fs::remove(LockFileName))) { Error = EC; return; } @@ -171,8 +169,8 @@ LockFileManager::~LockFileManager() { return; // Since we own the lock, remove the lock file and our own unique lock file. - sys::fs::remove(LockFileName.str()); - sys::fs::remove(UniqueLockFileName.str()); + sys::fs::remove(LockFileName); + sys::fs::remove(UniqueLockFileName); } LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() { @@ -186,9 +184,9 @@ LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() { Interval.tv_sec = 0; Interval.tv_nsec = 1000000; #endif - // Don't wait more than five minutes for the file to appear. - unsigned MaxSeconds = 300; - bool LockFileGone = false; + // Don't wait more than five minutes per iteration. Total timeout for the file + // to appear is ~8.5 mins. + const unsigned MaxSeconds = 5*60; do { // Sleep for the designated interval, to allow the owning process time to // finish up and remove the lock file. @@ -199,47 +197,18 @@ LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() { #else nanosleep(&Interval, nullptr); #endif - bool LockFileJustDisappeared = false; - // If the lock file is still expected to be there, check whether it still - // is. - if (!LockFileGone) { - if (sys::fs::access(LockFileName.c_str(), sys::fs::AccessMode::Exist) == - errc::no_such_file_or_directory) { - LockFileGone = true; - LockFileJustDisappeared = true; - } + if (sys::fs::access(LockFileName.c_str(), sys::fs::AccessMode::Exist) == + errc::no_such_file_or_directory) { + // If the original file wasn't created, somone thought the lock was dead. + if (!sys::fs::exists(FileName)) + return Res_OwnerDied; + return Res_Success; } - // If the lock file is no longer there, check if the original file is - // available now. - if (LockFileGone) { - if (sys::fs::exists(FileName.str())) { - return Res_Success; - } - - // The lock file is gone, so now we're waiting for the original file to - // show up. If this just happened, reset our waiting intervals and keep - // waiting. - if (LockFileJustDisappeared) { - MaxSeconds = 5; - -#if LLVM_ON_WIN32 - Interval = 1; -#else - Interval.tv_sec = 0; - Interval.tv_nsec = 1000000; -#endif - continue; - } - } - - // If we're looking for the lock file to disappear, but the process - // owning the lock died without cleaning up, just bail out. - if (!LockFileGone && - !processStillExecuting((*Owner).first, (*Owner).second)) { + // If the process owning the lock died without cleaning up, just bail out. + if (!processStillExecuting((*Owner).first, (*Owner).second)) return Res_OwnerDied; - } // Exponentially increase the time we wait for the lock to be removed. #if LLVM_ON_WIN32 @@ -263,3 +232,7 @@ LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() { // Give up. return Res_Timeout; } + +std::error_code LockFileManager::unsafeRemoveLockFile() { + return sys::fs::remove(LockFileName); +} diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp index 379db8811d4d..98862e96b749 100644 --- a/lib/Support/MemoryBuffer.cpp +++ b/lib/Support/MemoryBuffer.cpp @@ -23,7 +23,6 @@ #include "llvm/Support/Program.h" #include <cassert> #include <cerrno> -#include <cstdio> #include <cstring> #include <new> #include <sys/types.h> diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp index fdb27e6aa664..cf467381db8c 100644 --- a/lib/Support/Path.cpp +++ b/lib/Support/Path.cpp @@ -19,9 +19,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include <cctype> -#include <cstdio> #include <cstring> -#include <fcntl.h> #if !defined(_MSC_VER) && !defined(__MINGW32__) #include <unistd.h> @@ -30,6 +28,7 @@ #endif using namespace llvm; +using namespace llvm::support::endian; namespace { using llvm::StringRef; @@ -48,7 +47,6 @@ namespace { // * empty (in this case we return an empty string) // * either C: or {//,\\}net. // * {/,\} - // * {.,..} // * {file,directory}name if (path.empty()) @@ -75,12 +73,6 @@ namespace { if (is_separator(path[0])) return path.substr(0, 1); - if (path.startswith("..")) - return path.substr(0, 2); - - if (path[0] == '.') - return path.substr(0, 1); - // * {file,directory}name size_t end = path.find_first_of(separators); return path.substr(0, end); @@ -917,7 +909,7 @@ file_magic identify_magic(StringRef Magic) { if (Magic.size() < MinSize) return file_magic::coff_import_library; - int BigObjVersion = *reinterpret_cast<const support::ulittle16_t*>( + int BigObjVersion = read16le( Magic.data() + offsetof(COFF::BigObjHeader, Version)); if (BigObjVersion < COFF::BigObjHeader::MinBigObjectVersion) return file_magic::coff_import_library; @@ -960,7 +952,7 @@ file_magic identify_magic(StringRef Magic) { unsigned low = Data2MSB ? 17 : 16; if (Magic[high] == 0) switch (Magic[low]) { - default: break; + default: return file_magic::elf; case 1: return file_magic::elf_relocatable; case 2: return file_magic::elf_executable; case 3: return file_magic::elf_shared_object; @@ -1012,6 +1004,7 @@ file_magic identify_magic(StringRef Magic) { case 8: return file_magic::macho_bundle; case 9: return file_magic::macho_dynamically_linked_shared_lib_stub; case 10: return file_magic::macho_dsym_companion; + case 11: return file_magic::macho_kext_bundle; } break; } @@ -1033,8 +1026,7 @@ file_magic identify_magic(StringRef Magic) { case 'M': // Possible MS-DOS stub on Windows PE file if (Magic[1] == 'Z') { - uint32_t off = - *reinterpret_cast<const support::ulittle32_t*>(Magic.data() + 0x3c); + uint32_t off = read32le(Magic.data() + 0x3c); // PE/COFF file, either EXE or DLL. if (off < Magic.size() && memcmp(Magic.data()+off, COFF::PEMagic, sizeof(COFF::PEMagic)) == 0) diff --git a/lib/Support/PrettyStackTrace.cpp b/lib/Support/PrettyStackTrace.cpp index 987778a1bde6..f9f8cab9d933 100644 --- a/lib/Support/PrettyStackTrace.cpp +++ b/lib/Support/PrettyStackTrace.cpp @@ -16,9 +16,8 @@ #include "llvm-c/Core.h" #include "llvm/ADT/SmallString.h" #include "llvm/Config/config.h" // Get autoconf configuration settings -#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Signals.h" -#include "llvm/Support/ThreadLocal.h" #include "llvm/Support/Watchdog.h" #include "llvm/Support/raw_ostream.h" @@ -28,7 +27,17 @@ using namespace llvm; -static ManagedStatic<sys::ThreadLocal<const PrettyStackTraceEntry> > PrettyStackTraceHead; +// If backtrace support is not enabled, compile out support for pretty stack +// traces. This has the secondary effect of not requiring thread local storage +// when backtrace support is disabled. +#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) + +// We need a thread local pointer to manage the stack of our stack trace +// objects, but we *really* cannot tolerate destructors running and do not want +// to pay any overhead of synchronizing. As a consequence, we use a raw +// thread-local variable. +static LLVM_THREAD_LOCAL const PrettyStackTraceEntry *PrettyStackTraceHead = + nullptr; static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){ unsigned NextID = 0; @@ -46,12 +55,12 @@ static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){ /// PrintCurStackTrace - Print the current stack trace to the specified stream. static void PrintCurStackTrace(raw_ostream &OS) { // Don't print an empty trace. - if (!PrettyStackTraceHead->get()) return; + if (!PrettyStackTraceHead) return; // If there are pretty stack frames registered, walk and emit them. OS << "Stack dump:\n"; - PrintStack(PrettyStackTraceHead->get(), OS); + PrintStack(PrettyStackTraceHead, OS); OS.flush(); } @@ -99,28 +108,23 @@ static void CrashHandler(void *) { #endif } +// defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) +#endif + PrettyStackTraceEntry::PrettyStackTraceEntry() { +#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) // Link ourselves. - NextEntry = PrettyStackTraceHead->get(); - PrettyStackTraceHead->set(this); + NextEntry = PrettyStackTraceHead; + PrettyStackTraceHead = this; +#endif } PrettyStackTraceEntry::~PrettyStackTraceEntry() { - // Do nothing if PrettyStackTraceHead is uninitialized. This can only happen - // if a shutdown occurred after we created the PrettyStackTraceEntry. That - // does occur in the following idiom: - // - // PrettyStackTraceProgram X(...); - // llvm_shutdown_obj Y; - // - // Without this check, we may end up removing ourselves from the stack trace - // after PrettyStackTraceHead has already been destroyed. - if (!PrettyStackTraceHead.isConstructed()) - return; - - assert(PrettyStackTraceHead->get() == this && +#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) + assert(PrettyStackTraceHead == this && "Pretty stack trace entry destruction is out of order"); - PrettyStackTraceHead->set(getNextEntry()); + PrettyStackTraceHead = getNextEntry(); +#endif } void PrettyStackTraceString::print(raw_ostream &OS) const { @@ -135,15 +139,19 @@ void PrettyStackTraceProgram::print(raw_ostream &OS) const { OS << '\n'; } +#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) static bool RegisterCrashPrinter() { sys::AddSignalHandler(CrashHandler, nullptr); return false; } +#endif void llvm::EnablePrettyStackTrace() { +#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) // The first time this is called, we register the crash printer. static bool HandlerRegistered = RegisterCrashPrinter(); (void)HandlerRegistered; +#endif } void LLVMEnablePrettyStackTrace() { diff --git a/lib/Support/Process.cpp b/lib/Support/Process.cpp index ad67e1b10b48..6dcbb47e87d0 100644 --- a/lib/Support/Process.cpp +++ b/lib/Support/Process.cpp @@ -13,8 +13,8 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" @@ -26,27 +26,10 @@ using namespace sys; //=== independent code. //===----------------------------------------------------------------------===// -/// \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(); - Optional<std::string> Process::FindInEnvPath(const std::string& EnvName, const std::string& FileName) { + assert(!path::is_absolute(FileName)); Optional<std::string> FoundPath; Optional<std::string> OptPath = Process::GetEnv(EnvName); if (!OptPath.hasValue()) diff --git a/lib/Support/Program.cpp b/lib/Support/Program.cpp index b84b82b1f10b..34e336b354d6 100644 --- a/lib/Support/Program.cpp +++ b/lib/Support/Program.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Program.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" #include <system_error> using namespace llvm; diff --git a/lib/Support/RandomNumberGenerator.cpp b/lib/Support/RandomNumberGenerator.cpp index 294313769bf9..81d0411d60b4 100644 --- a/lib/Support/RandomNumberGenerator.cpp +++ b/lib/Support/RandomNumberGenerator.cpp @@ -13,13 +13,15 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "rng" +#include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/RandomNumberGenerator.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; +#define DEBUG_TYPE "rng" + // Tracking BUG: 19665 // http://llvm.org/bugs/show_bug.cgi?id=19665 // diff --git a/lib/Support/Regex.cpp b/lib/Support/Regex.cpp index f7fe1e4c7925..e8344ef74d9c 100644 --- a/lib/Support/Regex.cpp +++ b/lib/Support/Regex.cpp @@ -14,8 +14,8 @@ #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/StringRef.h" +#include "llvm/ADT/Twine.h" #include <string> using namespace llvm; @@ -159,7 +159,7 @@ std::string Regex::sub(StringRef Repl, StringRef String, RefValue < Matches.size()) Res += Matches[RefValue]; else if (Error && Error->empty()) - *Error = "invalid backreference string '" + Ref.str() + "'"; + *Error = ("invalid backreference string '" + Twine(Ref) + "'").str(); break; } } diff --git a/lib/Support/ScaledNumber.cpp b/lib/Support/ScaledNumber.cpp index 6f6699cfa7c4..987c2d803b7e 100644 --- a/lib/Support/ScaledNumber.cpp +++ b/lib/Support/ScaledNumber.cpp @@ -14,6 +14,7 @@ #include "llvm/Support/ScaledNumber.h" #include "llvm/ADT/APFloat.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::ScaledNumbers; diff --git a/lib/Support/SmallPtrSet.cpp b/lib/Support/SmallPtrSet.cpp index c87ee7d106e2..358c8e8abbe9 100644 --- a/lib/Support/SmallPtrSet.cpp +++ b/lib/Support/SmallPtrSet.cpp @@ -50,11 +50,12 @@ SmallPtrSetImplBase::insert_imp(const void *Ptr) { } // Otherwise, hit the big set case, which will call grow. } - - if (NumElements*4 >= CurArraySize*3) { + + if (LLVM_UNLIKELY(NumElements * 4 >= CurArraySize * 3)) { // If more than 3/4 of the array is full, grow. Grow(CurArraySize < 64 ? 128 : CurArraySize*2); - } else if (CurArraySize-(NumElements+NumTombstones) < CurArraySize/8) { + } else if (LLVM_UNLIKELY(CurArraySize - (NumElements + NumTombstones) < + CurArraySize / 8)) { // If fewer of 1/8 of the array is empty (meaning that many are filled with // tombstones), rehash. Grow(CurArraySize); @@ -107,16 +108,16 @@ const void * const *SmallPtrSetImplBase::FindBucketFor(const void *Ptr) const { const void *const *Array = CurArray; const void *const *Tombstone = nullptr; while (1) { - // Found Ptr's bucket? - if (Array[Bucket] == Ptr) - return Array+Bucket; - // If we found an empty bucket, the pointer doesn't exist in the set. // Return a tombstone if we've seen one so far, or the empty bucket if // not. - if (Array[Bucket] == getEmptyMarker()) + if (LLVM_LIKELY(Array[Bucket] == getEmptyMarker())) return Tombstone ? Tombstone : Array+Bucket; - + + // Found Ptr's bucket? + if (LLVM_LIKELY(Array[Bucket] == Ptr)) + return Array+Bucket; + // If this is a tombstone, remember it. If Ptr ends up not in the set, we // prefer to return it than something that would require more probing. if (Array[Bucket] == getTombstoneMarker() && !Tombstone) diff --git a/lib/Support/SourceMgr.cpp b/lib/Support/SourceMgr.cpp index b50a66b2974f..d5e3157b064e 100644 --- a/lib/Support/SourceMgr.cpp +++ b/lib/Support/SourceMgr.cpp @@ -14,13 +14,11 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/SourceMgr.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Locale.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" -#include <system_error> using namespace llvm; static const size_t TabStop = 8; diff --git a/lib/Support/SpecialCaseList.cpp b/lib/Support/SpecialCaseList.cpp index 785cc609f48c..ea417c41c0a7 100644 --- a/lib/Support/SpecialCaseList.cpp +++ b/lib/Support/SpecialCaseList.cpp @@ -15,13 +15,11 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/SpecialCaseList.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Regex.h" -#include "llvm/Support/raw_ostream.h" #include <string> #include <system_error> #include <utility> @@ -46,19 +44,27 @@ struct SpecialCaseList::Entry { } }; -SpecialCaseList::SpecialCaseList() : Entries() {} +SpecialCaseList::SpecialCaseList() : Entries(), Regexps(), IsCompiled(false) {} -std::unique_ptr<SpecialCaseList> SpecialCaseList::create(StringRef Path, - std::string &Error) { - if (Path.empty()) - return std::unique_ptr<SpecialCaseList>(new SpecialCaseList()); - ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = - MemoryBuffer::getFile(Path); - if (std::error_code EC = FileOrErr.getError()) { - Error = (Twine("Can't open file '") + Path + "': " + EC.message()).str(); - return nullptr; +std::unique_ptr<SpecialCaseList> +SpecialCaseList::create(const std::vector<std::string> &Paths, + std::string &Error) { + std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList()); + for (auto Path : Paths) { + ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = + MemoryBuffer::getFile(Path); + if (std::error_code EC = FileOrErr.getError()) { + Error = (Twine("can't open file '") + Path + "': " + EC.message()).str(); + return nullptr; + } + std::string ParseError; + if (!SCL->parse(FileOrErr.get().get(), ParseError)) { + Error = (Twine("error parsing file '") + Path + "': " + ParseError).str(); + return nullptr; + } } - return create(FileOrErr.get().get(), Error); + SCL->compile(); + return SCL; } std::unique_ptr<SpecialCaseList> SpecialCaseList::create(const MemoryBuffer *MB, @@ -66,12 +72,14 @@ std::unique_ptr<SpecialCaseList> SpecialCaseList::create(const MemoryBuffer *MB, std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList()); if (!SCL->parse(MB, Error)) return nullptr; + SCL->compile(); return SCL; } -std::unique_ptr<SpecialCaseList> SpecialCaseList::createOrDie(StringRef Path) { +std::unique_ptr<SpecialCaseList> +SpecialCaseList::createOrDie(const std::vector<std::string> &Paths) { std::string Error; - if (auto SCL = create(Path, Error)) + if (auto SCL = create(Paths, Error)) return SCL; report_fatal_error(Error); } @@ -80,12 +88,8 @@ bool SpecialCaseList::parse(const MemoryBuffer *MB, std::string &Error) { // Iterate through each line in the blacklist file. SmallVector<StringRef, 16> Lines; SplitString(MB->getBuffer(), Lines, "\n\r"); - StringMap<StringMap<std::string> > Regexps; - assert(Entries.empty() && - "parse() should be called on an empty SpecialCaseList"); int LineNo = 1; - for (SmallVectorImpl<StringRef>::iterator I = Lines.begin(), E = Lines.end(); - I != E; ++I, ++LineNo) { + for (auto I = Lines.begin(), E = Lines.end(); I != E; ++I, ++LineNo) { // Ignore empty lines and lines starting with "#" if (I->empty() || I->startswith("#")) continue; @@ -94,7 +98,7 @@ bool SpecialCaseList::parse(const MemoryBuffer *MB, std::string &Error) { StringRef Prefix = SplitLine.first; if (SplitLine.second.empty()) { // Missing ':' in the line. - Error = (Twine("Malformed line ") + Twine(LineNo) + ": '" + + Error = (Twine("malformed line ") + Twine(LineNo) + ": '" + SplitLine.first + "'").str(); return false; } @@ -119,7 +123,7 @@ bool SpecialCaseList::parse(const MemoryBuffer *MB, std::string &Error) { Regex CheckRE(Regexp); std::string REError; if (!CheckRE.isValid(REError)) { - Error = (Twine("Malformed regex in line ") + Twine(LineNo) + ": '" + + Error = (Twine("malformed regex in line ") + Twine(LineNo) + ": '" + SplitLine.second + "': " + REError).str(); return false; } @@ -129,10 +133,14 @@ bool SpecialCaseList::parse(const MemoryBuffer *MB, std::string &Error) { Regexps[Prefix][Category] += "|"; Regexps[Prefix][Category] += "^" + Regexp + "$"; } + return true; +} +void SpecialCaseList::compile() { + assert(!IsCompiled && "compile() should only be called once"); // Iterate through each of the prefixes, and create Regexs for them. - for (StringMap<StringMap<std::string> >::const_iterator I = Regexps.begin(), - E = Regexps.end(); + for (StringMap<StringMap<std::string>>::const_iterator I = Regexps.begin(), + E = Regexps.end(); I != E; ++I) { for (StringMap<std::string>::const_iterator II = I->second.begin(), IE = I->second.end(); @@ -140,13 +148,15 @@ bool SpecialCaseList::parse(const MemoryBuffer *MB, std::string &Error) { Entries[I->getKey()][II->getKey()].RegEx.reset(new Regex(II->getValue())); } } - return true; + Regexps.clear(); + IsCompiled = true; } SpecialCaseList::~SpecialCaseList() {} bool SpecialCaseList::inSection(StringRef Section, StringRef Query, StringRef Category) const { + assert(IsCompiled && "SpecialCaseList::compile() was not called!"); StringMap<StringMap<Entry> >::const_iterator I = Entries.find(Section); if (I == Entries.end()) return false; StringMap<Entry>::const_iterator II = I->second.find(Category); diff --git a/lib/Support/StreamingMemoryObject.cpp b/lib/Support/StreamingMemoryObject.cpp index 68beeef4dc7f..6c5652af04c2 100644 --- a/lib/Support/StreamingMemoryObject.cpp +++ b/lib/Support/StreamingMemoryObject.cpp @@ -8,12 +8,9 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/StreamingMemoryObject.h" -#include "llvm/Support/Compiler.h" #include <cassert> #include <cstddef> #include <cstring> - - using namespace llvm; namespace { @@ -45,8 +42,8 @@ private: return static_cast<std::ptrdiff_t>(address) < LastChar - FirstChar; } - RawMemoryObject(const RawMemoryObject&) LLVM_DELETED_FUNCTION; - void operator=(const RawMemoryObject&) LLVM_DELETED_FUNCTION; + RawMemoryObject(const RawMemoryObject&) = delete; + void operator=(const RawMemoryObject&) = delete; }; uint64_t RawMemoryObject::readBytes(uint8_t *Buf, uint64_t Size, @@ -76,7 +73,7 @@ namespace llvm { // block until we actually want to read it. bool StreamingMemoryObject::isValidAddress(uint64_t address) const { if (ObjectSize && address < ObjectSize) return true; - return fetchToPos(address); + return fetchToPos(address); } uint64_t StreamingMemoryObject::getExtent() const { @@ -90,13 +87,18 @@ uint64_t StreamingMemoryObject::getExtent() const { uint64_t StreamingMemoryObject::readBytes(uint8_t *Buf, uint64_t Size, uint64_t Address) const { fetchToPos(Address + Size - 1); - if (Address >= BytesRead) + // Note: For wrapped bitcode files will set ObjectSize after the + // first call to fetchToPos. In such cases, ObjectSize can be + // smaller than BytesRead. + size_t MaxAddress = + (ObjectSize && ObjectSize < BytesRead) ? ObjectSize : BytesRead; + if (Address >= MaxAddress) return 0; uint64_t End = Address + Size; - if (End > BytesRead) - End = BytesRead; - assert(static_cast<int64_t>(End - Address) >= 0); + if (End > MaxAddress) + End = MaxAddress; + assert(End >= Address); Size = End - Address; memcpy(Buf, &Bytes[Address + BytesSkipped], Size); return Size; @@ -112,6 +114,8 @@ bool StreamingMemoryObject::dropLeadingBytes(size_t s) { void StreamingMemoryObject::setKnownObjectSize(size_t size) { ObjectSize = size; Bytes.reserve(size); + if (ObjectSize <= BytesRead) + EOFReached = true; } MemoryObject *getNonStreamedMemoryObject(const unsigned char *Start, diff --git a/lib/Support/StringExtras.cpp b/lib/Support/StringExtras.cpp index d77ad7f55a18..3e2420f67760 100644 --- a/lib/Support/StringExtras.cpp +++ b/lib/Support/StringExtras.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" using namespace llvm; diff --git a/lib/Support/StringMap.cpp b/lib/Support/StringMap.cpp index ddb73494ff5d..7be946642d90 100644 --- a/lib/Support/StringMap.cpp +++ b/lib/Support/StringMap.cpp @@ -188,9 +188,10 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) { // If the hash table is now more than 3/4 full, or if fewer than 1/8 of // the buckets are empty (meaning that many are filled with tombstones), // grow/rehash the table. - if (NumItems*4 > NumBuckets*3) { + if (LLVM_UNLIKELY(NumItems * 4 > NumBuckets * 3)) { NewSize = NumBuckets*2; - } else if (NumBuckets-(NumItems+NumTombstones) <= NumBuckets/8) { + } else if (LLVM_UNLIKELY(NumBuckets - (NumItems + NumTombstones) <= + NumBuckets / 8)) { NewSize = NumBuckets; } else { return BucketNo; diff --git a/lib/Support/SystemUtils.cpp b/lib/Support/SystemUtils.cpp index 2036364dc51d..7fa6ae3f6199 100644 --- a/lib/Support/SystemUtils.cpp +++ b/lib/Support/SystemUtils.cpp @@ -13,8 +13,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/SystemUtils.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; diff --git a/lib/Support/TargetParser.cpp b/lib/Support/TargetParser.cpp new file mode 100644 index 000000000000..a3998d2d13ea --- /dev/null +++ b/lib/Support/TargetParser.cpp @@ -0,0 +1,467 @@ +//===-- TargetParser - Parser for target features ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a target parser to recognise hardware features such as +// FPU/CPU/ARCH names as well as specific support such as HDIV, etc. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ARMBuildAttributes.h" +#include "llvm/Support/TargetParser.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include <cctype> + +using namespace llvm; + +namespace { + +// List of canonical FPU names (use getFPUSynonym) +// FIXME: TableGen this. +struct { + const char * Name; + ARM::FPUKind ID; +} FPUNames[] = { + { "invalid", ARM::FK_INVALID }, + { "vfp", ARM::FK_VFP }, + { "vfpv2", ARM::FK_VFPV2 }, + { "vfpv3", ARM::FK_VFPV3 }, + { "vfpv3-d16", ARM::FK_VFPV3_D16 }, + { "vfpv4", ARM::FK_VFPV4 }, + { "vfpv4-d16", ARM::FK_VFPV4_D16 }, + { "fpv5-d16", ARM::FK_FPV5_D16 }, + { "fp-armv8", ARM::FK_FP_ARMV8 }, + { "neon", ARM::FK_NEON }, + { "neon-vfpv4", ARM::FK_NEON_VFPV4 }, + { "neon-fp-armv8", ARM::FK_NEON_FP_ARMV8 }, + { "crypto-neon-fp-armv8", ARM::FK_CRYPTO_NEON_FP_ARMV8 }, + { "softvfp", ARM::FK_SOFTVFP } +}; +// List of canonical arch names (use getArchSynonym) +// FIXME: TableGen this. +struct { + const char *Name; + ARM::ArchKind ID; + const char *DefaultCPU; + ARMBuildAttrs::CPUArch DefaultArch; +} ARCHNames[] = { + { "invalid", ARM::AK_INVALID, nullptr, ARMBuildAttrs::CPUArch::Pre_v4 }, + { "armv2", ARM::AK_ARMV2, "2", ARMBuildAttrs::CPUArch::v4 }, + { "armv2a", ARM::AK_ARMV2A, "2A", ARMBuildAttrs::CPUArch::v4 }, + { "armv3", ARM::AK_ARMV3, "3", ARMBuildAttrs::CPUArch::v4 }, + { "armv3m", ARM::AK_ARMV3M, "3M", ARMBuildAttrs::CPUArch::v4 }, + { "armv4", ARM::AK_ARMV4, "4", ARMBuildAttrs::CPUArch::v4 }, + { "armv4t", ARM::AK_ARMV4T, "4T", ARMBuildAttrs::CPUArch::v4T }, + { "armv5", ARM::AK_ARMV5, "5", ARMBuildAttrs::CPUArch::v5T }, + { "armv5t", ARM::AK_ARMV5T, "5T", ARMBuildAttrs::CPUArch::v5T }, + { "armv5te", ARM::AK_ARMV5TE, "5TE", ARMBuildAttrs::CPUArch::v5TE }, + { "armv6", ARM::AK_ARMV6, "6", ARMBuildAttrs::CPUArch::v6 }, + { "armv6j", ARM::AK_ARMV6J, "6J", ARMBuildAttrs::CPUArch::v6 }, + { "armv6k", ARM::AK_ARMV6K, "6K", ARMBuildAttrs::CPUArch::v6K }, + { "armv6t2", ARM::AK_ARMV6T2, "6T2", ARMBuildAttrs::CPUArch::v6T2 }, + { "armv6z", ARM::AK_ARMV6Z, "6Z", ARMBuildAttrs::CPUArch::v6KZ }, + { "armv6zk", ARM::AK_ARMV6ZK, "6ZK", ARMBuildAttrs::CPUArch::v6KZ }, + { "armv6-m", ARM::AK_ARMV6M, "6-M", ARMBuildAttrs::CPUArch::v6_M }, + { "armv7", ARM::AK_ARMV7, "7", ARMBuildAttrs::CPUArch::v7 }, + { "armv7-a", ARM::AK_ARMV7A, "7-A", ARMBuildAttrs::CPUArch::v7 }, + { "armv7-r", ARM::AK_ARMV7R, "7-R", ARMBuildAttrs::CPUArch::v7 }, + { "armv7-m", ARM::AK_ARMV7M, "7-M", ARMBuildAttrs::CPUArch::v7 }, + { "armv8-a", ARM::AK_ARMV8A, "8-A", ARMBuildAttrs::CPUArch::v8 }, + { "armv8.1-a", ARM::AK_ARMV8_1A, "8.1-A", ARMBuildAttrs::CPUArch::v8 }, + // Non-standard Arch names. + { "iwmmxt", ARM::AK_IWMMXT, "iwmmxt", ARMBuildAttrs::CPUArch::v5TE }, + { "iwmmxt2", ARM::AK_IWMMXT2, "iwmmxt2", ARMBuildAttrs::CPUArch::v5TE }, + { "xscale", ARM::AK_XSCALE, "xscale", ARMBuildAttrs::CPUArch::v5TE }, + { "armv5e", ARM::AK_ARMV5E, "5E", ARMBuildAttrs::CPUArch::v5TE }, + { "armv5tej", ARM::AK_ARMV5TEJ, "5TE", ARMBuildAttrs::CPUArch::v5TE }, + { "armv6sm", ARM::AK_ARMV6SM, "6-M", ARMBuildAttrs::CPUArch::v6_M }, + { "armv6hl", ARM::AK_ARMV6HL, "6-M", ARMBuildAttrs::CPUArch::v6_M }, + { "armv7e-m", ARM::AK_ARMV7EM, "7E-M", ARMBuildAttrs::CPUArch::v7E_M }, + { "armv7l", ARM::AK_ARMV7L, "7-L", ARMBuildAttrs::CPUArch::v7 }, + { "armv7hl", ARM::AK_ARMV7HL, "7H-L", ARMBuildAttrs::CPUArch::v7 }, + { "armv7s", ARM::AK_ARMV7S, "7-S", ARMBuildAttrs::CPUArch::v7 } +}; +// List of canonical ARCH names (use getARCHSynonym) +// FIXME: TableGen this. +struct { + const char *Name; + ARM::ArchExtKind ID; +} ARCHExtNames[] = { + { "invalid", ARM::AEK_INVALID }, + { "crc", ARM::AEK_CRC }, + { "crypto", ARM::AEK_CRYPTO }, + { "fp", ARM::AEK_FP }, + { "idiv", ARM::AEK_HWDIV }, + { "mp", ARM::AEK_MP }, + { "sec", ARM::AEK_SEC }, + { "virt", ARM::AEK_VIRT } +}; +// List of CPU names and their arches. +// The same CPU can have multiple arches and can be default on multiple arches. +// When finding the Arch for a CPU, first-found prevails. Sort them accordingly. +// FIXME: TableGen this. +struct { + const char *Name; + ARM::ArchKind ArchID; + bool Default; +} CPUNames[] = { + { "arm2", ARM::AK_ARMV2, true }, + { "arm6", ARM::AK_ARMV3, true }, + { "arm7m", ARM::AK_ARMV3M, true }, + { "strongarm", ARM::AK_ARMV4, true }, + { "arm7tdmi", ARM::AK_ARMV4T, true }, + { "arm7tdmi-s", ARM::AK_ARMV4T, false }, + { "arm710t", ARM::AK_ARMV4T, false }, + { "arm720t", ARM::AK_ARMV4T, false }, + { "arm9", ARM::AK_ARMV4T, false }, + { "arm9tdmi", ARM::AK_ARMV4T, false }, + { "arm920", ARM::AK_ARMV4T, false }, + { "arm920t", ARM::AK_ARMV4T, false }, + { "arm922t", ARM::AK_ARMV4T, false }, + { "arm9312", ARM::AK_ARMV4T, false }, + { "arm940t", ARM::AK_ARMV4T, false }, + { "ep9312", ARM::AK_ARMV4T, false }, + { "arm10tdmi", ARM::AK_ARMV5, true }, + { "arm10tdmi", ARM::AK_ARMV5T, true }, + { "arm1020t", ARM::AK_ARMV5T, false }, + { "xscale", ARM::AK_XSCALE, true }, + { "xscale", ARM::AK_ARMV5TE, false }, + { "arm9e", ARM::AK_ARMV5TE, false }, + { "arm926ej-s", ARM::AK_ARMV5TE, false }, + { "arm946ej-s", ARM::AK_ARMV5TE, false }, + { "arm966e-s", ARM::AK_ARMV5TE, false }, + { "arm968e-s", ARM::AK_ARMV5TE, false }, + { "arm1020e", ARM::AK_ARMV5TE, false }, + { "arm1022e", ARM::AK_ARMV5TE, true }, + { "iwmmxt", ARM::AK_ARMV5TE, false }, + { "iwmmxt", ARM::AK_IWMMXT, true }, + { "arm1136jf-s", ARM::AK_ARMV6, true }, + { "arm1136j-s", ARM::AK_ARMV6J, true }, + { "arm1136jz-s", ARM::AK_ARMV6J, false }, + { "arm1176j-s", ARM::AK_ARMV6K, false }, + { "mpcore", ARM::AK_ARMV6K, false }, + { "mpcorenovfp", ARM::AK_ARMV6K, false }, + { "arm1176jzf-s", ARM::AK_ARMV6K, true }, + { "arm1176jzf-s", ARM::AK_ARMV6Z, true }, + { "arm1176jzf-s", ARM::AK_ARMV6ZK, true }, + { "arm1156t2-s", ARM::AK_ARMV6T2, true }, + { "arm1156t2f-s", ARM::AK_ARMV6T2, false }, + { "cortex-m0", ARM::AK_ARMV6M, true }, + { "cortex-m0plus", ARM::AK_ARMV6M, false }, + { "cortex-m1", ARM::AK_ARMV6M, false }, + { "sc000", ARM::AK_ARMV6M, false }, + { "cortex-a8", ARM::AK_ARMV7, true }, + { "cortex-a5", ARM::AK_ARMV7A, false }, + { "cortex-a7", ARM::AK_ARMV7A, false }, + { "cortex-a8", ARM::AK_ARMV7A, true }, + { "cortex-a9", ARM::AK_ARMV7A, false }, + { "cortex-a12", ARM::AK_ARMV7A, false }, + { "cortex-a15", ARM::AK_ARMV7A, false }, + { "cortex-a17", ARM::AK_ARMV7A, false }, + { "krait", ARM::AK_ARMV7A, false }, + { "cortex-r4", ARM::AK_ARMV7R, true }, + { "cortex-r4f", ARM::AK_ARMV7R, false }, + { "cortex-r5", ARM::AK_ARMV7R, false }, + { "cortex-r7", ARM::AK_ARMV7R, false }, + { "sc300", ARM::AK_ARMV7M, false }, + { "cortex-m3", ARM::AK_ARMV7M, true }, + { "cortex-m4", ARM::AK_ARMV7M, false }, + { "cortex-m7", ARM::AK_ARMV7M, false }, + { "cortex-a53", ARM::AK_ARMV8A, true }, + { "cortex-a57", ARM::AK_ARMV8A, false }, + { "cortex-a72", ARM::AK_ARMV8A, false }, + { "cyclone", ARM::AK_ARMV8A, false }, + { "generic", ARM::AK_ARMV8_1A, true }, + // Non-standard Arch names. + { "arm1022e", ARM::AK_ARMV5E, true }, + { "arm926ej-s", ARM::AK_ARMV5TEJ, true }, + { "cortex-m0", ARM::AK_ARMV6SM, true }, + { "arm1176jzf-s", ARM::AK_ARMV6HL, true }, + { "cortex-a8", ARM::AK_ARMV7L, true }, + { "cortex-a8", ARM::AK_ARMV7HL, true }, + { "cortex-m4", ARM::AK_ARMV7EM, true }, + { "swift", ARM::AK_ARMV7S, true }, + // Invalid CPU + { "invalid", ARM::AK_INVALID, true } +}; + +} // namespace + +namespace llvm { + +// ======================================================= // +// Information by ID +// ======================================================= // + +const char *ARMTargetParser::getFPUName(unsigned FPUKind) { + if (FPUKind >= ARM::FK_LAST) + return nullptr; + return FPUNames[FPUKind].Name; +} + +const char *ARMTargetParser::getArchName(unsigned ArchKind) { + if (ArchKind >= ARM::AK_LAST) + return nullptr; + return ARCHNames[ArchKind].Name; +} + +const char *ARMTargetParser::getArchDefaultCPUName(unsigned ArchKind) { + if (ArchKind >= ARM::AK_LAST) + return nullptr; + return ARCHNames[ArchKind].DefaultCPU; +} + +unsigned ARMTargetParser::getArchDefaultCPUArch(unsigned ArchKind) { + if (ArchKind >= ARM::AK_LAST) + return ARMBuildAttrs::CPUArch::Pre_v4; + return ARCHNames[ArchKind].DefaultArch; +} + +const char *ARMTargetParser::getArchExtName(unsigned ArchExtKind) { + if (ArchExtKind >= ARM::AEK_LAST) + return nullptr; + return ARCHExtNames[ArchExtKind].Name; +} + +const char *ARMTargetParser::getDefaultCPU(StringRef Arch) { + unsigned AK = parseArch(Arch); + if (AK == ARM::AK_INVALID) + return nullptr; + + // Look for multiple AKs to find the default for pair AK+Name. + for (const auto CPU : CPUNames) { + if (CPU.ArchID == AK && CPU.Default) + return CPU.Name; + } + return nullptr; +} + +// ======================================================= // +// Parsers +// ======================================================= // + +StringRef ARMTargetParser::getFPUSynonym(StringRef FPU) { + return StringSwitch<StringRef>(FPU) + .Cases("fpa", "fpe2", "fpe3", "maverick", "invalid") // Unsupported + .Case("vfp2", "vfpv2") + .Case("vfp3", "vfpv3") + .Case("vfp4", "vfpv4") + .Case("vfp3-d16", "vfpv3-d16") + .Case("vfp4-d16", "vfpv4-d16") + // FIXME: sp-16 is NOT the same as d16 + .Cases("fp4-sp-d16", "fpv4-sp-d16", "vfpv4-d16") + .Cases("fp4-dp-d16", "fpv4-dp-d16", "vfpv4-d16") + .Cases("fp5-sp-d16", "fpv5-sp-d16", "fpv5-d16") + .Cases("fp5-dp-d16", "fpv5-dp-d16", "fpv5-d16") + // FIXME: Clang uses it, but it's bogus, since neon defaults to vfpv3. + .Case("neon-vfpv3", "neon") + .Default(FPU); +} + +StringRef ARMTargetParser::getArchSynonym(StringRef Arch) { + return StringSwitch<StringRef>(Arch) + .Cases("armv6m", "v6m", "armv6-m") + .Cases("armv7a", "v7a", "armv7-a") + .Cases("armv7r", "v7r", "armv7-r") + .Cases("armv7m", "v7m", "armv7-m") + .Cases("armv7em", "v7em", "armv7e-m") + .Cases("armv8", "v8", "armv8-a") + .Cases("armv8a", "v8a", "armv8-a") + .Cases("armv8.1a", "v8.1a", "armv8.1-a") + .Cases("aarch64", "arm64", "armv8-a") + .Default(Arch); +} + +// MArch is expected to be of the form (arm|thumb)?(eb)?(v.+)?(eb)?, but +// (iwmmxt|xscale)(eb)? is also permitted. If the former, return +// "v.+", if the latter, return unmodified string, minus 'eb'. +// If invalid, return empty string. +StringRef ARMTargetParser::getCanonicalArchName(StringRef Arch) { + size_t offset = StringRef::npos; + StringRef A = Arch; + StringRef Error = ""; + + // Begins with "arm" / "thumb", move past it. + if (A.startswith("arm64")) + offset = 5; + else if (A.startswith("arm")) + offset = 3; + else if (A.startswith("thumb")) + offset = 5; + else if (A.startswith("aarch64")) { + offset = 7; + // AArch64 uses "_be", not "eb" suffix. + if (A.find("eb") != StringRef::npos) + return Error; + if (A.substr(offset,3) == "_be") + offset += 3; + } + + // Ex. "armebv7", move past the "eb". + if (offset != StringRef::npos && A.substr(offset, 2) == "eb") + offset += 2; + // Or, if it ends with eb ("armv7eb"), chop it off. + else if (A.endswith("eb")) + A = A.substr(0, A.size() - 2); + // Trim the head + if (offset != StringRef::npos) + A = A.substr(offset); + + // Empty string means offset reached the end, which means it's valid. + if (A.empty()) + return Arch; + + // Only match non-marketing names + if (offset != StringRef::npos) { + // Must start with 'vN'. + if (A[0] != 'v' || !std::isdigit(A[1])) + return Error; + // Can't have an extra 'eb'. + if (A.find("eb") != StringRef::npos) + return Error; + } + + // Arch will either be a 'v' name (v7a) or a marketing name (xscale). + return A; +} + +unsigned ARMTargetParser::parseFPU(StringRef FPU) { + StringRef Syn = getFPUSynonym(FPU); + for (const auto F : FPUNames) { + if (Syn == F.Name) + return F.ID; + } + return ARM::FK_INVALID; +} + +// Allows partial match, ex. "v7a" matches "armv7a". +unsigned ARMTargetParser::parseArch(StringRef Arch) { + StringRef Syn = getArchSynonym(Arch); + for (const auto A : ARCHNames) { + if (StringRef(A.Name).endswith(Syn)) + return A.ID; + } + return ARM::AK_INVALID; +} + +unsigned ARMTargetParser::parseArchExt(StringRef ArchExt) { + for (const auto A : ARCHExtNames) { + if (ArchExt == A.Name) + return A.ID; + } + return ARM::AEK_INVALID; +} + +unsigned ARMTargetParser::parseCPUArch(StringRef CPU) { + for (const auto C : CPUNames) { + if (CPU == C.Name) + return C.ArchID; + } + return ARM::AK_INVALID; +} + +// ARM, Thumb, AArch64 +unsigned ARMTargetParser::parseArchISA(StringRef Arch) { + return StringSwitch<unsigned>(Arch) + .StartsWith("aarch64", ARM::IK_AARCH64) + .StartsWith("arm64", ARM::IK_AARCH64) + .StartsWith("thumb", ARM::IK_THUMB) + .StartsWith("arm", ARM::IK_ARM) + .Default(ARM::EK_INVALID); +} + +// Little/Big endian +unsigned ARMTargetParser::parseArchEndian(StringRef Arch) { + if (Arch.startswith("armeb") || + Arch.startswith("thumbeb") || + Arch.startswith("aarch64_be")) + return ARM::EK_BIG; + + if (Arch.startswith("arm") || Arch.startswith("thumb")) { + if (Arch.endswith("eb")) + return ARM::EK_BIG; + else + return ARM::EK_LITTLE; + } + + if (Arch.startswith("aarch64")) + return ARM::EK_LITTLE; + + return ARM::EK_INVALID; +} + +// Profile A/R/M +unsigned ARMTargetParser::parseArchProfile(StringRef Arch) { + Arch = getCanonicalArchName(Arch); + switch(parseArch(Arch)) { + case ARM::AK_ARMV6M: + case ARM::AK_ARMV7M: + case ARM::AK_ARMV6SM: + case ARM::AK_ARMV7EM: + return ARM::PK_M; + case ARM::AK_ARMV7R: + return ARM::PK_R; + case ARM::AK_ARMV7: + case ARM::AK_ARMV7A: + case ARM::AK_ARMV8A: + case ARM::AK_ARMV8_1A: + return ARM::PK_A; + } + return ARM::PK_INVALID; +} + +// Version number (ex. v7 = 7). +unsigned ARMTargetParser::parseArchVersion(StringRef Arch) { + Arch = getCanonicalArchName(Arch); + switch(parseArch(Arch)) { + case ARM::AK_ARMV2: + case ARM::AK_ARMV2A: + return 2; + case ARM::AK_ARMV3: + case ARM::AK_ARMV3M: + return 3; + case ARM::AK_ARMV4: + case ARM::AK_ARMV4T: + return 4; + case ARM::AK_ARMV5: + case ARM::AK_ARMV5T: + case ARM::AK_ARMV5TE: + case ARM::AK_IWMMXT: + case ARM::AK_IWMMXT2: + case ARM::AK_XSCALE: + case ARM::AK_ARMV5E: + case ARM::AK_ARMV5TEJ: + return 5; + case ARM::AK_ARMV6: + case ARM::AK_ARMV6J: + case ARM::AK_ARMV6K: + case ARM::AK_ARMV6T2: + case ARM::AK_ARMV6Z: + case ARM::AK_ARMV6ZK: + case ARM::AK_ARMV6M: + case ARM::AK_ARMV6SM: + case ARM::AK_ARMV6HL: + return 6; + case ARM::AK_ARMV7: + case ARM::AK_ARMV7A: + case ARM::AK_ARMV7R: + case ARM::AK_ARMV7M: + case ARM::AK_ARMV7L: + case ARM::AK_ARMV7HL: + case ARM::AK_ARMV7S: + case ARM::AK_ARMV7EM: + return 7; + case ARM::AK_ARMV8A: + case ARM::AK_ARMV8_1A: + return 8; + } + return 0; +} + +} // namespace llvm diff --git a/lib/Support/TargetRegistry.cpp b/lib/Support/TargetRegistry.cpp index f6918835f74b..eefef8ad8eaa 100644 --- a/lib/Support/TargetRegistry.cpp +++ b/lib/Support/TargetRegistry.cpp @@ -10,7 +10,6 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/Host.h" #include "llvm/Support/raw_ostream.h" #include <cassert> #include <vector> @@ -19,8 +18,8 @@ using namespace llvm; // Clients are responsible for avoid race conditions in registration. static Target *FirstTarget = nullptr; -TargetRegistry::iterator TargetRegistry::begin() { - return iterator(FirstTarget); +iterator_range<TargetRegistry::iterator> TargetRegistry::targets() { + return make_range(iterator(FirstTarget), iterator()); } const Target *TargetRegistry::lookupTarget(const std::string &ArchName, @@ -31,19 +30,17 @@ const Target *TargetRegistry::lookupTarget(const std::string &ArchName, // name, because it might be a backend that has no mapping to a target triple. const Target *TheTarget = nullptr; if (!ArchName.empty()) { - for (TargetRegistry::iterator it = TargetRegistry::begin(), - ie = TargetRegistry::end(); it != ie; ++it) { - if (ArchName == it->getName()) { - TheTarget = &*it; - break; - } - } + auto I = + std::find_if(targets().begin(), targets().end(), + [&](const Target &T) { return ArchName == T.getName(); }); - if (!TheTarget) { + if (I == targets().end()) { Error = "error: invalid target '" + ArchName + "'.\n"; return nullptr; } + TheTarget = &*I; + // Adjust the triple to match (if known), otherwise stick with the // given triple. Triple::ArchType Type = Triple::getArchTypeForLLVMName(ArchName); @@ -67,30 +64,28 @@ const Target *TargetRegistry::lookupTarget(const std::string &ArchName, const Target *TargetRegistry::lookupTarget(const std::string &TT, std::string &Error) { // Provide special warning when no targets are initialized. - if (begin() == end()) { + if (targets().begin() == targets().end()) { Error = "Unable to find target for this triple (no targets are registered)"; return nullptr; } - const Target *Matching = nullptr; - Triple::ArchType Arch = Triple(TT).getArch(); - for (iterator it = begin(), ie = end(); it != ie; ++it) { - if (it->ArchMatchFn(Arch)) { - if (Matching) { - Error = std::string("Cannot choose between targets \"") + - Matching->Name + "\" and \"" + it->Name + "\""; - return nullptr; - } - Matching = &*it; - } - } + Triple::ArchType Arch = Triple(TT).getArch(); + auto ArchMatch = [&](const Target &T) { return T.ArchMatchFn(Arch); }; + auto I = std::find_if(targets().begin(), targets().end(), ArchMatch); - if (!Matching) { + if (I == targets().end()) { Error = "No available targets are compatible with this triple, " "see -version for the available targets."; return nullptr; } - return Matching; + auto J = std::find_if(std::next(I), targets().end(), ArchMatch); + if (J != targets().end()) { + Error = std::string("Cannot choose between targets \"") + I->Name + + "\" and \"" + J->Name + "\""; + return nullptr; + } + + return &*I; } void TargetRegistry::RegisterTarget(Target &T, @@ -124,10 +119,8 @@ static int TargetArraySortFn(const std::pair<StringRef, const Target *> *LHS, void TargetRegistry::printRegisteredTargetsForVersion() { std::vector<std::pair<StringRef, const Target*> > Targets; size_t Width = 0; - for (TargetRegistry::iterator I = TargetRegistry::begin(), - E = TargetRegistry::end(); - I != E; ++I) { - Targets.push_back(std::make_pair(I->getName(), &*I)); + for (const auto &T : TargetRegistry::targets()) { + Targets.push_back(std::make_pair(T.getName(), &T)); Width = std::max(Width, Targets.back().first.size()); } array_pod_sort(Targets.begin(), Targets.end(), TargetArraySortFn); diff --git a/lib/Support/Timer.cpp b/lib/Support/Timer.cpp index e1a531a0af25..d7b65155d6ef 100644 --- a/lib/Support/Timer.cpp +++ b/lib/Support/Timer.cpp @@ -14,12 +14,10 @@ #include "llvm/Support/Timer.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Mutex.h" -#include "llvm/Support/MutexGuard.h" #include "llvm/Support/Process.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp index 0838e90baaec..a63426f88571 100644 --- a/lib/Support/Triple.cpp +++ b/lib/Support/Triple.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetParser.h" #include <cstring> using namespace llvm; @@ -23,6 +24,7 @@ const char *Triple::getArchTypeName(ArchType Kind) { case aarch64_be: return "aarch64_be"; case arm: return "arm"; case armeb: return "armeb"; + case bpf: return "bpf"; case hexagon: return "hexagon"; case mips: return "mips"; case mipsel: return "mipsel"; @@ -36,6 +38,7 @@ const char *Triple::getArchTypeName(ArchType Kind) { case amdgcn: return "amdgcn"; case sparc: return "sparc"; case sparcv9: return "sparcv9"; + case sparcel: return "sparcel"; case systemz: return "s390x"; case tce: return "tce"; case thumb: return "thumb"; @@ -86,10 +89,13 @@ const char *Triple::getArchTypePrefix(ArchType Kind) { case amdgcn: case r600: return "amdgpu"; + case bpf: return "bpf"; + case sparcv9: + case sparcel: case sparc: return "sparc"; - case systemz: return "systemz"; + case systemz: return "s390"; case x86: case x86_64: return "x86"; @@ -138,6 +144,7 @@ const char *Triple::getOSTypeName(OSType Kind) { switch (Kind) { case UnknownOS: return "unknown"; + case CloudABI: return "cloudabi"; case Darwin: return "darwin"; case DragonFly: return "dragonfly"; case FreeBSD: return "freebsd"; @@ -160,6 +167,7 @@ const char *Triple::getOSTypeName(OSType Kind) { case CUDA: return "cuda"; case NVCL: return "nvcl"; case AMDHSA: return "amdhsa"; + case PS4: return "ps4"; } llvm_unreachable("Invalid OSType"); @@ -191,6 +199,7 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { .Case("arm64", aarch64) // "arm64" is an alias for "aarch64" .Case("arm", arm) .Case("armeb", armeb) + .Case("bpf", bpf) .Case("mips", mips) .Case("mipsel", mipsel) .Case("mips64", mips64) @@ -204,6 +213,7 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { .Case("amdgcn", amdgcn) .Case("hexagon", hexagon) .Case("sparc", sparc) + .Case("sparcel", sparcel) .Case("sparcv9", sparcv9) .Case("systemz", systemz) .Case("tce", tce) @@ -227,55 +237,61 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { } static Triple::ArchType parseARMArch(StringRef ArchName) { - size_t offset = StringRef::npos; + unsigned ISA = ARMTargetParser::parseArchISA(ArchName); + unsigned ENDIAN = ARMTargetParser::parseArchEndian(ArchName); + Triple::ArchType arch = Triple::UnknownArch; - bool isThumb = ArchName.startswith("thumb"); - - if (ArchName.equals("arm")) - return Triple::arm; - if (ArchName.equals("armeb")) - return Triple::armeb; - if (ArchName.equals("thumb")) - return Triple::thumb; - if (ArchName.equals("thumbeb")) - return Triple::thumbeb; - if (ArchName.equals("arm64") || ArchName.equals("aarch64")) - return Triple::aarch64; - if (ArchName.equals("aarch64_be")) - return Triple::aarch64_be; - - if (ArchName.startswith("armv")) { - offset = 3; - if (ArchName.endswith("eb")) { - arch = Triple::armeb; - ArchName = ArchName.substr(0, ArchName.size() - 2); - } else + switch (ENDIAN) { + case ARM::EK_LITTLE: { + switch (ISA) { + case ARM::IK_ARM: arch = Triple::arm; - } else if (ArchName.startswith("armebv")) { - offset = 5; - arch = Triple::armeb; - } else if (ArchName.startswith("thumbv")) { - offset = 5; - if (ArchName.endswith("eb")) { - arch = Triple::thumbeb; - ArchName = ArchName.substr(0, ArchName.size() - 2); - } else + break; + case ARM::IK_THUMB: arch = Triple::thumb; - } else if (ArchName.startswith("thumbebv")) { - offset = 7; - arch = Triple::thumbeb; + break; + case ARM::IK_AARCH64: + arch = Triple::aarch64; + break; + } + break; } - return StringSwitch<Triple::ArchType>(ArchName.substr(offset)) - .Cases("v2", "v2a", isThumb ? Triple::UnknownArch : arch) - .Cases("v3", "v3m", isThumb ? Triple::UnknownArch : arch) - .Cases("v4", "v4t", arch) - .Cases("v5", "v5e", "v5t", "v5te", "v5tej", arch) - .Cases("v6", "v6j", "v6k", "v6m", arch) - .Cases("v6t2", "v6z", "v6zk", arch) - .Cases("v7", "v7a", "v7em", "v7l", arch) - .Cases("v7m", "v7r", "v7s", arch) - .Cases("v8", "v8a", arch) - .Default(Triple::UnknownArch); + case ARM::EK_BIG: { + switch (ISA) { + case ARM::IK_ARM: + arch = Triple::armeb; + break; + case ARM::IK_THUMB: + arch = Triple::thumbeb; + break; + case ARM::IK_AARCH64: + arch = Triple::aarch64_be; + break; + } + break; + } + } + + ArchName = ARMTargetParser::getCanonicalArchName(ArchName); + if (ArchName.empty()) + return Triple::UnknownArch; + + // Thumb only exists in v4+ + if (ISA == ARM::IK_THUMB && + (ArchName.startswith("v2") || ArchName.startswith("v3"))) + return Triple::UnknownArch; + + // Thumb only for v6m + unsigned Profile = ARMTargetParser::parseArchProfile(ArchName); + unsigned Version = ARMTargetParser::parseArchVersion(ArchName); + if (Profile == ARM::PK_M && Version == 6) { + if (ENDIAN == ARM::EK_BIG) + return Triple::thumbeb; + else + return Triple::thumb; + } + + return arch; } static Triple::ArchType parseArch(StringRef ArchName) { @@ -301,9 +317,11 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Case("mips64el", Triple::mips64el) .Case("r600", Triple::r600) .Case("amdgcn", Triple::amdgcn) + .Case("bpf", Triple::bpf) .Case("hexagon", Triple::hexagon) .Case("s390x", Triple::systemz) .Case("sparc", Triple::sparc) + .Case("sparcel", Triple::sparcel) .Cases("sparcv9", "sparc64", Triple::sparcv9) .Case("tce", Triple::tce) .Case("xcore", Triple::xcore) @@ -339,6 +357,7 @@ static Triple::VendorType parseVendor(StringRef VendorName) { static Triple::OSType parseOS(StringRef OSName) { return StringSwitch<Triple::OSType>(OSName) + .StartsWith("cloudabi", Triple::CloudABI) .StartsWith("darwin", Triple::Darwin) .StartsWith("dragonfly", Triple::DragonFly) .StartsWith("freebsd", Triple::FreeBSD) @@ -362,6 +381,7 @@ static Triple::OSType parseOS(StringRef OSName) { .StartsWith("cuda", Triple::CUDA) .StartsWith("nvcl", Triple::NVCL) .StartsWith("amdhsa", Triple::AMDHSA) + .StartsWith("ps4", Triple::PS4) .Default(Triple::UnknownOS); } @@ -390,31 +410,64 @@ static Triple::ObjectFormatType parseFormat(StringRef EnvironmentName) { } static Triple::SubArchType parseSubArch(StringRef SubArchName) { - if (SubArchName.endswith("eb")) - SubArchName = SubArchName.substr(0, SubArchName.size() - 2); - - return StringSwitch<Triple::SubArchType>(SubArchName) - .EndsWith("v8", Triple::ARMSubArch_v8) - .EndsWith("v8a", Triple::ARMSubArch_v8) - .EndsWith("v7", Triple::ARMSubArch_v7) - .EndsWith("v7a", Triple::ARMSubArch_v7) - .EndsWith("v7em", Triple::ARMSubArch_v7em) - .EndsWith("v7l", Triple::ARMSubArch_v7) - .EndsWith("v7m", Triple::ARMSubArch_v7m) - .EndsWith("v7r", Triple::ARMSubArch_v7) - .EndsWith("v7s", Triple::ARMSubArch_v7s) - .EndsWith("v6", Triple::ARMSubArch_v6) - .EndsWith("v6m", Triple::ARMSubArch_v6m) - .EndsWith("v6t2", Triple::ARMSubArch_v6t2) - .EndsWith("v5", Triple::ARMSubArch_v5) - .EndsWith("v5e", Triple::ARMSubArch_v5) - .EndsWith("v5t", Triple::ARMSubArch_v5) - .EndsWith("v5te", Triple::ARMSubArch_v5te) - .EndsWith("v4t", Triple::ARMSubArch_v4t) - .EndsWith("kalimba3", Triple::KalimbaSubArch_v3) - .EndsWith("kalimba4", Triple::KalimbaSubArch_v4) - .EndsWith("kalimba5", Triple::KalimbaSubArch_v5) - .Default(Triple::NoSubArch); + StringRef ARMSubArch = ARMTargetParser::getCanonicalArchName(SubArchName); + + // For now, this is the small part. Early return. + if (ARMSubArch.empty()) + return StringSwitch<Triple::SubArchType>(SubArchName) + .EndsWith("kalimba3", Triple::KalimbaSubArch_v3) + .EndsWith("kalimba4", Triple::KalimbaSubArch_v4) + .EndsWith("kalimba5", Triple::KalimbaSubArch_v5) + .Default(Triple::NoSubArch); + + // ARM sub arch. + switch(ARMTargetParser::parseArch(ARMSubArch)) { + case ARM::AK_ARMV4: + return Triple::NoSubArch; + case ARM::AK_ARMV4T: + return Triple::ARMSubArch_v4t; + case ARM::AK_ARMV5: + case ARM::AK_ARMV5T: + case ARM::AK_ARMV5E: + return Triple::ARMSubArch_v5; + case ARM::AK_ARMV5TE: + case ARM::AK_IWMMXT: + case ARM::AK_IWMMXT2: + case ARM::AK_XSCALE: + case ARM::AK_ARMV5TEJ: + return Triple::ARMSubArch_v5te; + case ARM::AK_ARMV6: + case ARM::AK_ARMV6J: + case ARM::AK_ARMV6Z: + return Triple::ARMSubArch_v6; + case ARM::AK_ARMV6K: + case ARM::AK_ARMV6ZK: + case ARM::AK_ARMV6HL: + return Triple::ARMSubArch_v6k; + case ARM::AK_ARMV6T2: + return Triple::ARMSubArch_v6t2; + case ARM::AK_ARMV6M: + case ARM::AK_ARMV6SM: + return Triple::ARMSubArch_v6m; + case ARM::AK_ARMV7: + case ARM::AK_ARMV7A: + case ARM::AK_ARMV7R: + case ARM::AK_ARMV7L: + case ARM::AK_ARMV7HL: + return Triple::ARMSubArch_v7; + case ARM::AK_ARMV7M: + return Triple::ARMSubArch_v7m; + case ARM::AK_ARMV7S: + return Triple::ARMSubArch_v7s; + case ARM::AK_ARMV7EM: + return Triple::ARMSubArch_v7em; + case ARM::AK_ARMV8A: + return Triple::ARMSubArch_v8; + case ARM::AK_ARMV8_1A: + return Triple::ARMSubArch_v8_1a; + default: + return Triple::NoSubArch; + } } static const char *getObjectFormatTypeName(Triple::ObjectFormatType Kind) { @@ -428,6 +481,30 @@ static const char *getObjectFormatTypeName(Triple::ObjectFormatType Kind) { } static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { + switch (T.getArch()) { + default: + break; + case Triple::hexagon: + case Triple::mips: + case Triple::mipsel: + case Triple::mips64: + case Triple::mips64el: + case Triple::r600: + case Triple::amdgcn: + case Triple::sparc: + case Triple::sparcv9: + case Triple::systemz: + case Triple::xcore: + case Triple::ppc64le: + return Triple::ELF; + + case Triple::ppc: + case Triple::ppc64: + if (T.isOSDarwin()) + return Triple::MachO; + return Triple::ELF; + } + if (T.isOSDarwin()) return Triple::MachO; else if (T.isOSWindows()) @@ -706,6 +783,14 @@ void Triple::getOSVersion(unsigned &Major, unsigned &Minor, unsigned &Micro) const { StringRef OSName = getOSName(); + // For Android, we care about the Android version rather than the Linux + // version. + if (getEnvironment() == Android) { + OSName = getEnvironmentName().substr(strlen("android")); + if (OSName.startswith("eabi")) + OSName = OSName.substr(strlen("eabi")); + } + // Assume that the OS portion of the triple starts with the canonical name. StringRef OSTypeName = getOSTypeName(getOS()); if (OSName.startswith(OSTypeName)) @@ -808,7 +893,11 @@ void Triple::setOS(OSType Kind) { } void Triple::setEnvironment(EnvironmentType Kind) { - setEnvironmentName(getEnvironmentTypeName(Kind)); + if (ObjectFormat == getDefaultFormat(*this)) + return setEnvironmentName(getEnvironmentTypeName(Kind)); + + setEnvironmentName((getEnvironmentTypeName(Kind) + Twine("-") + + getObjectFormatTypeName(ObjectFormat)).str()); } void Triple::setObjectFormat(ObjectFormatType Kind) { @@ -827,7 +916,7 @@ void Triple::setArchName(StringRef Str) { Triple += getVendorName(); Triple += "-"; Triple += getOSAndEnvironmentName(); - setTriple(Triple.str()); + setTriple(Triple); } void Triple::setVendorName(StringRef Str) { @@ -869,6 +958,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::ppc: case llvm::Triple::r600: case llvm::Triple::sparc: + case llvm::Triple::sparcel: case llvm::Triple::tce: case llvm::Triple::thumb: case llvm::Triple::thumbeb: @@ -883,6 +973,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: case llvm::Triple::amdgcn: + case llvm::Triple::bpf: case llvm::Triple::le64: case llvm::Triple::mips64: case llvm::Triple::mips64el: @@ -919,6 +1010,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::aarch64: case Triple::aarch64_be: case Triple::amdgcn: + case Triple::bpf: case Triple::msp430: case Triple::systemz: case Triple::ppc64le: @@ -939,6 +1031,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::ppc: case Triple::r600: case Triple::sparc: + case Triple::sparcel: case Triple::tce: case Triple::thumb: case Triple::thumbeb: @@ -975,11 +1068,13 @@ Triple Triple::get64BitArchVariant() const { case Triple::thumb: case Triple::thumbeb: case Triple::xcore: + case Triple::sparcel: T.setArch(UnknownArch); break; case Triple::aarch64: case Triple::aarch64_be: + case Triple::bpf: case Triple::le64: case Triple::amdil64: case Triple::amdgcn: @@ -1010,14 +1105,15 @@ Triple Triple::get64BitArchVariant() const { return T; } -// FIXME: tblgen this. const char *Triple::getARMCPUForArch(StringRef MArch) const { if (MArch.empty()) MArch = getArchName(); + // Some defaults are forced. switch (getOS()) { case llvm::Triple::FreeBSD: case llvm::Triple::NetBSD: + // FIXME: This doesn't work on BE/thumb variants. if (MArch == "armv6") return "arm1176jzf-s"; break; @@ -1028,51 +1124,16 @@ const char *Triple::getARMCPUForArch(StringRef MArch) const { break; } - const char *result = nullptr; - size_t offset = StringRef::npos; - if (MArch.startswith("arm")) - offset = 3; - if (MArch.startswith("thumb")) - offset = 5; - if (offset != StringRef::npos && MArch.substr(offset, 2) == "eb") - offset += 2; - if (MArch.endswith("eb")) - MArch = MArch.substr(0, MArch.size() - 2); - if (offset != StringRef::npos) - result = llvm::StringSwitch<const char *>(MArch.substr(offset)) - .Cases("v2", "v2a", "arm2") - .Case("v3", "arm6") - .Case("v3m", "arm7m") - .Case("v4", "strongarm") - .Case("v4t", "arm7tdmi") - .Cases("v5", "v5t", "arm10tdmi") - .Cases("v5e", "v5te", "arm1022e") - .Case("v5tej", "arm926ej-s") - .Cases("v6", "v6k", "arm1136jf-s") - .Case("v6j", "arm1136j-s") - .Cases("v6z", "v6zk", "arm1176jzf-s") - .Case("v6t2", "arm1156t2-s") - .Cases("v6m", "v6-m", "cortex-m0") - .Cases("v7", "v7a", "v7-a", "v7l", "v7-l", "cortex-a8") - .Cases("v7s", "v7-s", "swift") - .Cases("v7r", "v7-r", "cortex-r4") - .Cases("v7m", "v7-m", "cortex-m3") - .Cases("v7em", "v7e-m", "cortex-m4") - .Cases("v8", "v8a", "v8-a", "cortex-a53") - .Default(nullptr); - else - result = llvm::StringSwitch<const char *>(MArch) - .Case("ep9312", "ep9312") - .Case("iwmmxt", "iwmmxt") - .Case("xscale", "xscale") - .Default(nullptr); - - if (result) - return result; - - // If all else failed, return the most base CPU with thumb interworking - // supported by LLVM. - // FIXME: Should warn once that we're falling back. + MArch = ARMTargetParser::getCanonicalArchName(MArch); + if (MArch.empty()) + return nullptr; + + const char *CPU = ARMTargetParser::getDefaultCPU(MArch); + if (CPU) + return CPU; + + // If no specific architecture version is requested, return the minimum CPU + // required by the OS and environment. switch (getOS()) { case llvm::Triple::NetBSD: switch (getEnvironment()) { @@ -1084,6 +1145,8 @@ const char *Triple::getARMCPUForArch(StringRef MArch) const { default: return "strongarm"; } + case llvm::Triple::NaCl: + return "cortex-a8"; default: switch (getEnvironment()) { case llvm::Triple::EABIHF: @@ -1093,4 +1156,6 @@ const char *Triple::getARMCPUForArch(StringRef MArch) const { return "arm7tdmi"; } } + + llvm_unreachable("invalid arch name"); } diff --git a/lib/Support/Twine.cpp b/lib/Support/Twine.cpp index 56ed964a50eb..020dd9596d9c 100644 --- a/lib/Support/Twine.cpp +++ b/lib/Support/Twine.cpp @@ -28,13 +28,6 @@ void Twine::toVector(SmallVectorImpl<char> &Out) const { print(OS); } -StringRef Twine::toStringRef(SmallVectorImpl<char> &Out) const { - if (isSingleStringRef()) - return getSingleStringRef(); - toVector(Out); - return StringRef(Out.data(), Out.size()); -} - StringRef Twine::toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const { if (isUnary()) { switch (getLHSKind()) { @@ -72,6 +65,9 @@ void Twine::printOneChild(raw_ostream &OS, Child Ptr, case Twine::StringRefKind: OS << *Ptr.stringRef; break; + case Twine::SmallStringKind: + OS << *Ptr.smallString; + break; case Twine::CharKind: OS << Ptr.character; break; @@ -122,6 +118,9 @@ void Twine::printOneChildRepr(raw_ostream &OS, Child Ptr, OS << "stringref:\"" << Ptr.stringRef << "\""; break; + case Twine::SmallStringKind: + OS << "smallstring:\"" << *Ptr.smallString << "\""; + break; case Twine::CharKind: OS << "char:\"" << Ptr.character << "\""; break; diff --git a/lib/Support/Unix/COM.inc b/lib/Support/Unix/COM.inc new file mode 100644 index 000000000000..5b71de74ebf3 --- /dev/null +++ b/lib/Support/Unix/COM.inc @@ -0,0 +1,27 @@ +//===- llvm/Support/Unix/COM.inc - Unix COM Implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix portion of COM support. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +namespace llvm { +namespace sys { + +InitializeCOMRAII::InitializeCOMRAII(COMThreadingMode Threading, + bool SpeedOverMemory) {} + +InitializeCOMRAII::~InitializeCOMRAII() {} +} +} diff --git a/lib/Support/Unix/Host.inc b/lib/Support/Unix/Host.inc index 519f2a1fe687..457217125a22 100644 --- a/lib/Support/Unix/Host.inc +++ b/lib/Support/Unix/Host.inc @@ -35,29 +35,15 @@ static std::string getOSVersion() { } std::string sys::getDefaultTargetTriple() { - StringRef TargetTripleString(LLVM_DEFAULT_TARGET_TRIPLE); - std::pair<StringRef, StringRef> ArchSplit = TargetTripleString.split('-'); - - // Normalize the arch, since the target triple may not actually match the - // target. - std::string Arch = ArchSplit.first; - - std::string Triple(Arch); - Triple += '-'; - Triple += ArchSplit.second; - - // Force i<N>86 to i386. - if (Triple[0] == 'i' && isdigit(Triple[1]) && - Triple[2] == '8' && Triple[3] == '6') - Triple[1] = '3'; + std::string TargetTripleString(LLVM_DEFAULT_TARGET_TRIPLE); // On darwin, we want to update the version to match that of the // target. - std::string::size_type DarwinDashIdx = Triple.find("-darwin"); + std::string::size_type DarwinDashIdx = TargetTripleString.find("-darwin"); if (DarwinDashIdx != std::string::npos) { - Triple.resize(DarwinDashIdx + strlen("-darwin")); - Triple += getOSVersion(); + TargetTripleString.resize(DarwinDashIdx + strlen("-darwin")); + TargetTripleString += getOSVersion(); } - return Triple::normalize(Triple); + return Triple::normalize(TargetTripleString); } diff --git a/lib/Support/Unix/Process.inc b/lib/Support/Unix/Process.inc index 530f86cf9070..df13bd221739 100644 --- a/lib/Support/Unix/Process.inc +++ b/lib/Support/Unix/Process.inc @@ -39,6 +39,9 @@ !defined(__OpenBSD__) && !defined(__Bitrig__) #include <malloc.h> #endif +#if defined(HAVE_MALLCTL) +#include <malloc_np.h> +#endif #ifdef HAVE_MALLOC_MALLOC_H #include <malloc/malloc.h> #endif @@ -98,6 +101,12 @@ size_t Process::GetMallocUsage() { malloc_statistics_t Stats; malloc_zone_statistics(malloc_default_zone(), &Stats); return Stats.size_in_use; // darwin +#elif defined(HAVE_MALLCTL) + size_t alloc, sz; + sz = sizeof(size_t); + if (mallctl("stats.allocated", &alloc, &sz, NULL, 0) == 0) + return alloc; + return 0; #elif defined(HAVE_SBRK) // Note this is only an approximation and more closely resembles // the value returned by mallinfo in the arena field. @@ -105,8 +114,7 @@ size_t Process::GetMallocUsage() { char *EndOfMemory = (char*)sbrk(0); if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) return EndOfMemory - StartOfMemory; - else - return 0; + return 0; #else #warning Cannot get malloc info on this platform return 0; @@ -191,8 +199,8 @@ public: } private: - FDCloser(const FDCloser &) LLVM_DELETED_FUNCTION; - void operator=(const FDCloser &) LLVM_DELETED_FUNCTION; + FDCloser(const FDCloser &) = delete; + void operator=(const FDCloser &) = delete; int &FD; bool KeepOpen; diff --git a/lib/Support/Unix/Program.inc b/lib/Support/Unix/Program.inc index 0f45df1a0da0..5816fb812e9f 100644 --- a/lib/Support/Unix/Program.inc +++ b/lib/Support/Unix/Program.inc @@ -18,10 +18,11 @@ #include "Unix.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" -#include <llvm/Config/config.h> #if HAVE_SYS_STAT_H #include <sys/stat.h> #endif @@ -42,7 +43,18 @@ #define _RESTRICT_KYWD #endif #include <spawn.h> -#if !defined(__APPLE__) + +#if defined(__APPLE__) +#include <TargetConditionals.h> +#endif + +#if defined(__APPLE__) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) +#define USE_NSGETENVIRON 1 +#else +#define USE_NSGETENVIRON 0 +#endif + +#if !USE_NSGETENVIRON extern char **environ; #else #include <crt_externs.h> // _NSGetEnviron @@ -217,7 +229,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, } if (!envp) -#if !defined(__APPLE__) +#if !USE_NSGETENVIRON envp = const_cast<const char **>(environ); #else // environ is missing in dylibs. diff --git a/lib/Support/Unix/Signals.inc b/lib/Support/Unix/Signals.inc index e8f4643dc8a7..bfe2a3a380ed 100644 --- a/lib/Support/Unix/Signals.inc +++ b/lib/Support/Unix/Signals.inc @@ -14,6 +14,7 @@ #include "Unix.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Format.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/ManagedStatic.h" @@ -111,6 +112,12 @@ static void RegisterHandler(int Signal) { } static void RegisterHandlers() { + // We need to dereference the signals mutex during handler registration so + // that we force its construction. This is to prevent the first use being + // during handling an actual signal because you can't safely call new in a + // signal handler. + *SignalsMutex; + // If the handlers are already registered, we're done. if (NumRegisteredSignals != 0) return; @@ -132,6 +139,11 @@ static void UnregisterHandlers() { /// NB: This must be an async signal safe function. It cannot allocate or free /// memory, even in debug builds. static void RemoveFilesToRemove() { + // Avoid constructing ManagedStatic in the signal handler. + // If FilesToRemove is not constructed, there are no files to remove. + if (!FilesToRemove.isConstructed()) + return; + // We avoid iterators in case of debug iterators that allocate or release // memory. std::vector<std::string>& FilesToRemoveRef = *FilesToRemove; @@ -193,10 +205,11 @@ static RETSIGTYPE SignalHandler(int Sig) { } // Otherwise if it is a fault (like SEGV) run any handler. - std::vector<std::pair<void (*)(void *), void *>>& CallBacksToRunRef = - *CallBacksToRun; - for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i) - CallBacksToRunRef[i].first(CallBacksToRunRef[i].second); + if (CallBacksToRun.isConstructed()) { + auto &CallBacksToRunRef = *CallBacksToRun; + for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i) + CallBacksToRunRef[i].first(CallBacksToRunRef[i].second); + } #ifdef __s390__ // On S/390, certain signals are delivered with PSW Address pointing to @@ -324,7 +337,8 @@ static bool findModulesAndOffsets(void **StackTrace, int Depth, } #endif -static bool printSymbolizedStackTrace(void **StackTrace, int Depth, FILE *FD) { +static bool printSymbolizedStackTrace(void **StackTrace, int Depth, + llvm::raw_ostream &OS) { // FIXME: Subtract necessary number from StackTrace entries to turn return addresses // into actual instruction addresses. // Use llvm-symbolizer tool to symbolize the stack traces. @@ -382,7 +396,7 @@ static bool printSymbolizedStackTrace(void **StackTrace, int Depth, FILE *FD) { int frame_no = 0; for (int i = 0; i < Depth; i++) { if (!Modules[i]) { - fprintf(FD, "#%d %p\n", frame_no++, StackTrace[i]); + OS << format("#%d %p\n", frame_no++, StackTrace[i]); continue; } // Read pairs of lines (function name and file/line info) until we @@ -393,17 +407,17 @@ static bool printSymbolizedStackTrace(void **StackTrace, int Depth, FILE *FD) { StringRef FunctionName = *CurLine++; if (FunctionName.empty()) break; - fprintf(FD, "#%d %p ", frame_no++, StackTrace[i]); + OS << format("#%d %p ", frame_no++, StackTrace[i]); if (!FunctionName.startswith("??")) - fprintf(FD, "%s ", FunctionName.str().c_str()); + OS << format("%s ", FunctionName.str().c_str()); if (CurLine == Lines.end()) return false; StringRef FileLineInfo = *CurLine++; if (!FileLineInfo.startswith("??")) - fprintf(FD, "%s", FileLineInfo.str().c_str()); + OS << format("%s", FileLineInfo.str().c_str()); else - fprintf(FD, "(%s+%p)", Modules[i], (void *)Offsets[i]); - fprintf(FD, "\n"); + OS << format("(%s+%p)", Modules[i], (void *)Offsets[i]); + OS << "\n"; } } return true; @@ -415,13 +429,13 @@ static bool printSymbolizedStackTrace(void **StackTrace, int Depth, FILE *FD) { // // On glibc systems we have the 'backtrace' function, which works nicely, but // doesn't demangle symbols. -void llvm::sys::PrintStackTrace(FILE *FD) { +void llvm::sys::PrintStackTrace(raw_ostream &OS) { #if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) static void* StackTrace[256]; // Use backtrace() to output a backtrace on Linux systems with glibc. int depth = backtrace(StackTrace, static_cast<int>(array_lengthof(StackTrace))); - if (printSymbolizedStackTrace(StackTrace, depth, FD)) + if (printSymbolizedStackTrace(StackTrace, depth, OS)) return; #if HAVE_DLFCN_H && __GNUG__ int width = 0; @@ -441,34 +455,34 @@ void llvm::sys::PrintStackTrace(FILE *FD) { Dl_info dlinfo; dladdr(StackTrace[i], &dlinfo); - fprintf(FD, "%-2d", i); + OS << format("%-2d", i); const char* name = strrchr(dlinfo.dli_fname, '/'); - if (!name) fprintf(FD, " %-*s", width, dlinfo.dli_fname); - else fprintf(FD, " %-*s", width, name+1); + if (!name) OS << format(" %-*s", width, dlinfo.dli_fname); + else OS << format(" %-*s", width, name+1); - fprintf(FD, " %#0*lx", - (int)(sizeof(void*) * 2) + 2, (unsigned long)StackTrace[i]); + OS << format(" %#0*lx", (int)(sizeof(void*) * 2) + 2, + (unsigned long)StackTrace[i]); if (dlinfo.dli_sname != nullptr) { - fputc(' ', FD); + OS << ' '; # if HAVE_CXXABI_H int res; char* d = abi::__cxa_demangle(dlinfo.dli_sname, nullptr, nullptr, &res); # else char* d = NULL; # endif - if (!d) fputs(dlinfo.dli_sname, FD); - else fputs(d, FD); + if (!d) OS << dlinfo.dli_sname; + else OS << d; free(d); // 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)); + OS << format(" + %u",(unsigned)((char*)StackTrace[i]- + (char*)dlinfo.dli_saddr)); } - fputc('\n', FD); + OS << '\n'; } #else backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); @@ -477,17 +491,19 @@ void llvm::sys::PrintStackTrace(FILE *FD) { } static void PrintStackTraceSignalHandler(void *) { - PrintStackTrace(stderr); + PrintStackTrace(llvm::errs()); } +void llvm::sys::DisableSystemDialogsOnCrash() {} + /// PrintStackTraceOnErrorSignal - When an error signal (such as SIGABRT or /// SIGSEGV) is delivered to the process, print a stack trace and then exit. -void llvm::sys::PrintStackTraceOnErrorSignal() { +void llvm::sys::PrintStackTraceOnErrorSignal(bool DisableCrashReporting) { AddSignalHandler(PrintStackTraceSignalHandler, nullptr); #if defined(__APPLE__) && defined(ENABLE_CRASH_OVERRIDES) // Environment variable to disable any kind of crash dialog. - if (getenv("LLVM_DISABLE_CRASH_REPORT")) { + if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) { mach_port_t self = mach_task_self(); exception_mask_t mask = EXC_MASK_CRASH; diff --git a/lib/Support/Valgrind.cpp b/lib/Support/Valgrind.cpp index 2c6d6aaadfff..facf8d927ecd 100644 --- a/lib/Support/Valgrind.cpp +++ b/lib/Support/Valgrind.cpp @@ -53,7 +53,6 @@ void llvm::sys::ValgrindDiscardTranslations(const void *Addr, size_t Len) { #endif // !HAVE_VALGRIND_VALGRIND_H -#if LLVM_ENABLE_THREADS != 0 && !defined(NDEBUG) // These functions require no implementation, tsan just looks at the arguments // they're called with. However, they are required to be weak as some other // application or library may already be providing these definitions for the @@ -72,4 +71,4 @@ void AnnotateIgnoreWritesBegin(const char *file, int line) {} LLVM_ATTRIBUTE_WEAK void AnnotateIgnoreWritesEnd(const char *file, int line); void AnnotateIgnoreWritesEnd(const char *file, int line) {} } -#endif + diff --git a/lib/Support/Windows/COM.inc b/lib/Support/Windows/COM.inc new file mode 100644 index 000000000000..0c50d6f74ea3 --- /dev/null +++ b/lib/Support/Windows/COM.inc @@ -0,0 +1,37 @@ +//===- llvm/Support/Windows/COM.inc - Windows COM Implementation *- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Windows portion of COM support. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Windows code. +//===----------------------------------------------------------------------===// + +#include <objbase.h> + +namespace llvm { +namespace sys { + +InitializeCOMRAII::InitializeCOMRAII(COMThreadingMode Threading, + bool SpeedOverMemory) { + DWORD Coinit = 0; + if (Threading == COMThreadingMode::SingleThreaded) + Coinit |= COINIT_APARTMENTTHREADED; + else + Coinit |= COINIT_MULTITHREADED; + if (SpeedOverMemory) + Coinit |= COINIT_SPEED_OVER_MEMORY; + ::CoInitializeEx(nullptr, Coinit); +} + +InitializeCOMRAII::~InitializeCOMRAII() { ::CoUninitialize(); } +} +} diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc index d8b5702bf156..72da7c5fec32 100644 --- a/lib/Support/Windows/Path.inc +++ b/lib/Support/Windows/Path.inc @@ -46,10 +46,6 @@ using llvm::sys::windows::UTF8ToUTF16; using llvm::sys::windows::UTF16ToUTF8; using llvm::sys::path::widenPath; -static std::error_code windows_error(DWORD E) { - return mapWindowsError(E); -} - static bool is_separator(const wchar_t value) { switch (value) { case L'\\': @@ -83,7 +79,7 @@ std::error_code widenPath(const Twine &Path8, else { CurPathLen = ::GetCurrentDirectoryW(0, NULL); if (CurPathLen == 0) - return windows_error(::GetLastError()); + return mapWindowsError(::GetLastError()); } // Would the absolute path be longer than our limit? @@ -174,7 +170,7 @@ std::error_code current_path(SmallVectorImpl<char> &result) { // A zero return value indicates a failure other than insufficient space. if (len == 0) - return windows_error(::GetLastError()); + return mapWindowsError(::GetLastError()); // If there's insufficient space, the len returned is larger than the len // given. @@ -195,7 +191,7 @@ std::error_code create_directory(const Twine &path, bool IgnoreExisting) { if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { DWORD LastError = ::GetLastError(); if (LastError != ERROR_ALREADY_EXISTS || !IgnoreExisting) - return windows_error(LastError); + return mapWindowsError(LastError); } return std::error_code(); @@ -212,7 +208,7 @@ std::error_code create_link(const Twine &to, const Twine &from) { return ec; if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) - return windows_error(::GetLastError()); + return mapWindowsError(::GetLastError()); return std::error_code(); } @@ -232,14 +228,14 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) { if (ST.type() == file_type::directory_file) { if (!::RemoveDirectoryW(c_str(path_utf16))) { - std::error_code EC = windows_error(::GetLastError()); + std::error_code EC = mapWindowsError(::GetLastError()); if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) return EC; } return std::error_code(); } if (!::DeleteFileW(c_str(path_utf16))) { - std::error_code EC = windows_error(::GetLastError()); + std::error_code EC = mapWindowsError(::GetLastError()); if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) return EC; } @@ -261,6 +257,7 @@ std::error_code rename(const Twine &from, const Twine &to) { MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) return std::error_code(); DWORD LastError = ::GetLastError(); + ec = mapWindowsError(LastError); if (LastError != ERROR_ACCESS_DENIED) break; // Retry MoveFile() at ACCESS_DENIED. @@ -294,7 +291,7 @@ std::error_code access(const Twine &Path, AccessMode Mode) { DWORD LastError = ::GetLastError(); if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND) - return windows_error(LastError); + return mapWindowsError(LastError); return errc::no_such_file_or_directory; } @@ -358,7 +355,7 @@ static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { case FILE_TYPE_UNKNOWN: { DWORD Err = ::GetLastError(); if (Err != NO_ERROR) - return windows_error(Err); + return mapWindowsError(Err); Result = file_status(file_type::type_unknown); return std::error_code(); } @@ -397,7 +394,7 @@ handle_status_error: Result = file_status(file_type::type_unknown); else Result = file_status(file_type::status_error); - return windows_error(LastError); + return mapWindowsError(LastError); } std::error_code status(const Twine &path, file_status &result) { @@ -454,7 +451,7 @@ std::error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { FT.dwHighDateTime = UI.HighPart; HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); if (!SetFileTime(FileHandle, NULL, &FT, &FT)) - return windows_error(::GetLastError()); + return mapWindowsError(::GetLastError()); return std::error_code(); } @@ -481,7 +478,7 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, (Offset + Size) & 0xffffffff, 0); if (FileMappingHandle == NULL) { - std::error_code ec = windows_error(GetLastError()); + std::error_code ec = mapWindowsError(GetLastError()); return ec; } @@ -497,7 +494,7 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, Offset & 0xffffffff, Size); if (Mapping == NULL) { - std::error_code ec = windows_error(GetLastError()); + std::error_code ec = mapWindowsError(GetLastError()); ::CloseHandle(FileMappingHandle); return ec; } @@ -506,7 +503,7 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, MEMORY_BASIC_INFORMATION mbi; SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi)); if (Result == 0) { - std::error_code ec = windows_error(GetLastError()); + std::error_code ec = mapWindowsError(GetLastError()); ::UnmapViewOfFile(Mapping); ::CloseHandle(FileMappingHandle); return ec; @@ -575,7 +572,7 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it, WIN32_FIND_DATAW FirstFind; ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind)); if (!FindHandle) - return windows_error(::GetLastError()); + return mapWindowsError(::GetLastError()); size_t FilenameLen = ::wcslen(FirstFind.cFileName); while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || @@ -586,7 +583,7 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it, // Check for end. if (LastError == ERROR_NO_MORE_FILES) return detail::directory_iterator_destruct(it); - return windows_error(LastError); + return mapWindowsError(LastError); } else FilenameLen = ::wcslen(FirstFind.cFileName); @@ -599,8 +596,8 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it, it.IterationHandle = intptr_t(FindHandle.take()); SmallString<128> directory_entry_path(path); - path::append(directory_entry_path, directory_entry_name_utf8.str()); - it.CurrentEntry = directory_entry(directory_entry_path.str()); + path::append(directory_entry_path, directory_entry_name_utf8); + it.CurrentEntry = directory_entry(directory_entry_path); return std::error_code(); } @@ -621,7 +618,7 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { // Check for end. if (LastError == ERROR_NO_MORE_FILES) return detail::directory_iterator_destruct(it); - return windows_error(LastError); + return mapWindowsError(LastError); } size_t FilenameLen = ::wcslen(FindData.cFileName); @@ -651,7 +648,7 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (H == INVALID_HANDLE_VALUE) { DWORD LastError = ::GetLastError(); - std::error_code EC = windows_error(LastError); + std::error_code EC = mapWindowsError(LastError); // Provide a better error message when trying to open directories. // This only runs if we failed to open the file, so there is probably // no performances issues. @@ -665,7 +662,7 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD) { int FD = ::_open_osfhandle(intptr_t(H), 0); if (FD == -1) { ::CloseHandle(H); - return windows_error(ERROR_INVALID_HANDLE); + return mapWindowsError(ERROR_INVALID_HANDLE); } ResultFD = FD; @@ -701,7 +698,7 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD, if (H == INVALID_HANDLE_VALUE) { DWORD LastError = ::GetLastError(); - std::error_code EC = windows_error(LastError); + std::error_code EC = mapWindowsError(LastError); // Provide a better error message when trying to open directories. // This only runs if we failed to open the file, so there is probably // no performances issues. @@ -722,7 +719,7 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD, int FD = ::_open_osfhandle(intptr_t(H), OpenFlags); if (FD == -1) { ::CloseHandle(H); - return windows_error(ERROR_INVALID_HANDLE); + return mapWindowsError(ERROR_INVALID_HANDLE); } ResultFD = FD; @@ -799,7 +796,7 @@ std::error_code UTF8ToUTF16(llvm::StringRef utf8, utf8.size(), utf16.begin(), 0); if (len == 0) - return windows_error(::GetLastError()); + return mapWindowsError(::GetLastError()); utf16.reserve(len + 1); utf16.set_size(len); @@ -808,7 +805,7 @@ std::error_code UTF8ToUTF16(llvm::StringRef utf8, utf8.size(), utf16.begin(), utf16.size()); if (len == 0) - return windows_error(::GetLastError()); + return mapWindowsError(::GetLastError()); } // Make utf16 null terminated. @@ -828,7 +825,7 @@ std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16, 0, NULL, NULL); if (len == 0) - return windows_error(::GetLastError()); + return mapWindowsError(::GetLastError()); utf8.reserve(len); utf8.set_size(len); @@ -838,7 +835,7 @@ std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16, utf8.size(), NULL, NULL); if (len == 0) - return windows_error(::GetLastError()); + return mapWindowsError(::GetLastError()); } // Make utf8 null terminated. diff --git a/lib/Support/Windows/Process.inc b/lib/Support/Windows/Process.inc index 854eac73f230..8164956d1511 100644 --- a/lib/Support/Windows/Process.inc +++ b/lib/Support/Windows/Process.inc @@ -156,10 +156,6 @@ Optional<std::string> Process::GetEnv(StringRef Name) { return std::string(Res.data()); } -static std::error_code windows_error(DWORD E) { - return mapWindowsError(E); -} - static void AllocateAndPush(const SmallVectorImpl<char> &S, SmallVectorImpl<const char *> &Vector, SpecificBumpPtrAllocator<char> &Allocator) { @@ -235,7 +231,7 @@ Process::GetArgumentVector(SmallVectorImpl<const char *> &Args, wchar_t **UnicodeCommandLine = CommandLineToArgvW(GetCommandLineW(), &ArgCount); if (!UnicodeCommandLine) - return windows_error(::GetLastError()); + return mapWindowsError(::GetLastError()); Args.reserve(ArgCount); std::error_code ec; @@ -329,6 +325,16 @@ class DefaultColors }; DefaultColors defaultColors; + +WORD fg_color(WORD color) { + return color & (FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_INTENSITY | FOREGROUND_RED); +} + +WORD bg_color(WORD color) { + return color & (BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_INTENSITY | BACKGROUND_RED); +} } bool Process::ColorNeedsFlush() { @@ -350,6 +356,7 @@ const char *Process::OutputBold(bool bg) { const char *Process::OutputColor(char code, bool bold, bool bg) { if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7]; + WORD current = DefaultColors::GetCurrentColor(); WORD colors; if (bg) { colors = ((code&1) ? BACKGROUND_RED : 0) | @@ -357,12 +364,14 @@ const char *Process::OutputColor(char code, bool bold, bool bg) { ((code&4) ? BACKGROUND_BLUE : 0); if (bold) colors |= BACKGROUND_INTENSITY; + colors |= fg_color(current); } else { colors = ((code&1) ? FOREGROUND_RED : 0) | ((code&2) ? FOREGROUND_GREEN : 0 ) | ((code&4) ? FOREGROUND_BLUE : 0); if (bold) colors |= FOREGROUND_INTENSITY; + colors |= bg_color(current); } SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); return 0; diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc index c3700774514c..75685de45547 100644 --- a/lib/Support/Windows/Program.inc +++ b/lib/Support/Windows/Program.inc @@ -434,7 +434,8 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, DWORD status; BOOL rc = GetExitCodeProcess(PI.ProcessHandle, &status); DWORD err = GetLastError(); - CloseHandle(PI.ProcessHandle); + if (err != ERROR_INVALID_HANDLE) + CloseHandle(PI.ProcessHandle); if (!rc) { SetLastError(err); diff --git a/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc index 35ba6f8e1bba..6006499f4da2 100644 --- a/lib/Support/Windows/Signals.inc +++ b/lib/Support/Windows/Signals.inc @@ -10,12 +10,15 @@ // This file provides the Win32 specific implementation of the Signals class. // //===----------------------------------------------------------------------===// - #include "llvm/Support/FileSystem.h" #include <algorithm> +#include <signal.h> #include <stdio.h> #include <vector> +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + // The Windows.h header must be after LLVM and standard headers. #include "WindowsSupport.h" @@ -165,13 +168,97 @@ static std::vector<std::string> *FilesToRemove = NULL; static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0; static bool RegisteredUnhandledExceptionFilter = false; static bool CleanupExecuted = false; -static bool ExitOnUnhandledExceptions = false; static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; // Windows creates a new thread to execute the console handler when an event // (such as CTRL/C) occurs. This causes concurrency issues with the above // globals which this critical section addresses. static CRITICAL_SECTION CriticalSection; +static bool CriticalSectionInitialized = false; + +static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess, + HANDLE hThread, STACKFRAME64 &StackFrame, + CONTEXT *Context) { + DWORD machineType; +#if defined(_M_X64) + machineType = IMAGE_FILE_MACHINE_AMD64; +#else + machineType = IMAGE_FILE_MACHINE_I386; +#endif + + // Initialize the symbol handler. + SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); + SymInitialize(hProcess, NULL, TRUE); + + while (true) { + if (!StackWalk64(machineType, hProcess, hThread, &StackFrame, Context, NULL, + SymFunctionTableAccess64, SymGetModuleBase64, NULL)) { + break; + } + + if (StackFrame.AddrFrame.Offset == 0) + break; + + using namespace llvm; + // Print the PC in hexadecimal. + DWORD64 PC = StackFrame.AddrPC.Offset; +#if defined(_M_X64) + OS << format("0x%016llX", PC); +#elif defined(_M_IX86) + OS << format("0x%08lX", static_cast<DWORD>(PC)); +#endif + +// Print the parameters. Assume there are four. +#if defined(_M_X64) + OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)", + StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2], + StackFrame.Params[3]); +#elif defined(_M_IX86) + OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", + static_cast<DWORD>(StackFrame.Params[0]), + static_cast<DWORD>(StackFrame.Params[1]), + static_cast<DWORD>(StackFrame.Params[2]), + static_cast<DWORD>(StackFrame.Params[3])); +#endif + // Verify the PC belongs to a module in this process. + if (!SymGetModuleBase64(hProcess, PC)) { + OS << " <unknown module>\n"; + continue; + } + + // Print the symbol name. + char buffer[512]; + IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer); + memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); + symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); + + DWORD64 dwDisp; + if (!SymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { + OS << '\n'; + continue; + } + + buffer[511] = 0; + if (dwDisp > 0) + OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name, + dwDisp); + else + OS << format(", %s", (const char*)symbol->Name); + + // Print the source file and line number information. + IMAGEHLP_LINE64 line = {}; + DWORD dwLineDisp; + line.SizeOfStruct = sizeof(line); + if (SymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { + OS << format(", %s, line %lu", line.FileName, line.LineNumber); + if (dwLineDisp > 0) + OS << format(" + 0x%lX byte(s)", dwLineDisp); + } + + OS << '\n'; + } +} namespace llvm { @@ -184,7 +271,8 @@ namespace llvm { /// AvoidMessageBoxHook - Emulates hitting "retry" from an "abort, retry, /// ignore" CRT debug report dialog. "retry" raises an exception which /// ultimately triggers our stack dumper. -static int AvoidMessageBoxHook(int ReportType, char *Message, int *Return) { +static LLVM_ATTRIBUTE_UNUSED int +AvoidMessageBoxHook(int ReportType, char *Message, int *Return) { // Set *Return to the retry code for the return value of _CrtDbgReport: // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx // This may also trigger just-in-time debugging via DebugBreak(). @@ -196,6 +284,22 @@ static int AvoidMessageBoxHook(int ReportType, char *Message, int *Return) { #endif +extern "C" void HandleAbort(int Sig) { + if (Sig == SIGABRT) { + LLVM_BUILTIN_TRAP; + } +} + +static void InitializeThreading() { + if (CriticalSectionInitialized) + return; + + // Now's the time to create the critical section. This is the first time + // through here, and there's only one thread. + InitializeCriticalSection(&CriticalSection); + CriticalSectionInitialized = true; +} + static void RegisterHandler() { #if __MINGW32__ && !defined(__MINGW64_VERSION_MAJOR) // On MinGW.org, we need to load up the symbols explicitly, because the @@ -214,9 +318,7 @@ static void RegisterHandler() { return; } - // Now's the time to create the critical section. This is the first time - // through here, and there's only one thread. - InitializeCriticalSection(&CriticalSection); + InitializeThreading(); // Enter it immediately. Now if someone hits CTRL/C, the console handler // can't proceed until the globals are updated. @@ -226,17 +328,6 @@ static void RegisterHandler() { OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); - // Environment variable to disable any kind of crash dialog. - if (getenv("LLVM_DISABLE_CRASH_REPORT")) { -#ifdef _MSC_VER - _CrtSetReportHook(AvoidMessageBoxHook); -#endif - SetErrorMode(SEM_FAILCRITICALERRORS | - SEM_NOGPFAULTERRORBOX | - SEM_NOOPENFILEERRORBOX); - ExitOnUnhandledExceptions = true; - } - // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or // else multi-threading problems will ensue. } @@ -267,7 +358,6 @@ void sys::DontRemoveFileOnSignal(StringRef Filename) { RegisterHandler(); - FilesToRemove->push_back(Filename); std::vector<std::string>::reverse_iterator I = std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename); if (I != FilesToRemove->rend()) @@ -276,19 +366,63 @@ void sys::DontRemoveFileOnSignal(StringRef Filename) { LeaveCriticalSection(&CriticalSection); } +void sys::DisableSystemDialogsOnCrash() { + // Crash to stack trace handler on abort. + signal(SIGABRT, HandleAbort); + + // The following functions are not reliably accessible on MinGW. +#ifdef _MSC_VER + // We're already handling writing a "something went wrong" message. + _set_abort_behavior(0, _WRITE_ABORT_MSG); + // Disable Dr. Watson. + _set_abort_behavior(0, _CALL_REPORTFAULT); + _CrtSetReportHook(AvoidMessageBoxHook); +#endif + + // Disable standard error dialog box. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); + _set_error_mode(_OUT_TO_STDERR); +} + /// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or /// SIGSEGV) is delivered to the process, print a stack trace and then exit. -void sys::PrintStackTraceOnErrorSignal() { +void sys::PrintStackTraceOnErrorSignal(bool DisableCrashReporting) { + DisableSystemDialogsOnCrash(); RegisterHandler(); LeaveCriticalSection(&CriticalSection); } +} + +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +// Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is +// missing it but mingw-w64 has it. +extern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord); +#endif -void llvm::sys::PrintStackTrace(FILE *) { - // FIXME: Implement. +void llvm::sys::PrintStackTrace(raw_ostream &OS) { + + STACKFRAME64 StackFrame = {}; + CONTEXT Context = {}; + ::RtlCaptureContext(&Context); +#if defined(_M_X64) + StackFrame.AddrPC.Offset = Context.Rip; + StackFrame.AddrStack.Offset = Context.Rsp; + StackFrame.AddrFrame.Offset = Context.Rbp; +#else + StackFrame.AddrPC.Offset = Context.Eip; + StackFrame.AddrStack.Offset = Context.Esp; + StackFrame.AddrFrame.Offset = Context.Ebp; +#endif + StackFrame.AddrPC.Mode = AddrModeFlat; + StackFrame.AddrStack.Mode = AddrModeFlat; + StackFrame.AddrFrame.Mode = AddrModeFlat; + PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(), + StackFrame, &Context); } -void sys::SetInterruptFunction(void (*IF)()) { +void llvm::sys::SetInterruptFunction(void (*IF)()) { RegisterHandler(); InterruptFunction = IF; LeaveCriticalSection(&CriticalSection); @@ -298,16 +432,18 @@ void sys::SetInterruptFunction(void (*IF)()) { /// AddSignalHandler - Add a function to be called when a signal is delivered /// to the process. The handler can have a cookie passed to it to identify /// what instance of the handler it is. -void sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { +void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { if (CallBacksToRun == 0) CallBacksToRun = new std::vector<std::pair<void(*)(void*), void*> >(); CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); RegisterHandler(); LeaveCriticalSection(&CriticalSection); } -} static void Cleanup() { + if (CleanupExecuted) + return; + EnterCriticalSection(&CriticalSection); // Prevent other thread from registering new files and directories for @@ -323,13 +459,18 @@ static void Cleanup() { } if (CallBacksToRun) - for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i) - (*CallBacksToRun)[i].first((*CallBacksToRun)[i].second); + for (auto &I : *CallBacksToRun) + I.first(I.second); LeaveCriticalSection(&CriticalSection); } void llvm::sys::RunInterruptHandlers() { + // The interrupt handler may be called from an interrupt, but it may also be + // called manually (such as the case of report_fatal_error with no registered + // error handler). We must ensure that the critical section is properly + // initialized. + InitializeThreading(); Cleanup(); } @@ -337,12 +478,9 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { Cleanup(); // Initialize the STACKFRAME structure. - STACKFRAME64 StackFrame; - memset(&StackFrame, 0, sizeof(StackFrame)); + STACKFRAME64 StackFrame = {}; - DWORD machineType; #if defined(_M_X64) - machineType = IMAGE_FILE_MACHINE_AMD64; StackFrame.AddrPC.Offset = ep->ContextRecord->Rip; StackFrame.AddrPC.Mode = AddrModeFlat; StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp; @@ -350,7 +488,6 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp; StackFrame.AddrFrame.Mode = AddrModeFlat; #elif defined(_M_IX86) - machineType = IMAGE_FILE_MACHINE_I386; StackFrame.AddrPC.Offset = ep->ContextRecord->Eip; StackFrame.AddrPC.Mode = AddrModeFlat; StackFrame.AddrStack.Offset = ep->ContextRecord->Esp; @@ -361,90 +498,10 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { HANDLE hProcess = GetCurrentProcess(); HANDLE hThread = GetCurrentThread(); + PrintStackTraceForThread(llvm::errs(), hProcess, hThread, StackFrame, + ep->ContextRecord); - // Initialize the symbol handler. - SymSetOptions(SYMOPT_DEFERRED_LOADS|SYMOPT_LOAD_LINES); - SymInitialize(hProcess, NULL, TRUE); - - while (true) { - if (!StackWalk64(machineType, hProcess, hThread, &StackFrame, - ep->ContextRecord, NULL, SymFunctionTableAccess64, - SymGetModuleBase64, NULL)) { - break; - } - - if (StackFrame.AddrFrame.Offset == 0) - break; - - // Print the PC in hexadecimal. - DWORD64 PC = StackFrame.AddrPC.Offset; -#if defined(_M_X64) - fprintf(stderr, "0x%016llX", PC); -#elif defined(_M_IX86) - fprintf(stderr, "0x%08lX", static_cast<DWORD>(PC)); -#endif - - // Print the parameters. Assume there are four. -#if defined(_M_X64) - fprintf(stderr, " (0x%016llX 0x%016llX 0x%016llX 0x%016llX)", - StackFrame.Params[0], - StackFrame.Params[1], - StackFrame.Params[2], - StackFrame.Params[3]); -#elif defined(_M_IX86) - fprintf(stderr, " (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", - static_cast<DWORD>(StackFrame.Params[0]), - static_cast<DWORD>(StackFrame.Params[1]), - static_cast<DWORD>(StackFrame.Params[2]), - static_cast<DWORD>(StackFrame.Params[3])); -#endif - // Verify the PC belongs to a module in this process. - if (!SymGetModuleBase64(hProcess, PC)) { - fputs(" <unknown module>\n", stderr); - continue; - } - - // Print the symbol name. - char buffer[512]; - IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer); - memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); - symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); - - DWORD64 dwDisp; - if (!SymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { - fputc('\n', stderr); - continue; - } - - buffer[511] = 0; - if (dwDisp > 0) - fprintf(stderr, ", %s() + 0x%llX bytes(s)", symbol->Name, dwDisp); - else - fprintf(stderr, ", %s", symbol->Name); - - // Print the source file and line number information. - IMAGEHLP_LINE64 line; - DWORD dwLineDisp; - memset(&line, 0, sizeof(line)); - line.SizeOfStruct = sizeof(line); - if (SymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { - fprintf(stderr, ", %s, line %lu", line.FileName, line.LineNumber); - if (dwLineDisp > 0) - fprintf(stderr, " + 0x%lX byte(s)", dwLineDisp); - } - - fputc('\n', stderr); - } - - if (ExitOnUnhandledExceptions) - _exit(ep->ExceptionRecord->ExceptionCode); - - // Allow dialog box to pop up allowing choice to start debugger. - if (OldFilter) - return (*OldFilter)(ep); - else - return EXCEPTION_CONTINUE_SEARCH; + _exit(ep->ExceptionRecord->ExceptionCode); } static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { diff --git a/lib/Support/Windows/TimeValue.inc b/lib/Support/Windows/TimeValue.inc index 0223ab424488..b90b4f1da008 100644 --- a/lib/Support/Windows/TimeValue.inc +++ b/lib/Support/Windows/TimeValue.inc @@ -47,6 +47,7 @@ std::string TimeValue::str() const { __time64_t OurTime = this->toEpochTime(); int Error = ::_localtime64_s(&Storage, &OurTime); assert(!Error); + (void)Error; LT = &Storage; #endif diff --git a/lib/Support/Windows/WindowsSupport.h b/lib/Support/Windows/WindowsSupport.h index 1d1cedcce299..5bb0b8d2d788 100644 --- a/lib/Support/Windows/WindowsSupport.h +++ b/lib/Support/Windows/WindowsSupport.h @@ -19,6 +19,9 @@ //=== is guaranteed to work on *all* Win32 variants. //===----------------------------------------------------------------------===// +#ifndef LLVM_SUPPORT_WINDOWSSUPPORT_H +#define LLVM_SUPPORT_WINDOWSSUPPORT_H + // mingw-w64 tends to define it as 0x0502 in its headers. #undef _WIN32_WINNT #undef _WIN32_IE @@ -89,7 +92,7 @@ public: } // True if Handle is valid. - LLVM_EXPLICIT operator bool() const { + explicit operator bool() const { return HandleTraits::IsValid(Handle) ? true : false; } @@ -178,3 +181,5 @@ std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, } // end namespace windows } // end namespace sys } // end namespace llvm. + +#endif diff --git a/lib/Support/YAMLParser.cpp b/lib/Support/YAMLParser.cpp index 4688ff173df7..d55da5ef1e4a 100644 --- a/lib/Support/YAMLParser.cpp +++ b/lib/Support/YAMLParser.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/YAMLParser.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" @@ -100,6 +101,7 @@ namespace yaml { void Node::anchor() {} void NullNode::anchor() {} void ScalarNode::anchor() {} +void BlockScalarNode::anchor() {} void KeyValueNode::anchor() {} void MappingNode::anchor() {} void SequenceNode::anchor() {} @@ -127,6 +129,7 @@ struct Token : ilist_node<Token> { TK_Key, TK_Value, TK_Scalar, + TK_BlockScalar, TK_Alias, TK_Anchor, TK_Tag @@ -136,6 +139,9 @@ struct Token : ilist_node<Token> { /// of the token in the input. StringRef Range; + /// The value of a block scalar node. + std::string Value; + Token() : Kind(TK_Error) {} }; } @@ -162,7 +168,7 @@ struct ilist_node_traits<Token> { Token *createNode(const Token &V) { return new (Alloc.Allocate<Token>()) Token(V); } - static void deleteNode(Token *V) {} + static void deleteNode(Token *V) { V->~Token(); } void addNodeToList(Token *) {} void removeNodeFromList(Token *) {} @@ -259,8 +265,8 @@ namespace yaml { /// @brief Scans YAML tokens from a MemoryBuffer. class Scanner { public: - Scanner(StringRef Input, SourceMgr &SM); - Scanner(MemoryBufferRef Buffer, SourceMgr &SM_); + Scanner(StringRef Input, SourceMgr &SM, bool ShowColors = true); + Scanner(MemoryBufferRef Buffer, SourceMgr &SM_, bool ShowColors = true); /// @brief Parse the next token and return it without popping it. Token &peekNext(); @@ -270,7 +276,7 @@ public: void printError(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Message, ArrayRef<SMRange> Ranges = None) { - SM.PrintMessage(Loc, Kind, Message, Ranges); + SM.PrintMessage(Loc, Kind, Message, Ranges, /* FixIts= */ None, ShowColors); } void setError(const Twine &Message, StringRef::iterator Position) { @@ -347,6 +353,14 @@ private: /// b-break. StringRef::iterator skip_b_break(StringRef::iterator Position); + /// Skip a single s-space[31] starting at Position. + /// + /// An s-space is 0x20 + /// + /// @returns The code unit after the s-space, or Position if it's not a + /// s-space. + StringRef::iterator skip_s_space(StringRef::iterator Position); + /// @brief Skip a single s-white[33] starting at Position. /// /// A s-white is 0x20 | 0x9 @@ -372,6 +386,10 @@ private: StringRef::iterator skip_while( SkipWhileFunc Func , StringRef::iterator Position); + /// Skip minimal well-formed code unit subsequences until Func returns its + /// input. + void advanceWhile(SkipWhileFunc Func); + /// @brief Scan ns-uri-char[39]s starting at Cur. /// /// This updates Cur and Column while scanning. @@ -392,6 +410,11 @@ private: /// Pos is whitespace or a new line bool isBlankOrBreak(StringRef::iterator Position); + /// Consume a single b-break[28] if it's present at the current position. + /// + /// Return false if the code unit at the current position isn't a line break. + bool consumeLineBreakIfPresent(); + /// @brief If IsSimpleKeyAllowed, create and push_back a new SimpleKey. void saveSimpleKeyCandidate( TokenQueueT::iterator Tok , unsigned AtColumn @@ -416,6 +439,10 @@ private: , Token::TokenKind Kind , TokenQueueT::iterator InsertPoint); + /// @brief Skip a single-line comment when the comment starts at the current + /// position of the scanner. + void skipComment(); + /// @brief Skip whitespace and comments until the start of the next token. void scanToNextToken(); @@ -461,6 +488,30 @@ private: /// @brief Scan a block scalar starting with | or >. bool scanBlockScalar(bool IsLiteral); + /// Scan a chomping indicator in a block scalar header. + char scanBlockChompingIndicator(); + + /// Scan an indentation indicator in a block scalar header. + unsigned scanBlockIndentationIndicator(); + + /// Scan a block scalar header. + /// + /// Return false if an error occurred. + bool scanBlockScalarHeader(char &ChompingIndicator, unsigned &IndentIndicator, + bool &IsDone); + + /// Look for the indentation level of a block scalar. + /// + /// Return false if an error occurred. + bool findBlockScalarIndent(unsigned &BlockIndent, unsigned BlockExitIndent, + unsigned &LineBreaks, bool &IsDone); + + /// Scan the indentation of a text line in a block scalar. + /// + /// Return false if an error occurred. + bool scanBlockScalarIndent(unsigned BlockIndent, unsigned BlockExitIndent, + bool &IsDone); + /// @brief Scan a tag of the form !stuff. bool scanTag(); @@ -500,6 +551,9 @@ private: /// @brief True if an error has occurred. bool Failed; + /// @brief Should colors be used when printing out the diagnostic messages? + bool ShowColors; + /// @brief Queue of tokens. This is required to queue up tokens while looking /// for the end of a simple key. And for cases where a single character /// can produce multiple tokens (e.g. BlockEnd). @@ -604,6 +658,9 @@ bool yaml::dumpTokens(StringRef Input, raw_ostream &OS) { case Token::TK_Scalar: OS << "Scalar: "; break; + case Token::TK_BlockScalar: + OS << "Block Scalar: "; + break; case Token::TK_Alias: OS << "Alias: "; break; @@ -701,11 +758,13 @@ std::string yaml::escape(StringRef Input) { return EscapedInput; } -Scanner::Scanner(StringRef Input, SourceMgr &sm) : SM(sm) { +Scanner::Scanner(StringRef Input, SourceMgr &sm, bool ShowColors) + : SM(sm), ShowColors(ShowColors) { init(MemoryBufferRef(Input, "YAML")); } -Scanner::Scanner(MemoryBufferRef Buffer, SourceMgr &SM_) : SM(SM_) { +Scanner::Scanner(MemoryBufferRef Buffer, SourceMgr &SM_, bool ShowColors) + : SM(SM_), ShowColors(ShowColors) { init(Buffer); } @@ -806,6 +865,13 @@ StringRef::iterator Scanner::skip_b_break(StringRef::iterator Position) { return Position; } +StringRef::iterator Scanner::skip_s_space(StringRef::iterator Position) { + if (Position == End) + return Position; + if (*Position == ' ') + return Position + 1; + return Position; +} StringRef::iterator Scanner::skip_s_white(StringRef::iterator Position) { if (Position == End) @@ -834,6 +900,12 @@ StringRef::iterator Scanner::skip_while( SkipWhileFunc Func return Position; } +void Scanner::advanceWhile(SkipWhileFunc Func) { + auto Final = skip_while(Func, Current); + Column += Final - Current; + Current = Final; +} + static bool is_ns_hex_digit(const char C) { return (C >= '0' && C <= '9') || (C >= 'a' && C <= 'z') @@ -896,6 +968,16 @@ bool Scanner::isBlankOrBreak(StringRef::iterator Position) { return false; } +bool Scanner::consumeLineBreakIfPresent() { + auto Next = skip_b_break(Current); + if (Next == Current) + return false; + Column = 0; + ++Line; + Current = Next; + return true; +} + void Scanner::saveSimpleKeyCandidate( TokenQueueT::iterator Tok , unsigned AtColumn , bool IsRequired) { @@ -961,24 +1043,27 @@ bool Scanner::rollIndent( int ToColumn return true; } +void Scanner::skipComment() { + if (*Current != '#') + return; + while (true) { + // This may skip more than one byte, thus Column is only incremented + // for code points. + StringRef::iterator I = skip_nb_char(Current); + if (I == Current) + break; + Current = I; + ++Column; + } +} + void Scanner::scanToNextToken() { while (true) { while (*Current == ' ' || *Current == '\t') { skip(1); } - // Skip comment. - if (*Current == '#') { - while (true) { - // This may skip more than one byte, thus Column is only incremented - // for code points. - StringRef::iterator i = skip_nb_char(Current); - if (i == Current) - break; - Current = i; - ++Column; - } - } + skipComment(); // Skip EOL. StringRef::iterator i = skip_b_break(Current); @@ -1361,38 +1446,204 @@ bool Scanner::scanAliasOrAnchor(bool IsAlias) { return true; } -bool Scanner::scanBlockScalar(bool IsLiteral) { - StringRef::iterator Start = Current; - skip(1); // Eat | or > - while(true) { - StringRef::iterator i = skip_nb_char(Current); - if (i == Current) { - if (Column == 0) - break; - i = skip_b_break(Current); - if (i != Current) { - // We got a line break. - Column = 0; - ++Line; - Current = i; - continue; - } else { - // There was an error, which should already have been printed out. +char Scanner::scanBlockChompingIndicator() { + char Indicator = ' '; + if (Current != End && (*Current == '+' || *Current == '-')) { + Indicator = *Current; + skip(1); + } + return Indicator; +} + +/// Get the number of line breaks after chomping. +/// +/// Return the number of trailing line breaks to emit, depending on +/// \p ChompingIndicator. +static unsigned getChompedLineBreaks(char ChompingIndicator, + unsigned LineBreaks, StringRef Str) { + if (ChompingIndicator == '-') // Strip all line breaks. + return 0; + if (ChompingIndicator == '+') // Keep all line breaks. + return LineBreaks; + // Clip trailing lines. + return Str.empty() ? 0 : 1; +} + +unsigned Scanner::scanBlockIndentationIndicator() { + unsigned Indent = 0; + if (Current != End && (*Current >= '1' && *Current <= '9')) { + Indent = unsigned(*Current - '0'); + skip(1); + } + return Indent; +} + +bool Scanner::scanBlockScalarHeader(char &ChompingIndicator, + unsigned &IndentIndicator, bool &IsDone) { + auto Start = Current; + + ChompingIndicator = scanBlockChompingIndicator(); + IndentIndicator = scanBlockIndentationIndicator(); + // Check for the chomping indicator once again. + if (ChompingIndicator == ' ') + ChompingIndicator = scanBlockChompingIndicator(); + Current = skip_while(&Scanner::skip_s_white, Current); + skipComment(); + + if (Current == End) { // EOF, we have an empty scalar. + Token T; + T.Kind = Token::TK_BlockScalar; + T.Range = StringRef(Start, Current - Start); + TokenQueue.push_back(T); + IsDone = true; + return true; + } + + if (!consumeLineBreakIfPresent()) { + setError("Expected a line break after block scalar header", Current); + return false; + } + return true; +} + +bool Scanner::findBlockScalarIndent(unsigned &BlockIndent, + unsigned BlockExitIndent, + unsigned &LineBreaks, bool &IsDone) { + unsigned MaxAllSpaceLineCharacters = 0; + StringRef::iterator LongestAllSpaceLine; + + while (true) { + advanceWhile(&Scanner::skip_s_space); + if (skip_nb_char(Current) != Current) { + // This line isn't empty, so try and find the indentation. + if (Column <= BlockExitIndent) { // End of the block literal. + IsDone = true; + return true; + } + // We found the block's indentation. + BlockIndent = Column; + if (MaxAllSpaceLineCharacters > BlockIndent) { + setError( + "Leading all-spaces line must be smaller than the block indent", + LongestAllSpaceLine); return false; } + return true; } - Current = i; + if (skip_b_break(Current) != Current && + Column > MaxAllSpaceLineCharacters) { + // Record the longest all-space line in case it's longer than the + // discovered block indent. + MaxAllSpaceLineCharacters = Column; + LongestAllSpaceLine = Current; + } + + // Check for EOF. + if (Current == End) { + IsDone = true; + return true; + } + + if (!consumeLineBreakIfPresent()) { + IsDone = true; + return true; + } + ++LineBreaks; + } + return true; +} + +bool Scanner::scanBlockScalarIndent(unsigned BlockIndent, + unsigned BlockExitIndent, bool &IsDone) { + // Skip the indentation. + while (Column < BlockIndent) { + auto I = skip_s_space(Current); + if (I == Current) + break; + Current = I; ++Column; } - if (Start == Current) { - setError("Got empty block scalar", Start); + if (skip_nb_char(Current) == Current) + return true; + + if (Column <= BlockExitIndent) { // End of the block literal. + IsDone = true; + return true; + } + + if (Column < BlockIndent) { + if (Current != End && *Current == '#') { // Trailing comment. + IsDone = true; + return true; + } + setError("A text line is less indented than the block scalar", Current); + return false; + } + return true; // A normal text line. +} + +bool Scanner::scanBlockScalar(bool IsLiteral) { + // Eat '|' or '>' + assert(*Current == '|' || *Current == '>'); + skip(1); + + char ChompingIndicator; + unsigned BlockIndent; + bool IsDone = false; + if (!scanBlockScalarHeader(ChompingIndicator, BlockIndent, IsDone)) return false; + if (IsDone) + return true; + + auto Start = Current; + unsigned BlockExitIndent = Indent < 0 ? 0 : (unsigned)Indent; + unsigned LineBreaks = 0; + if (BlockIndent == 0) { + if (!findBlockScalarIndent(BlockIndent, BlockExitIndent, LineBreaks, + IsDone)) + return false; } + // Scan the block's scalars body. + SmallString<256> Str; + while (!IsDone) { + if (!scanBlockScalarIndent(BlockIndent, BlockExitIndent, IsDone)) + return false; + if (IsDone) + break; + + // Parse the current line. + auto LineStart = Current; + advanceWhile(&Scanner::skip_nb_char); + if (LineStart != Current) { + Str.append(LineBreaks, '\n'); + Str.append(StringRef(LineStart, Current - LineStart)); + LineBreaks = 0; + } + + // Check for EOF. + if (Current == End) + break; + + if (!consumeLineBreakIfPresent()) + break; + ++LineBreaks; + } + + if (Current == End && !LineBreaks) + // Ensure that there is at least one line break before the end of file. + LineBreaks = 1; + Str.append(getChompedLineBreaks(ChompingIndicator, LineBreaks, Str), '\n'); + + // New lines may start a simple key. + if (!FlowLevel) + IsSimpleKeyAllowed = true; + Token T; - T.Kind = Token::TK_Scalar; + T.Kind = Token::TK_BlockScalar; T.Range = StringRef(Start, Current - Start); + T.Value = Str.str().str(); TokenQueue.push_back(T); return true; } @@ -1517,23 +1768,21 @@ bool Scanner::fetchMoreTokens() { return false; } -Stream::Stream(StringRef Input, SourceMgr &SM) - : scanner(new Scanner(Input, SM)), CurrentDoc() {} +Stream::Stream(StringRef Input, SourceMgr &SM, bool ShowColors) + : scanner(new Scanner(Input, SM, ShowColors)), CurrentDoc() {} -Stream::Stream(MemoryBufferRef InputBuffer, SourceMgr &SM) - : scanner(new Scanner(InputBuffer, SM)), CurrentDoc() {} +Stream::Stream(MemoryBufferRef InputBuffer, SourceMgr &SM, bool ShowColors) + : scanner(new Scanner(InputBuffer, SM, ShowColors)), CurrentDoc() {} Stream::~Stream() {} bool Stream::failed() { return scanner->failed(); } void Stream::printError(Node *N, const Twine &Msg) { - SmallVector<SMRange, 1> Ranges; - Ranges.push_back(N->getSourceRange()); scanner->printError( N->getSourceRange().Start , SourceMgr::DK_Error , Msg - , Ranges); + , N->getSourceRange()); } document_iterator Stream::begin() { @@ -1570,11 +1819,11 @@ std::string Node::getVerbatimTag() const { if (Raw.find_last_of('!') == 0) { Ret = Doc->getTagMap().find("!")->second; Ret += Raw.substr(1); - return std::move(Ret); + return Ret; } else if (Raw.startswith("!!")) { Ret = Doc->getTagMap().find("!!")->second; Ret += Raw.substr(2); - return std::move(Ret); + return Ret; } else { StringRef TagHandle = Raw.substr(0, Raw.find_last_of('!') + 1); std::map<StringRef, StringRef>::const_iterator It = @@ -1588,7 +1837,7 @@ std::string Node::getVerbatimTag() const { setError(Twine("Unknown tag handle ") + TagHandle, T); } Ret += Raw.substr(Raw.find_last_of('!') + 1); - return std::move(Ret); + return Ret; } } @@ -1596,6 +1845,7 @@ std::string Node::getVerbatimTag() const { case NK_Null: return "tag:yaml.org,2002:null"; case NK_Scalar: + case NK_BlockScalar: // TODO: Tag resolution. return "tag:yaml.org,2002:str"; case NK_Mapping: @@ -2127,6 +2377,14 @@ parse_property: , AnchorInfo.Range.substr(1) , TagInfo.Range , T.Range); + case Token::TK_BlockScalar: { + getNext(); + StringRef NullTerminatedStr(T.Value.c_str(), T.Value.length() + 1); + StringRef StrCopy = NullTerminatedStr.copy(NodeAllocator).drop_back(); + return new (NodeAllocator) + BlockScalarNode(stream.CurrentDoc, AnchorInfo.Range.substr(1), + TagInfo.Range, StrCopy, T.Range); + } case Token::TK_Key: // Don't eat the TK_Key, KeyValueNode expects it. return new (NodeAllocator) diff --git a/lib/Support/YAMLTraits.cpp b/lib/Support/YAMLTraits.cpp index c87790efb8c8..90f34f6e232d 100644 --- a/lib/Support/YAMLTraits.cpp +++ b/lib/Support/YAMLTraits.cpp @@ -7,13 +7,15 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/Errc.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" +#include "llvm/Support/LineIterator.h" #include "llvm/Support/YAMLParser.h" -#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include <cctype> #include <cstring> @@ -167,10 +169,22 @@ void Input::endMapping() { } } +void Input::beginFlowMapping() { beginMapping(); } + +void Input::endFlowMapping() { endMapping(); } + unsigned Input::beginSequence() { - if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) { + if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) return SQ->Entries.size(); + if (isa<EmptyHNode>(CurrentNode)) + return 0; + // Treat case where there's a scalar "null" value as an empty sequence. + if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) { + if (isNull(SN->value())) + return 0; } + // Any other type of HNode is an error. + setError(CurrentNode, "not a sequence"); return 0; } @@ -192,12 +206,7 @@ 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; -} +unsigned Input::beginFlowSequence() { return beginSequence(); } bool Input::preflightFlowElement(unsigned index, void *&SaveInfo) { if (EC) @@ -233,6 +242,13 @@ bool Input::matchEnumScalar(const char *Str, bool) { return false; } +bool Input::matchEnumFallback() { + if (ScalarMatchFound) + return false; + ScalarMatchFound = true; + return true; +} + void Input::endEnumScalar() { if (!ScalarMatchFound) { setError(CurrentNode, "unknown enumerated scalar"); @@ -294,6 +310,8 @@ void Input::scalarString(StringRef &S, bool) { } } +void Input::blockScalarString(StringRef &S) { scalarString(S, false); } + void Input::setError(HNode *hnode, const Twine &message) { assert(hnode && "HNode must not be NULL"); this->setError(hnode->_node, message); @@ -316,6 +334,11 @@ std::unique_ptr<Input::HNode> Input::createHNodes(Node *N) { KeyStr = StringRef(Buf, Len); } return llvm::make_unique<ScalarHNode>(N, KeyStr); + } else if (BlockScalarNode *BSN = dyn_cast<BlockScalarNode>(N)) { + StringRef Value = BSN->getValue(); + char *Buf = StringAllocator.Allocate<char>(Value.size()); + memcpy(Buf, Value.data(), Value.size()); + return llvm::make_unique<ScalarHNode>(N, StringRef(Buf, Value.size())); } else if (SequenceNode *SQ = dyn_cast<SequenceNode>(N)) { auto SQHNode = llvm::make_unique<SequenceHNode>(N); for (Node &SN : *SQ) { @@ -382,6 +405,7 @@ Output::Output(raw_ostream &yout, void *context) Out(yout), Column(0), ColumnAtFlowStart(0), + ColumnAtMapFlowStart(0), NeedBitValueComma(false), NeedFlowSequenceComma(false), EnumerationMatchFound(false), @@ -416,8 +440,13 @@ bool Output::preflightKey(const char *Key, bool Required, bool SameAsDefault, bool &UseDefault, void *&) { UseDefault = false; if (Required || !SameAsDefault) { - this->newLineCheck(); - this->paddedKey(Key); + auto State = StateStack.back(); + if (State == inFlowMapFirstKey || State == inFlowMapOtherKey) { + flowKey(Key); + } else { + this->newLineCheck(); + this->paddedKey(Key); + } return true; } return false; @@ -427,9 +456,24 @@ void Output::postflightKey(void *) { if (StateStack.back() == inMapFirstKey) { StateStack.pop_back(); StateStack.push_back(inMapOtherKey); + } else if (StateStack.back() == inFlowMapFirstKey) { + StateStack.pop_back(); + StateStack.push_back(inFlowMapOtherKey); } } +void Output::beginFlowMapping() { + StateStack.push_back(inFlowMapFirstKey); + this->newLineCheck(); + ColumnAtMapFlowStart = Column; + output("{ "); +} + +void Output::endFlowMapping() { + StateStack.pop_back(); + this->outputUpToEndOfLine(" }"); +} + void Output::beginDocuments() { this->outputUpToEndOfLine("---"); } @@ -508,6 +552,13 @@ bool Output::matchEnumScalar(const char *Str, bool Match) { return false; } +bool Output::matchEnumFallback() { + if (EnumerationMatchFound) + return false; + EnumerationMatchFound = true; + return true; +} + void Output::endEnumScalar() { if (!EnumerationMatchFound) llvm_unreachable("bad runtime enum value"); @@ -566,6 +617,24 @@ void Output::scalarString(StringRef &S, bool MustQuote) { this->outputUpToEndOfLine("'"); // Ending single quote. } +void Output::blockScalarString(StringRef &S) { + if (!StateStack.empty()) + newLineCheck(); + output(" |"); + outputNewLine(); + + unsigned Indent = StateStack.empty() ? 1 : StateStack.size(); + + auto Buffer = MemoryBuffer::getMemBuffer(S, "", false); + for (line_iterator Lines(*Buffer, false); !Lines.is_at_end(); ++Lines) { + for (unsigned I = 0; I < Indent; ++I) { + output(" "); + } + output(*Lines); + outputNewLine(); + } +} + void Output::setError(const Twine &message) { } @@ -589,7 +658,9 @@ void Output::output(StringRef s) { void Output::outputUpToEndOfLine(StringRef s) { this->output(s); - if (StateStack.empty() || StateStack.back() != inFlowSeq) + if (StateStack.empty() || (StateStack.back() != inFlowSeq && + StateStack.back() != inFlowMapFirstKey && + StateStack.back() != inFlowMapOtherKey)) NeedsNewLine = true; } @@ -615,7 +686,9 @@ void Output::newLineCheck() { if (StateStack.back() == inSeq) { OutputDash = true; - } else if ((StateStack.size() > 1) && (StateStack.back() == inMapFirstKey) && + } else if ((StateStack.size() > 1) && ((StateStack.back() == inMapFirstKey) || + (StateStack.back() == inFlowSeq) || + (StateStack.back() == inFlowMapFirstKey)) && (StateStack[StateStack.size() - 2] == inSeq)) { --Indent; OutputDash = true; @@ -640,6 +713,20 @@ void Output::paddedKey(StringRef key) { output(" "); } +void Output::flowKey(StringRef Key) { + if (StateStack.back() == inFlowMapOtherKey) + output(", "); + if (Column > 70) { + output("\n"); + for (int I = 0; I < ColumnAtMapFlowStart; ++I) + output(" "); + Column = ColumnAtMapFlowStart; + output(" "); + } + output(Key); + output(": "); +} + //===----------------------------------------------------------------------===// // traits for built-in types //===----------------------------------------------------------------------===// @@ -669,7 +756,7 @@ StringRef ScalarTraits<StringRef>::input(StringRef Scalar, void *, Val = Scalar; return StringRef(); } - + void ScalarTraits<std::string>::output(const std::string &Val, void *, raw_ostream &Out) { Out << Val; diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp index 1bcc31b40a4f..4c0b6c7b5634 100644 --- a/lib/Support/raw_ostream.cpp +++ b/lib/Support/raw_ostream.cpp @@ -242,7 +242,7 @@ raw_ostream &raw_ostream::operator<<(double N) { char buf[16]; unsigned len; - len = snprintf(buf, sizeof(buf), "%e", N); + len = format("%e", N).snprint(buf, sizeof(buf)); if (len <= sizeof(buf) - 2) { if (len >= 5 && buf[len - 5] == 'e' && buf[len - 3] == '0') { int cs = buf[len - 4]; @@ -410,9 +410,12 @@ raw_ostream &raw_ostream::operator<<(const FormattedString &FS) { raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) { if (FN.Hex) { unsigned Nibbles = (64 - countLeadingZeros(FN.HexValue)+3)/4; - unsigned Width = (FN.Width > Nibbles+2) ? FN.Width : Nibbles+2; - + unsigned PrefixChars = FN.HexPrefix ? 2 : 0; + unsigned Width = std::max(FN.Width, Nibbles + PrefixChars); + char NumberBuffer[20] = "0x0000000000000000"; + if (!FN.HexPrefix) + NumberBuffer[1] = '0'; char *EndPtr = NumberBuffer+Width; char *CurPtr = EndPtr; const char A = FN.Upper ? 'A' : 'a'; @@ -484,51 +487,53 @@ void format_object_base::home() { // raw_fd_ostream //===----------------------------------------------------------------------===// -raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC, - sys::fs::OpenFlags Flags) - : Error(false), UseAtomicWrites(false), pos(0) { - EC = std::error_code(); +static int getFD(StringRef Filename, std::error_code &EC, + sys::fs::OpenFlags Flags) { // Handle "-" as stdout. Note that when we do this, we consider ourself // the owner of stdout. This means that we can do things like close the // file descriptor when we're done and set the "binary" flag globally. if (Filename == "-") { - FD = STDOUT_FILENO; + EC = std::error_code(); // If user requested binary then put stdout into binary mode if // possible. if (!(Flags & sys::fs::F_Text)) sys::ChangeStdoutToBinary(); - // Close stdout when we're done, to detect any output errors. - ShouldClose = true; - return; + return STDOUT_FILENO; } + int FD; EC = sys::fs::openFileForWrite(Filename, FD, Flags); + if (EC) + return -1; - if (EC) { - ShouldClose = false; - return; - } - - // Ok, we successfully opened the file, so it'll need to be closed. - ShouldClose = true; + return FD; } -/// raw_fd_ostream ctor - FD is the file descriptor that this writes to. If -/// ShouldClose is true, this closes the file when the stream is destroyed. +raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC, + sys::fs::OpenFlags Flags) + : raw_fd_ostream(getFD(Filename, EC, Flags), true) {} + +/// FD is the file descriptor that this writes to. If ShouldClose is true, this +/// closes the file when the stream is destroyed. raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered) - : raw_ostream(unbuffered), FD(fd), - ShouldClose(shouldClose), Error(false), UseAtomicWrites(false) { -#ifdef O_BINARY - // Setting STDOUT to binary mode is necessary in Win32 - // to avoid undesirable linefeed conversion. - // Don't touch STDERR, or w*printf() (in assert()) would barf wide chars. - if (fd == STDOUT_FILENO) - setmode(fd, O_BINARY); -#endif + : raw_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose), + Error(false), UseAtomicWrites(false) { + if (FD < 0 ) { + ShouldClose = false; + return; + } // Get the starting position. off_t loc = ::lseek(FD, 0, SEEK_CUR); - if (loc == (off_t)-1) +#ifdef LLVM_ON_WIN32 + // MSVCRT's _lseek(SEEK_CUR) doesn't return -1 for pipes. + sys::fs::file_status Status; + std::error_code EC = status(FD, Status); + SupportsSeeking = !EC && Status.type() == sys::fs::file_type::regular_file; +#else + SupportsSeeking = loc != (off_t)-1; +#endif + if (!SupportsSeeking) pos = 0; else pos = static_cast<uint64_t>(loc); @@ -620,11 +625,19 @@ void raw_fd_ostream::close() { uint64_t raw_fd_ostream::seek(uint64_t off) { flush(); pos = ::lseek(FD, off, SEEK_SET); - if (pos != off) + if (pos == (uint64_t)-1) error_detected(); return pos; } +void raw_fd_ostream::pwrite_impl(const char *Ptr, size_t Size, + uint64_t Offset) { + uint64_t Pos = tell(); + seek(Offset); + write(Ptr, Size); + seek(Pos); +} + size_t raw_fd_ostream::preferred_buffer_size() const { #if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__minix) // Windows and Minix have no st_blksize. @@ -705,7 +718,9 @@ raw_ostream &llvm::outs() { // Set buffer settings to model stdout behavior. // Delete the file descriptor when the program exits, forcing error // detection. If you don't want this behavior, don't use outs(). - static raw_fd_ostream S(STDOUT_FILENO, true); + std::error_code EC; + static raw_fd_ostream S("-", EC, sys::fs::F_None); + assert(!EC); return S; } @@ -746,7 +761,14 @@ void raw_string_ostream::write_impl(const char *Ptr, size_t Size) { // capacity. This allows raw_ostream to write directly into the correct place, // and we only need to set the vector size when the data is flushed. +raw_svector_ostream::raw_svector_ostream(SmallVectorImpl<char> &O, unsigned) + : OS(O) {} + raw_svector_ostream::raw_svector_ostream(SmallVectorImpl<char> &O) : OS(O) { + init(); +} + +void raw_svector_ostream::init() { // Set up the initial external buffer. We make sure that the buffer has at // least 128 bytes free; raw_ostream itself only requires 64, but we want to // make sure that we don't grow the buffer unnecessarily on destruction (when @@ -760,6 +782,12 @@ raw_svector_ostream::~raw_svector_ostream() { flush(); } +void raw_svector_ostream::pwrite_impl(const char *Ptr, size_t Size, + uint64_t Offset) { + flush(); + memcpy(OS.begin() + Offset, Ptr, Size); +} + /// resync - This is called when the SmallVector we're appending to is changed /// outside of the raw_svector_ostream's control. It is only safe to do this /// if the raw_svector_ostream has previously been flushed. @@ -814,3 +842,6 @@ void raw_null_ostream::write_impl(const char *Ptr, size_t Size) { uint64_t raw_null_ostream::current_pos() const { return 0; } + +void raw_null_ostream::pwrite_impl(const char *Ptr, size_t Size, + uint64_t Offset) {} diff --git a/lib/Support/regcomp.c b/lib/Support/regcomp.c index b79692966473..ebde64f9cf75 100644 --- a/lib/Support/regcomp.c +++ b/lib/Support/regcomp.c @@ -1422,7 +1422,7 @@ enlarge(struct parse *p, sopno size) if (p->ssize >= size) return; - if ((unsigned long)size > SIZE_MAX / sizeof(sop)) { + if ((uintptr_t)size > SIZE_MAX / sizeof(sop)) { SETERROR(REG_ESPACE); return; } @@ -1443,7 +1443,7 @@ static void stripsnug(struct parse *p, struct re_guts *g) { g->nstates = p->slen; - if ((unsigned long)p->slen > SIZE_MAX / sizeof(sop)) { + if ((uintptr_t)p->slen > SIZE_MAX / sizeof(sop)) { g->strip = p->strip; SETERROR(REG_ESPACE); return; |