diff options
author | Eli Bendersky <eliben@chromium.org> | 2013-07-15 16:09:15 -0700 |
---|---|---|
committer | Eli Bendersky <eliben@chromium.org> | 2013-07-15 16:09:15 -0700 |
commit | c6cf05cb5108f356dde97c01ee4188b0671d4542 (patch) | |
tree | 436fdc2a55296d3c202e7ef11f31be3be53efb5f /lib/Support | |
parent | c75199c649c739aade160289d93f257edc798cde (diff) | |
parent | 7dfcb84fc16b3bf6b2379713b53090757f0a45f9 (diff) |
Merge commit '7dfcb84fc16b3bf6b2379713b53090757f0a45f9'
Conflicts:
docs/LangRef.rst
include/llvm/CodeGen/CallingConvLower.h
include/llvm/IRReader/IRReader.h
include/llvm/Target/TargetMachine.h
lib/CodeGen/CallingConvLower.cpp
lib/IRReader/IRReader.cpp
lib/IRReader/LLVMBuild.txt
lib/IRReader/Makefile
lib/LLVMBuild.txt
lib/Makefile
lib/Support/MemoryBuffer.cpp
lib/Support/Unix/PathV2.inc
lib/Target/ARM/ARMBaseInstrInfo.cpp
lib/Target/ARM/ARMISelLowering.cpp
lib/Target/ARM/ARMInstrInfo.td
lib/Target/ARM/ARMSubtarget.cpp
lib/Target/ARM/ARMTargetMachine.cpp
lib/Target/Mips/CMakeLists.txt
lib/Target/Mips/MipsDelaySlotFiller.cpp
lib/Target/Mips/MipsISelLowering.cpp
lib/Target/Mips/MipsInstrInfo.td
lib/Target/Mips/MipsSubtarget.cpp
lib/Target/Mips/MipsSubtarget.h
lib/Target/X86/X86FastISel.cpp
lib/Target/X86/X86ISelDAGToDAG.cpp
lib/Target/X86/X86ISelLowering.cpp
lib/Target/X86/X86InstrControl.td
lib/Target/X86/X86InstrFormats.td
lib/Transforms/IPO/ExtractGV.cpp
lib/Transforms/InstCombine/InstCombineCompares.cpp
lib/Transforms/Utils/SimplifyLibCalls.cpp
test/CodeGen/X86/fast-isel-divrem.ll
test/MC/ARM/data-in-code.ll
tools/Makefile
tools/llvm-extract/llvm-extract.cpp
tools/llvm-link/CMakeLists.txt
tools/opt/CMakeLists.txt
tools/opt/LLVMBuild.txt
tools/opt/Makefile
tools/opt/opt.cpp
Diffstat (limited to 'lib/Support')
30 files changed, 799 insertions, 166 deletions
diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index 5b68fbb270..6182e34150 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -3311,10 +3311,8 @@ namespace { significand = significand.udiv(divisor); - // Truncate the significand down to its active bit count, but - // don't try to drop below 32. - unsigned newPrecision = std::max(32U, significand.getActiveBits()); - significand = significand.trunc(newPrecision); + // Truncate the significand down to its active bit count. + significand = significand.trunc(significand.getActiveBits()); } diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index 07cb057b48..e8534753b4 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -559,12 +559,12 @@ bool APInt::slt(const APInt& RHS) const { if (lhsNeg) { // Sign bit is set so perform two's complement to make it positive lhs.flipAllBits(); - lhs++; + ++lhs; } if (rhsNeg) { // Sign bit is set so perform two's complement to make it positive rhs.flipAllBits(); - rhs++; + ++rhs; } // Now we have unsigned values to compare so do the comparison if necessary @@ -2116,7 +2116,7 @@ void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) { } // If its negative, put it in two's complement form if (isNeg) { - (*this)--; + --(*this); this->flipAllBits(); } } @@ -2197,7 +2197,7 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, // Flip the bits and add one to turn it into the equivalent positive // value and put a '-' in the result. Tmp.flipAllBits(); - Tmp++; + ++Tmp; Str.push_back('-'); } diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt index 5ba69fc3c8..01565c5776 100644 --- a/lib/Support/CMakeLists.txt +++ b/lib/Support/CMakeLists.txt @@ -7,6 +7,7 @@ add_llvm_library(LLVMSupport BranchProbability.cpp circular_raw_ostream.cpp CommandLine.cpp + Compression.cpp ConstantRange.cpp ConvertUTF.c ConvertUTFWrapper.cpp @@ -83,6 +84,7 @@ add_llvm_library(LLVMSupport Threading.cpp TimeValue.cpp Valgrind.cpp + Watchdog.cpp Unix/Host.inc Unix/Memory.inc Unix/Mutex.inc @@ -95,6 +97,7 @@ add_llvm_library(LLVMSupport Unix/system_error.inc Unix/ThreadLocal.inc Unix/TimeValue.inc + Unix/Watchdog.inc Windows/DynamicLibrary.inc Windows/Host.inc Windows/Memory.inc @@ -108,4 +111,5 @@ add_llvm_library(LLVMSupport Windows/system_error.inc Windows/ThreadLocal.inc Windows/TimeValue.inc + Windows/Watchdog.inc ) diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index 53fcf06f82..18d3db527b 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -33,6 +33,7 @@ #include "llvm/Support/system_error.h" #include <cerrno> #include <cstdlib> +#include <map> using namespace llvm; using namespace cl; @@ -106,6 +107,17 @@ void Option::addArgument() { 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() +{ + RegisteredOptionCategories->insert(this); +} //===----------------------------------------------------------------------===// // Basic, shared command line option processing machinery. @@ -1222,15 +1234,20 @@ sortOpts(StringMap<Option*> &OptMap, namespace { class HelpPrinter { - size_t MaxArgLen; - const Option *EmptyArg; +protected: const bool ShowHidden; + typedef SmallVector<std::pair<const char *, Option*>,128> StrOptionPairVector; + // Print the options. Opts is assumed to be alphabetically sorted. + virtual void printOptions(StrOptionPairVector &Opts, size_t MaxArgLen) { + for (size_t i = 0, e = Opts.size(); i != e; ++i) + Opts[i].second->printOptionInfo(MaxArgLen); + } public: - explicit HelpPrinter(bool showHidden) : ShowHidden(showHidden) { - EmptyArg = 0; - } + explicit HelpPrinter(bool showHidden) : ShowHidden(showHidden) {} + virtual ~HelpPrinter() {} + // Invoke the printer. void operator=(bool Value) { if (Value == false) return; @@ -1240,7 +1257,7 @@ public: StringMap<Option*> OptMap; GetOptionInfo(PositionalOpts, SinkOpts, OptMap); - SmallVector<std::pair<const char *, Option*>, 128> Opts; + StrOptionPairVector Opts; sortOpts(OptMap, Opts, ShowHidden); if (ProgramOverview) @@ -1266,17 +1283,17 @@ public: outs() << "\n\n"; // Compute the maximum argument length... - MaxArgLen = 0; + size_t MaxArgLen = 0; for (size_t i = 0, e = Opts.size(); i != e; ++i) MaxArgLen = std::max(MaxArgLen, Opts[i].second->getOptionWidth()); outs() << "OPTIONS:\n"; - for (size_t i = 0, e = Opts.size(); i != e; ++i) - Opts[i].second->printOptionInfo(MaxArgLen); + 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) + E = MoreHelp->end(); + I != E; ++I) outs() << *I; MoreHelp->clear(); @@ -1284,21 +1301,152 @@ public: exit(1); } }; + +class CategorizedHelpPrinter : public HelpPrinter { +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) { + int Length = strcmp(A->getName(), B->getName()); + assert(Length != 0 && "Duplicate option categories"); + return Length < 0; + } + + // Make sure we inherit our base class's operator=() + using HelpPrinter::operator= ; + +protected: + virtual void printOptions(StrOptionPairVector &Opts, size_t MaxArgLen) { + std::vector<OptionCategory *> SortedCategories; + std::map<OptionCategory *, std::vector<Option *> > CategorizedOptions; + + // Collect registered option categories into vector in preperation for + // sorting. + for (OptionCatSet::const_iterator I = RegisteredOptionCategories->begin(), + E = 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); + + // Create map to empty vectors. + for (std::vector<OptionCategory *>::const_iterator + I = SortedCategories.begin(), + E = SortedCategories.end(); + I != E; ++I) + CategorizedOptions[*I] = std::vector<Option *>(); + + // Walk through pre-sorted options and assign into categories. + // Because the options are already alphabetically sorted the + // options within categories will also be alphabetically sorted. + for (size_t I = 0, E = Opts.size(); I != E; ++I) { + Option *Opt = Opts[I].second; + assert(CategorizedOptions.count(Opt->Category) > 0 && + "Option has an unregistered category"); + CategorizedOptions[Opt->Category].push_back(Opt); + } + + // Now do printing. + for (std::vector<OptionCategory *>::const_iterator + Category = SortedCategories.begin(), + E = SortedCategories.end(); + Category != E; ++Category) { + // Hide empty categories for -help, but show for -help-hidden. + bool IsEmptyCategory = CategorizedOptions[*Category].size() == 0; + if (!ShowHidden && IsEmptyCategory) + continue; + + // Print category information. + outs() << "\n"; + outs() << (*Category)->getName() << ":\n"; + + // Check if description is set. + if ((*Category)->getDescription() != 0) + outs() << (*Category)->getDescription() << "\n\n"; + else + outs() << "\n"; + + // When using -help-hidden explicitly state if the category has no + // options associated with it. + if (IsEmptyCategory) { + outs() << " This option category has no options.\n"; + continue; + } + // Loop over the options in the category and print. + for (std::vector<Option *>::const_iterator + Opt = CategorizedOptions[*Category].begin(), + E = CategorizedOptions[*Category].end(); + Opt != E; ++Opt) + (*Opt)->printOptionInfo(MaxArgLen); + } + } +}; + +// This wraps the Uncategorizing and Categorizing printers and decides +// at run time which should be invoked. +class HelpPrinterWrapper { +private: + HelpPrinter &UncategorizedPrinter; + CategorizedHelpPrinter &CategorizedPrinter; + +public: + explicit HelpPrinterWrapper(HelpPrinter &UncategorizedPrinter, + CategorizedHelpPrinter &CategorizedPrinter) : + UncategorizedPrinter(UncategorizedPrinter), + CategorizedPrinter(CategorizedPrinter) { } + + // Invoke the printer. + void operator=(bool Value); +}; + } // End anonymous namespace -// Define the two HelpPrinter instances that are used to print out help, or -// help-hidden... -// -static HelpPrinter NormalPrinter(false); -static HelpPrinter HiddenPrinter(true); +// Declare the four HelpPrinter instances that are used to print out help, or +// help-hidden as an uncategorized list or in categories. +static HelpPrinter UncategorizedNormalPrinter(false); +static HelpPrinter UncategorizedHiddenPrinter(true); +static CategorizedHelpPrinter CategorizedNormalPrinter(false); +static CategorizedHelpPrinter CategorizedHiddenPrinter(true); + +// Declare HelpPrinter wrappers that will decide whether or not to invoke +// a categorizing help printer +static HelpPrinterWrapper WrappedNormalPrinter(UncategorizedNormalPrinter, + CategorizedNormalPrinter); +static HelpPrinterWrapper WrappedHiddenPrinter(UncategorizedHiddenPrinter, + CategorizedHiddenPrinter); + +// 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> > -HOp("help", cl::desc("Display available options (-help-hidden for more)"), - cl::location(NormalPrinter), cl::ValueDisallowed); +HLOp("help-list", + cl::desc("Display list of available options (-help-list-hidden for more)"), + cl::location(UncategorizedNormalPrinter), cl::Hidden, cl::ValueDisallowed); 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); + +// 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); + +static cl::opt<HelpPrinterWrapper, true, parser<bool> > HHOp("help-hidden", cl::desc("Display all available options"), - cl::location(HiddenPrinter), cl::Hidden, cl::ValueDisallowed); + cl::location(WrappedHiddenPrinter), cl::Hidden, cl::ValueDisallowed); + + static cl::opt<bool> PrintOptions("print-options", @@ -1310,6 +1458,24 @@ PrintAllOptions("print-all-options", cl::desc("Print all option values after command line parsing"), cl::Hidden, cl::init(false)); +void HelpPrinterWrapper::operator=(bool Value) { + if (Value == false) + 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) { + // unhide -help-list option so user can have uncategorized output if they + // want it. + HLOp.setHiddenFlag(NotHidden); + + CategorizedPrinter = true; // Invoke categorized printer + } + else + UncategorizedPrinter = true; // Invoke uncategorized printer +} + // Print the value of each option. void cl::PrintOptionValues() { if (!PrintOptions && !PrintAllOptions) return; @@ -1397,14 +1563,22 @@ VersOp("version", cl::desc("Display the version of this program"), cl::location(VersionPrinterInstance), cl::ValueDisallowed); // Utility function for printing the help message. -void cl::PrintHelpMessage() { - // This looks weird, but it actually prints the help message. The - // NormalPrinter variable is a HelpPrinter and the help gets printed when - // its operator= is invoked. That's because the "normal" usages of the - // help printer is to be assigned true/false depending on whether the - // -help option was given or not. Since we're circumventing that we have - // to make it look like -help was given, so we assign true. - NormalPrinter = true; +void cl::PrintHelpMessage(bool Hidden, bool Categorized) { + // This looks weird, but it actually prints the help message. The Printers are + // types of HelpPrinter and the help gets printed when its operator= is + // invoked. That's because the "normal" usages of the help printer is to be + // assigned true/false depending on whether -help or -help-hidden was given or + // not. Since we're circumventing that we have to make it look like -help or + // -help-hidden were given, so we assign true. + + if (!Hidden && !Categorized) + UncategorizedNormalPrinter = true; + else if (!Hidden && Categorized) + CategorizedNormalPrinter = true; + else if (Hidden && !Categorized) + UncategorizedHiddenPrinter = true; + else + CategorizedHiddenPrinter = true; } /// Utility function for printing version number. @@ -1422,3 +1596,13 @@ 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; +} diff --git a/lib/Support/Compression.cpp b/lib/Support/Compression.cpp new file mode 100644 index 0000000000..fd8a8743ea --- /dev/null +++ b/lib/Support/Compression.cpp @@ -0,0 +1,97 @@ +//===--- Compression.cpp - Compression implementation ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements compression functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Compression.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Config/config.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#if LLVM_ENABLE_ZLIB == 1 && HAVE_ZLIB_H +#include <zlib.h> +#endif + +using namespace llvm; + +#if LLVM_ENABLE_ZLIB == 1 && HAVE_LIBZ +static int encodeZlibCompressionLevel(zlib::CompressionLevel Level) { + switch (Level) { + case zlib::NoCompression: return 0; + case zlib::BestSpeedCompression: return 1; + case zlib::DefaultCompression: return Z_DEFAULT_COMPRESSION; + case zlib::BestSizeCompression: return 9; + } + llvm_unreachable("Invalid zlib::CompressionLevel!"); +} + +static zlib::Status encodeZlibReturnValue(int ReturnValue) { + switch (ReturnValue) { + case Z_OK: return zlib::StatusOK; + case Z_MEM_ERROR: return zlib::StatusOutOfMemory; + case Z_BUF_ERROR: return zlib::StatusBufferTooShort; + case Z_STREAM_ERROR: return zlib::StatusInvalidArg; + case Z_DATA_ERROR: return zlib::StatusInvalidData; + default: llvm_unreachable("unknown zlib return status!"); + } +} + +bool zlib::isAvailable() { return true; } +zlib::Status zlib::compress(StringRef InputBuffer, + OwningPtr<MemoryBuffer> &CompressedBuffer, + CompressionLevel Level) { + unsigned long CompressedSize = ::compressBound(InputBuffer.size()); + OwningArrayPtr<char> TmpBuffer(new char[CompressedSize]); + int CLevel = encodeZlibCompressionLevel(Level); + Status Res = encodeZlibReturnValue(::compress2( + (Bytef *)TmpBuffer.get(), &CompressedSize, + (const Bytef *)InputBuffer.data(), InputBuffer.size(), CLevel)); + if (Res == StatusOK) { + CompressedBuffer.reset(MemoryBuffer::getMemBufferCopy( + StringRef(TmpBuffer.get(), CompressedSize))); + // Tell MSan that memory initialized by zlib is valid. + __msan_unpoison(CompressedBuffer->getBufferStart(), CompressedSize); + } + return Res; +} + +zlib::Status zlib::uncompress(StringRef InputBuffer, + OwningPtr<MemoryBuffer> &UncompressedBuffer, + size_t UncompressedSize) { + OwningArrayPtr<char> TmpBuffer(new char[UncompressedSize]); + Status Res = encodeZlibReturnValue( + ::uncompress((Bytef *)TmpBuffer.get(), (uLongf *)&UncompressedSize, + (const Bytef *)InputBuffer.data(), InputBuffer.size())); + if (Res == StatusOK) { + UncompressedBuffer.reset(MemoryBuffer::getMemBufferCopy( + StringRef(TmpBuffer.get(), UncompressedSize))); + // Tell MSan that memory initialized by zlib is valid. + __msan_unpoison(UncompressedBuffer->getBufferStart(), UncompressedSize); + } + return Res; +} + +#else +bool zlib::isAvailable() { return false; } +zlib::Status zlib::compress(StringRef InputBuffer, + OwningPtr<MemoryBuffer> &CompressedBuffer, + CompressionLevel Level) { + return zlib::StatusUnsupported; +} +zlib::Status zlib::uncompress(StringRef InputBuffer, + OwningPtr<MemoryBuffer> &UncompressedBuffer, + size_t UncompressedSize) { + return zlib::StatusUnsupported; +} +#endif + diff --git a/lib/Support/DataExtractor.cpp b/lib/Support/DataExtractor.cpp index 3d5cce0535..a564d211b1 100644 --- a/lib/Support/DataExtractor.cpp +++ b/lib/Support/DataExtractor.cpp @@ -20,7 +20,7 @@ static T getU(uint32_t *offset_ptr, const DataExtractor *de, uint32_t offset = *offset_ptr; if (de->isValidOffsetForDataOfSize(offset, sizeof(val))) { std::memcpy(&val, &Data[offset], sizeof(val)); - if (sys::isLittleEndianHost() != isLittleEndian) + if (sys::IsLittleEndianHost != isLittleEndian) val = sys::SwapByteOrder(val); // Advance the offset diff --git a/lib/Support/ErrorHandling.cpp b/lib/Support/ErrorHandling.cpp index d4382e54e0..f4b591e777 100644 --- a/lib/Support/ErrorHandling.cpp +++ b/lib/Support/ErrorHandling.cpp @@ -49,21 +49,21 @@ void llvm::remove_fatal_error_handler() { ErrorHandler = 0; } -void llvm::report_fatal_error(const char *Reason) { - report_fatal_error(Twine(Reason)); +void llvm::report_fatal_error(const char *Reason, bool GenCrashDiag) { + report_fatal_error(Twine(Reason), GenCrashDiag); } -void llvm::report_fatal_error(const std::string &Reason) { - report_fatal_error(Twine(Reason)); +void llvm::report_fatal_error(const std::string &Reason, bool GenCrashDiag) { + report_fatal_error(Twine(Reason), GenCrashDiag); } -void llvm::report_fatal_error(StringRef Reason) { - report_fatal_error(Twine(Reason)); +void llvm::report_fatal_error(StringRef Reason, bool GenCrashDiag) { + report_fatal_error(Twine(Reason), GenCrashDiag); } -void llvm::report_fatal_error(const Twine &Reason) { +void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) { if (ErrorHandler) { - ErrorHandler(ErrorHandlerUserData, Reason.str()); + ErrorHandler(ErrorHandlerUserData, Reason.str(), GenCrashDiag); } else { // Blast the result out to stderr. We don't try hard to make sure this // succeeds (e.g. handling EINTR) and we can't use errs() here because diff --git a/lib/Support/FileOutputBuffer.cpp b/lib/Support/FileOutputBuffer.cpp index cd430f218b..1ee69b6023 100644 --- a/lib/Support/FileOutputBuffer.cpp +++ b/lib/Support/FileOutputBuffer.cpp @@ -70,8 +70,8 @@ error_code FileOutputBuffer::create(StringRef FilePath, if (EC) return EC; - OwningPtr<mapped_file_region> MappedFile( - new mapped_file_region(FD, mapped_file_region::readwrite, Size, 0, EC)); + OwningPtr<mapped_file_region> MappedFile(new mapped_file_region( + FD, true, mapped_file_region::readwrite, Size, 0, EC)); if (EC) return EC; diff --git a/lib/Support/FoldingSet.cpp b/lib/Support/FoldingSet.cpp index 36e33b5aaf..145f12dc1e 100644 --- a/lib/Support/FoldingSet.cpp +++ b/lib/Support/FoldingSet.cpp @@ -101,7 +101,7 @@ 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. - if (sys::isBigEndianHost()) { + if (sys::IsBigEndianHost) { for (Pos += 4; Pos <= Size; Pos += 4) { unsigned V = ((unsigned char)String[Pos - 4] << 24) | ((unsigned char)String[Pos - 3] << 16) | @@ -110,7 +110,7 @@ void FoldingSetNodeID::AddString(StringRef String) { Bits.push_back(V); } } else { - assert(sys::isLittleEndianHost() && "Unexpected host endianness"); + assert(sys::IsLittleEndianHost && "Unexpected host endianness"); for (Pos += 4; Pos <= Size; Pos += 4) { unsigned V = ((unsigned char)String[Pos - 1] << 24) | ((unsigned char)String[Pos - 2] << 16) | diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp index b9bbcb9322..a7c7a95800 100644 --- a/lib/Support/Host.cpp +++ b/lib/Support/Host.cpp @@ -112,6 +112,21 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, #endif } +static bool OSHasAVXSupport() { +#if defined(__GNUC__) + // Check xgetbv; this uses a .byte sequence instead of the instruction + // directly because older assemblers do not include support for xgetbv and + // there is no easy way to conditionally compile based on the assembler used. + int rEAX, rEDX; + __asm__ (".byte 0x0f, 0x01, 0xd0" : "=a" (rEAX), "=d" (rEDX) : "c" (0)); +#elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) + unsigned long long rEAX = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); +#else + int rEAX = 0; // Ensures we return false +#endif + return (rEAX & 6) == 6; +} + static void DetectX86FamilyModel(unsigned EAX, unsigned &Family, unsigned &Model) { Family = (EAX >> 8) & 0xf; // Bits 8 - 11 @@ -134,6 +149,11 @@ std::string sys::getHostCPUName() { DetectX86FamilyModel(EAX, Family, Model); bool HasSSE3 = (ECX & 0x1); + // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV + // indicates that the AVX registers will be saved and restored on context + // switch, then we have full AVX support. + const unsigned AVXBits = (1 << 27) | (1 << 28); + bool HasAVX = ((ECX & AVXBits) == AVXBits) && OSHasAVXSupport(); GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); bool Em64T = (EDX >> 29) & 0x1; @@ -243,11 +263,15 @@ std::string sys::getHostCPUName() { case 42: // Intel Core i7 processor. All processors are manufactured // using the 32 nm process. case 45: - return "corei7-avx"; + // Not all Sandy Bridge processors support AVX (such as the Pentium + // versions instead of the i7 versions). + return HasAVX ? "corei7-avx" : "corei7"; // Ivy Bridge: case 58: - return "core-avx-i"; + // Not all Ivy Bridge processors support AVX (such as the Pentium + // versions instead of the i7 versions). + return HasAVX ? "core-avx-i" : "corei7"; case 28: // Most 45 nm Intel Atom processors case 38: // 45 nm Atom Lincroft @@ -331,10 +355,15 @@ std::string sys::getHostCPUName() { case 20: return "btver1"; case 21: - if (Model <= 15) - return "bdver1"; - else if (Model <= 31) + if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback. + return "btver1"; + if (Model > 15 && Model <= 31) return "bdver2"; + return "bdver1"; + case 22: + if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback. + return "btver1"; + return "btver2"; default: return "generic"; } @@ -584,7 +613,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features){ #endif std::string sys::getProcessTriple() { - Triple PT(LLVM_HOSTTRIPLE); + Triple PT(LLVM_HOST_TRIPLE); if (sizeof(void *) == 8 && PT.isArch32Bit()) PT = PT.get64BitArchVariant(); diff --git a/lib/Support/LockFileManager.cpp b/lib/Support/LockFileManager.cpp index f49d025c11..819d25546b 100644 --- a/lib/Support/LockFileManager.cpp +++ b/lib/Support/LockFileManager.cpp @@ -174,8 +174,8 @@ void LockFileManager::waitForUnlock() { Interval.tv_sec = 0; Interval.tv_nsec = 1000000; #endif - // Don't wait more than an hour for the file to appear. - const unsigned MaxSeconds = 3600; + // Don't wait more than five minutes for the file to appear. + unsigned MaxSeconds = 300; bool LockFileGone = false; do { // Sleep for the designated interval, to allow the owning process time to @@ -187,21 +187,48 @@ void LockFileManager::waitForUnlock() { #else nanosleep(&Interval, NULL); #endif - // If the lock file no longer exists, wait for the actual file. bool Exists = false; + bool LockFileJustDisappeared = false; + + // If the lock file is still expected to be there, check whether it still + // is. if (!LockFileGone) { if (!sys::fs::exists(LockFileName.str(), Exists) && !Exists) { LockFileGone = true; + LockFileJustDisappeared = true; Exists = false; } } + + // If the lock file is no longer there, check if the original file is + // available now. if (LockFileGone) { - if (!sys::fs::exists(FileName.str(), Exists) && Exists) + if (!sys::fs::exists(FileName.str(), Exists) && Exists) { return; + } + + // 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 (!processStillExecuting((*Owner).first, (*Owner).second)) + // 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)) { return; + } // Exponentially increase the time we wait for the lock to be removed. #if LLVM_ON_WIN32 diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp index 265f14ad48..7a8b0ecd3d 100644 --- a/lib/Support/MemoryBuffer.cpp +++ b/lib/Support/MemoryBuffer.cpp @@ -72,13 +72,17 @@ static void CopyStringRef(char *Memory, StringRef Data) { Memory[Data.size()] = 0; // Null terminate string. } -/// GetNamedBuffer - Allocates a new MemoryBuffer with Name copied after it. -template <typename T> -static T *GetNamedBuffer(StringRef Buffer, StringRef Name, - bool RequiresNullTerminator) { - char *Mem = static_cast<char*>(operator new(sizeof(T) + Name.size() + 1)); - CopyStringRef(Mem + sizeof(T), Name); - return new (Mem) T(Buffer, RequiresNullTerminator); +namespace { +struct NamedBufferAlloc { + StringRef Name; + NamedBufferAlloc(StringRef Name) : Name(Name) {} +}; +} + +void *operator new(size_t N, const NamedBufferAlloc &Alloc) { + char *Mem = static_cast<char *>(operator new(N + Alloc.Name.size() + 1)); + CopyStringRef(Mem + N, Alloc.Name); + return Mem; } namespace { @@ -105,8 +109,8 @@ public: MemoryBuffer *MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName, bool RequiresNullTerminator) { - return GetNamedBuffer<MemoryBufferMem>(InputData, BufferName, - RequiresNullTerminator); + return new (NamedBufferAlloc(BufferName)) + MemoryBufferMem(InputData, RequiresNullTerminator); } /// getMemBufferCopy - Open the specified memory range as a MemoryBuffer, @@ -183,24 +187,38 @@ error_code MemoryBuffer::getFileOrSTDIN(const char *Filename, //===----------------------------------------------------------------------===// namespace { -/// MemoryBufferMMapFile - This represents a file that was mapped in with the -/// sys::Path::MapInFilePages method. When destroyed, it calls the -/// sys::Path::UnMapFilePages method. -class MemoryBufferMMapFile : public MemoryBufferMem { -public: - MemoryBufferMMapFile(StringRef Buffer, bool RequiresNullTerminator) - : MemoryBufferMem(Buffer, RequiresNullTerminator) { } +/// \brief Memorry maps a file descriptor using sys::fs::mapped_file_region. +/// +/// This handles converting the offset into a legal offset on the platform. +class MemoryBufferMMapFile : public MemoryBuffer { + sys::fs::mapped_file_region MFR; + + static uint64_t getLegalMapOffset(uint64_t Offset) { + return Offset & ~(sys::fs::mapped_file_region::alignment() - 1); + } + + static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) { + return Len + (Offset - getLegalMapOffset(Offset)); + } - ~MemoryBufferMMapFile() { - static int PageSize = sys::process::get_self()->page_size(); + const char *getStart(uint64_t Len, uint64_t Offset) { + return MFR.const_data() + (Offset - getLegalMapOffset(Offset)); + } - uintptr_t Start = reinterpret_cast<uintptr_t>(getBufferStart()); - size_t Size = getBufferSize(); - uintptr_t RealStart = Start & ~(PageSize - 1); - size_t RealSize = Size + (Start - RealStart); +public: + MemoryBufferMMapFile(bool RequiresNullTerminator, int FD, uint64_t Len, + uint64_t Offset, error_code EC) + : MFR(FD, false, sys::fs::mapped_file_region::readonly, + getLegalMapSize(Len, Offset), getLegalMapOffset(Offset), EC) { + if (!EC) { + const char *Start = getStart(Len, Offset); + init(Start, Start + Len, RequiresNullTerminator); + } + } - sys::Path::UnMapFilePages(reinterpret_cast<const char*>(RealStart), - RealSize); + virtual const char *getBufferIdentifier() const LLVM_OVERRIDE { + // The name is stored after the class itself. + return reinterpret_cast<const char *>(this + 1); } virtual BufferKind getBufferKind() const LLVM_OVERRIDE { @@ -244,6 +262,8 @@ error_code MemoryBuffer::getFile(const char *Filename, OwningPtr<MemoryBuffer> &result, int64_t FileSize, bool RequiresNullTerminator) { + // FIXME: Review if this check is unnecessary on windows as well. +#ifdef LLVM_ON_WIN32 // First check that the "file" is not a directory bool is_dir = false; error_code err = sys::fs::is_directory(Filename, is_dir); @@ -251,6 +271,7 @@ error_code MemoryBuffer::getFile(const char *Filename, return err; if (is_dir) return make_error_code(errc::is_a_directory); +#endif int OpenFlags = O_RDONLY; #ifdef O_BINARY @@ -269,7 +290,7 @@ error_code MemoryBuffer::getFile(const char *Filename, static bool shouldUseMmap(int FD, size_t FileSize, size_t MapSize, - int64_t Offset, + int64_t Offset, // @LOCALMOD (?) bool RequiresNullTerminator, int PageSize) { // We don't use mmap for small files because this can severely fragment our @@ -280,6 +301,7 @@ static bool shouldUseMmap(int FD, if (!RequiresNullTerminator) return true; + // If we don't know the file size, use fstat to find out. fstat on an open // file descriptor is cheaper than stat on a random path. // FIXME: this chunk of code is duplicated, but it avoids a fstat when @@ -340,17 +362,11 @@ error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, PageSize)) { - int64_t RealMapOffset = Offset & ~(PageSize - 1); - int64_t Delta = Offset - RealMapOffset; - size_t RealMapSize = MapSize + Delta; - - if (const char *Pages = sys::Path::MapInFilePages(FD, - RealMapSize, - RealMapOffset)) { - result.reset(GetNamedBuffer<MemoryBufferMMapFile>( - StringRef(Pages + Delta, MapSize), Filename, RequiresNullTerminator)); + error_code EC; + result.reset(new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile( + RequiresNullTerminator, FD, MapSize, Offset, EC)); + if (!EC) return error_code::success(); - } } MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename); diff --git a/lib/Support/PathV2.cpp b/lib/Support/PathV2.cpp index 41add96194..ac53a9e9e6 100644 --- a/lib/Support/PathV2.cpp +++ b/lib/Support/PathV2.cpp @@ -18,6 +18,9 @@ #include <cctype> #include <cstdio> #include <cstring> +#ifdef __APPLE__ +#include <unistd.h> +#endif namespace { using llvm::StringRef; @@ -493,6 +496,27 @@ bool is_separator(char value) { void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result) { result.clear(); +#ifdef __APPLE__ + // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR. + int ConfName = erasedOnReboot? _CS_DARWIN_USER_TEMP_DIR + : _CS_DARWIN_USER_CACHE_DIR; + size_t ConfLen = confstr(ConfName, 0, 0); + if (ConfLen > 0) { + do { + result.resize(ConfLen); + ConfLen = confstr(ConfName, result.data(), result.size()); + } while (ConfLen > 0 && ConfLen != result.size()); + + if (ConfLen > 0) { + assert(result.back() == 0); + result.pop_back(); + return; + } + + result.clear(); + } +#endif + // Check whether the temporary directory is specified by an environment // variable. const char *EnvironmentVariable; @@ -765,8 +789,11 @@ file_magic identify_magic(StringRef magic) { case '\177': if (magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') { - if (magic.size() >= 18 && magic[17] == 0) - switch (magic[16]) { + bool Data2MSB = magic[5] == 2; + unsigned high = Data2MSB ? 16 : 17; + unsigned low = Data2MSB ? 17 : 16; + if (magic.size() >= 18 && magic[high] == 0) + switch (magic[low]) { default: break; case 1: return file_magic::elf_relocatable; case 2: return file_magic::elf_executable; diff --git a/lib/Support/PrettyStackTrace.cpp b/lib/Support/PrettyStackTrace.cpp index 21d56adb5e..23ee5ab105 100644 --- a/lib/Support/PrettyStackTrace.cpp +++ b/lib/Support/PrettyStackTrace.cpp @@ -17,6 +17,7 @@ #include "llvm/Config/config.h" // Get autoconf configuration settings #include "llvm/Support/Signals.h" #include "llvm/Support/ThreadLocal.h" +#include "llvm/Support/Watchdog.h" #include "llvm/Support/raw_ostream.h" #ifdef HAVE_CRASHREPORTERCLIENT_H @@ -37,7 +38,10 @@ static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){ if (Entry->getNextEntry()) NextID = PrintStack(Entry->getNextEntry(), OS); OS << NextID << ".\t"; - Entry->print(OS); + { + sys::Watchdog W(5); + Entry->print(OS); + } return NextID+1; } diff --git a/lib/Support/Program.cpp b/lib/Support/Program.cpp index 75bc282d9b..201d5c0d30 100644 --- a/lib/Support/Program.cpp +++ b/lib/Support/Program.cpp @@ -29,12 +29,15 @@ Program::ExecuteAndWait(const Path& path, const Path** redirects, unsigned secondsToWait, unsigned memoryLimit, - std::string* ErrMsg) { + std::string* ErrMsg, + bool *ExecutionFailed) { Program prg; - if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg)) + if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg)) { + if (ExecutionFailed) *ExecutionFailed = false; return prg.Wait(path, secondsToWait, ErrMsg); - else - return -1; + } + if (ExecutionFailed) *ExecutionFailed = true; + return -1; } void diff --git a/lib/Support/SmallPtrSet.cpp b/lib/Support/SmallPtrSet.cpp index 3b53e9ff49..f0fed7792c 100644 --- a/lib/Support/SmallPtrSet.cpp +++ b/lib/Support/SmallPtrSet.cpp @@ -29,13 +29,9 @@ void SmallPtrSetImpl::shrink_and_clear() { NumElements = NumTombstones = 0; // Install the new array. Clear all the buckets to empty. - CurArray = (const void**)malloc(sizeof(void*) * (CurArraySize+1)); + CurArray = (const void**)malloc(sizeof(void*) * CurArraySize); assert(CurArray && "Failed to allocate memory?"); memset(CurArray, -1, CurArraySize*sizeof(void*)); - - // The end pointer, always valid, is set to a valid element to help the - // iterator. - CurArray[CurArraySize] = 0; } bool SmallPtrSetImpl::insert_imp(const void * Ptr) { @@ -139,15 +135,11 @@ void SmallPtrSetImpl::Grow(unsigned NewSize) { bool WasSmall = isSmall(); // Install the new array. Clear all the buckets to empty. - CurArray = (const void**)malloc(sizeof(void*) * (NewSize+1)); + CurArray = (const void**)malloc(sizeof(void*) * NewSize); assert(CurArray && "Failed to allocate memory?"); CurArraySize = NewSize; memset(CurArray, -1, NewSize*sizeof(void*)); - // The end pointer, always valid, is set to a valid element to help the - // iterator. - CurArray[NewSize] = 0; - // Copy over all the elements. if (WasSmall) { // Small sets store their elements in order. @@ -180,7 +172,7 @@ SmallPtrSetImpl::SmallPtrSetImpl(const void **SmallStorage, CurArray = SmallArray; // Otherwise, allocate new heap space (unless we were the same size) } else { - CurArray = (const void**)malloc(sizeof(void*) * (that.CurArraySize+1)); + CurArray = (const void**)malloc(sizeof(void*) * that.CurArraySize); assert(CurArray && "Failed to allocate memory?"); } @@ -188,7 +180,7 @@ SmallPtrSetImpl::SmallPtrSetImpl(const void **SmallStorage, CurArraySize = that.CurArraySize; // Copy over the contents from the other set - memcpy(CurArray, that.CurArray, sizeof(void*)*(CurArraySize+1)); + memcpy(CurArray, that.CurArray, sizeof(void*)*CurArraySize); NumElements = that.NumElements; NumTombstones = that.NumTombstones; @@ -200,7 +192,7 @@ void SmallPtrSetImpl::CopyFrom(const SmallPtrSetImpl &RHS) { if (isSmall() && RHS.isSmall()) assert(CurArraySize == RHS.CurArraySize && "Cannot assign sets with different small sizes"); - + // If we're becoming small, prepare to insert into our stack space if (RHS.isSmall()) { if (!isSmall()) @@ -209,9 +201,9 @@ void SmallPtrSetImpl::CopyFrom(const SmallPtrSetImpl &RHS) { // Otherwise, allocate new heap space (unless we were the same size) } else if (CurArraySize != RHS.CurArraySize) { if (isSmall()) - CurArray = (const void**)malloc(sizeof(void*) * (RHS.CurArraySize+1)); + CurArray = (const void**)malloc(sizeof(void*) * RHS.CurArraySize); else - CurArray = (const void**)realloc(CurArray, sizeof(void*)*(RHS.CurArraySize+1)); + CurArray = (const void**)realloc(CurArray, sizeof(void*)*RHS.CurArraySize); assert(CurArray && "Failed to allocate memory?"); } @@ -219,7 +211,7 @@ void SmallPtrSetImpl::CopyFrom(const SmallPtrSetImpl &RHS) { CurArraySize = RHS.CurArraySize; // Copy over the contents from the other set - memcpy(CurArray, RHS.CurArray, sizeof(void*)*(CurArraySize+1)); + memcpy(CurArray, RHS.CurArray, sizeof(void*)*CurArraySize); NumElements = RHS.NumElements; NumTombstones = RHS.NumTombstones; diff --git a/lib/Support/Statistic.cpp b/lib/Support/Statistic.cpp index 3a6522101d..9c28176b73 100644 --- a/lib/Support/Statistic.cpp +++ b/lib/Support/Statistic.cpp @@ -40,7 +40,9 @@ namespace llvm { extern raw_ostream *CreateInfoOutputFile(); } /// what they did. /// static cl::opt<bool> -Enabled("stats", cl::desc("Enable statistics output from program")); +Enabled( + "stats", + cl::desc("Enable statistics output from program (available with Asserts)")); namespace { @@ -142,6 +144,7 @@ void llvm::PrintStatistics(raw_ostream &OS) { } void llvm::PrintStatistics() { +#if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS) StatisticInfo &Stats = *StatInfo; // Statistics not enabled? @@ -151,4 +154,17 @@ void llvm::PrintStatistics() { raw_ostream &OutStream = *CreateInfoOutputFile(); PrintStatistics(OutStream); delete &OutStream; // Close the file. +#else + // Check if the -stats option is set instead of checking + // !Stats.Stats.empty(). In release builds, Statistics operators + // do nothing, so stats are never Registered. + if (Enabled) { + // Get the stream to write to. + raw_ostream &OutStream = *CreateInfoOutputFile(); + OutStream << "Statistics are disabled. " + << "Build with asserts or with -DLLVM_ENABLE_STATS\n"; + OutStream.flush(); + delete &OutStream; // Close the file. + } +#endif } diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp index d2508ac1ef..412e34ccc5 100644 --- a/lib/Support/Triple.cpp +++ b/lib/Support/Triple.cpp @@ -32,6 +32,7 @@ const char *Triple::getArchTypeName(ArchType Kind) { case r600: return "r600"; case sparc: return "sparc"; case sparcv9: return "sparcv9"; + case systemz: return "s390x"; case tce: return "tce"; case thumb: return "thumb"; case x86: return "i386"; @@ -76,6 +77,8 @@ const char *Triple::getArchTypePrefix(ArchType Kind) { case sparcv9: case sparc: return "sparc"; + case systemz: return "systemz"; + case x86: case x86_64: return "x86"; @@ -170,6 +173,7 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { .Case("hexagon", hexagon) .Case("sparc", sparc) .Case("sparcv9", sparcv9) + .Case("systemz", systemz) .Case("tce", tce) .Case("thumb", thumb) .Case("x86", x86) @@ -233,6 +237,7 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Case("mips64el", Triple::mips64el) .Case("r600", Triple::r600) .Case("hexagon", Triple::hexagon) + .Case("s390x", Triple::systemz) .Case("sparc", Triple::sparc) .Case("sparcv9", Triple::sparcv9) .Case("tce", Triple::tce) @@ -687,6 +692,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::nvptx64: case llvm::Triple::ppc64: case llvm::Triple::sparcv9: + case llvm::Triple::systemz: case llvm::Triple::x86_64: case llvm::Triple::spir64: return 64; @@ -712,6 +718,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::UnknownArch: case Triple::aarch64: case Triple::msp430: + case Triple::systemz: T.setArch(UnknownArch); break; @@ -769,6 +776,7 @@ Triple Triple::get64BitArchVariant() const { case Triple::nvptx64: case Triple::ppc64: case Triple::sparcv9: + case Triple::systemz: case Triple::x86_64: // Already 64-bit. break; diff --git a/lib/Support/Unix/Memory.inc b/lib/Support/Unix/Memory.inc index e6fba6801c..6be3ee045f 100644 --- a/lib/Support/Unix/Memory.inc +++ b/lib/Support/Unix/Memory.inc @@ -329,14 +329,23 @@ void Memory::InvalidateInstructionCache(const void *Addr, for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) asm volatile("icbi 0, %0" : : "r"(Line)); asm volatile("isync"); -# elif defined(__arm__) && defined(__GNUC__) +# elif (defined(__arm__) || defined(__aarch64__)) && defined(__GNUC__) // FIXME: Can we safely always call this for __GNUC__ everywhere? const char *Start = static_cast<const char *>(Addr); const char *End = Start + Len; __clear_cache(const_cast<char *>(Start), const_cast<char *>(End)); # elif defined(__mips__) const char *Start = static_cast<const char *>(Addr); +# if defined(ANDROID) + // The declaration of "cacheflush" in Android bionic: + // extern int cacheflush(long start, long end, long flags); + const char *End = Start + Len; + long LStart = reinterpret_cast<long>(const_cast<char *>(Start)); + long LEnd = reinterpret_cast<long>(const_cast<char *>(End)); + cacheflush(LStart, LEnd, BCACHE); +# else cacheflush(const_cast<char *>(Start), Len, BCACHE); +# endif # endif #endif // end apple diff --git a/lib/Support/Unix/PathV2.inc b/lib/Support/Unix/PathV2.inc index 4e77f1a82b..f426fbf7fc 100644 --- a/lib/Support/Unix/PathV2.inc +++ b/lib/Support/Unix/PathV2.inc @@ -260,6 +260,7 @@ error_code remove(const Twine &path, bool &existed) { existed = false; } else existed = true; + return error_code::success(); #endif } @@ -416,9 +417,6 @@ error_code permissions(const Twine &path, perms prms) { error_code unique_file(const Twine &model, int &result_fd, SmallVectorImpl<char> &result_path, bool makeAbsolute, unsigned mode) { -#ifdef __native_client__ - llvm_unreachable("unique_file() not implemented for Native Client"); -#else SmallString<128> Model; model.toVector(Model); // Null terminate. @@ -459,9 +457,7 @@ rety_open_create: if (SavedErrno == errc::file_exists) goto retry_random_path; // If path prefix doesn't exist, try to create it. - if (SavedErrno == errc::no_such_file_or_directory && - !exists(path::parent_path(RandomPath)) && - !TriedToCreateParent) { + if (SavedErrno == errc::no_such_file_or_directory && !TriedToCreateParent) { TriedToCreateParent = true; StringRef p(RandomPath); SmallString<64> dir_to_create; @@ -502,19 +498,20 @@ rety_open_create: result_fd = RandomFD; return error_code::success(); -#endif } -error_code mapped_file_region::init(int fd, uint64_t offset) { +error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { #ifdef __native_client__ // Newlib does not have ftruncate. llvm_unreachable("mapped_file_region not implemented for native client"); #else - AutoFD FD(fd); + AutoFD ScopedFD(FD); + if (!CloseFD) + ScopedFD.take(); // Figure out how large the file is. struct stat FileInfo; - if (fstat(fd, &FileInfo) == -1) + if (fstat(FD, &FileInfo) == -1) return error_code(errno, system_category()); uint64_t FileSize = FileInfo.st_size; @@ -522,7 +519,7 @@ error_code mapped_file_region::init(int fd, uint64_t offset) { Size = FileSize; else if (FileSize < Size) { // We need to grow the file. - if (ftruncate(fd, Size) == -1) + if (ftruncate(FD, Size) == -1) return error_code(errno, system_category()); } @@ -531,7 +528,7 @@ error_code mapped_file_region::init(int fd, uint64_t offset) { #ifdef MAP_FILE flags |= MAP_FILE; #endif - Mapping = ::mmap(0, Size, prot, flags, fd, offset); + Mapping = ::mmap(0, Size, prot, flags, FD, Offset); if (Mapping == MAP_FAILED) return error_code(errno, system_category()); return error_code::success(); @@ -564,12 +561,13 @@ mapped_file_region::mapped_file_region(const Twine &path, return; } - ec = init(ofd, offset); + ec = init(ofd, true, offset); if (ec) Mapping = 0; } mapped_file_region::mapped_file_region(int fd, + bool closefd, mapmode mode, uint64_t length, uint64_t offset, @@ -586,7 +584,7 @@ mapped_file_region::mapped_file_region(int fd, return; } - ec = init(fd, offset); + ec = init(fd, closefd, offset); if (ec) Mapping = 0; } diff --git a/lib/Support/Unix/Program.inc b/lib/Support/Unix/Program.inc index 834b1cc5dc..c6cc698e9b 100644 --- a/lib/Support/Unix/Program.inc +++ b/lib/Support/Unix/Program.inc @@ -32,6 +32,9 @@ #if HAVE_FCNTL_H #include <fcntl.h> #endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif #ifdef HAVE_POSIX_SPAWN #include <spawn.h> #if !defined(__APPLE__) @@ -431,4 +434,25 @@ error_code Program::ChangeStderrToBinary(){ return make_error_code(errc::success); } +bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) { + static long ArgMax = sysconf(_SC_ARG_MAX); + + // System says no practical limit. + if (ArgMax == -1) + return true; + + // Conservatively account for space required by environment variables. + ArgMax /= 2; + + size_t ArgLength = 0; + for (ArrayRef<const char*>::iterator I = Args.begin(), E = Args.end(); + I != E; ++I) { + ArgLength += strlen(*I) + 1; + if (ArgLength > size_t(ArgMax)) { + return false; + } + } + return true; +} + } diff --git a/lib/Support/Unix/Signals.inc b/lib/Support/Unix/Signals.inc index d6fe7861bb..cdb1be900b 100644 --- a/lib/Support/Unix/Signals.inc +++ b/lib/Support/Unix/Signals.inc @@ -27,10 +27,12 @@ #if HAVE_SYS_STAT_H #include <sys/stat.h> #endif -#if HAVE_DLFCN_H && __GNUG__ -#include <dlfcn.h> +#if HAVE_CXXABI_H #include <cxxabi.h> #endif +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif #if HAVE_MACH_MACH_H #include <mach/mach.h> #endif @@ -190,6 +192,15 @@ static RETSIGTYPE SignalHandler(int Sig) { // Otherwise if it is a fault (like SEGV) run any handler. for (unsigned i = 0, e = CallBacksToRun.size(); i != e; ++i) CallBacksToRun[i].first(CallBacksToRun[i].second); + +#ifdef __s390__ + // On S/390, certain signals are delivered with PSW Address pointing to + // *after* the faulting instruction. Simply returning from the signal + // handler would continue execution after that point, instead of + // re-raising the signal. Raise the signal manually in those cases. + if (Sig == SIGILL || Sig == SIGFPE || Sig == SIGTRAP) + raise(Sig); +#endif } void llvm::sys::RunInterruptHandlers() { @@ -296,9 +307,13 @@ void llvm::sys::PrintStackTrace(FILE *FD) { (int)(sizeof(void*) * 2) + 2, (unsigned long)StackTrace[i]); if (dlinfo.dli_sname != NULL) { - int res; fputc(' ', FD); +# if HAVE_CXXABI_H + int res; char* d = abi::__cxa_demangle(dlinfo.dli_sname, NULL, NULL, &res); +# else + char* d = NULL; +# endif if (d == NULL) fputs(dlinfo.dli_sname, FD); else fputs(d, FD); free(d); diff --git a/lib/Support/Unix/Watchdog.inc b/lib/Support/Unix/Watchdog.inc new file mode 100644 index 0000000000..5d89c0e51b --- /dev/null +++ b/lib/Support/Unix/Watchdog.inc @@ -0,0 +1,32 @@ +//===--- Unix/Watchdog.inc - Unix Watchdog Implementation -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the generic Unix implementation of the Watchdog class. +// +//===----------------------------------------------------------------------===// + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +namespace llvm { + namespace sys { + Watchdog::Watchdog(unsigned int seconds) { +#ifdef HAVE_UNISTD_H + alarm(seconds); +#endif + } + + Watchdog::~Watchdog() { +#ifdef HAVE_UNISTD_H + alarm(0); +#endif + } + } +} diff --git a/lib/Support/Watchdog.cpp b/lib/Support/Watchdog.cpp new file mode 100644 index 0000000000..724aa001f1 --- /dev/null +++ b/lib/Support/Watchdog.cpp @@ -0,0 +1,23 @@ +//===---- Watchdog.cpp - Implement Watchdog ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Watchdog class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Watchdog.h" +#include "llvm/Config/config.h" + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Watchdog.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Watchdog.inc" +#endif diff --git a/lib/Support/Windows/PathV2.inc b/lib/Support/Windows/PathV2.inc index 2e6cc96e7f..23f3d14f91 100644 --- a/lib/Support/Windows/PathV2.inc +++ b/lib/Support/Windows/PathV2.inc @@ -593,6 +593,10 @@ retry_random_path: random_path_utf16.push_back(0); random_path_utf16.pop_back(); + // Make sure we don't fall into an infinite loop by constantly trying + // to create the parent path. + bool TriedToCreateParent = false; + // Try to create + open the path. retry_create_file: HANDLE TempFileHandle = ::CreateFileW(random_path_utf16.begin(), @@ -610,7 +614,9 @@ retry_create_file: if (ec == windows_error::file_exists) goto retry_random_path; // Check for non-existing parent directories. - if (ec == windows_error::path_not_found) { + if (ec == windows_error::path_not_found && !TriedToCreateParent) { + TriedToCreateParent = true; + // Create the directories using result_path as temp storage. if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), random_path_utf16.size(), result_path)) @@ -705,13 +711,14 @@ error_code get_magic(const Twine &path, uint32_t len, return error_code::success(); } -error_code mapped_file_region::init(int FD, uint64_t Offset) { +error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { FileDescriptor = FD; // Make sure that the requested size fits within SIZE_T. if (Size > std::numeric_limits<SIZE_T>::max()) { - if (FileDescriptor) - _close(FileDescriptor); - else + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); + } else ::CloseHandle(FileHandle); return make_error_code(errc::invalid_argument); } @@ -732,9 +739,10 @@ error_code mapped_file_region::init(int FD, uint64_t Offset) { 0); if (FileMappingHandle == NULL) { error_code ec = windows_error(GetLastError()); - if (FileDescriptor) - _close(FileDescriptor); - else + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); + } else ::CloseHandle(FileHandle); return ec; } @@ -754,9 +762,10 @@ error_code mapped_file_region::init(int FD, uint64_t Offset) { if (Mapping == NULL) { error_code ec = windows_error(GetLastError()); ::CloseHandle(FileMappingHandle); - if (FileDescriptor) - _close(FileDescriptor); - else + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); + } else ::CloseHandle(FileHandle); return ec; } @@ -768,14 +777,24 @@ error_code mapped_file_region::init(int FD, uint64_t Offset) { error_code ec = windows_error(GetLastError()); ::UnmapViewOfFile(Mapping); ::CloseHandle(FileMappingHandle); - if (FileDescriptor) - _close(FileDescriptor); - else + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); + } else ::CloseHandle(FileHandle); return ec; } Size = mbi.RegionSize; } + + // Close all the handles except for the view. It will keep the other handles + // alive. + ::CloseHandle(FileMappingHandle); + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); // Also closes FileHandle. + } else + ::CloseHandle(FileHandle); return error_code::success(); } @@ -815,7 +834,7 @@ mapped_file_region::mapped_file_region(const Twine &path, } FileDescriptor = 0; - ec = init(FileDescriptor, offset); + ec = init(FileDescriptor, true, offset); if (ec) { Mapping = FileMappingHandle = 0; FileHandle = INVALID_HANDLE_VALUE; @@ -824,6 +843,7 @@ mapped_file_region::mapped_file_region(const Twine &path, } mapped_file_region::mapped_file_region(int fd, + bool closefd, mapmode mode, uint64_t length, uint64_t offset, @@ -836,13 +856,14 @@ mapped_file_region::mapped_file_region(int fd, , FileMappingHandle() { FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd)); if (FileHandle == INVALID_HANDLE_VALUE) { - _close(FileDescriptor); + if (closefd) + _close(FileDescriptor); FileDescriptor = 0; ec = make_error_code(errc::bad_file_descriptor); return; } - ec = init(FileDescriptor, offset); + ec = init(FileDescriptor, closefd, offset); if (ec) { Mapping = FileMappingHandle = 0; FileHandle = INVALID_HANDLE_VALUE; @@ -853,12 +874,6 @@ mapped_file_region::mapped_file_region(int fd, mapped_file_region::~mapped_file_region() { if (Mapping) ::UnmapViewOfFile(Mapping); - if (FileMappingHandle) - ::CloseHandle(FileMappingHandle); - if (FileDescriptor) - _close(FileDescriptor); - else if (FileHandle != INVALID_HANDLE_VALUE) - ::CloseHandle(FileHandle); } #if LLVM_HAS_RVALUE_REFERENCES diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc index 691d6d4555..619ae5d8f7 100644 --- a/lib/Support/Windows/Program.inc +++ b/lib/Support/Windows/Program.inc @@ -126,20 +126,58 @@ static bool ArgNeedsQuotes(const char *Str) { return Str[0] == '\0' || strpbrk(Str, "\t \"&\'()*<>\\`^|") != 0; } +/// CountPrecedingBackslashes - Returns the number of backslashes preceding Cur +/// in the C string Start. +static unsigned int CountPrecedingBackslashes(const char *Start, + const char *Cur) { + unsigned int Count = 0; + --Cur; + while (Cur >= Start && *Cur == '\\') { + ++Count; + --Cur; + } + return Count; +} + +/// EscapePrecedingEscapes - Append a backslash to Dst for every backslash +/// preceding Cur in the Start string. Assumes Dst has enough space. +static char *EscapePrecedingEscapes(char *Dst, const char *Start, + const char *Cur) { + unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Cur); + while (PrecedingEscapes > 0) { + *Dst++ = '\\'; + --PrecedingEscapes; + } + return Dst; +} /// ArgLenWithQuotes - Check whether argument needs to be quoted when calling /// CreateProcess and returns length of quoted arg with escaped quotes static unsigned int ArgLenWithQuotes(const char *Str) { - unsigned int len = ArgNeedsQuotes(Str) ? 2 : 0; + const char *Start = Str; + bool Quoted = ArgNeedsQuotes(Str); + unsigned int len = Quoted ? 2 : 0; while (*Str != '\0') { - if (*Str == '\"') - ++len; + if (*Str == '\"') { + // We need to add a backslash, but ensure that it isn't escaped. + unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Str); + len += PrecedingEscapes + 1; + } + // Note that we *don't* need to escape runs of backslashes that don't + // precede a double quote! See MSDN: + // http://msdn.microsoft.com/en-us/library/17w5ykft%28v=vs.85%29.aspx ++len; ++Str; } + if (Quoted) { + // Make sure the closing quote doesn't get escaped by a trailing backslash. + unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Str); + len += PrecedingEscapes + 1; + } + return len; } @@ -180,20 +218,27 @@ Program::Execute(const Path& path, for (unsigned i = 0; args[i]; i++) { const char *arg = args[i]; + const char *start = arg; bool needsQuoting = ArgNeedsQuotes(arg); if (needsQuoting) *p++ = '"'; while (*arg != '\0') { - if (*arg == '\"') + if (*arg == '\"') { + // Escape all preceding escapes (if any), and then escape the quote. + p = EscapePrecedingEscapes(p, start, arg); *p++ = '\\'; + } *p++ = *arg++; } - if (needsQuoting) + if (needsQuoting) { + // Make sure our quote doesn't get escaped by a trailing backslash. + p = EscapePrecedingEscapes(p, start, arg); *p++ = '"'; + } *p++ = ' '; } @@ -396,4 +441,20 @@ error_code Program::ChangeStderrToBinary(){ return make_error_code(errc::success); } +bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) { + // The documented max length of the command line passed to CreateProcess. + static const size_t MaxCommandStringLength = 32768; + size_t ArgLength = 0; + for (ArrayRef<const char*>::iterator I = Args.begin(), E = Args.end(); + I != E; ++I) { + // Account for the trailing space for every arg but the last one and the + // trailing NULL of the last argument. + ArgLength += ArgLenWithQuotes(*I) + 1; + if (ArgLength > MaxCommandStringLength) { + return false; + } + } + return true; +} + } diff --git a/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc index 3dd6660b03..b18b4d1dac 100644 --- a/lib/Support/Windows/Signals.inc +++ b/lib/Support/Windows/Signals.inc @@ -178,6 +178,19 @@ namespace llvm { //===----------------------------------------------------------------------===// #ifdef _MSC_VER +/// AvoidMessageBoxHook - Emulates hitting "retry" from an "abort, retry, +/// ignore" CRT debug report dialog. "retry" raises an exception which +/// ultimately triggers our stack dumper. +static 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(). + if (Return) + *Return = 1; + // Don't call _CrtDbgReport. + return TRUE; +} + /// CRTReportHook - Function called on a CRT debugging event. static int CRTReportHook(int ReportType, char *Message, int *Return) { // Don't cause a DebugBreak() on return. @@ -238,6 +251,15 @@ static void RegisterHandler() { OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); +#ifdef _MSC_VER + const char *EnableMsgbox = getenv("LLVM_ENABLE_CRT_REPORT"); + if (!EnableMsgbox || strcmp("0", EnableMsgbox) == 0) { + // Setting a report hook overrides the default behavior of popping an "abort, + // retry, or ignore" dialog. + _CrtSetReportHook(AvoidMessageBoxHook); + } +#endif + // Environment variable to disable any kind of crash dialog. if (getenv("LLVM_DISABLE_CRASH_REPORT")) { #ifdef _MSC_VER diff --git a/lib/Support/Windows/Watchdog.inc b/lib/Support/Windows/Watchdog.inc new file mode 100644 index 0000000000..fab2bdf2a9 --- /dev/null +++ b/lib/Support/Windows/Watchdog.inc @@ -0,0 +1,24 @@ +//===--- Windows/Watchdog.inc - Windows Watchdog Implementation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the generic Windows implementation of the Watchdog class. +// +//===----------------------------------------------------------------------===// + +// TODO: implement. +// Currently this is only used by PrettyStackTrace which is also unimplemented +// on Windows. Roughly, a Windows implementation would use CreateWaitableTimer +// and a second thread to run the TimerAPCProc. + +namespace llvm { + namespace sys { + Watchdog::Watchdog(unsigned int seconds) {} + Watchdog::~Watchdog() {} + } +} diff --git a/lib/Support/YAMLParser.cpp b/lib/Support/YAMLParser.cpp index 2cead20c0b..213f5e1568 100644 --- a/lib/Support/YAMLParser.cpp +++ b/lib/Support/YAMLParser.cpp @@ -260,7 +260,7 @@ public: Token getNext(); void printError(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Message, - ArrayRef<SMRange> Ranges = ArrayRef<SMRange>()) { + ArrayRef<SMRange> Ranges = None) { SM.PrintMessage(Loc, Kind, Message, Ranges); } diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp index f71abd3b24..a433088b19 100644 --- a/lib/Support/raw_ostream.cpp +++ b/lib/Support/raw_ostream.cpp @@ -306,7 +306,12 @@ raw_ostream &raw_ostream::write(const char *Ptr, size_t Size) { if (LLVM_UNLIKELY(OutBufCur == OutBufStart)) { size_t BytesToWrite = Size - (Size % NumBytes); write_impl(Ptr, BytesToWrite); - copy_to_buffer(Ptr + BytesToWrite, Size - BytesToWrite); + size_t BytesRemaining = Size - BytesToWrite; + if (BytesRemaining > size_t(OutBufEnd - OutBufCur)) { + // Too much left over to copy into our buffer. + return write(Ptr + BytesToWrite, BytesRemaining); + } + copy_to_buffer(Ptr + BytesToWrite, BytesRemaining); return *this; } @@ -512,7 +517,7 @@ raw_fd_ostream::~raw_fd_ostream() { // has_error() and clear the error flag with clear_error() before // destructing raw_ostream objects which may have errors. if (has_error()) - report_fatal_error("IO failure on output stream."); + report_fatal_error("IO failure on output stream.", /*GenCrashDiag=*/false); } |