diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
| commit | 044eb2f6afba375a914ac9d8024f8f5142bb912e (patch) | |
| tree | 1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /lib/Support | |
| parent | eb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff) | |
Notes
Diffstat (limited to 'lib/Support')
64 files changed, 2281 insertions, 1996 deletions
diff --git a/lib/Support/AMDGPUCodeObjectMetadata.cpp b/lib/Support/AMDGPUMetadata.cpp index 863093ab7def..ddb25935e0ef 100644 --- a/lib/Support/AMDGPUCodeObjectMetadata.cpp +++ b/lib/Support/AMDGPUMetadata.cpp @@ -1,4 +1,4 @@ -//===--- AMDGPUCodeObjectMetadata.cpp ---------------------------*- C++ -*-===// +//===--- AMDGPUMetadata.cpp -------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -8,17 +8,17 @@ //===----------------------------------------------------------------------===// // /// \file -/// \brief AMDGPU Code Object Metadata definitions and in-memory -/// representations. +/// \brief AMDGPU metadata definitions and in-memory representations. /// // //===----------------------------------------------------------------------===// -#include "llvm/Support/AMDGPUCodeObjectMetadata.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/AMDGPUMetadata.h" #include "llvm/Support/YAMLTraits.h" using namespace llvm::AMDGPU; -using namespace llvm::AMDGPU::CodeObject; +using namespace llvm::AMDGPU::HSAMD; LLVM_YAML_IS_SEQUENCE_VECTOR(Kernel::Arg::Metadata) LLVM_YAML_IS_SEQUENCE_VECTOR(Kernel::Metadata) @@ -96,52 +96,62 @@ struct MappingTraits<Kernel::Attrs::Metadata> { MD.mWorkGroupSizeHint, std::vector<uint32_t>()); YIO.mapOptional(Kernel::Attrs::Key::VecTypeHint, MD.mVecTypeHint, std::string()); + YIO.mapOptional(Kernel::Attrs::Key::RuntimeHandle, MD.mRuntimeHandle, + std::string()); } }; template <> struct MappingTraits<Kernel::Arg::Metadata> { static void mapping(IO &YIO, Kernel::Arg::Metadata &MD) { + YIO.mapOptional(Kernel::Arg::Key::Name, MD.mName, std::string()); + YIO.mapOptional(Kernel::Arg::Key::TypeName, MD.mTypeName, std::string()); YIO.mapRequired(Kernel::Arg::Key::Size, MD.mSize); YIO.mapRequired(Kernel::Arg::Key::Align, MD.mAlign); YIO.mapRequired(Kernel::Arg::Key::ValueKind, MD.mValueKind); YIO.mapRequired(Kernel::Arg::Key::ValueType, MD.mValueType); YIO.mapOptional(Kernel::Arg::Key::PointeeAlign, MD.mPointeeAlign, uint32_t(0)); - YIO.mapOptional(Kernel::Arg::Key::AccQual, MD.mAccQual, - AccessQualifier::Unknown); YIO.mapOptional(Kernel::Arg::Key::AddrSpaceQual, MD.mAddrSpaceQual, AddressSpaceQualifier::Unknown); + YIO.mapOptional(Kernel::Arg::Key::AccQual, MD.mAccQual, + AccessQualifier::Unknown); + YIO.mapOptional(Kernel::Arg::Key::ActualAccQual, MD.mActualAccQual, + AccessQualifier::Unknown); YIO.mapOptional(Kernel::Arg::Key::IsConst, MD.mIsConst, false); - YIO.mapOptional(Kernel::Arg::Key::IsPipe, MD.mIsPipe, false); YIO.mapOptional(Kernel::Arg::Key::IsRestrict, MD.mIsRestrict, false); YIO.mapOptional(Kernel::Arg::Key::IsVolatile, MD.mIsVolatile, false); - YIO.mapOptional(Kernel::Arg::Key::Name, MD.mName, std::string()); - YIO.mapOptional(Kernel::Arg::Key::TypeName, MD.mTypeName, std::string()); + YIO.mapOptional(Kernel::Arg::Key::IsPipe, MD.mIsPipe, false); } }; template <> struct MappingTraits<Kernel::CodeProps::Metadata> { static void mapping(IO &YIO, Kernel::CodeProps::Metadata &MD) { - YIO.mapOptional(Kernel::CodeProps::Key::KernargSegmentSize, - MD.mKernargSegmentSize, uint64_t(0)); - YIO.mapOptional(Kernel::CodeProps::Key::WorkgroupGroupSegmentSize, - MD.mWorkgroupGroupSegmentSize, uint32_t(0)); - YIO.mapOptional(Kernel::CodeProps::Key::WorkitemPrivateSegmentSize, - MD.mWorkitemPrivateSegmentSize, uint32_t(0)); - YIO.mapOptional(Kernel::CodeProps::Key::WavefrontNumSGPRs, - MD.mWavefrontNumSGPRs, uint16_t(0)); - YIO.mapOptional(Kernel::CodeProps::Key::WorkitemNumVGPRs, - MD.mWorkitemNumVGPRs, uint16_t(0)); - YIO.mapOptional(Kernel::CodeProps::Key::KernargSegmentAlign, - MD.mKernargSegmentAlign, uint8_t(0)); - YIO.mapOptional(Kernel::CodeProps::Key::GroupSegmentAlign, - MD.mGroupSegmentAlign, uint8_t(0)); - YIO.mapOptional(Kernel::CodeProps::Key::PrivateSegmentAlign, - MD.mPrivateSegmentAlign, uint8_t(0)); - YIO.mapOptional(Kernel::CodeProps::Key::WavefrontSize, - MD.mWavefrontSize, uint8_t(0)); + YIO.mapRequired(Kernel::CodeProps::Key::KernargSegmentSize, + MD.mKernargSegmentSize); + YIO.mapRequired(Kernel::CodeProps::Key::GroupSegmentFixedSize, + MD.mGroupSegmentFixedSize); + YIO.mapRequired(Kernel::CodeProps::Key::PrivateSegmentFixedSize, + MD.mPrivateSegmentFixedSize); + YIO.mapRequired(Kernel::CodeProps::Key::KernargSegmentAlign, + MD.mKernargSegmentAlign); + YIO.mapRequired(Kernel::CodeProps::Key::WavefrontSize, + MD.mWavefrontSize); + YIO.mapOptional(Kernel::CodeProps::Key::NumSGPRs, + MD.mNumSGPRs, uint16_t(0)); + YIO.mapOptional(Kernel::CodeProps::Key::NumVGPRs, + MD.mNumVGPRs, uint16_t(0)); + YIO.mapOptional(Kernel::CodeProps::Key::MaxFlatWorkGroupSize, + MD.mMaxFlatWorkGroupSize, uint32_t(0)); + YIO.mapOptional(Kernel::CodeProps::Key::IsDynamicCallStack, + MD.mIsDynamicCallStack, false); + YIO.mapOptional(Kernel::CodeProps::Key::IsXNACKEnabled, + MD.mIsXNACKEnabled, false); + YIO.mapOptional(Kernel::CodeProps::Key::NumSpilledSGPRs, + MD.mNumSpilledSGPRs, uint16_t(0)); + YIO.mapOptional(Kernel::CodeProps::Key::NumSpilledVGPRs, + MD.mNumSpilledVGPRs, uint16_t(0)); } }; @@ -165,6 +175,7 @@ template <> struct MappingTraits<Kernel::Metadata> { static void mapping(IO &YIO, Kernel::Metadata &MD) { YIO.mapRequired(Kernel::Key::Name, MD.mName); + YIO.mapRequired(Kernel::Key::SymbolName, MD.mSymbolName); YIO.mapOptional(Kernel::Key::Language, MD.mLanguage, std::string()); YIO.mapOptional(Kernel::Key::LanguageVersion, MD.mLanguageVersion, std::vector<uint32_t>()); @@ -180,8 +191,8 @@ struct MappingTraits<Kernel::Metadata> { }; template <> -struct MappingTraits<CodeObject::Metadata> { - static void mapping(IO &YIO, CodeObject::Metadata &MD) { +struct MappingTraits<HSAMD::Metadata> { + static void mapping(IO &YIO, HSAMD::Metadata &MD) { YIO.mapRequired(Key::Version, MD.mVersion); YIO.mapOptional(Key::Printf, MD.mPrintf, std::vector<std::string>()); if (!MD.mKernels.empty() || !YIO.outputting()) @@ -192,25 +203,35 @@ struct MappingTraits<CodeObject::Metadata> { } // end namespace yaml namespace AMDGPU { -namespace CodeObject { +namespace HSAMD { -/* static */ -std::error_code Metadata::fromYamlString( - std::string YamlString, Metadata &CodeObjectMetadata) { - yaml::Input YamlInput(YamlString); - YamlInput >> CodeObjectMetadata; +std::error_code fromString(std::string String, Metadata &HSAMetadata) { + yaml::Input YamlInput(String); + YamlInput >> HSAMetadata; return YamlInput.error(); } -/* static */ -std::error_code Metadata::toYamlString( - Metadata CodeObjectMetadata, std::string &YamlString) { - raw_string_ostream YamlStream(YamlString); +std::error_code toString(Metadata HSAMetadata, std::string &String) { + raw_string_ostream YamlStream(String); yaml::Output YamlOutput(YamlStream, nullptr, std::numeric_limits<int>::max()); - YamlOutput << CodeObjectMetadata; + YamlOutput << HSAMetadata; + return std::error_code(); +} + +} // end namespace HSAMD + +namespace PALMD { + +std::error_code toString(const Metadata &PALMetadata, std::string &String) { + raw_string_ostream Stream(String); + for (auto I = PALMetadata.begin(), E = PALMetadata.end(); I != E; ++I) { + Stream << Twine(I == PALMetadata.begin() ? " 0x" : ",0x"); + Stream << Twine::utohexstr(*I); + } + Stream.flush(); return std::error_code(); } -} // end namespace CodeObject +} // end namespace PALMD } // end namespace AMDGPU } // end namespace llvm diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index deb76cb565d1..f7fb0cef16bf 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -1743,6 +1743,7 @@ IEEEFloat::opStatus IEEEFloat::remainder(const IEEEFloat &rhs) { IEEEFloat::opStatus IEEEFloat::mod(const IEEEFloat &rhs) { opStatus fs; fs = modSpecials(rhs); + unsigned int origSign = sign; while (isFiniteNonZero() && rhs.isFiniteNonZero() && compareAbsoluteValue(rhs) != cmpLessThan) { @@ -1754,6 +1755,8 @@ IEEEFloat::opStatus IEEEFloat::mod(const IEEEFloat &rhs) { fs = subtract(V, rmNearestTiesToEven); assert(fs==opOK); } + if (isZero()) + sign = origSign; // fmod requires this return fs; } @@ -4363,10 +4366,7 @@ bool DoubleAPFloat::isLargest() const { bool DoubleAPFloat::isInteger() const { assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); - APFloat Tmp(semPPCDoubleDoubleLegacy); - (void)Tmp.add(Floats[0], rmNearestTiesToEven); - (void)Tmp.add(Floats[1], rmNearestTiesToEven); - return Tmp.isInteger(); + return Floats[0].isInteger() && Floats[1].isInteger(); } void DoubleAPFloat::toString(SmallVectorImpl<char> &Str, diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index c558ddd82161..1ea6319acfad 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -1252,6 +1252,14 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, // b denotes the base of the number system. In our case b is 2^32. const uint64_t b = uint64_t(1) << 32; +// The DEBUG macros here tend to be spam in the debug output if you're not +// debugging this code. Disable them unless KNUTH_DEBUG is defined. +#pragma push_macro("DEBUG") +#ifndef KNUTH_DEBUG +#undef DEBUG +#define DEBUG(X) do {} while (false) +#endif + DEBUG(dbgs() << "KnuthDiv: m=" << m << " n=" << n << '\n'); DEBUG(dbgs() << "KnuthDiv: original:"); DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); @@ -1391,6 +1399,8 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, DEBUG(dbgs() << '\n'); } DEBUG(dbgs() << '\n'); + +#pragma pop_macro("DEBUG") } void APInt::divide(const WordType *LHS, unsigned lhsWords, const WordType *RHS, diff --git a/lib/Support/ARMAttributeParser.cpp b/lib/Support/ARMAttributeParser.cpp index a9a0c1d1a4d3..3d800eb7a96c 100644 --- a/lib/Support/ARMAttributeParser.cpp +++ b/lib/Support/ARMAttributeParser.cpp @@ -592,7 +592,7 @@ void ARMAttributeParser::ParseAttributeList(const uint8_t *Data, bool Handled = false; for (unsigned AHI = 0, AHE = array_lengthof(DisplayRoutines); AHI != AHE && !Handled; ++AHI) { - if (DisplayRoutines[AHI].Attribute == Tag) { + if (uint64_t(DisplayRoutines[AHI].Attribute) == Tag) { (this->*DisplayRoutines[AHI].Routine)(ARMBuildAttrs::AttrType(Tag), Data, Offset); Handled = true; diff --git a/lib/Support/Atomic.cpp b/lib/Support/Atomic.cpp index 55910c489faf..7328a93052cc 100644 --- a/lib/Support/Atomic.cpp +++ b/lib/Support/Atomic.cpp @@ -17,9 +17,9 @@ using namespace llvm; #if defined(_MSC_VER) -#include <Intrin.h> +#include <intrin.h> -// We must include windows.h after Intrin.h. +// We must include windows.h after intrin.h. #include <windows.h> #undef MemoryFence #endif diff --git a/lib/Support/BinaryStreamRef.cpp b/lib/Support/BinaryStreamRef.cpp index fe9a8171e146..60a03fe9930f 100644 --- a/lib/Support/BinaryStreamRef.cpp +++ b/lib/Support/BinaryStreamRef.cpp @@ -66,9 +66,9 @@ private: } BinaryStreamRef::BinaryStreamRef(BinaryStream &Stream) - : BinaryStreamRef(Stream, 0, Stream.getLength()) {} + : BinaryStreamRefBase(Stream) {} BinaryStreamRef::BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, - uint32_t Length) + Optional<uint32_t> Length) : BinaryStreamRefBase(Stream, Offset, Length) {} BinaryStreamRef::BinaryStreamRef(ArrayRef<uint8_t> Data, endianness Endian) : BinaryStreamRefBase(std::make_shared<ArrayRefImpl>(Data, Endian), 0, @@ -77,19 +77,16 @@ BinaryStreamRef::BinaryStreamRef(StringRef Data, endianness Endian) : BinaryStreamRef(makeArrayRef(Data.bytes_begin(), Data.bytes_end()), Endian) {} -BinaryStreamRef::BinaryStreamRef(const BinaryStreamRef &Other) - : BinaryStreamRefBase(Other) {} - Error BinaryStreamRef::readBytes(uint32_t Offset, uint32_t Size, ArrayRef<uint8_t> &Buffer) const { - if (auto EC = checkOffset(Offset, Size)) + if (auto EC = checkOffsetForRead(Offset, Size)) return EC; return BorrowedImpl->readBytes(ViewOffset + Offset, Size, Buffer); } Error BinaryStreamRef::readLongestContiguousChunk( uint32_t Offset, ArrayRef<uint8_t> &Buffer) const { - if (auto EC = checkOffset(Offset, 1)) + if (auto EC = checkOffsetForRead(Offset, 1)) return EC; if (auto EC = @@ -98,18 +95,18 @@ Error BinaryStreamRef::readLongestContiguousChunk( // This StreamRef might refer to a smaller window over a larger stream. In // that case we will have read out more bytes than we should return, because // we should not read past the end of the current view. - uint32_t MaxLength = Length - Offset; + uint32_t MaxLength = getLength() - Offset; if (Buffer.size() > MaxLength) Buffer = Buffer.slice(0, MaxLength); return Error::success(); } WritableBinaryStreamRef::WritableBinaryStreamRef(WritableBinaryStream &Stream) - : WritableBinaryStreamRef(Stream, 0, Stream.getLength()) {} + : BinaryStreamRefBase(Stream) {} WritableBinaryStreamRef::WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset, - uint32_t Length) + Optional<uint32_t> Length) : BinaryStreamRefBase(Stream, Offset, Length) {} WritableBinaryStreamRef::WritableBinaryStreamRef(MutableArrayRef<uint8_t> Data, @@ -117,13 +114,10 @@ WritableBinaryStreamRef::WritableBinaryStreamRef(MutableArrayRef<uint8_t> Data, : BinaryStreamRefBase(std::make_shared<MutableArrayRefImpl>(Data, Endian), 0, Data.size()) {} -WritableBinaryStreamRef::WritableBinaryStreamRef( - const WritableBinaryStreamRef &Other) - : BinaryStreamRefBase(Other) {} Error WritableBinaryStreamRef::writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const { - if (auto EC = checkOffset(Offset, Data.size())) + if (auto EC = checkOffsetForWrite(Offset, Data.size())) return EC; return BorrowedImpl->writeBytes(ViewOffset + Offset, Data); diff --git a/lib/Support/BinaryStreamWriter.cpp b/lib/Support/BinaryStreamWriter.cpp index c4276518b191..bfad1280b929 100644 --- a/lib/Support/BinaryStreamWriter.cpp +++ b/lib/Support/BinaryStreamWriter.cpp @@ -42,7 +42,8 @@ Error BinaryStreamWriter::writeCString(StringRef Str) { } Error BinaryStreamWriter::writeFixedString(StringRef Str) { - return writeBytes(ArrayRef<uint8_t>(Str.bytes_begin(), Str.bytes_end())); + + return writeBytes(arrayRefFromStringRef(Str)); } Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) { diff --git a/lib/Support/BlockFrequency.cpp b/lib/Support/BlockFrequency.cpp index e7f3e1764c52..34fcbde23a28 100644 --- a/lib/Support/BlockFrequency.cpp +++ b/lib/Support/BlockFrequency.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/BlockFrequency.h" -#include "llvm/Support/raw_ostream.h" #include <cassert> using namespace llvm; diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt index 0a8e3897cce9..5723f8fcf5bb 100644 --- a/lib/Support/CMakeLists.txt +++ b/lib/Support/CMakeLists.txt @@ -1,4 +1,7 @@ set(system_libs) +if ( LLVM_ENABLE_ZLIB AND HAVE_LIBZ ) + set(system_libs ${system_libs} ${ZLIB_LIBRARIES}) +endif() if( MSVC OR MINGW ) # libuuid required for FOLDERID_Profile usage in lib/Support/Windows/Path.inc. set(system_libs ${system_libs} psapi shell32 ole32 uuid) @@ -21,16 +24,13 @@ elseif( CMAKE_HOST_UNIX ) set(system_libs ${system_libs} atomic) endif() set(system_libs ${system_libs} ${LLVM_PTHREAD_LIB}) - if ( LLVM_ENABLE_ZLIB AND HAVE_LIBZ ) - set(system_libs ${system_libs} z) - endif() if( UNIX AND NOT (BEOS OR HAIKU) ) set(system_libs ${system_libs} m) endif() endif( MSVC OR MINGW ) add_llvm_library(LLVMSupport - AMDGPUCodeObjectMetadata.cpp + AMDGPUMetadata.cpp APFloat.cpp APInt.cpp APSInt.cpp @@ -48,6 +48,7 @@ add_llvm_library(LLVMSupport circular_raw_ostream.cpp Chrono.cpp COM.cpp + CodeGenCoverage.cpp CommandLine.cpp Compression.cpp ConvertUTF.cpp @@ -71,6 +72,7 @@ add_llvm_library(LLVMSupport IntEqClasses.cpp IntervalMap.cpp JamCRC.cpp + KnownBits.cpp LEB128.cpp LineIterator.cpp Locale.cpp diff --git a/lib/Support/CachePruning.cpp b/lib/Support/CachePruning.cpp index 60d0964f2764..3e97c991f504 100644 --- a/lib/Support/CachePruning.cpp +++ b/lib/Support/CachePruning.cpp @@ -113,6 +113,10 @@ llvm::parseCachePruningPolicy(StringRef PolicyStr) { return make_error<StringError>("'" + Value + "' not an integer", inconvertibleErrorCode()); Policy.MaxSizeBytes = Size * Mult; + } else if (Key == "cache_size_files") { + if (Value.getAsInteger(0, Policy.MaxSizeFiles)) + return make_error<StringError>("'" + Value + "' not an integer", + inconvertibleErrorCode()); } else { return make_error<StringError>("Unknown key: '" + Key + "'", inconvertibleErrorCode()); @@ -141,7 +145,7 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { if (Policy.Expiration == seconds(0) && Policy.MaxSizePercentageOfAvailableSpace == 0 && - Policy.MaxSizeBytes == 0) { + Policy.MaxSizeBytes == 0 && Policy.MaxSizeFiles == 0) { DEBUG(dbgs() << "No pruning settings set, exit early\n"); // Nothing will be pruned, early exit return false; @@ -161,7 +165,7 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { return false; } } else { - if (Policy.Interval == seconds(0)) { + if (Policy.Interval != seconds(0)) { // Check whether the time stamp is older than our pruning interval. // If not, do nothing. const auto TimeStampModTime = FileStatus.getLastModificationTime(); @@ -179,22 +183,9 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { writeTimestampFile(TimestampFile); } - bool ShouldComputeSize = - (Policy.MaxSizePercentageOfAvailableSpace > 0 || Policy.MaxSizeBytes > 0); - - // Keep track of space + // Keep track of space. Needs to be kept ordered by size for determinism. std::set<std::pair<uint64_t, std::string>> FileSizes; uint64_t TotalSize = 0; - // Helper to add a path to the set of files to consider for size-based - // pruning, sorted by size. - auto AddToFileListForSizePruning = - [&](StringRef Path) { - if (!ShouldComputeSize) - return; - TotalSize += FileStatus.getSize(); - FileSizes.insert( - std::make_pair(FileStatus.getSize(), std::string(Path))); - }; // Walk the entire directory cache, looking for unused files. std::error_code EC; @@ -212,15 +203,16 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { // Look at this file. If we can't stat it, there's nothing interesting // there. - if (sys::fs::status(File->path(), FileStatus)) { + ErrorOr<sys::fs::basic_file_status> StatusOrErr = File->status(); + if (!StatusOrErr) { DEBUG(dbgs() << "Ignore " << File->path() << " (can't stat)\n"); continue; } // If the file hasn't been used recently enough, delete it - const auto FileAccessTime = FileStatus.getLastAccessedTime(); + const auto FileAccessTime = StatusOrErr->getLastAccessedTime(); auto FileAge = CurrentTime - FileAccessTime; - if (FileAge > Policy.Expiration) { + if (Policy.Expiration != seconds(0) && FileAge > Policy.Expiration) { DEBUG(dbgs() << "Remove " << File->path() << " (" << duration_cast<seconds>(FileAge).count() << "s old)\n"); sys::fs::remove(File->path()); @@ -228,11 +220,32 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { } // Leave it here for now, but add it to the list of size-based pruning. - AddToFileListForSizePruning(File->path()); + TotalSize += StatusOrErr->getSize(); + FileSizes.insert({StatusOrErr->getSize(), std::string(File->path())}); } + auto FileAndSize = FileSizes.rbegin(); + size_t NumFiles = FileSizes.size(); + + auto RemoveCacheFile = [&]() { + // Remove the file. + sys::fs::remove(FileAndSize->second); + // Update size + TotalSize -= FileAndSize->first; + NumFiles--; + DEBUG(dbgs() << " - Remove " << FileAndSize->second << " (size " + << FileAndSize->first << "), new occupancy is " << TotalSize + << "%\n"); + ++FileAndSize; + }; + + // Prune for number of files. + if (Policy.MaxSizeFiles) + while (NumFiles > Policy.MaxSizeFiles) + RemoveCacheFile(); + // Prune for size now if needed - if (ShouldComputeSize) { + if (Policy.MaxSizePercentageOfAvailableSpace > 0 || Policy.MaxSizeBytes > 0) { auto ErrOrSpaceInfo = sys::fs::disk_space(Path); if (!ErrOrSpaceInfo) { report_fatal_error("Can't get available size"); @@ -252,18 +265,9 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { << "% target is: " << Policy.MaxSizePercentageOfAvailableSpace << "%, " << Policy.MaxSizeBytes << " bytes\n"); - auto FileAndSize = FileSizes.rbegin(); - // Remove the oldest accessed files first, till we get below the threshold - while (TotalSize > TotalSizeTarget && FileAndSize != FileSizes.rend()) { - // Remove the file. - sys::fs::remove(FileAndSize->second); - // Update size - TotalSize -= FileAndSize->first; - DEBUG(dbgs() << " - Remove " << FileAndSize->second << " (size " - << FileAndSize->first << "), new occupancy is " << TotalSize - << "%\n"); - ++FileAndSize; - } + // Remove the oldest accessed files first, till we get below the threshold. + while (TotalSize > TotalSizeTarget && FileAndSize != FileSizes.rend()) + RemoveCacheFile(); } return true; } diff --git a/lib/Support/Chrono.cpp b/lib/Support/Chrono.cpp index daccaf1fc103..84f5aab6fc45 100644 --- a/lib/Support/Chrono.cpp +++ b/lib/Support/Chrono.cpp @@ -51,4 +51,44 @@ raw_ostream &operator<<(raw_ostream &OS, TimePoint<> TP) { .count())); } +void format_provider<TimePoint<>>::format(const TimePoint<> &T, raw_ostream &OS, + StringRef Style) { + using namespace std::chrono; + TimePoint<seconds> Truncated = time_point_cast<seconds>(T); + auto Fractional = T - Truncated; + struct tm LT = getStructTM(Truncated); + // Handle extensions first. strftime mangles unknown %x on some platforms. + if (Style.empty()) Style = "%Y-%m-%d %H:%M:%S.%N"; + std::string Format; + raw_string_ostream FStream(Format); + for (unsigned I = 0; I < Style.size(); ++I) { + if (Style[I] == '%' && Style.size() > I + 1) switch (Style[I + 1]) { + case 'L': // Milliseconds, from Ruby. + FStream << llvm::format( + "%.3lu", (long)duration_cast<milliseconds>(Fractional).count()); + ++I; + continue; + case 'f': // Microseconds, from Python. + FStream << llvm::format( + "%.6lu", (long)duration_cast<microseconds>(Fractional).count()); + ++I; + continue; + case 'N': // Nanoseconds, from date(1). + FStream << llvm::format( + "%.6lu", (long)duration_cast<nanoseconds>(Fractional).count()); + ++I; + continue; + case '%': // Consume %%, so %%f parses as (%%)f not %(%f) + FStream << "%%"; + ++I; + continue; + } + FStream << Style[I]; + } + FStream.flush(); + char Buffer[256]; // Should be enough for anywhen. + size_t Len = strftime(Buffer, sizeof(Buffer), Format.c_str(), <); + OS << (Len ? Buffer : "BAD-DATE-FORMAT"); +} + } // namespace llvm diff --git a/lib/Support/CodeGenCoverage.cpp b/lib/Support/CodeGenCoverage.cpp new file mode 100644 index 000000000000..ebfe65a398c3 --- /dev/null +++ b/lib/Support/CodeGenCoverage.cpp @@ -0,0 +1,120 @@ +//===- lib/Support/CodeGenCoverage.cpp -------------------------------------==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file implements the CodeGenCoverage class. +//===----------------------------------------------------------------------===// + +#include "llvm/Support/CodeGenCoverage.h" + +#include "llvm/Config/config.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/ToolOutputFile.h" + +#if LLVM_ON_UNIX +#include <unistd.h> +#elif LLVM_ON_WIN32 +#include <windows.h> +#endif + +using namespace llvm; + +static sys::SmartMutex<true> OutputMutex; + +CodeGenCoverage::CodeGenCoverage() {} + +void CodeGenCoverage::setCovered(uint64_t RuleID) { + if (RuleCoverage.size() <= RuleID) + RuleCoverage.resize(RuleID + 1, 0); + RuleCoverage[RuleID] = true; +} + +bool CodeGenCoverage::isCovered(uint64_t RuleID) { + if (RuleCoverage.size() <= RuleID) + return false; + return RuleCoverage[RuleID]; +} + +bool CodeGenCoverage::parse(MemoryBuffer &Buffer, StringRef BackendName) { + const char *CurPtr = Buffer.getBufferStart(); + + while (CurPtr != Buffer.getBufferEnd()) { + // Read the backend name from the input. + const char *LexedBackendName = CurPtr; + while (*CurPtr++ != 0) + ; + if (CurPtr == Buffer.getBufferEnd()) + return false; // Data is invalid, expected rule id's to follow. + + bool IsForThisBackend = BackendName.equals(LexedBackendName); + while (CurPtr != Buffer.getBufferEnd()) { + if (std::distance(CurPtr, Buffer.getBufferEnd()) < 8) + return false; // Data is invalid. Not enough bytes for another rule id. + + uint64_t RuleID = support::endian::read64(CurPtr, support::native); + CurPtr += 8; + + // ~0ull terminates the rule id list. + if (RuleID == ~0ull) + break; + + // Anything else, is recorded or ignored depending on whether it's + // intended for the backend we're interested in. + if (IsForThisBackend) + setCovered(RuleID); + } + } + + return true; +} + +bool CodeGenCoverage::emit(StringRef CoveragePrefix, + StringRef BackendName) const { + if (!CoveragePrefix.empty() && !RuleCoverage.empty()) { + sys::SmartScopedLock<true> Lock(OutputMutex); + + // We can handle locking within a process easily enough but we don't want to + // manage it between multiple processes. Use the process ID to ensure no + // more than one process is ever writing to the same file at the same time. + std::string Pid = +#if LLVM_ON_UNIX + llvm::to_string(::getpid()); +#elif LLVM_ON_WIN32 + llvm::to_string(::GetCurrentProcessId()); +#else + ""; +#endif + + std::string CoverageFilename = (CoveragePrefix + Pid).str(); + + std::error_code EC; + sys::fs::OpenFlags OpenFlags = sys::fs::F_Append; + std::unique_ptr<ToolOutputFile> CoverageFile = + llvm::make_unique<ToolOutputFile>(CoverageFilename, EC, OpenFlags); + if (EC) + return false; + + uint64_t Zero = 0; + uint64_t InvZero = ~0ull; + CoverageFile->os() << BackendName; + CoverageFile->os().write((const char *)&Zero, sizeof(unsigned char)); + for (uint64_t I : RuleCoverage.set_bits()) + CoverageFile->os().write((const char *)&I, sizeof(uint64_t)); + CoverageFile->os().write((const char *)&InvZero, sizeof(uint64_t)); + + CoverageFile->keep(); + } + + return true; +} + +void CodeGenCoverage::reset() { RuleCoverage.resize(0); } diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index 8eeb685a18a9..b547a0932709 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -19,7 +19,6 @@ #include "llvm/Support/CommandLine.h" #include "llvm-c/Support.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" @@ -46,17 +45,6 @@ using namespace cl; #define DEBUG_TYPE "commandline" -#if LLVM_ENABLE_ABI_BREAKING_CHECKS -namespace llvm { -// If LLVM_ENABLE_ABI_BREAKING_CHECKS is set the flag -mllvm -reverse-iterate -// can be used to toggle forward/reverse iteration of unordered containers. -// This will help uncover differences in codegen caused due to undefined -// iteration order. -static cl::opt<bool, true> ReverseIteration("reverse-iterate", - cl::location(ReverseIterate<bool>::value)); -} -#endif - //===----------------------------------------------------------------------===// // Template instantiations and anchors. // @@ -1769,7 +1757,13 @@ public: void operator=(bool Value) { if (!Value) return; + printHelp(); + + // Halt the program since help information was printed + exit(0); + } + void printHelp() { SubCommand *Sub = GlobalParser->getActiveSubCommand(); auto &OptionsMap = Sub->OptionsMap; auto &PositionalOpts = Sub->PositionalOpts; @@ -1837,9 +1831,6 @@ public: for (auto I : GlobalParser->MoreHelp) outs() << I; GlobalParser->MoreHelp.clear(); - - // Halt the program since help information was printed - exit(0); } }; @@ -2039,9 +2030,9 @@ void CommandLineParser::printOptionValues() { Opts[i].second->printOptionValue(MaxArgLen, PrintAllOptions); } -static void (*OverrideVersionPrinter)() = nullptr; +static VersionPrinterTy OverrideVersionPrinter = nullptr; -static std::vector<void (*)()> *ExtraVersionPrinters = nullptr; +static std::vector<VersionPrinterTy> *ExtraVersionPrinters = nullptr; namespace { class VersionPrinter { @@ -2081,7 +2072,7 @@ public: return; if (OverrideVersionPrinter != nullptr) { - (*OverrideVersionPrinter)(); + OverrideVersionPrinter(outs()); exit(0); } print(); @@ -2090,10 +2081,8 @@ public: // information. if (ExtraVersionPrinters != nullptr) { outs() << '\n'; - for (std::vector<void (*)()>::iterator I = ExtraVersionPrinters->begin(), - E = ExtraVersionPrinters->end(); - I != E; ++I) - (*I)(); + for (auto I : *ExtraVersionPrinters) + I(outs()); } exit(0); @@ -2111,31 +2100,24 @@ static cl::opt<VersionPrinter, true, parser<bool>> // Utility function for printing the help message. 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; + UncategorizedNormalPrinter.printHelp(); else if (!Hidden && Categorized) - CategorizedNormalPrinter = true; + CategorizedNormalPrinter.printHelp(); else if (Hidden && !Categorized) - UncategorizedHiddenPrinter = true; + UncategorizedHiddenPrinter.printHelp(); else - CategorizedHiddenPrinter = true; + CategorizedHiddenPrinter.printHelp(); } /// Utility function for printing version number. void cl::PrintVersionMessage() { VersionPrinterInstance.print(); } -void cl::SetVersionPrinter(void (*func)()) { OverrideVersionPrinter = func; } +void cl::SetVersionPrinter(VersionPrinterTy func) { OverrideVersionPrinter = func; } -void cl::AddExtraVersionPrinter(void (*func)()) { +void cl::AddExtraVersionPrinter(VersionPrinterTy func) { if (!ExtraVersionPrinters) - ExtraVersionPrinters = new std::vector<void (*)()>; + ExtraVersionPrinters = new std::vector<VersionPrinterTy>; ExtraVersionPrinters->push_back(func); } diff --git a/lib/Support/Error.cpp b/lib/Support/Error.cpp index bb02c03ff2b6..c43a1fa813e2 100644 --- a/lib/Support/Error.cpp +++ b/lib/Support/Error.cpp @@ -91,6 +91,18 @@ std::error_code errorToErrorCode(Error Err) { return EC; } +#if LLVM_ENABLE_ABI_BREAKING_CHECKS +void Error::fatalUncheckedError() const { + dbgs() << "Program aborted due to an unhandled Error:\n"; + if (getPtr()) + getPtr()->log(dbgs()); + else + dbgs() << "Error value was Success. (Note: Success values must still be " + "checked prior to being destroyed).\n"; + abort(); +} +#endif + StringError::StringError(const Twine &S, std::error_code EC) : Msg(S.str()), EC(EC) {} diff --git a/lib/Support/FileOutputBuffer.cpp b/lib/Support/FileOutputBuffer.cpp index 731740d012d9..c4ff563e5f44 100644 --- a/lib/Support/FileOutputBuffer.cpp +++ b/lib/Support/FileOutputBuffer.cpp @@ -15,8 +15,8 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Errc.h" +#include "llvm/Support/Memory.h" #include "llvm/Support/Path.h" -#include "llvm/Support/Signals.h" #include <system_error> #if !defined(_MSC_VER) && !defined(__MINGW32__) @@ -25,117 +25,146 @@ #include <io.h> #endif -using llvm::sys::fs::mapped_file_region; +using namespace llvm; +using namespace llvm::sys; -namespace llvm { -FileOutputBuffer::FileOutputBuffer(std::unique_ptr<mapped_file_region> R, - StringRef Path, StringRef TmpPath, - bool IsRegular) - : Region(std::move(R)), FinalPath(Path), TempPath(TmpPath), - IsRegular(IsRegular) {} +namespace { +// A FileOutputBuffer which creates a temporary file in the same directory +// as the final output file. The final output file is atomically replaced +// with the temporary file on commit(). +class OnDiskBuffer : public FileOutputBuffer { +public: + OnDiskBuffer(StringRef Path, fs::TempFile Temp, + std::unique_ptr<fs::mapped_file_region> Buf) + : FileOutputBuffer(Path), Buffer(std::move(Buf)), Temp(std::move(Temp)) {} -FileOutputBuffer::~FileOutputBuffer() { - // Close the mapping before deleting the temp file, so that the removal - // succeeds. - Region.reset(); - sys::fs::remove(Twine(TempPath)); -} + uint8_t *getBufferStart() const override { return (uint8_t *)Buffer->data(); } -ErrorOr<std::unique_ptr<FileOutputBuffer>> -FileOutputBuffer::create(StringRef FilePath, size_t Size, unsigned Flags) { - // Check file is not a regular file, in which case we cannot remove it. - sys::fs::file_status Stat; - std::error_code EC = sys::fs::status(FilePath, Stat); - bool IsRegular = true; - switch (Stat.type()) { - case sys::fs::file_type::file_not_found: - // If file does not exist, we'll create one. - break; - case sys::fs::file_type::regular_file: { - // If file is not currently writable, error out. - // FIXME: There is no sys::fs:: api for checking this. - // FIXME: In posix, you use the access() call to check this. - } - break; - case sys::fs::file_type::directory_file: - return errc::is_a_directory; - default: - if (EC) - return EC; - IsRegular = false; + uint8_t *getBufferEnd() const override { + return (uint8_t *)Buffer->data() + Buffer->size(); + } + + size_t getBufferSize() const override { return Buffer->size(); } + + Error commit() override { + // Unmap buffer, letting OS flush dirty pages to file on disk. + Buffer.reset(); + + // Atomically replace the existing file with the new one. + return Temp.keep(FinalPath); + } + + ~OnDiskBuffer() override { + // Close the mapping before deleting the temp file, so that the removal + // succeeds. + Buffer.reset(); + consumeError(Temp.discard()); } - if (IsRegular) { - // Delete target file. - EC = sys::fs::remove(FilePath); - if (EC) - return EC; +private: + std::unique_ptr<fs::mapped_file_region> Buffer; + fs::TempFile Temp; +}; + +// A FileOutputBuffer which keeps data in memory and writes to the final +// output file on commit(). This is used only when we cannot use OnDiskBuffer. +class InMemoryBuffer : public FileOutputBuffer { +public: + InMemoryBuffer(StringRef Path, MemoryBlock Buf, unsigned Mode) + : FileOutputBuffer(Path), Buffer(Buf), Mode(Mode) {} + + uint8_t *getBufferStart() const override { return (uint8_t *)Buffer.base(); } + + uint8_t *getBufferEnd() const override { + return (uint8_t *)Buffer.base() + Buffer.size(); } - SmallString<128> TempFilePath; - int FD; - if (IsRegular) { - unsigned Mode = sys::fs::all_read | sys::fs::all_write; - // If requested, make the output file executable. - if (Flags & F_executable) - Mode |= sys::fs::all_exe; - // Create new file in same directory but with random name. - EC = sys::fs::createUniqueFile(Twine(FilePath) + ".tmp%%%%%%%", FD, - TempFilePath, Mode); - } else { - // Create a temporary file. Since this is a special file, we will not move - // it and the new file can be in another filesystem. This avoids trying to - // create a temporary file in /dev when outputting to /dev/null for example. - EC = sys::fs::createTemporaryFile(sys::path::filename(FilePath), "", FD, - TempFilePath); + size_t getBufferSize() const override { return Buffer.size(); } + + Error commit() override { + int FD; + std::error_code EC; + if (auto EC = openFileForWrite(FinalPath, FD, fs::F_None, Mode)) + return errorCodeToError(EC); + raw_fd_ostream OS(FD, /*shouldClose=*/true, /*unbuffered=*/true); + OS << StringRef((const char *)Buffer.base(), Buffer.size()); + return Error::success(); } +private: + OwningMemoryBlock Buffer; + unsigned Mode; +}; +} // namespace + +static Expected<std::unique_ptr<InMemoryBuffer>> +createInMemoryBuffer(StringRef Path, size_t Size, unsigned Mode) { + std::error_code EC; + MemoryBlock MB = Memory::allocateMappedMemory( + Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC); if (EC) - return EC; + return errorCodeToError(EC); + return llvm::make_unique<InMemoryBuffer>(Path, MB, Mode); +} - sys::RemoveFileOnSignal(TempFilePath); +static Expected<std::unique_ptr<OnDiskBuffer>> +createOnDiskBuffer(StringRef Path, size_t Size, unsigned Mode) { + Expected<fs::TempFile> FileOrErr = + fs::TempFile::create(Path + ".tmp%%%%%%%", Mode); + if (!FileOrErr) + return FileOrErr.takeError(); + fs::TempFile File = std::move(*FileOrErr); #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; + // so we should avoid calling that function. + if (auto EC = fs::resize_file(File.FD, Size)) { + consumeError(File.discard()); + return errorCodeToError(EC); + } #endif - auto MappedFile = llvm::make_unique<mapped_file_region>( - FD, mapped_file_region::readwrite, Size, 0, EC); - int Ret = close(FD); - if (EC) - return EC; - if (Ret) - return std::error_code(errno, std::generic_category()); - - std::unique_ptr<FileOutputBuffer> Buf(new FileOutputBuffer( - std::move(MappedFile), FilePath, TempFilePath, IsRegular)); - return std::move(Buf); -} - -std::error_code FileOutputBuffer::commit() { - // Unmap buffer, letting OS flush dirty pages to file on disk. - Region.reset(); - + // Mmap it. std::error_code EC; - if (IsRegular) { - // Rename file to final name. - EC = sys::fs::rename(Twine(TempPath), Twine(FinalPath)); - sys::DontRemoveFileOnSignal(TempPath); - } else { - EC = sys::fs::copy_file(TempPath, FinalPath); - std::error_code RMEC = sys::fs::remove(TempPath); - sys::DontRemoveFileOnSignal(TempPath); - if (RMEC) - return RMEC; + auto MappedFile = llvm::make_unique<fs::mapped_file_region>( + File.FD, fs::mapped_file_region::readwrite, Size, 0, EC); + if (EC) { + consumeError(File.discard()); + return errorCodeToError(EC); } + return llvm::make_unique<OnDiskBuffer>(Path, std::move(File), + std::move(MappedFile)); +} - return EC; +// Create an instance of FileOutputBuffer. +Expected<std::unique_ptr<FileOutputBuffer>> +FileOutputBuffer::create(StringRef Path, size_t Size, unsigned Flags) { + unsigned Mode = fs::all_read | fs::all_write; + if (Flags & F_executable) + Mode |= fs::all_exe; + + fs::file_status Stat; + fs::status(Path, Stat); + + // Usually, we want to create OnDiskBuffer to create a temporary file in + // the same directory as the destination file and atomically replaces it + // by rename(2). + // + // However, if the destination file is a special file, we don't want to + // use rename (e.g. we don't want to replace /dev/null with a regular + // file.) If that's the case, we create an in-memory buffer, open the + // destination file and write to it on commit(). + switch (Stat.type()) { + case fs::file_type::directory_file: + return errorCodeToError(errc::is_a_directory); + case fs::file_type::regular_file: + case fs::file_type::file_not_found: + case fs::file_type::status_error: + return createOnDiskBuffer(Path, Size, Mode); + default: + return createInMemoryBuffer(Path, Size, Mode); + } } -} // namespace diff --git a/lib/Support/FoldingSet.cpp b/lib/Support/FoldingSet.cpp index 4496d06a15f3..942379549039 100644 --- a/lib/Support/FoldingSet.cpp +++ b/lib/Support/FoldingSet.cpp @@ -215,6 +215,10 @@ static void **GetBucketFor(unsigned Hash, void **Buckets, unsigned NumBuckets) { /// AllocateBuckets - Allocated initialized bucket memory. static void **AllocateBuckets(unsigned NumBuckets) { void **Buckets = static_cast<void**>(calloc(NumBuckets+1, sizeof(void*))); + + if (Buckets == nullptr) + report_bad_alloc_error("Allocation of Buckets failed."); + // Set the very last bucket to be a non-null "pointer". Buckets[NumBuckets] = reinterpret_cast<void*>(-1); return Buckets; @@ -271,10 +275,11 @@ void FoldingSetBase::GrowBucketCount(unsigned NewBucketCount) { assert(isPowerOf2_32(NewBucketCount) && "Bad bucket count!"); void **OldBuckets = Buckets; unsigned OldNumBuckets = NumBuckets; - NumBuckets = NewBucketCount; // Clear out new buckets. - Buckets = AllocateBuckets(NumBuckets); + Buckets = AllocateBuckets(NewBucketCount); + // Set NumBuckets only if allocation of new buckets was succesful + NumBuckets = NewBucketCount; NumNodes = 0; // Walk the old buckets, rehashing nodes into their new place. diff --git a/lib/Support/FormatVariadic.cpp b/lib/Support/FormatVariadic.cpp index de61dae814b5..6dd133e6c50a 100644 --- a/lib/Support/FormatVariadic.cpp +++ b/lib/Support/FormatVariadic.cpp @@ -91,8 +91,6 @@ formatv_object_base::parseReplacementItem(StringRef Spec) { std::pair<ReplacementItem, StringRef> formatv_object_base::splitLiteralAndReplacement(StringRef Fmt) { - StringRef Rep; - StringRef Remainder; std::size_t From = 0; while (From < Fmt.size() && From != StringRef::npos) { std::size_t BO = Fmt.find_first_of('{', From); diff --git a/lib/Support/GlobPattern.cpp b/lib/Support/GlobPattern.cpp index 8ee2febeeea1..4ea110301f16 100644 --- a/lib/Support/GlobPattern.cpp +++ b/lib/Support/GlobPattern.cpp @@ -33,27 +33,30 @@ static Expected<BitVector> expand(StringRef S, StringRef Original) { if (S.size() < 3) break; + uint8_t Start = S[0]; + uint8_t End = S[2]; + // If it doesn't start with something like X-Y, // consume the first character and proceed. if (S[1] != '-') { - BV[S[0]] = true; + BV[Start] = true; S = S.substr(1); continue; } // It must be in the form of X-Y. // Validate it and then interpret the range. - if (S[0] > S[2]) + if (Start > End) return make_error<StringError>("invalid glob pattern: " + Original, errc::invalid_argument); - for (int C = S[0]; C <= S[2]; ++C) - BV[C] = true; + for (int C = Start; C <= End; ++C) + BV[(uint8_t)C] = true; S = S.substr(3); } for (char C : S) - BV[C] = true; + BV[(uint8_t)C] = true; return BV; } @@ -89,7 +92,7 @@ static Expected<BitVector> scan(StringRef &S, StringRef Original) { } default: BitVector BV(256, false); - BV[S[0]] = true; + BV[(uint8_t)S[0]] = true; S = S.substr(1); return BV; } @@ -159,7 +162,7 @@ bool GlobPattern::matchOne(ArrayRef<BitVector> Pats, StringRef S) const { } // If Pats[0] is not '*', it must consume one character. - if (S.empty() || !Pats[0][S[0]]) + if (S.empty() || !Pats[0][(uint8_t)S[0]]) return false; Pats = Pats.slice(1); S = S.substr(1); diff --git a/lib/Support/GraphWriter.cpp b/lib/Support/GraphWriter.cpp index e04bd8bb3b9a..fd7fab08278e 100644 --- a/lib/Support/GraphWriter.cpp +++ b/lib/Support/GraphWriter.cpp @@ -96,7 +96,7 @@ static bool ExecGraphViewer(StringRef ExecPath, std::vector<const char *> &args, std::string &ErrMsg) { assert(args.back() == nullptr); if (wait) { - if (sys::ExecuteAndWait(ExecPath, args.data(), nullptr, nullptr, 0, 0, + if (sys::ExecuteAndWait(ExecPath, args.data(), nullptr, {}, 0, 0, &ErrMsg)) { errs() << "Error: " << ErrMsg << "\n"; return true; @@ -104,7 +104,7 @@ static bool ExecGraphViewer(StringRef ExecPath, std::vector<const char *> &args, sys::fs::remove(Filename); errs() << " done. \n"; } else { - sys::ExecuteNoWait(ExecPath, args.data(), nullptr, nullptr, 0, &ErrMsg); + sys::ExecuteNoWait(ExecPath, args.data(), nullptr, {}, 0, &ErrMsg); errs() << "Remember to erase graph file: " << Filename << "\n"; } return false; diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp index f1c0d3ac32d2..3dc67ad782af 100644 --- a/lib/Support/Host.cpp +++ b/lib/Support/Host.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Host.h" +#include "llvm/Support/TargetParser.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -208,9 +209,44 @@ StringRef sys::detail::getHostCPUNameForARM( .Case("0x06f", "krait") // APQ8064 .Case("0x201", "kryo") .Case("0x205", "kryo") + .Case("0x211", "kryo") + .Case("0x800", "cortex-a73") + .Case("0x801", "cortex-a73") .Case("0xc00", "falkor") + .Case("0xc01", "saphira") .Default("generic"); + if (Implementer == "0x53") { // Samsung Electronics Co., Ltd. + // The Exynos chips have a convoluted ID scheme that doesn't seem to follow + // any predictive pattern across variants and parts. + unsigned Variant = 0, Part = 0; + + // Look for the CPU variant line, whose value is a 1 digit hexadecimal + // number, corresponding to the Variant bits in the CP15/C0 register. + for (auto I : Lines) + if (I.consume_front("CPU variant")) + I.ltrim("\t :").getAsInteger(0, Variant); + + // Look for the CPU part line, whose value is a 3 digit hexadecimal + // number, corresponding to the PartNum bits in the CP15/C0 register. + for (auto I : Lines) + if (I.consume_front("CPU part")) + I.ltrim("\t :").getAsInteger(0, Part); + + unsigned Exynos = (Variant << 12) | Part; + switch (Exynos) { + default: + // Default by falling through to Exynos M1. + LLVM_FALLTHROUGH; + + case 0x1001: + return "exynos-m1"; + + case 0x4001: + return "exynos-m2"; + } + } + return "generic"; } @@ -268,6 +304,47 @@ StringRef sys::detail::getHostCPUNameForS390x( return "generic"; } +StringRef sys::detail::getHostCPUNameForBPF() { +#if !defined(__linux__) || !defined(__x86_64__) + return "generic"; +#else + uint8_t insns[40] __attribute__ ((aligned (8))) = + /* BPF_MOV64_IMM(BPF_REG_0, 0) */ + { 0xb7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* BPF_MOV64_IMM(BPF_REG_2, 1) */ + 0xb7, 0x2, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, + /* BPF_JMP_REG(BPF_JLT, BPF_REG_0, BPF_REG_2, 1) */ + 0xad, 0x20, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + /* BPF_MOV64_IMM(BPF_REG_0, 1) */ + 0xb7, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, + /* BPF_EXIT_INSN() */ + 0x95, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + + struct bpf_prog_load_attr { + uint32_t prog_type; + uint32_t insn_cnt; + uint64_t insns; + uint64_t license; + uint32_t log_level; + uint32_t log_size; + uint64_t log_buf; + uint32_t kern_version; + uint32_t prog_flags; + } attr = {}; + attr.prog_type = 1; /* BPF_PROG_TYPE_SOCKET_FILTER */ + attr.insn_cnt = 5; + attr.insns = (uint64_t)insns; + attr.license = (uint64_t)"DUMMY"; + + int fd = syscall(321 /* __NR_bpf */, 5 /* BPF_PROG_LOAD */, &attr, sizeof(attr)); + if (fd >= 0) { + close(fd); + return "v2"; + } + return "v1"; +#endif +} + #if defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64__) || defined(_M_X64) @@ -276,114 +353,6 @@ enum VendorSignatures { SIG_AMD = 0x68747541 /* Auth */ }; -enum ProcessorVendors { - VENDOR_INTEL = 1, - VENDOR_AMD, - VENDOR_OTHER, - VENDOR_MAX -}; - -enum ProcessorTypes { - INTEL_BONNELL = 1, - INTEL_CORE2, - INTEL_COREI7, - AMDFAM10H, - AMDFAM15H, - INTEL_SILVERMONT, - INTEL_KNL, - AMD_BTVER1, - AMD_BTVER2, - AMDFAM17H, - // Entries below this are not in libgcc/compiler-rt. - INTEL_i386, - INTEL_i486, - INTEL_PENTIUM, - INTEL_PENTIUM_PRO, - INTEL_PENTIUM_II, - INTEL_PENTIUM_III, - INTEL_PENTIUM_IV, - INTEL_PENTIUM_M, - INTEL_CORE_DUO, - INTEL_X86_64, - INTEL_NOCONA, - INTEL_PRESCOTT, - AMD_i486, - AMDPENTIUM, - AMDATHLON, - INTEL_GOLDMONT, - CPU_TYPE_MAX -}; - -enum ProcessorSubtypes { - INTEL_COREI7_NEHALEM = 1, - INTEL_COREI7_WESTMERE, - INTEL_COREI7_SANDYBRIDGE, - AMDFAM10H_BARCELONA, - AMDFAM10H_SHANGHAI, - AMDFAM10H_ISTANBUL, - AMDFAM15H_BDVER1, - AMDFAM15H_BDVER2, - AMDFAM15H_BDVER3, - AMDFAM15H_BDVER4, - AMDFAM17H_ZNVER1, - INTEL_COREI7_IVYBRIDGE, - INTEL_COREI7_HASWELL, - INTEL_COREI7_BROADWELL, - INTEL_COREI7_SKYLAKE, - INTEL_COREI7_SKYLAKE_AVX512, - // Entries below this are not in libgcc/compiler-rt. - INTEL_PENTIUM_MMX, - INTEL_CORE2_65, - INTEL_CORE2_45, - AMDPENTIUM_K6, - AMDPENTIUM_K62, - AMDPENTIUM_K63, - AMDPENTIUM_GEODE, - AMDATHLON_CLASSIC, - AMDATHLON_XP, - AMDATHLON_K8, - AMDATHLON_K8SSE3, - CPU_SUBTYPE_MAX -}; - -enum ProcessorFeatures { - FEATURE_CMOV = 0, - FEATURE_MMX, - FEATURE_POPCNT, - FEATURE_SSE, - FEATURE_SSE2, - FEATURE_SSE3, - FEATURE_SSSE3, - FEATURE_SSE4_1, - FEATURE_SSE4_2, - FEATURE_AVX, - FEATURE_AVX2, - FEATURE_SSE4_A, - FEATURE_FMA4, - FEATURE_XOP, - FEATURE_FMA, - FEATURE_AVX512F, - FEATURE_BMI, - FEATURE_BMI2, - FEATURE_AES, - FEATURE_PCLMUL, - FEATURE_AVX512VL, - FEATURE_AVX512BW, - FEATURE_AVX512DQ, - FEATURE_AVX512CD, - FEATURE_AVX512ER, - FEATURE_AVX512PF, - FEATURE_AVX512VBMI, - FEATURE_AVX512IFMA, - FEATURE_AVX5124VNNIW, - FEATURE_AVX5124FMAPS, - FEATURE_AVX512VPOPCNTDQ, - // Only one bit free left in the first 32 features. - FEATURE_MOVBE = 32, - FEATURE_ADX, - FEATURE_EM64T -}; - // The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max). // Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID // support. Consequently, for i386, the presence of CPUID is checked first @@ -536,57 +505,29 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, return; switch (Family) { case 3: - *Type = INTEL_i386; + *Type = X86::INTEL_i386; break; case 4: - switch (Model) { - case 0: // Intel486 DX processors - case 1: // Intel486 DX processors - case 2: // Intel486 SX processors - case 3: // Intel487 processors, IntelDX2 OverDrive processors, - // IntelDX2 processors - case 4: // Intel486 SL processor - case 5: // IntelSX2 processors - case 7: // Write-Back Enhanced IntelDX2 processors - case 8: // IntelDX4 OverDrive processors, IntelDX4 processors - default: - *Type = INTEL_i486; - break; - } + *Type = X86::INTEL_i486; break; case 5: - switch (Model) { - case 1: // Pentium OverDrive processor for Pentium processor (60, 66), - // Pentium processors (60, 66) - case 2: // Pentium OverDrive processor for Pentium processor (75, 90, - // 100, 120, 133), Pentium processors (75, 90, 100, 120, 133, - // 150, 166, 200) - case 3: // Pentium OverDrive processors for Intel486 processor-based - // systems - *Type = INTEL_PENTIUM; - break; - case 4: // Pentium OverDrive processor with MMX technology for Pentium - // processor (75, 90, 100, 120, 133), Pentium processor with - // MMX technology (166, 200) - *Type = INTEL_PENTIUM; - *Subtype = INTEL_PENTIUM_MMX; - break; - default: - *Type = INTEL_PENTIUM; + if (Features & (1 << X86::FEATURE_MMX)) { + *Type = X86::INTEL_PENTIUM_MMX; break; } + *Type = X86::INTEL_PENTIUM; break; case 6: switch (Model) { case 0x01: // Pentium Pro processor - *Type = INTEL_PENTIUM_PRO; + *Type = X86::INTEL_PENTIUM_PRO; break; case 0x03: // Intel Pentium II OverDrive processor, Pentium II processor, // model 03 case 0x05: // Pentium II processor, model 05, Pentium II Xeon processor, // model 05, and Intel Celeron processor, model 05 case 0x06: // Celeron processor, model 06 - *Type = INTEL_PENTIUM_II; + *Type = X86::INTEL_PENTIUM_II; break; case 0x07: // Pentium III processor, model 07, and Pentium III Xeon // processor, model 07 @@ -594,18 +535,18 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, // model 08, and Celeron processor, model 08 case 0x0a: // Pentium III Xeon processor, model 0Ah case 0x0b: // Pentium III processor, model 0Bh - *Type = INTEL_PENTIUM_III; + *Type = X86::INTEL_PENTIUM_III; break; case 0x09: // Intel Pentium M processor, Intel Celeron M processor model 09. case 0x0d: // Intel Pentium M processor, Intel Celeron M processor, model // 0Dh. All processors are manufactured using the 90 nm process. case 0x15: // Intel EP80579 Integrated Processor and Intel EP80579 // Integrated Processor with Intel QuickAssist Technology - *Type = INTEL_PENTIUM_M; + *Type = X86::INTEL_PENTIUM_M; break; case 0x0e: // Intel Core Duo processor, Intel Core Solo processor, model // 0Eh. All processors are manufactured using the 65 nm process. - *Type = INTEL_CORE_DUO; + *Type = X86::INTEL_CORE_DUO; break; // yonah case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile // processor, Intel Core 2 Quad processor, Intel Core 2 Quad @@ -614,8 +555,8 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, // 0Fh. All processors are manufactured using the 65 nm process. case 0x16: // Intel Celeron processor model 16h. All processors are // manufactured using the 65 nm process - *Type = INTEL_CORE2; // "core2" - *Subtype = INTEL_CORE2_65; + *Type = X86::INTEL_CORE2; // "core2" + *Subtype = X86::INTEL_CORE2_65; break; case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model // 17h. All processors are manufactured using the 45 nm process. @@ -623,8 +564,8 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, // 45nm: Penryn , Wolfdale, Yorkfield (XE) case 0x1d: // Intel Xeon processor MP. All processors are manufactured using // the 45 nm process. - *Type = INTEL_CORE2; // "penryn" - *Subtype = INTEL_CORE2_45; + *Type = X86::INTEL_CORE2; // "penryn" + *Subtype = X86::INTEL_CORE2_45; break; case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All // processors are manufactured using the 45 nm process. @@ -632,26 +573,26 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, // As found in a Summer 2010 model iMac. case 0x1f: case 0x2e: // Nehalem EX - *Type = INTEL_COREI7; // "nehalem" - *Subtype = INTEL_COREI7_NEHALEM; + *Type = X86::INTEL_COREI7; // "nehalem" + *Subtype = X86::INTEL_COREI7_NEHALEM; break; case 0x25: // Intel Core i7, laptop version. case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All // processors are manufactured using the 32 nm process. case 0x2f: // Westmere EX - *Type = INTEL_COREI7; // "westmere" - *Subtype = INTEL_COREI7_WESTMERE; + *Type = X86::INTEL_COREI7; // "westmere" + *Subtype = X86::INTEL_COREI7_WESTMERE; break; case 0x2a: // Intel Core i7 processor. All processors are manufactured // using the 32 nm process. case 0x2d: - *Type = INTEL_COREI7; //"sandybridge" - *Subtype = INTEL_COREI7_SANDYBRIDGE; + *Type = X86::INTEL_COREI7; //"sandybridge" + *Subtype = X86::INTEL_COREI7_SANDYBRIDGE; break; case 0x3a: case 0x3e: // Ivy Bridge EP - *Type = INTEL_COREI7; // "ivybridge" - *Subtype = INTEL_COREI7_IVYBRIDGE; + *Type = X86::INTEL_COREI7; // "ivybridge" + *Subtype = X86::INTEL_COREI7_IVYBRIDGE; break; // Haswell: @@ -659,8 +600,8 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 0x3f: case 0x45: case 0x46: - *Type = INTEL_COREI7; // "haswell" - *Subtype = INTEL_COREI7_HASWELL; + *Type = X86::INTEL_COREI7; // "haswell" + *Subtype = X86::INTEL_COREI7_HASWELL; break; // Broadwell: @@ -668,8 +609,8 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 0x47: case 0x4f: case 0x56: - *Type = INTEL_COREI7; // "broadwell" - *Subtype = INTEL_COREI7_BROADWELL; + *Type = X86::INTEL_COREI7; // "broadwell" + *Subtype = X86::INTEL_COREI7_BROADWELL; break; // Skylake: @@ -677,14 +618,20 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 0x5e: // Skylake desktop case 0x8e: // Kaby Lake mobile case 0x9e: // Kaby Lake desktop - *Type = INTEL_COREI7; // "skylake" - *Subtype = INTEL_COREI7_SKYLAKE; + *Type = X86::INTEL_COREI7; // "skylake" + *Subtype = X86::INTEL_COREI7_SKYLAKE; break; // Skylake Xeon: case 0x55: - *Type = INTEL_COREI7; - *Subtype = INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512" + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512" + break; + + // Cannonlake: + case 0x66: + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_CANNONLAKE; // "cannonlake" break; case 0x1c: // Most 45 nm Intel Atom processors @@ -692,7 +639,7 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 0x27: // 32 nm Atom Medfield case 0x35: // 32 nm Atom Midview case 0x36: // 32 nm Atom Midview - *Type = INTEL_BONNELL; + *Type = X86::INTEL_BONNELL; break; // "bonnell" // Atom Silvermont codes from the Intel software optimization guide. @@ -702,115 +649,121 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 0x5a: case 0x5d: case 0x4c: // really airmont - *Type = INTEL_SILVERMONT; + *Type = X86::INTEL_SILVERMONT; break; // "silvermont" // Goldmont: - case 0x5c: - case 0x5f: - *Type = INTEL_GOLDMONT; + case 0x5c: // Apollo Lake + case 0x5f: // Denverton + case 0x7a: // Gemini Lake + *Type = X86::INTEL_GOLDMONT; break; // "goldmont" case 0x57: - *Type = INTEL_KNL; // knl + *Type = X86::INTEL_KNL; // knl + break; + case 0x85: + *Type = X86::INTEL_KNM; // knm break; default: // Unknown family 6 CPU, try to guess. - if (Features & (1 << FEATURE_AVX512F)) { - *Type = INTEL_KNL; // knl + if (Features & (1 << X86::FEATURE_AVX512VBMI)) { + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_CANNONLAKE; break; } - if (Features2 & (1 << (FEATURE_ADX - 32))) { - *Type = INTEL_COREI7; - *Subtype = INTEL_COREI7_BROADWELL; + + if (Features & (1 << X86::FEATURE_AVX512VL)) { + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_SKYLAKE_AVX512; break; } - if (Features & (1 << FEATURE_AVX2)) { - *Type = INTEL_COREI7; - *Subtype = INTEL_COREI7_HASWELL; + + if (Features & (1 << X86::FEATURE_AVX512ER)) { + *Type = X86::INTEL_KNL; // knl + break; + } + + if (Features2 & (1 << (X86::FEATURE_CLFLUSHOPT - 32))) { + if (Features2 & (1 << (X86::FEATURE_SHA - 32))) { + *Type = X86::INTEL_GOLDMONT; + } else { + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_SKYLAKE; + } break; } - if (Features & (1 << FEATURE_AVX)) { - *Type = INTEL_COREI7; - *Subtype = INTEL_COREI7_SANDYBRIDGE; + if (Features2 & (1 << (X86::FEATURE_ADX - 32))) { + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_BROADWELL; break; } - if (Features & (1 << FEATURE_SSE4_2)) { - if (Features2 & (1 << (FEATURE_MOVBE - 32))) { - *Type = INTEL_SILVERMONT; + if (Features & (1 << X86::FEATURE_AVX2)) { + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_HASWELL; + break; + } + if (Features & (1 << X86::FEATURE_AVX)) { + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_SANDYBRIDGE; + break; + } + if (Features & (1 << X86::FEATURE_SSE4_2)) { + if (Features2 & (1 << (X86::FEATURE_MOVBE - 32))) { + *Type = X86::INTEL_SILVERMONT; } else { - *Type = INTEL_COREI7; - *Subtype = INTEL_COREI7_NEHALEM; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_NEHALEM; } break; } - if (Features & (1 << FEATURE_SSE4_1)) { - *Type = INTEL_CORE2; // "penryn" - *Subtype = INTEL_CORE2_45; + if (Features & (1 << X86::FEATURE_SSE4_1)) { + *Type = X86::INTEL_CORE2; // "penryn" + *Subtype = X86::INTEL_CORE2_45; break; } - if (Features & (1 << FEATURE_SSSE3)) { - if (Features2 & (1 << (FEATURE_MOVBE - 32))) { - *Type = INTEL_BONNELL; // "bonnell" + if (Features & (1 << X86::FEATURE_SSSE3)) { + if (Features2 & (1 << (X86::FEATURE_MOVBE - 32))) { + *Type = X86::INTEL_BONNELL; // "bonnell" } else { - *Type = INTEL_CORE2; // "core2" - *Subtype = INTEL_CORE2_65; + *Type = X86::INTEL_CORE2; // "core2" + *Subtype = X86::INTEL_CORE2_65; } break; } - if (Features2 & (1 << (FEATURE_EM64T - 32))) { - *Type = INTEL_X86_64; - break; // x86-64 + if (Features2 & (1 << (X86::FEATURE_EM64T - 32))) { + *Type = X86::INTEL_CORE2; // "core2" + *Subtype = X86::INTEL_CORE2_65; + break; + } + if (Features & (1 << X86::FEATURE_SSE3)) { + *Type = X86::INTEL_CORE_DUO; + break; } - if (Features & (1 << FEATURE_SSE2)) { - *Type = INTEL_PENTIUM_M; + if (Features & (1 << X86::FEATURE_SSE2)) { + *Type = X86::INTEL_PENTIUM_M; break; } - if (Features & (1 << FEATURE_SSE)) { - *Type = INTEL_PENTIUM_III; + if (Features & (1 << X86::FEATURE_SSE)) { + *Type = X86::INTEL_PENTIUM_III; break; } - if (Features & (1 << FEATURE_MMX)) { - *Type = INTEL_PENTIUM_II; + if (Features & (1 << X86::FEATURE_MMX)) { + *Type = X86::INTEL_PENTIUM_II; break; } - *Type = INTEL_PENTIUM_PRO; + *Type = X86::INTEL_PENTIUM_PRO; break; } break; case 15: { - switch (Model) { - case 0: // Pentium 4 processor, Intel Xeon processor. All processors are - // model 00h and manufactured using the 0.18 micron process. - case 1: // Pentium 4 processor, Intel Xeon processor, Intel Xeon - // processor MP, and Intel Celeron processor. All processors are - // model 01h and manufactured using the 0.18 micron process. - case 2: // Pentium 4 processor, Mobile Intel Pentium 4 processor - M, - // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron - // processor, and Mobile Intel Celeron processor. All processors - // are model 02h and manufactured using the 0.13 micron process. - *Type = ((Features2 & (1 << (FEATURE_EM64T - 32))) ? INTEL_X86_64 - : INTEL_PENTIUM_IV); - break; - - case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D - // processor. All processors are model 03h and manufactured using - // the 90 nm process. - case 4: // Pentium 4 processor, Pentium 4 processor Extreme Edition, - // Pentium D processor, Intel Xeon processor, Intel Xeon - // processor MP, Intel Celeron D processor. All processors are - // model 04h and manufactured using the 90 nm process. - case 6: // Pentium 4 processor, Pentium D processor, Pentium processor - // Extreme Edition, Intel Xeon processor, Intel Xeon processor - // MP, Intel Celeron D processor. All processors are model 06h - // and manufactured using the 65 nm process. - *Type = ((Features2 & (1 << (FEATURE_EM64T - 32))) ? INTEL_NOCONA - : INTEL_PRESCOTT); + if (Features2 & (1 << (X86::FEATURE_EM64T - 32))) { + *Type = X86::INTEL_NOCONA; break; - - default: - *Type = ((Features2 & (1 << (FEATURE_EM64T - 32))) ? INTEL_X86_64 - : INTEL_PENTIUM_IV); + } + if (Features & (1 << X86::FEATURE_SSE3)) { + *Type = X86::INTEL_PRESCOTT; break; } + *Type = X86::INTEL_PENTIUM_IV; break; } default: @@ -826,85 +779,83 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, // from the information returned from CPUID. switch (Family) { case 4: - *Type = AMD_i486; + *Type = X86::AMD_i486; break; case 5: - *Type = AMDPENTIUM; + *Type = X86::AMDPENTIUM; switch (Model) { case 6: case 7: - *Subtype = AMDPENTIUM_K6; + *Subtype = X86::AMDPENTIUM_K6; break; // "k6" case 8: - *Subtype = AMDPENTIUM_K62; + *Subtype = X86::AMDPENTIUM_K62; break; // "k6-2" case 9: case 13: - *Subtype = AMDPENTIUM_K63; + *Subtype = X86::AMDPENTIUM_K63; break; // "k6-3" case 10: - *Subtype = AMDPENTIUM_GEODE; + *Subtype = X86::AMDPENTIUM_GEODE; break; // "geode" } break; case 6: - *Type = AMDATHLON; - if (Features & (1 << FEATURE_SSE)) { - *Subtype = AMDATHLON_XP; + if (Features & (1 << X86::FEATURE_SSE)) { + *Type = X86::AMD_ATHLON_XP; break; // "athlon-xp" } - *Subtype = AMDATHLON_CLASSIC; + *Type = X86::AMD_ATHLON; break; // "athlon" case 15: - *Type = AMDATHLON; - if (Features & (1 << FEATURE_SSE3)) { - *Subtype = AMDATHLON_K8SSE3; + if (Features & (1 << X86::FEATURE_SSE3)) { + *Type = X86::AMD_K8SSE3; break; // "k8-sse3" } - *Subtype = AMDATHLON_K8; + *Type = X86::AMD_K8; break; // "k8" case 16: - *Type = AMDFAM10H; // "amdfam10" + *Type = X86::AMDFAM10H; // "amdfam10" switch (Model) { case 2: - *Subtype = AMDFAM10H_BARCELONA; + *Subtype = X86::AMDFAM10H_BARCELONA; break; case 4: - *Subtype = AMDFAM10H_SHANGHAI; + *Subtype = X86::AMDFAM10H_SHANGHAI; break; case 8: - *Subtype = AMDFAM10H_ISTANBUL; + *Subtype = X86::AMDFAM10H_ISTANBUL; break; } break; case 20: - *Type = AMD_BTVER1; + *Type = X86::AMD_BTVER1; break; // "btver1"; case 21: - *Type = AMDFAM15H; + *Type = X86::AMDFAM15H; if (Model >= 0x60 && Model <= 0x7f) { - *Subtype = AMDFAM15H_BDVER4; + *Subtype = X86::AMDFAM15H_BDVER4; break; // "bdver4"; 60h-7Fh: Excavator } if (Model >= 0x30 && Model <= 0x3f) { - *Subtype = AMDFAM15H_BDVER3; + *Subtype = X86::AMDFAM15H_BDVER3; break; // "bdver3"; 30h-3Fh: Steamroller } if (Model >= 0x10 && Model <= 0x1f) { - *Subtype = AMDFAM15H_BDVER2; + *Subtype = X86::AMDFAM15H_BDVER2; break; // "bdver2"; 10h-1Fh: Piledriver } if (Model <= 0x0f) { - *Subtype = AMDFAM15H_BDVER1; + *Subtype = X86::AMDFAM15H_BDVER1; break; // "bdver1"; 00h-0Fh: Bulldozer } break; case 22: - *Type = AMD_BTVER2; + *Type = X86::AMD_BTVER2; break; // "btver2" case 23: - *Type = AMDFAM17H; - *Subtype = AMDFAM17H_ZNVER1; + *Type = X86::AMDFAM17H; + *Subtype = X86::AMDFAM17H_ZNVER1; break; default: break; // "generic" @@ -919,33 +870,33 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, unsigned EAX, EBX; if ((EDX >> 15) & 1) - Features |= 1 << FEATURE_CMOV; + Features |= 1 << X86::FEATURE_CMOV; if ((EDX >> 23) & 1) - Features |= 1 << FEATURE_MMX; + Features |= 1 << X86::FEATURE_MMX; if ((EDX >> 25) & 1) - Features |= 1 << FEATURE_SSE; + Features |= 1 << X86::FEATURE_SSE; if ((EDX >> 26) & 1) - Features |= 1 << FEATURE_SSE2; + Features |= 1 << X86::FEATURE_SSE2; if ((ECX >> 0) & 1) - Features |= 1 << FEATURE_SSE3; + Features |= 1 << X86::FEATURE_SSE3; if ((ECX >> 1) & 1) - Features |= 1 << FEATURE_PCLMUL; + Features |= 1 << X86::FEATURE_PCLMUL; if ((ECX >> 9) & 1) - Features |= 1 << FEATURE_SSSE3; + Features |= 1 << X86::FEATURE_SSSE3; if ((ECX >> 12) & 1) - Features |= 1 << FEATURE_FMA; + Features |= 1 << X86::FEATURE_FMA; if ((ECX >> 19) & 1) - Features |= 1 << FEATURE_SSE4_1; + Features |= 1 << X86::FEATURE_SSE4_1; if ((ECX >> 20) & 1) - Features |= 1 << FEATURE_SSE4_2; + Features |= 1 << X86::FEATURE_SSE4_2; if ((ECX >> 23) & 1) - Features |= 1 << FEATURE_POPCNT; + Features |= 1 << X86::FEATURE_POPCNT; if ((ECX >> 25) & 1) - Features |= 1 << FEATURE_AES; + Features |= 1 << X86::FEATURE_AES; if ((ECX >> 22) & 1) - Features2 |= 1 << (FEATURE_MOVBE - 32); + Features2 |= 1 << (X86::FEATURE_MOVBE - 32); // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV // indicates that the AVX registers will be saved and restored on context @@ -956,45 +907,49 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); if (HasAVX) - Features |= 1 << FEATURE_AVX; + Features |= 1 << X86::FEATURE_AVX; bool HasLeaf7 = MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); if (HasLeaf7 && ((EBX >> 3) & 1)) - Features |= 1 << FEATURE_BMI; + Features |= 1 << X86::FEATURE_BMI; if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX) - Features |= 1 << FEATURE_AVX2; + Features |= 1 << X86::FEATURE_AVX2; if (HasLeaf7 && ((EBX >> 9) & 1)) - Features |= 1 << FEATURE_BMI2; + Features |= 1 << X86::FEATURE_BMI2; if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save) - Features |= 1 << FEATURE_AVX512F; + Features |= 1 << X86::FEATURE_AVX512F; if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save) - Features |= 1 << FEATURE_AVX512DQ; + Features |= 1 << X86::FEATURE_AVX512DQ; if (HasLeaf7 && ((EBX >> 19) & 1)) - Features2 |= 1 << (FEATURE_ADX - 32); + Features2 |= 1 << (X86::FEATURE_ADX - 32); if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save) - Features |= 1 << FEATURE_AVX512IFMA; + Features |= 1 << X86::FEATURE_AVX512IFMA; + if (HasLeaf7 && ((EBX >> 23) & 1)) + Features2 |= 1 << (X86::FEATURE_CLFLUSHOPT - 32); if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save) - Features |= 1 << FEATURE_AVX512PF; + Features |= 1 << X86::FEATURE_AVX512PF; if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save) - Features |= 1 << FEATURE_AVX512ER; + Features |= 1 << X86::FEATURE_AVX512ER; if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save) - Features |= 1 << FEATURE_AVX512CD; + Features |= 1 << X86::FEATURE_AVX512CD; + if (HasLeaf7 && ((EBX >> 29) & 1)) + Features2 |= 1 << (X86::FEATURE_SHA - 32); if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save) - Features |= 1 << FEATURE_AVX512BW; + Features |= 1 << X86::FEATURE_AVX512BW; if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save) - Features |= 1 << FEATURE_AVX512VL; + Features |= 1 << X86::FEATURE_AVX512VL; if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save) - Features |= 1 << FEATURE_AVX512VBMI; + Features |= 1 << X86::FEATURE_AVX512VBMI; if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save) - Features |= 1 << FEATURE_AVX512VPOPCNTDQ; + Features |= 1 << X86::FEATURE_AVX512VPOPCNTDQ; if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save) - Features |= 1 << FEATURE_AVX5124VNNIW; + Features |= 1 << X86::FEATURE_AVX5124VNNIW; if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save) - Features |= 1 << FEATURE_AVX5124FMAPS; + Features |= 1 << X86::FEATURE_AVX5124FMAPS; unsigned MaxExtLevel; getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); @@ -1002,14 +957,14 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 && !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); if (HasExtLeaf1 && ((ECX >> 6) & 1)) - Features |= 1 << FEATURE_SSE4_A; + Features |= 1 << X86::FEATURE_SSE4_A; if (HasExtLeaf1 && ((ECX >> 11) & 1)) - Features |= 1 << FEATURE_XOP; + Features |= 1 << X86::FEATURE_XOP; if (HasExtLeaf1 && ((ECX >> 16) & 1)) - Features |= 1 << FEATURE_FMA4; + Features |= 1 << X86::FEATURE_FMA4; if (HasExtLeaf1 && ((EDX >> 29) & 1)) - Features2 |= 1 << (FEATURE_EM64T - 32); + Features2 |= 1 << (X86::FEATURE_EM64T - 32); *FeaturesOut = Features; *Features2Out = Features2; @@ -1037,135 +992,28 @@ StringRef sys::getHostCPUName() { detectX86FamilyModel(EAX, &Family, &Model); getAvailableFeatures(ECX, EDX, MaxLeaf, &Features, &Features2); - unsigned Type; - unsigned Subtype; + unsigned Type = 0; + unsigned Subtype = 0; if (Vendor == SIG_INTEL) { getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features, Features2, &Type, &Subtype); - switch (Type) { - case INTEL_i386: - return "i386"; - case INTEL_i486: - return "i486"; - case INTEL_PENTIUM: - if (Subtype == INTEL_PENTIUM_MMX) - return "pentium-mmx"; - return "pentium"; - case INTEL_PENTIUM_PRO: - return "pentiumpro"; - case INTEL_PENTIUM_II: - return "pentium2"; - case INTEL_PENTIUM_III: - return "pentium3"; - case INTEL_PENTIUM_IV: - return "pentium4"; - case INTEL_PENTIUM_M: - return "pentium-m"; - case INTEL_CORE_DUO: - return "yonah"; - case INTEL_CORE2: - switch (Subtype) { - case INTEL_CORE2_65: - return "core2"; - case INTEL_CORE2_45: - return "penryn"; - default: - llvm_unreachable("Unexpected subtype!"); - } - case INTEL_COREI7: - switch (Subtype) { - case INTEL_COREI7_NEHALEM: - return "nehalem"; - case INTEL_COREI7_WESTMERE: - return "westmere"; - case INTEL_COREI7_SANDYBRIDGE: - return "sandybridge"; - case INTEL_COREI7_IVYBRIDGE: - return "ivybridge"; - case INTEL_COREI7_HASWELL: - return "haswell"; - case INTEL_COREI7_BROADWELL: - return "broadwell"; - case INTEL_COREI7_SKYLAKE: - return "skylake"; - case INTEL_COREI7_SKYLAKE_AVX512: - return "skylake-avx512"; - default: - llvm_unreachable("Unexpected subtype!"); - } - case INTEL_BONNELL: - return "bonnell"; - case INTEL_SILVERMONT: - return "silvermont"; - case INTEL_GOLDMONT: - return "goldmont"; - case INTEL_KNL: - return "knl"; - case INTEL_X86_64: - return "x86-64"; - case INTEL_NOCONA: - return "nocona"; - case INTEL_PRESCOTT: - return "prescott"; - default: - break; - } } else if (Vendor == SIG_AMD) { getAMDProcessorTypeAndSubtype(Family, Model, Features, &Type, &Subtype); - switch (Type) { - case AMD_i486: - return "i486"; - case AMDPENTIUM: - switch (Subtype) { - case AMDPENTIUM_K6: - return "k6"; - case AMDPENTIUM_K62: - return "k6-2"; - case AMDPENTIUM_K63: - return "k6-3"; - case AMDPENTIUM_GEODE: - return "geode"; - default: - return "pentium"; - } - case AMDATHLON: - switch (Subtype) { - case AMDATHLON_CLASSIC: - return "athlon"; - case AMDATHLON_XP: - return "athlon-xp"; - case AMDATHLON_K8: - return "k8"; - case AMDATHLON_K8SSE3: - return "k8-sse3"; - default: - llvm_unreachable("Unexpected subtype!"); - } - case AMDFAM10H: - return "amdfam10"; - case AMD_BTVER1: - return "btver1"; - case AMDFAM15H: - switch (Subtype) { - default: // There are gaps in the subtype detection. - case AMDFAM15H_BDVER1: - return "bdver1"; - case AMDFAM15H_BDVER2: - return "bdver2"; - case AMDFAM15H_BDVER3: - return "bdver3"; - case AMDFAM15H_BDVER4: - return "bdver4"; - } - case AMD_BTVER2: - return "btver2"; - case AMDFAM17H: - return "znver1"; - default: - break; - } } + + // Check subtypes first since those are more specific. +#define X86_CPU_SUBTYPE(ARCHNAME, ENUM) \ + if (Subtype == X86::ENUM) \ + return ARCHNAME; +#include "llvm/Support/X86TargetParser.def" + + // Now check types. +#define X86_CPU_SUBTYPE(ARCHNAME, ENUM) \ + if (Type == X86::ENUM) \ + return ARCHNAME; +#include "llvm/Support/X86TargetParser.def" + return "generic"; } @@ -1323,95 +1171,99 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { 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["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["pclmul"] = (ECX >> 1) & 1; + Features["ssse3"] = (ECX >> 9) & 1; + Features["cx16"] = (ECX >> 13) & 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["movbe"] = (ECX >> 22) & 1; Features["popcnt"] = (ECX >> 23) & 1; - Features["aes"] = (ECX >> 25) & 1; - Features["rdrnd"] = (ECX >> 30) & 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 HasAVXSave = ((ECX >> 27) & 1) && ((ECX >> 28) & 1) && !getX86XCR0(&EAX, &EDX) && ((EAX & 0x6) == 0x6); - Features["avx"] = HasAVXSave; - Features["fma"] = HasAVXSave && (ECX >> 12) & 1; - Features["f16c"] = HasAVXSave && (ECX >> 29) & 1; - - // Only enable XSAVE if OS has enabled support for saving YMM state. - Features["xsave"] = HasAVXSave && (ECX >> 26) & 1; - // AVX512 requires additional context to be saved by the OS. bool HasAVX512Save = HasAVXSave && ((EAX & 0xe0) == 0xe0); + Features["avx"] = HasAVXSave; + Features["fma"] = ((ECX >> 12) & 1) && HasAVXSave; + // Only enable XSAVE if OS has enabled support for saving YMM state. + Features["xsave"] = ((ECX >> 26) & 1) && HasAVXSave; + Features["f16c"] = ((ECX >> 29) & 1) && HasAVXSave; + 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"] = HasExtLeaf1 && ((ECX >> 11) & 1) && HasAVXSave; - Features["lwp"] = HasExtLeaf1 && ((ECX >> 15) & 1); - Features["fma4"] = HasExtLeaf1 && ((ECX >> 16) & 1) && HasAVXSave; - Features["tbm"] = HasExtLeaf1 && ((ECX >> 21) & 1); + Features["lzcnt"] = HasExtLeaf1 && ((ECX >> 5) & 1); + Features["sse4a"] = HasExtLeaf1 && ((ECX >> 6) & 1); + Features["prfchw"] = HasExtLeaf1 && ((ECX >> 8) & 1); + Features["xop"] = HasExtLeaf1 && ((ECX >> 11) & 1) && HasAVXSave; + Features["lwp"] = HasExtLeaf1 && ((ECX >> 15) & 1); + Features["fma4"] = HasExtLeaf1 && ((ECX >> 16) & 1) && HasAVXSave; + Features["tbm"] = HasExtLeaf1 && ((ECX >> 21) & 1); Features["mwaitx"] = HasExtLeaf1 && ((ECX >> 29) & 1); bool HasExtLeaf8 = MaxExtLevel >= 0x80000008 && - !getX86CpuIDAndInfoEx(0x80000008,0x0, &EAX, &EBX, &ECX, &EDX); + !getX86CpuIDAndInfo(0x80000008, &EAX, &EBX, &ECX, &EDX); Features["clzero"] = HasExtLeaf8 && ((EBX >> 0) & 1); bool HasLeaf7 = MaxLevel >= 7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); + Features["fsgsbase"] = HasLeaf7 && ((EBX >> 0) & 1); + Features["sgx"] = HasLeaf7 && ((EBX >> 2) & 1); + Features["bmi"] = HasLeaf7 && ((EBX >> 3) & 1); // AVX2 is only supported if we have the OS save support from AVX. - Features["avx2"] = HasAVXSave && HasLeaf7 && ((EBX >> 5) & 1); - - Features["fsgsbase"] = HasLeaf7 && ((EBX >> 0) & 1); - Features["sgx"] = HasLeaf7 && ((EBX >> 2) & 1); - Features["bmi"] = HasLeaf7 && ((EBX >> 3) & 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["clflushopt"] = HasLeaf7 && ((EBX >> 23) & 1); - Features["clwb"] = HasLeaf7 && ((EBX >> 24) & 1); - Features["sha"] = HasLeaf7 && ((EBX >> 29) & 1); - + Features["avx2"] = HasLeaf7 && ((EBX >> 5) & 1) && HasAVXSave; + Features["bmi2"] = HasLeaf7 && ((EBX >> 8) & 1); + Features["rtm"] = HasLeaf7 && ((EBX >> 11) & 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["avx512f"] = HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save; + Features["avx512dq"] = HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save; + Features["rdseed"] = HasLeaf7 && ((EBX >> 18) & 1); + Features["adx"] = HasLeaf7 && ((EBX >> 19) & 1); Features["avx512ifma"] = HasLeaf7 && ((EBX >> 21) & 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; - - Features["prefetchwt1"] = HasLeaf7 && (ECX & 1); - Features["avx512vbmi"] = HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save; - Features["avx512vpopcntdq"] = HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save; - // Enable protection keys - Features["pku"] = HasLeaf7 && ((ECX >> 4) & 1); + Features["clflushopt"] = HasLeaf7 && ((EBX >> 23) & 1); + Features["clwb"] = HasLeaf7 && ((EBX >> 24) & 1); + Features["avx512pf"] = HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save; + Features["avx512er"] = HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save; + Features["avx512cd"] = HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save; + Features["sha"] = HasLeaf7 && ((EBX >> 29) & 1); + Features["avx512bw"] = HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save; + Features["avx512vl"] = HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save; + + Features["prefetchwt1"] = HasLeaf7 && ((ECX >> 0) & 1); + Features["avx512vbmi"] = HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save; + Features["pku"] = HasLeaf7 && ((ECX >> 4) & 1); + Features["avx512vbmi2"] = HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save; + Features["shstk"] = HasLeaf7 && ((ECX >> 7) & 1); + Features["gfni"] = HasLeaf7 && ((ECX >> 8) & 1); + Features["vaes"] = HasLeaf7 && ((ECX >> 9) & 1) && HasAVXSave; + Features["vpclmulqdq"] = HasLeaf7 && ((ECX >> 10) & 1) && HasAVXSave; + Features["avx512vnni"] = HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save; + Features["avx512bitalg"] = HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save; + Features["avx512vpopcntdq"] = HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save; + Features["ibt"] = HasLeaf7 && ((EDX >> 20) & 1); bool HasLeafD = MaxLevel >= 0xd && !getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX); // Only enable XSAVE if OS has enabled support for saving YMM state. - Features["xsaveopt"] = HasAVXSave && HasLeafD && ((EAX >> 0) & 1); - Features["xsavec"] = HasAVXSave && HasLeafD && ((EAX >> 1) & 1); - Features["xsaves"] = HasAVXSave && HasLeafD && ((EAX >> 3) & 1); + Features["xsaveopt"] = HasLeafD && ((EAX >> 0) & 1) && HasAVXSave; + Features["xsavec"] = HasLeafD && ((EAX >> 1) & 1) && HasAVXSave; + Features["xsaves"] = HasLeafD && ((EAX >> 3) & 1) && HasAVXSave; return true; } diff --git a/lib/Support/KnownBits.cpp b/lib/Support/KnownBits.cpp new file mode 100644 index 000000000000..ac790ebed352 --- /dev/null +++ b/lib/Support/KnownBits.cpp @@ -0,0 +1,65 @@ +//===-- KnownBits.cpp - Stores known zeros/ones ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a class for representing known zeros and ones used by +// computeKnownBits. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/KnownBits.h" + +using namespace llvm; + +KnownBits KnownBits::computeForAddSub(bool Add, bool NSW, + const KnownBits &LHS, KnownBits RHS) { + // Carry in a 1 for a subtract, rather than 0. + bool CarryIn = false; + if (!Add) { + // Sum = LHS + ~RHS + 1 + std::swap(RHS.Zero, RHS.One); + CarryIn = true; + } + + APInt PossibleSumZero = ~LHS.Zero + ~RHS.Zero + CarryIn; + APInt PossibleSumOne = LHS.One + RHS.One + CarryIn; + + // Compute known bits of the carry. + APInt CarryKnownZero = ~(PossibleSumZero ^ LHS.Zero ^ RHS.Zero); + APInt CarryKnownOne = PossibleSumOne ^ LHS.One ^ RHS.One; + + // Compute set of known bits (where all three relevant bits are known). + APInt LHSKnownUnion = LHS.Zero | LHS.One; + APInt RHSKnownUnion = RHS.Zero | RHS.One; + APInt CarryKnownUnion = std::move(CarryKnownZero) | CarryKnownOne; + APInt Known = std::move(LHSKnownUnion) & RHSKnownUnion & CarryKnownUnion; + + assert((PossibleSumZero & Known) == (PossibleSumOne & Known) && + "known bits of sum differ"); + + // Compute known bits of the result. + KnownBits KnownOut; + KnownOut.Zero = ~std::move(PossibleSumZero) & Known; + KnownOut.One = std::move(PossibleSumOne) & Known; + + // Are we still trying to solve for the sign bit? + if (!Known.isSignBitSet()) { + if (NSW) { + // Adding two non-negative numbers, or subtracting a negative number from + // a non-negative one, can't wrap into negative. + if (LHS.isNonNegative() && RHS.isNonNegative()) + KnownOut.makeNonNegative(); + // Adding two negative numbers, or subtracting a non-negative number from + // a negative one, can't wrap into non-negative. + else if (LHS.isNegative() && RHS.isNegative()) + KnownOut.makeNegative(); + } + } + + return KnownOut; +} diff --git a/lib/Support/LockFileManager.cpp b/lib/Support/LockFileManager.cpp index 3ee3af7731e6..ec951f33a36a 100644 --- a/lib/Support/LockFileManager.cpp +++ b/lib/Support/LockFileManager.cpp @@ -123,33 +123,21 @@ bool LockFileManager::processStillExecuting(StringRef HostID, int PID) { namespace { -/// An RAII helper object ensure that the unique lock file is removed. -/// -/// Ensures that if there is an error or a signal before we finish acquiring the -/// lock, the unique file will be removed. And if we successfully take the lock, -/// the signal handler is left in place so that signals while the lock is held -/// will remove the unique lock file. The caller should ensure there is a -/// matching call to sys::DontRemoveFileOnSignal when the lock is released. -class RemoveUniqueLockFileOnSignal { - StringRef Filename; - bool RemoveImmediately; +/// An RAII helper object for cleanups. +class RAIICleanup { + std::function<void()> Fn; + bool Canceled = false; + public: - RemoveUniqueLockFileOnSignal(StringRef Name) - : Filename(Name), RemoveImmediately(true) { - sys::RemoveFileOnSignal(Filename, nullptr); - } + RAIICleanup(std::function<void()> Fn) : Fn(Fn) {} - ~RemoveUniqueLockFileOnSignal() { - if (!RemoveImmediately) { - // Leave the signal handler enabled. It will be removed when the lock is - // released. + ~RAIICleanup() { + if (Canceled) return; - } - sys::fs::remove(Filename); - sys::DontRemoveFileOnSignal(Filename); + Fn(); } - void lockAcquired() { RemoveImmediately = false; } + void cancel() { Canceled = true; } }; } // end anonymous namespace @@ -172,16 +160,22 @@ LockFileManager::LockFileManager(StringRef FileName) return; // Create a lock file that is unique to this instance. - UniqueLockFileName = LockFileName; - UniqueLockFileName += "-%%%%%%%%"; - int UniqueLockFileID; - if (std::error_code EC = sys::fs::createUniqueFile( - UniqueLockFileName, UniqueLockFileID, UniqueLockFileName)) { - std::string S("failed to create unique file "); - S.append(UniqueLockFileName.str()); + Expected<sys::fs::TempFile> Temp = + sys::fs::TempFile::create(LockFileName + "-%%%%%%%%"); + if (!Temp) { + std::error_code EC = errorToErrorCode(Temp.takeError()); + std::string S("failed to create unique file with prefix "); + S.append(LockFileName.str()); setError(EC, S); return; } + UniqueLockFile = std::move(*Temp); + + // Make sure we discard the temporary file on exit. + RAIICleanup RemoveTempFile([&]() { + if (Error E = UniqueLockFile->discard()) + setError(errorToErrorCode(std::move(E))); + }); // Write our process ID to our unique lock file. { @@ -191,55 +185,46 @@ LockFileManager::LockFileManager(StringRef FileName) return; } - raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true); + raw_fd_ostream Out(UniqueLockFile->FD, /*shouldClose=*/false); Out << HostID << ' '; #if LLVM_ON_UNIX Out << getpid(); #else Out << "1"; #endif - Out.close(); + Out.flush(); if (Out.has_error()) { - // We failed to write out PID, so make up an excuse, remove the + // We failed to write out PID, so report the error, remove the // unique lock file, and fail. - auto EC = make_error_code(errc::no_space_on_device); std::string S("failed to write to "); - S.append(UniqueLockFileName.str()); - setError(EC, S); - sys::fs::remove(UniqueLockFileName); + S.append(UniqueLockFile->TmpName); + setError(Out.error(), S); return; } } - // Clean up the unique file on signal, which also releases the lock if it is - // held since the .lock symlink will point to a nonexistent file. - RemoveUniqueLockFileOnSignal RemoveUniqueFile(UniqueLockFileName); - while (true) { // Create a link from the lock file name. If this succeeds, we're done. std::error_code EC = - sys::fs::create_link(UniqueLockFileName, LockFileName); + sys::fs::create_link(UniqueLockFile->TmpName, LockFileName); if (!EC) { - RemoveUniqueFile.lockAcquired(); + RemoveTempFile.cancel(); return; } if (EC != errc::file_exists) { std::string S("failed to create link "); raw_string_ostream OSS(S); - OSS << LockFileName.str() << " to " << UniqueLockFileName.str(); + OSS << LockFileName.str() << " to " << UniqueLockFile->TmpName; setError(EC, OSS.str()); return; } // Someone else managed to create the lock file first. Read the process ID // from the lock file. - if ((Owner = readLockFile(LockFileName))) { - // Wipe out our unique lock file (it's useless now) - sys::fs::remove(UniqueLockFileName); - return; - } + if ((Owner = readLockFile(LockFileName))) + return; // RemoveTempFile will delete out our unique lock file. if (!sys::fs::exists(LockFileName)) { // The previous owner released the lock file before we could read it. @@ -251,7 +236,7 @@ LockFileManager::LockFileManager(StringRef FileName) // ownership. if ((EC = sys::fs::remove(LockFileName))) { std::string S("failed to remove lockfile "); - S.append(UniqueLockFileName.str()); + S.append(LockFileName.str()); setError(EC, S); return; } @@ -262,21 +247,20 @@ LockFileManager::LockFileState LockFileManager::getState() const { if (Owner) return LFS_Shared; - if (Error) + if (ErrorCode) return LFS_Error; return LFS_Owned; } std::string LockFileManager::getErrorMessage() const { - if (Error) { + if (ErrorCode) { std::string Str(ErrorDiagMsg); - std::string ErrCodeMsg = Error->message(); + std::string ErrCodeMsg = ErrorCode.message(); raw_string_ostream OSS(Str); if (!ErrCodeMsg.empty()) - OSS << ": " << Error->message(); - OSS.flush(); - return Str; + OSS << ": " << ErrCodeMsg; + return OSS.str(); } return ""; } @@ -287,10 +271,7 @@ LockFileManager::~LockFileManager() { // Since we own the lock, remove the lock file and our own unique lock file. sys::fs::remove(LockFileName); - sys::fs::remove(UniqueLockFileName); - // The unique file is now gone, so remove it from the signal handler. This - // matches a sys::RemoveFileOnSignal() in LockFileManager(). - sys::DontRemoveFileOnSignal(UniqueLockFileName); + consumeError(UniqueLockFile->discard()); } LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() { diff --git a/lib/Support/LowLevelType.cpp b/lib/Support/LowLevelType.cpp index 0ee3f1d0119e..cb2187405d6b 100644 --- a/lib/Support/LowLevelType.cpp +++ b/lib/Support/LowLevelType.cpp @@ -43,7 +43,7 @@ void LLT::print(raw_ostream &OS) const { assert(isScalar() && "unexpected type"); OS << "s" << getScalarSizeInBits(); } else - llvm_unreachable("trying to print an invalid type"); + OS << "LLT_invalid"; } const constexpr LLT::BitFieldInfo LLT::ScalarSizeFieldInfo; diff --git a/lib/Support/MD5.cpp b/lib/Support/MD5.cpp index 545a64cfc767..a53172279236 100644 --- a/lib/Support/MD5.cpp +++ b/lib/Support/MD5.cpp @@ -230,7 +230,7 @@ void MD5::update(StringRef Str) { } /// \brief Finish the hash and place the resulting hash into \p result. -/// \param result is assumed to be a minimum of 16-bytes in size. +/// \param Result is assumed to be a minimum of 16-bytes in size. void MD5::final(MD5Result &Result) { unsigned long used, free; diff --git a/lib/Support/Parallel.cpp b/lib/Support/Parallel.cpp index ab2cfdebf07d..010e42916f95 100644 --- a/lib/Support/Parallel.cpp +++ b/lib/Support/Parallel.cpp @@ -9,6 +9,7 @@ #include "llvm/Support/Parallel.h" #include "llvm/Config/llvm-config.h" +#include "llvm/Support/Threading.h" #include <atomic> #include <stack> @@ -70,8 +71,7 @@ Executor *Executor::getDefaultExecutor() { /// in filo order. class ThreadPoolExecutor : public Executor { public: - explicit ThreadPoolExecutor( - unsigned ThreadCount = std::thread::hardware_concurrency()) + explicit ThreadPoolExecutor(unsigned ThreadCount = hardware_concurrency()) : Done(ThreadCount) { // Spawn all but one of the threads in another thread as spawning threads // can take a while. diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp index ea59ba62d7bd..f229f23a4f84 100644 --- a/lib/Support/Path.cpp +++ b/lib/Support/Path.cpp @@ -18,6 +18,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Process.h" +#include "llvm/Support/Signals.h" #include <cctype> #include <cstring> @@ -159,10 +160,11 @@ enum FSEntity { FS_Name }; -static std::error_code createUniqueEntity(const Twine &Model, int &ResultFD, - SmallVectorImpl<char> &ResultPath, - bool MakeAbsolute, unsigned Mode, - FSEntity Type) { +static std::error_code +createUniqueEntity(const Twine &Model, int &ResultFD, + SmallVectorImpl<char> &ResultPath, bool MakeAbsolute, + unsigned Mode, FSEntity Type, + sys::fs::OpenFlags Flags = sys::fs::F_None) { SmallString<128> ModelStorage; Model.toVector(ModelStorage); @@ -195,7 +197,7 @@ retry_random_path: case FS_File: { if (std::error_code EC = sys::fs::openFileForWrite(Twine(ResultPath.begin()), ResultFD, - sys::fs::F_RW | sys::fs::F_Excl, Mode)) { + Flags | sys::fs::F_Excl, Mode)) { if (EC == errc::file_exists) goto retry_random_path; return EC; @@ -439,10 +441,6 @@ void append(SmallVectorImpl<char> &path, Style style, const Twine &a, for (auto &component : components) { bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1], style); - bool component_has_sep = - !component.empty() && is_separator(component[0], style); - bool is_root_name = has_root_name(component, style); - if (path_has_sep) { // Strip separators from beginning of component. size_t loc = component.find_first_not_of(separators(style)); @@ -453,7 +451,10 @@ void append(SmallVectorImpl<char> &path, Style style, const Twine &a, continue; } - if (!component_has_sep && !(path.empty() || is_root_name)) { + bool component_has_sep = + !component.empty() && is_separator(component[0], style); + if (!component_has_sep && + !(path.empty() || has_root_name(component, style))) { // Add a separator. path.push_back(preferred_separator(style)); } @@ -750,8 +751,9 @@ std::error_code getUniqueID(const Twine Path, UniqueID &Result) { std::error_code createUniqueFile(const Twine &Model, int &ResultFd, SmallVectorImpl<char> &ResultPath, - unsigned Mode) { - return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File); + unsigned Mode, sys::fs::OpenFlags Flags) { + return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File, + Flags); } std::error_code createUniqueFile(const Twine &Model, @@ -762,28 +764,32 @@ std::error_code createUniqueFile(const Twine &Model, static std::error_code createTemporaryFile(const Twine &Model, int &ResultFD, - llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) { + llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type, + sys::fs::OpenFlags Flags) { SmallString<128> Storage; StringRef P = Model.toNullTerminatedStringRef(Storage); assert(P.find_first_of(separators(Style::native)) == StringRef::npos && "Model must be a simple filename."); // Use P.begin() so that createUniqueEntity doesn't need to recreate Storage. - return createUniqueEntity(P.begin(), ResultFD, ResultPath, - true, owner_read | owner_write, Type); + return createUniqueEntity(P.begin(), ResultFD, ResultPath, true, + owner_read | owner_write, Type, Flags); } static std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD, - llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) { + llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type, + sys::fs::OpenFlags Flags = sys::fs::F_None) { const char *Middle = Suffix.empty() ? "-%%%%%%" : "-%%%%%%."; return createTemporaryFile(Prefix + Middle + Suffix, ResultFD, ResultPath, - Type); + Type, Flags); } std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD, - SmallVectorImpl<char> &ResultPath) { - return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File); + SmallVectorImpl<char> &ResultPath, + sys::fs::OpenFlags Flags) { + return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File, + Flags); } std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, @@ -953,11 +959,11 @@ ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path) { return Result; } -bool exists(file_status status) { +bool exists(const basic_file_status &status) { return status_known(status) && status.type() != file_type::file_not_found; } -bool status_known(file_status s) { +bool status_known(const basic_file_status &s) { return s.type() != file_type::status_error; } @@ -968,7 +974,7 @@ file_type get_file_type(const Twine &Path, bool Follow) { return st.type(); } -bool is_directory(file_status status) { +bool is_directory(const basic_file_status &status) { return status.type() == file_type::directory_file; } @@ -980,7 +986,7 @@ std::error_code is_directory(const Twine &path, bool &result) { return std::error_code(); } -bool is_regular_file(file_status status) { +bool is_regular_file(const basic_file_status &status) { return status.type() == file_type::regular_file; } @@ -992,7 +998,7 @@ std::error_code is_regular_file(const Twine &path, bool &result) { return std::error_code(); } -bool is_symlink_file(file_status status) { +bool is_symlink_file(const basic_file_status &status) { return status.type() == file_type::symlink_file; } @@ -1004,7 +1010,7 @@ std::error_code is_symlink_file(const Twine &path, bool &result) { return std::error_code(); } -bool is_other(file_status status) { +bool is_other(const basic_file_status &status) { return exists(status) && !is_regular_file(status) && !is_directory(status); @@ -1018,17 +1024,14 @@ std::error_code is_other(const Twine &Path, bool &Result) { return std::error_code(); } -void directory_entry::replace_filename(const Twine &filename, file_status st) { +void directory_entry::replace_filename(const Twine &filename, + basic_file_status st) { SmallString<128> path = path::parent_path(Path); path::append(path, filename); Path = path.str(); Status = st; } -std::error_code directory_entry::status(file_status &result) const { - return fs::status(Path, result, FollowSymlinks); -} - ErrorOr<perms> getPermissions(const Twine &Path) { file_status Status; if (std::error_code EC = status(Path, Status)) @@ -1051,6 +1054,116 @@ ErrorOr<perms> getPermissions(const Twine &Path) { namespace llvm { namespace sys { +namespace fs { +TempFile::TempFile(StringRef Name, int FD) : TmpName(Name), FD(FD) {} +TempFile::TempFile(TempFile &&Other) { *this = std::move(Other); } +TempFile &TempFile::operator=(TempFile &&Other) { + TmpName = std::move(Other.TmpName); + FD = Other.FD; + Other.Done = true; + return *this; +} + +TempFile::~TempFile() { assert(Done); } + +Error TempFile::discard() { + Done = true; + std::error_code RemoveEC; +// On windows closing will remove the file. +#ifndef LLVM_ON_WIN32 + // Always try to close and remove. + if (!TmpName.empty()) { + RemoveEC = fs::remove(TmpName); + sys::DontRemoveFileOnSignal(TmpName); + } +#endif + + if (!RemoveEC) + TmpName = ""; + + if (FD != -1 && close(FD) == -1) { + std::error_code EC = std::error_code(errno, std::generic_category()); + return errorCodeToError(EC); + } + FD = -1; + + return errorCodeToError(RemoveEC); +} + +Error TempFile::keep(const Twine &Name) { + assert(!Done); + Done = true; + // Always try to close and rename. +#ifdef LLVM_ON_WIN32 + // If we cant't cancel the delete don't rename. + std::error_code RenameEC = cancelDeleteOnClose(FD); + if (!RenameEC) + RenameEC = rename_fd(FD, Name); + // If we can't rename, discard the temporary file. + if (RenameEC) + removeFD(FD); +#else + std::error_code RenameEC = fs::rename(TmpName, Name); + // If we can't rename, discard the temporary file. + if (RenameEC) + remove(TmpName); + sys::DontRemoveFileOnSignal(TmpName); +#endif + + if (!RenameEC) + TmpName = ""; + + if (close(FD) == -1) { + std::error_code EC(errno, std::generic_category()); + return errorCodeToError(EC); + } + FD = -1; + + return errorCodeToError(RenameEC); +} + +Error TempFile::keep() { + assert(!Done); + Done = true; + +#ifdef LLVM_ON_WIN32 + if (std::error_code EC = cancelDeleteOnClose(FD)) + return errorCodeToError(EC); +#else + sys::DontRemoveFileOnSignal(TmpName); +#endif + + TmpName = ""; + + if (close(FD) == -1) { + std::error_code EC(errno, std::generic_category()); + return errorCodeToError(EC); + } + FD = -1; + + return Error::success(); +} + +Expected<TempFile> TempFile::create(const Twine &Model, unsigned Mode) { + int FD; + SmallString<128> ResultPath; + if (std::error_code EC = createUniqueFile(Model, FD, ResultPath, Mode, + sys::fs::F_RW | sys::fs::F_Delete)) + return errorCodeToError(EC); + + TempFile Ret(ResultPath, FD); +#ifndef LLVM_ON_WIN32 + if (sys::RemoveFileOnSignal(ResultPath)) { + // Make sure we delete the file when RemoveFileOnSignal fails. + consumeError(Ret.discard()); + std::error_code EC(errc::operation_not_permitted); + return errorCodeToError(EC); + } +#endif + return std::move(Ret); +} +} + namespace path { bool user_cache_directory(SmallVectorImpl<char> &Result, const Twine &Path1, diff --git a/lib/Support/Process.cpp b/lib/Support/Process.cpp index caec993ee165..1c8cc6e83ad1 100644 --- a/lib/Support/Process.cpp +++ b/lib/Support/Process.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Process.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" #include "llvm/Support/FileSystem.h" @@ -26,9 +27,14 @@ using namespace sys; //=== independent code. //===----------------------------------------------------------------------===// -Optional<std::string> Process::FindInEnvPath(const std::string& EnvName, - const std::string& FileName) -{ +Optional<std::string> Process::FindInEnvPath(StringRef EnvName, + StringRef FileName) { + return FindInEnvPath(EnvName, FileName, {}); +} + +Optional<std::string> Process::FindInEnvPath(StringRef EnvName, + StringRef FileName, + ArrayRef<std::string> IgnoreList) { assert(!path::is_absolute(FileName)); Optional<std::string> FoundPath; Optional<std::string> OptPath = Process::GetEnv(EnvName); @@ -39,10 +45,13 @@ Optional<std::string> Process::FindInEnvPath(const std::string& EnvName, SmallVector<StringRef, 8> Dirs; SplitString(OptPath.getValue(), Dirs, EnvPathSeparatorStr); - for (const auto &Dir : Dirs) { + for (StringRef Dir : Dirs) { if (Dir.empty()) continue; + if (any_of(IgnoreList, [&](StringRef S) { return fs::equivalent(S, Dir); })) + continue; + SmallString<128> FilePath(Dir); path::append(FilePath, FileName); if (fs::exists(Twine(FilePath))) { diff --git a/lib/Support/Program.cpp b/lib/Support/Program.cpp index 34e336b354d6..4212323bc0e1 100644 --- a/lib/Support/Program.cpp +++ b/lib/Support/Program.cpp @@ -23,20 +23,21 @@ using namespace sys; //=== independent code. //===----------------------------------------------------------------------===// -static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, - const char **env, const StringRef **Redirects, - unsigned memoryLimit, std::string *ErrMsg); +static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, + const char **Env, ArrayRef<Optional<StringRef>> Redirects, + unsigned MemoryLimit, std::string *ErrMsg); -int sys::ExecuteAndWait(StringRef Program, const char **args, const char **envp, - const StringRef **redirects, unsigned secondsToWait, - unsigned memoryLimit, std::string *ErrMsg, - bool *ExecutionFailed) { +int sys::ExecuteAndWait(StringRef Program, const char **Args, const char **Envp, + ArrayRef<Optional<StringRef>> Redirects, + unsigned SecondsToWait, unsigned MemoryLimit, + std::string *ErrMsg, bool *ExecutionFailed) { + assert(Redirects.empty() || Redirects.size() == 3); ProcessInfo PI; - if (Execute(PI, Program, args, envp, redirects, memoryLimit, ErrMsg)) { + if (Execute(PI, Program, Args, Envp, Redirects, MemoryLimit, ErrMsg)) { if (ExecutionFailed) *ExecutionFailed = false; ProcessInfo Result = Wait( - PI, secondsToWait, /*WaitUntilTerminates=*/secondsToWait == 0, ErrMsg); + PI, SecondsToWait, /*WaitUntilTerminates=*/SecondsToWait == 0, ErrMsg); return Result.ReturnCode; } @@ -46,14 +47,16 @@ int sys::ExecuteAndWait(StringRef Program, const char **args, const char **envp, return -1; } -ProcessInfo sys::ExecuteNoWait(StringRef Program, const char **args, - const char **envp, const StringRef **redirects, - unsigned memoryLimit, std::string *ErrMsg, +ProcessInfo sys::ExecuteNoWait(StringRef Program, const char **Args, + const char **Envp, + ArrayRef<Optional<StringRef>> Redirects, + unsigned MemoryLimit, std::string *ErrMsg, bool *ExecutionFailed) { + assert(Redirects.empty() || Redirects.size() == 3); ProcessInfo PI; if (ExecutionFailed) *ExecutionFailed = false; - if (!Execute(PI, Program, args, envp, redirects, memoryLimit, ErrMsg)) + if (!Execute(PI, Program, Args, Envp, Redirects, MemoryLimit, ErrMsg)) if (ExecutionFailed) *ExecutionFailed = true; diff --git a/lib/Support/RandomNumberGenerator.cpp b/lib/Support/RandomNumberGenerator.cpp index 8ea02d709df1..47d20159200b 100644 --- a/lib/Support/RandomNumberGenerator.cpp +++ b/lib/Support/RandomNumberGenerator.cpp @@ -32,8 +32,8 @@ using namespace llvm; // // Do not change to cl::opt<uint64_t> since this silently breaks argument parsing. static cl::opt<unsigned long long> -Seed("rng-seed", cl::value_desc("seed"), - cl::desc("Seed for the random number generator"), cl::init(0)); + Seed("rng-seed", cl::value_desc("seed"), cl::Hidden, + cl::desc("Seed for the random number generator"), cl::init(0)); RandomNumberGenerator::RandomNumberGenerator(StringRef Salt) { DEBUG( diff --git a/lib/Support/ScopedPrinter.cpp b/lib/Support/ScopedPrinter.cpp index 537ff62c7b09..981dfbff520a 100644 --- a/lib/Support/ScopedPrinter.cpp +++ b/lib/Support/ScopedPrinter.cpp @@ -1,6 +1,5 @@ #include "llvm/Support/ScopedPrinter.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/Support/Format.h" #include <cctype> diff --git a/lib/Support/Signals.cpp b/lib/Support/Signals.cpp index 256a22dee87b..661f4d649cdd 100644 --- a/lib/Support/Signals.cpp +++ b/lib/Support/Signals.cpp @@ -123,11 +123,7 @@ static bool printSymbolizedStackTrace(StringRef Argv0, } } - StringRef InputFileStr(InputFile); - StringRef OutputFileStr(OutputFile); - StringRef StderrFileStr; - const StringRef *Redirects[] = {&InputFileStr, &OutputFileStr, - &StderrFileStr}; + Optional<StringRef> Redirects[] = {InputFile.str(), OutputFile.str(), llvm::None}; const char *Args[] = {"llvm-symbolizer", "--functions=linkage", "--inlining", #ifdef LLVM_ON_WIN32 // Pass --relative-address on Windows so that we don't diff --git a/lib/Support/SmallPtrSet.cpp b/lib/Support/SmallPtrSet.cpp index aa12e85fa4c0..119bb871d4c0 100644 --- a/lib/Support/SmallPtrSet.cpp +++ b/lib/Support/SmallPtrSet.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/ErrorHandling.h" #include <algorithm> #include <cassert> #include <cstdlib> @@ -32,7 +33,9 @@ void SmallPtrSetImplBase::shrink_and_clear() { // Install the new array. Clear all the buckets to empty. CurArray = (const void**)malloc(sizeof(void*) * CurArraySize); - assert(CurArray && "Failed to allocate memory?"); + if (CurArray == nullptr) + report_bad_alloc_error("Allocation of SmallPtrSet bucket array failed."); + memset(CurArray, -1, CurArraySize*sizeof(void*)); } @@ -58,6 +61,7 @@ SmallPtrSetImplBase::insert_imp_big(const void *Ptr) { else ++NumNonEmpty; // Track density. *Bucket = Ptr; + incrementEpoch(); return std::make_pair(Bucket, true); } @@ -96,8 +100,12 @@ void SmallPtrSetImplBase::Grow(unsigned NewSize) { bool WasSmall = isSmall(); // Install the new array. Clear all the buckets to empty. - CurArray = (const void**)malloc(sizeof(void*) * NewSize); - assert(CurArray && "Failed to allocate memory?"); + const void **NewBuckets = (const void**) malloc(sizeof(void*) * NewSize); + if (NewBuckets == nullptr) + report_bad_alloc_error("Allocation of SmallPtrSet bucket array failed."); + + // Reset member only if memory was allocated successfully + CurArray = NewBuckets; CurArraySize = NewSize; memset(CurArray, -1, NewSize*sizeof(void*)); @@ -125,7 +133,8 @@ SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage, // Otherwise, allocate new heap space (unless we were the same size) } else { CurArray = (const void**)malloc(sizeof(void*) * that.CurArraySize); - assert(CurArray && "Failed to allocate memory?"); + if (CurArray == nullptr) + report_bad_alloc_error("Allocation of SmallPtrSet bucket array failed."); } // Copy over the that array. @@ -162,7 +171,8 @@ void SmallPtrSetImplBase::CopyFrom(const SmallPtrSetImplBase &RHS) { free(CurArray); CurArray = T; } - assert(CurArray && "Failed to allocate memory?"); + if (CurArray == nullptr) + report_bad_alloc_error("Allocation of SmallPtrSet bucket array failed."); } CopyHelper(RHS); diff --git a/lib/Support/SmallVector.cpp b/lib/Support/SmallVector.cpp index b931505bd6a1..74313151c762 100644 --- a/lib/Support/SmallVector.cpp +++ b/lib/Support/SmallVector.cpp @@ -26,14 +26,17 @@ void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSizeInBytes, void *NewElts; if (BeginX == FirstEl) { NewElts = malloc(NewCapacityInBytes); + if (NewElts == nullptr) + report_bad_alloc_error("Allocation of SmallVector element failed."); // Copy the elements over. No need to run dtors on PODs. memcpy(NewElts, this->BeginX, CurSizeBytes); } else { // If this wasn't grown from the inline copy, grow the allocated space. NewElts = realloc(this->BeginX, NewCapacityInBytes); + if (NewElts == nullptr) + report_bad_alloc_error("Reallocation of SmallVector element failed."); } - assert(NewElts && "Out of memory"); this->EndX = (char*)NewElts+CurSizeBytes; this->BeginX = NewElts; diff --git a/lib/Support/SourceMgr.cpp b/lib/Support/SourceMgr.cpp index b0609d4fe047..a8f6208a558c 100644 --- a/lib/Support/SourceMgr.cpp +++ b/lib/Support/SourceMgr.cpp @@ -384,6 +384,11 @@ void SMDiagnostic::print(const char *ProgName, raw_ostream &S, bool ShowColors, S.changeColor(raw_ostream::BLACK, true); S << "note: "; break; + case SourceMgr::DK_Remark: + if (ShowColors) + S.changeColor(raw_ostream::BLUE, true); + S << "remark: "; + break; } if (ShowColors) { diff --git a/lib/Support/SpecialCaseList.cpp b/lib/Support/SpecialCaseList.cpp index 05886eaa8aee..bf807e66e02c 100644 --- a/lib/Support/SpecialCaseList.cpp +++ b/lib/Support/SpecialCaseList.cpp @@ -17,65 +17,74 @@ #include "llvm/Support/SpecialCaseList.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/TrigramIndex.h" #include <string> #include <system_error> #include <utility> +#include <stdio.h> namespace llvm { -/// Represents a set of regular expressions. Regular expressions which are -/// "literal" (i.e. no regex metacharacters) are stored in Strings, while all -/// others are represented as a single pipe-separated regex in RegEx. The -/// reason for doing so is efficiency; StringSet is much faster at matching -/// literal strings than Regex. -struct SpecialCaseList::Entry { - StringSet<> Strings; - TrigramIndex Trigrams; - std::unique_ptr<Regex> RegEx; - - bool match(StringRef Query) const { - if (Strings.count(Query)) - return true; - if (Trigrams.isDefinitelyOut(Query)) - return false; - return RegEx && RegEx->match(Query); +bool SpecialCaseList::Matcher::insert(std::string Regexp, + unsigned LineNumber, + std::string &REError) { + if (Regexp.empty()) { + REError = "Supplied regexp was blank"; + return false; + } + + if (Regex::isLiteralERE(Regexp)) { + Strings[Regexp] = LineNumber; + return true; + } + Trigrams.insert(Regexp); + + // Replace * with .* + for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std::string::npos; + pos += strlen(".*")) { + Regexp.replace(pos, strlen("*"), ".*"); } -}; -SpecialCaseList::SpecialCaseList() : Entries(), Regexps(), IsCompiled(false) {} + Regexp = (Twine("^(") + StringRef(Regexp) + ")$").str(); + + // Check that the regexp is valid. + Regex CheckRE(Regexp); + if (!CheckRE.isValid(REError)) + return false; + + RegExes.emplace_back( + std::make_pair(make_unique<Regex>(std::move(CheckRE)), LineNumber)); + return true; +} + +unsigned SpecialCaseList::Matcher::match(StringRef Query) const { + auto It = Strings.find(Query); + if (It != Strings.end()) + return It->second; + if (Trigrams.isDefinitelyOut(Query)) + return false; + for (auto& RegExKV : RegExes) + if (RegExKV.first->match(Query)) + return RegExKV.second; + return 0; +} std::unique_ptr<SpecialCaseList> SpecialCaseList::create(const std::vector<std::string> &Paths, std::string &Error) { std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList()); - for (const 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; - } - } - SCL->compile(); - return SCL; + if (SCL->createInternal(Paths, Error)) + return SCL; + return nullptr; } std::unique_ptr<SpecialCaseList> SpecialCaseList::create(const MemoryBuffer *MB, std::string &Error) { std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList()); - if (!SCL->parse(MB, Error)) - return nullptr; - SCL->compile(); - return SCL; + if (SCL->createInternal(MB, Error)) + return SCL; + return nullptr; } std::unique_ptr<SpecialCaseList> @@ -86,15 +95,71 @@ SpecialCaseList::createOrDie(const std::vector<std::string> &Paths) { report_fatal_error(Error); } -bool SpecialCaseList::parse(const MemoryBuffer *MB, std::string &Error) { +bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths, + std::string &Error) { + StringMap<size_t> Sections; + for (const 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 false; + } + std::string ParseError; + if (!parse(FileOrErr.get().get(), Sections, ParseError)) { + Error = (Twine("error parsing file '") + Path + "': " + ParseError).str(); + return false; + } + } + return true; +} + +bool SpecialCaseList::createInternal(const MemoryBuffer *MB, + std::string &Error) { + StringMap<size_t> Sections; + if (!parse(MB, Sections, Error)) + return false; + return true; +} + +bool SpecialCaseList::parse(const MemoryBuffer *MB, + StringMap<size_t> &SectionsMap, + std::string &Error) { // Iterate through each line in the blacklist file. SmallVector<StringRef, 16> Lines; - SplitString(MB->getBuffer(), Lines, "\n\r"); - int LineNo = 1; + MB->getBuffer().split(Lines, '\n'); + + unsigned LineNo = 1; + StringRef Section = "*"; + for (auto I = Lines.begin(), E = Lines.end(); I != E; ++I, ++LineNo) { + *I = I->trim(); // Ignore empty lines and lines starting with "#" if (I->empty() || I->startswith("#")) continue; + + // Save section names + if (I->startswith("[")) { + if (!I->endswith("]")) { + Error = (Twine("malformed section header on line ") + Twine(LineNo) + + ": " + *I).str(); + return false; + } + + Section = I->slice(1, I->size() - 1); + + std::string REError; + Regex CheckRE(Section); + if (!CheckRE.isValid(REError)) { + Error = + (Twine("malformed regex for section ") + Section + ": '" + REError) + .str(); + return false; + } + + continue; + } + // Get our prefix and unparsed regexp. std::pair<StringRef, StringRef> SplitLine = I->split(":"); StringRef Prefix = SplitLine.first; @@ -109,62 +174,57 @@ bool SpecialCaseList::parse(const MemoryBuffer *MB, std::string &Error) { std::string Regexp = SplitRegexp.first; StringRef Category = SplitRegexp.second; - // See if we can store Regexp in Strings. - auto &Entry = Entries[Prefix][Category]; - if (Regex::isLiteralERE(Regexp)) { - Entry.Strings.insert(Regexp); - continue; + // Create this section if it has not been seen before. + if (SectionsMap.find(Section) == SectionsMap.end()) { + std::unique_ptr<Matcher> M = make_unique<Matcher>(); + std::string REError; + if (!M->insert(Section, LineNo, REError)) { + Error = (Twine("malformed section ") + Section + ": '" + REError).str(); + return false; + } + + SectionsMap[Section] = Sections.size(); + Sections.emplace_back(std::move(M)); } - Entry.Trigrams.insert(Regexp); - // Replace * with .* - for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std::string::npos; - pos += strlen(".*")) { - Regexp.replace(pos, strlen("*"), ".*"); - } - - // Check that the regexp is valid. - Regex CheckRE(Regexp); + auto &Entry = Sections[SectionsMap[Section]].Entries[Prefix][Category]; std::string REError; - if (!CheckRE.isValid(REError)) { + if (!Entry.insert(std::move(Regexp), LineNo, REError)) { Error = (Twine("malformed regex in line ") + Twine(LineNo) + ": '" + SplitLine.second + "': " + REError).str(); return false; } - - // Add this regexp into the proper group by its prefix. - if (!Regexps[Prefix][Category].empty()) - 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(); - I != E; ++I) { - for (StringMap<std::string>::const_iterator II = I->second.begin(), - IE = I->second.end(); - II != IE; ++II) { - Entries[I->getKey()][II->getKey()].RegEx.reset(new Regex(II->getValue())); - } - } - Regexps.clear(); - IsCompiled = true; +SpecialCaseList::~SpecialCaseList() {} + +bool SpecialCaseList::inSection(StringRef Section, StringRef Prefix, + StringRef Query, StringRef Category) const { + return inSectionBlame(Section, Prefix, Query, Category); } -SpecialCaseList::~SpecialCaseList() {} +unsigned SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix, + StringRef Query, + StringRef Category) const { + for (auto &SectionIter : Sections) + if (SectionIter.SectionMatcher->match(Section)) { + unsigned Blame = + inSectionBlame(SectionIter.Entries, Prefix, Query, Category); + if (Blame) + return Blame; + } + return 0; +} -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); - if (II == I->second.end()) return false; +unsigned SpecialCaseList::inSectionBlame(const SectionEntries &Entries, + StringRef Prefix, StringRef Query, + StringRef Category) const { + SectionEntries::const_iterator I = Entries.find(Prefix); + if (I == Entries.end()) return 0; + StringMap<Matcher>::const_iterator II = I->second.find(Category); + if (II == I->second.end()) return 0; return II->getValue().match(Query); } diff --git a/lib/Support/Statistic.cpp b/lib/Support/Statistic.cpp index 72ca22806c43..544ae2d0983c 100644 --- a/lib/Support/Statistic.cpp +++ b/lib/Support/Statistic.cpp @@ -39,12 +39,14 @@ using namespace llvm; /// -stats - Command line option to cause transformations to emit stats about /// what they did. /// -static cl::opt<bool> Stats("stats", - cl::desc("Enable statistics output from program (available with Asserts)")); - +static cl::opt<bool> Stats( + "stats", + cl::desc("Enable statistics output from program (available with Asserts)"), + cl::Hidden); static cl::opt<bool> StatsAsJSON("stats-json", - cl::desc("Display statistics as json data")); + cl::desc("Display statistics as json data"), + cl::Hidden); static bool Enabled; static bool PrintOnExit; @@ -166,9 +168,10 @@ void llvm::PrintStatisticsJSON(raw_ostream &OS) { const char *delim = ""; for (const Statistic *Stat : Stats.Stats) { OS << delim; - assert(!yaml::needsQuotes(Stat->getDebugType()) && + assert(yaml::needsQuotes(Stat->getDebugType()) == yaml::QuotingType::None && "Statistic group/type name is simple."); - assert(!yaml::needsQuotes(Stat->getName()) && "Statistic name is simple"); + assert(yaml::needsQuotes(Stat->getName()) == yaml::QuotingType::None && + "Statistic name is simple"); OS << "\t\"" << Stat->getDebugType() << '.' << Stat->getName() << "\": " << Stat->getValue(); delim = ",\n"; diff --git a/lib/Support/StringExtras.cpp b/lib/Support/StringExtras.cpp index b2f42dfcc04d..21157a14086d 100644 --- a/lib/Support/StringExtras.cpp +++ b/lib/Support/StringExtras.cpp @@ -13,6 +13,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; /// StrInStrNoCase - Portable version of strcasestr. Locates the first @@ -56,3 +57,8 @@ void llvm::SplitString(StringRef Source, S = getToken(S.second, Delimiters); } } + +void llvm::printLowerCase(StringRef String, raw_ostream &Out) { + for (const char C : String) + Out << toLower(C); +} diff --git a/lib/Support/StringMap.cpp b/lib/Support/StringMap.cpp index d2315966e32f..4341da2d97bd 100644 --- a/lib/Support/StringMap.cpp +++ b/lib/Support/StringMap.cpp @@ -52,14 +52,21 @@ StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) { void StringMapImpl::init(unsigned InitSize) { assert((InitSize & (InitSize-1)) == 0 && "Init Size must be a power of 2 or zero!"); - NumBuckets = InitSize ? InitSize : 16; + + unsigned NewNumBuckets = InitSize ? InitSize : 16; NumItems = 0; NumTombstones = 0; - TheTable = (StringMapEntryBase **)calloc(NumBuckets+1, + TheTable = (StringMapEntryBase **)calloc(NewNumBuckets+1, sizeof(StringMapEntryBase **) + sizeof(unsigned)); + if (TheTable == nullptr) + report_bad_alloc_error("Allocation of StringMap table failed."); + + // Set the member only if TheTable was successfully allocated + NumBuckets = NewNumBuckets; + // Allocate one extra bucket, set it to look filled so the iterators stop at // end. TheTable[NumBuckets] = (StringMapEntryBase*)2; @@ -215,6 +222,10 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) { StringMapEntryBase **NewTableArray = (StringMapEntryBase **)calloc(NewSize+1, sizeof(StringMapEntryBase *) + sizeof(unsigned)); + + if (NewTableArray == nullptr) + report_bad_alloc_error("Allocation of StringMap hash table failed."); + unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1); NewTableArray[NewSize] = (StringMapEntryBase*)2; diff --git a/lib/Support/StringRef.cpp b/lib/Support/StringRef.cpp index 9b7cc1c1d182..90992fce0bcc 100644 --- a/lib/Support/StringRef.cpp +++ b/lib/Support/StringRef.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/edit_distance.h" #include <bitset> @@ -21,28 +22,12 @@ using namespace llvm; const size_t StringRef::npos; #endif -static char ascii_tolower(char x) { - if (x >= 'A' && x <= 'Z') - return x - 'A' + 'a'; - return x; -} - -static char ascii_toupper(char x) { - if (x >= 'a' && x <= 'z') - return x - 'a' + 'A'; - return x; -} - -static bool ascii_isdigit(char x) { - return x >= '0' && x <= '9'; -} - // strncasecmp() is not available on non-POSIX systems, so define an // alternative function here. static int ascii_strncasecmp(const char *LHS, const char *RHS, size_t Length) { for (size_t I = 0; I < Length; ++I) { - unsigned char LHC = ascii_tolower(LHS[I]); - unsigned char RHC = ascii_tolower(RHS[I]); + unsigned char LHC = toLower(LHS[I]); + unsigned char RHC = toLower(RHS[I]); if (LHC != RHC) return LHC < RHC ? -1 : 1; } @@ -71,21 +56,21 @@ bool StringRef::endswith_lower(StringRef Suffix) const { } size_t StringRef::find_lower(char C, size_t From) const { - char L = ascii_tolower(C); - return find_if([L](char D) { return ascii_tolower(D) == L; }, From); + char L = toLower(C); + return find_if([L](char D) { return toLower(D) == L; }, From); } /// compare_numeric - Compare strings, handle embedded numbers. int StringRef::compare_numeric(StringRef RHS) const { for (size_t I = 0, E = std::min(Length, RHS.Length); I != E; ++I) { // Check for sequences of digits. - if (ascii_isdigit(Data[I]) && ascii_isdigit(RHS.Data[I])) { + if (isDigit(Data[I]) && isDigit(RHS.Data[I])) { // The longer sequence of numbers is considered larger. // This doesn't really handle prefixed zeros well. size_t J; for (J = I + 1; J != E + 1; ++J) { - bool ld = J < Length && ascii_isdigit(Data[J]); - bool rd = J < RHS.Length && ascii_isdigit(RHS.Data[J]); + bool ld = J < Length && isDigit(Data[J]); + bool rd = J < RHS.Length && isDigit(RHS.Data[J]); if (ld != rd) return rd ? -1 : 1; if (!rd) @@ -123,7 +108,7 @@ unsigned StringRef::edit_distance(llvm::StringRef Other, std::string StringRef::lower() const { std::string Result(size(), char()); for (size_type i = 0, e = size(); i != e; ++i) { - Result[i] = ascii_tolower(Data[i]); + Result[i] = toLower(Data[i]); } return Result; } @@ -131,7 +116,7 @@ std::string StringRef::lower() const { std::string StringRef::upper() const { std::string Result(size(), char()); for (size_type i = 0, e = size(); i != e; ++i) { - Result[i] = ascii_toupper(Data[i]); + Result[i] = toUpper(Data[i]); } return Result; } @@ -210,7 +195,7 @@ size_t StringRef::rfind_lower(char C, size_t From) const { size_t i = From; while (i != 0) { --i; - if (ascii_tolower(Data[i]) == ascii_tolower(C)) + if (toLower(Data[i]) == toLower(C)) return i; } return npos; @@ -415,7 +400,7 @@ static unsigned GetAutoSenseRadix(StringRef &Str) { return 8; } - if (Str[0] == '0' && Str.size() > 1 && ascii_isdigit(Str[1])) { + if (Str[0] == '0' && Str.size() > 1 && isDigit(Str[1])) { Str = Str.substr(1); return 8; } diff --git a/lib/Support/TarWriter.cpp b/lib/Support/TarWriter.cpp index f06abf46cce4..abc46d076576 100644 --- a/lib/Support/TarWriter.cpp +++ b/lib/Support/TarWriter.cpp @@ -116,34 +116,37 @@ static void writePaxHeader(raw_fd_ostream &OS, StringRef Path) { pad(OS); } -// In the Ustar header, a path can be split at any '/' to store -// a path into UstarHeader::Name and UstarHeader::Prefix. This -// function splits a given path for that purpose. -static std::pair<StringRef, StringRef> splitPath(StringRef Path) { - if (Path.size() <= sizeof(UstarHeader::Name)) - return {"", Path}; +// Path fits in a Ustar header if +// +// - Path is less than 100 characters long, or +// - Path is in the form of "<prefix>/<name>" where <prefix> is less +// than or equal to 155 characters long and <name> is less than 100 +// characters long. Both <prefix> and <name> can contain extra '/'. +// +// If Path fits in a Ustar header, updates Prefix and Name and returns true. +// Otherwise, returns false. +static bool splitUstar(StringRef Path, StringRef &Prefix, StringRef &Name) { + if (Path.size() < sizeof(UstarHeader::Name)) { + Prefix = ""; + Name = Path; + return true; + } + size_t Sep = Path.rfind('/', sizeof(UstarHeader::Prefix) + 1); if (Sep == StringRef::npos) - return {"", Path}; - return {Path.substr(0, Sep), Path.substr(Sep + 1)}; -} + return false; + if (Path.size() - Sep - 1 >= sizeof(UstarHeader::Name)) + return false; -// Returns true if a given path can be stored to a Ustar header -// without the PAX extension. -static bool fitsInUstar(StringRef Path) { - StringRef Prefix; - StringRef Name; - std::tie(Prefix, Name) = splitPath(Path); - return Name.size() <= sizeof(UstarHeader::Name); + Prefix = Path.substr(0, Sep); + Name = Path.substr(Sep + 1); + return true; } // The PAX header is an extended format, so a PAX header needs // to be followed by a "real" header. -static void writeUstarHeader(raw_fd_ostream &OS, StringRef Path, size_t Size) { - StringRef Prefix; - StringRef Name; - std::tie(Prefix, Name) = splitPath(Path); - +static void writeUstarHeader(raw_fd_ostream &OS, StringRef Prefix, + StringRef Name, size_t Size) { UstarHeader Hdr = makeUstarHeader(); memcpy(Hdr.Name, Name.data(), Name.size()); memcpy(Hdr.Mode, "0000664", 8); @@ -168,12 +171,19 @@ TarWriter::TarWriter(int FD, StringRef BaseDir) // Append a given file to an archive. void TarWriter::append(StringRef Path, StringRef Data) { // Write Path and Data. - std::string S = BaseDir + "/" + sys::path::convert_to_slash(Path) + "\0"; - if (fitsInUstar(S)) { - writeUstarHeader(OS, S, Data.size()); + std::string Fullpath = BaseDir + "/" + sys::path::convert_to_slash(Path); + + // We do not want to include the same file more than once. + if (!Files.insert(Fullpath).second) + return; + + StringRef Prefix; + StringRef Name; + if (splitUstar(Fullpath, Prefix, Name)) { + writeUstarHeader(OS, Prefix, Name, Data.size()); } else { - writePaxHeader(OS, S); - writeUstarHeader(OS, "", Data.size()); + writePaxHeader(OS, Fullpath); + writeUstarHeader(OS, "", "", Data.size()); } OS << Data; diff --git a/lib/Support/TargetParser.cpp b/lib/Support/TargetParser.cpp index e8ef1d2fd8b9..c59068cb3550 100644 --- a/lib/Support/TargetParser.cpp +++ b/lib/Support/TargetParser.cpp @@ -14,7 +14,6 @@ #include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/TargetParser.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include <cctype> @@ -75,7 +74,7 @@ template <typename T> struct ArchNames { ArchNames<ARM::ArchKind> ARCHNames[] = { #define ARM_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) \ {NAME, sizeof(NAME) - 1, CPU_ATTR, sizeof(CPU_ATTR) - 1, SUB_ARCH, \ - sizeof(SUB_ARCH) - 1, ARCH_FPU, ARCH_BASE_EXT, ID, ARCH_ATTR}, + sizeof(SUB_ARCH) - 1, ARCH_FPU, ARCH_BASE_EXT, ARM::ArchKind::ID, ARCH_ATTR}, #include "llvm/Support/ARMTargetParser.def" }; @@ -137,7 +136,7 @@ template <typename T> struct CpuNames { }; CpuNames<ARM::ArchKind> CPUNames[] = { #define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ - { NAME, sizeof(NAME) - 1, ID, IS_DEFAULT, DEFAULT_EXT }, + { NAME, sizeof(NAME) - 1, ARM::ArchKind::ID, IS_DEFAULT, DEFAULT_EXT }, #include "llvm/Support/ARMTargetParser.def" }; @@ -153,33 +152,33 @@ CpuNames<AArch64::ArchKind> AArch64CPUNames[] = { // Information by ID // ======================================================= // -StringRef llvm::ARM::getFPUName(unsigned FPUKind) { +StringRef ARM::getFPUName(unsigned FPUKind) { if (FPUKind >= ARM::FK_LAST) return StringRef(); return FPUNames[FPUKind].getName(); } -unsigned llvm::ARM::getFPUVersion(unsigned FPUKind) { +FPUVersion ARM::getFPUVersion(unsigned FPUKind) { if (FPUKind >= ARM::FK_LAST) - return 0; + return FPUVersion::NONE; return FPUNames[FPUKind].FPUVersion; } -unsigned llvm::ARM::getFPUNeonSupportLevel(unsigned FPUKind) { +ARM::NeonSupportLevel ARM::getFPUNeonSupportLevel(unsigned FPUKind) { if (FPUKind >= ARM::FK_LAST) - return 0; + return ARM::NeonSupportLevel::None; return FPUNames[FPUKind].NeonSupport; } -unsigned llvm::ARM::getFPURestriction(unsigned FPUKind) { +ARM::FPURestriction ARM::getFPURestriction(unsigned FPUKind) { if (FPUKind >= ARM::FK_LAST) - return 0; + return ARM::FPURestriction::None; return FPUNames[FPUKind].Restriction; } -unsigned llvm::ARM::getDefaultFPU(StringRef CPU, unsigned ArchKind) { +unsigned llvm::ARM::getDefaultFPU(StringRef CPU, ArchKind AK) { if (CPU == "generic") - return ARCHNames[ArchKind].DefaultFPU; + return ARCHNames[static_cast<unsigned>(AK)].DefaultFPU; return StringSwitch<unsigned>(CPU) #define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ @@ -188,13 +187,14 @@ unsigned llvm::ARM::getDefaultFPU(StringRef CPU, unsigned ArchKind) { .Default(ARM::FK_INVALID); } -unsigned llvm::ARM::getDefaultExtensions(StringRef CPU, unsigned ArchKind) { +unsigned llvm::ARM::getDefaultExtensions(StringRef CPU, ArchKind AK) { if (CPU == "generic") - return ARCHNames[ArchKind].ArchBaseExtensions; + return ARCHNames[static_cast<unsigned>(AK)].ArchBaseExtensions; return StringSwitch<unsigned>(CPU) #define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ - .Case(NAME, ARCHNames[ID].ArchBaseExtensions | DEFAULT_EXT) + .Case(NAME, ARCHNames[static_cast<unsigned>(ARM::ArchKind::ID)]\ + .ArchBaseExtensions | DEFAULT_EXT) #include "llvm/Support/ARMTargetParser.def" .Default(ARM::AEK_INVALID); } @@ -234,6 +234,16 @@ bool llvm::ARM::getExtensionFeatures(unsigned Extensions, else Features.push_back("-dsp"); + if (Extensions & ARM::AEK_RAS) + Features.push_back("+ras"); + else + Features.push_back("-ras"); + + if (Extensions & ARM::AEK_DOTPROD) + Features.push_back("+dotprod"); + else + Features.push_back("-dotprod"); + return getHWDivFeatures(Extensions, Features); } @@ -246,15 +256,15 @@ bool llvm::ARM::getFPUFeatures(unsigned FPUKind, // fp-only-sp and d16 subtarget features are independent of each other, so we // must enable/disable both. switch (FPUNames[FPUKind].Restriction) { - case ARM::FR_SP_D16: + case ARM::FPURestriction::SP_D16: Features.push_back("+fp-only-sp"); Features.push_back("+d16"); break; - case ARM::FR_D16: + case ARM::FPURestriction::D16: Features.push_back("-fp-only-sp"); Features.push_back("+d16"); break; - case ARM::FR_None: + case ARM::FPURestriction::None: Features.push_back("-fp-only-sp"); Features.push_back("-d16"); break; @@ -265,33 +275,33 @@ bool llvm::ARM::getFPUFeatures(unsigned FPUKind, // higher. We also have to make sure to disable fp16 when vfp4 is disabled, // as +vfp4 implies +fp16 but -vfp4 does not imply -fp16. switch (FPUNames[FPUKind].FPUVersion) { - case ARM::FV_VFPV5: + case ARM::FPUVersion::VFPV5: Features.push_back("+fp-armv8"); break; - case ARM::FV_VFPV4: + case ARM::FPUVersion::VFPV4: Features.push_back("+vfp4"); Features.push_back("-fp-armv8"); break; - case ARM::FV_VFPV3_FP16: + case ARM::FPUVersion::VFPV3_FP16: Features.push_back("+vfp3"); Features.push_back("+fp16"); Features.push_back("-vfp4"); Features.push_back("-fp-armv8"); break; - case ARM::FV_VFPV3: + case ARM::FPUVersion::VFPV3: Features.push_back("+vfp3"); Features.push_back("-fp16"); Features.push_back("-vfp4"); Features.push_back("-fp-armv8"); break; - case ARM::FV_VFPV2: + case ARM::FPUVersion::VFPV2: Features.push_back("+vfp2"); Features.push_back("-vfp3"); Features.push_back("-fp16"); Features.push_back("-vfp4"); Features.push_back("-fp-armv8"); break; - case ARM::FV_NONE: + case ARM::FPUVersion::NONE: Features.push_back("-vfp2"); Features.push_back("-vfp3"); Features.push_back("-fp16"); @@ -302,15 +312,15 @@ bool llvm::ARM::getFPUFeatures(unsigned FPUKind, // crypto includes neon, so we handle this similarly to FPU version. switch (FPUNames[FPUKind].NeonSupport) { - case ARM::NS_Crypto: + case ARM::NeonSupportLevel::Crypto: Features.push_back("+neon"); Features.push_back("+crypto"); break; - case ARM::NS_Neon: + case ARM::NeonSupportLevel::Neon: Features.push_back("+neon"); Features.push_back("-crypto"); break; - case ARM::NS_None: + case ARM::NeonSupportLevel::None: Features.push_back("-neon"); Features.push_back("-crypto"); break; @@ -319,28 +329,20 @@ bool llvm::ARM::getFPUFeatures(unsigned FPUKind, return true; } -StringRef llvm::ARM::getArchName(unsigned ArchKind) { - if (ArchKind >= ARM::AK_LAST) - return StringRef(); - return ARCHNames[ArchKind].getName(); +StringRef llvm::ARM::getArchName(ArchKind AK) { + return ARCHNames[static_cast<unsigned>(AK)].getName(); } -StringRef llvm::ARM::getCPUAttr(unsigned ArchKind) { - if (ArchKind == ARM::AK_INVALID || ArchKind >= ARM::AK_LAST) - return StringRef(); - return ARCHNames[ArchKind].getCPUAttr(); +StringRef llvm::ARM::getCPUAttr(ArchKind AK) { + return ARCHNames[static_cast<unsigned>(AK)].getCPUAttr(); } -StringRef llvm::ARM::getSubArch(unsigned ArchKind) { - if (ArchKind == ARM::AK_INVALID || ArchKind >= ARM::AK_LAST) - return StringRef(); - return ARCHNames[ArchKind].getSubArch(); +StringRef llvm::ARM::getSubArch(ArchKind AK) { + return ARCHNames[static_cast<unsigned>(AK)].getSubArch(); } -unsigned llvm::ARM::getArchAttr(unsigned ArchKind) { - if (ArchKind >= ARM::AK_LAST) - return ARMBuildAttrs::CPUArch::Pre_v4; - return ARCHNames[ArchKind].ArchAttr; +unsigned llvm::ARM::getArchAttr(ArchKind AK) { + return ARCHNames[static_cast<unsigned>(AK)].ArchAttr; } StringRef llvm::ARM::getArchExtName(unsigned ArchExtKind) { @@ -376,8 +378,8 @@ StringRef llvm::ARM::getHWDivName(unsigned HWDivKind) { } StringRef llvm::ARM::getDefaultCPU(StringRef Arch) { - unsigned AK = parseArch(Arch); - if (AK == ARM::AK_INVALID) + ArchKind AK = parseArch(Arch); + if (AK == ARM::ArchKind::INVALID) return StringRef(); // Look for multiple AKs to find the default for pair AK+Name. @@ -394,21 +396,21 @@ StringRef llvm::AArch64::getFPUName(unsigned FPUKind) { return ARM::getFPUName(FPUKind); } -unsigned llvm::AArch64::getFPUVersion(unsigned FPUKind) { +ARM::FPUVersion AArch64::getFPUVersion(unsigned FPUKind) { return ARM::getFPUVersion(FPUKind); } -unsigned llvm::AArch64::getFPUNeonSupportLevel(unsigned FPUKind) { +ARM::NeonSupportLevel AArch64::getFPUNeonSupportLevel(unsigned FPUKind) { return ARM::getFPUNeonSupportLevel( FPUKind); } -unsigned llvm::AArch64::getFPURestriction(unsigned FPUKind) { +ARM::FPURestriction AArch64::getFPURestriction(unsigned FPUKind) { return ARM::getFPURestriction(FPUKind); } -unsigned llvm::AArch64::getDefaultFPU(StringRef CPU, unsigned ArchKind) { +unsigned llvm::AArch64::getDefaultFPU(StringRef CPU, ArchKind AK) { if (CPU == "generic") - return AArch64ARCHNames[ArchKind].DefaultFPU; + return AArch64ARCHNames[static_cast<unsigned>(AK)].DefaultFPU; return StringSwitch<unsigned>(CPU) #define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ @@ -417,14 +419,15 @@ unsigned llvm::AArch64::getDefaultFPU(StringRef CPU, unsigned ArchKind) { .Default(ARM::FK_INVALID); } -unsigned llvm::AArch64::getDefaultExtensions(StringRef CPU, unsigned ArchKind) { +unsigned llvm::AArch64::getDefaultExtensions(StringRef CPU, ArchKind AK) { if (CPU == "generic") - return AArch64ARCHNames[ArchKind].ArchBaseExtensions; + return AArch64ARCHNames[static_cast<unsigned>(AK)].ArchBaseExtensions; return StringSwitch<unsigned>(CPU) #define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ .Case(NAME, \ - AArch64ARCHNames[(unsigned)AArch64::ArchKind::ID].ArchBaseExtensions | \ + AArch64ARCHNames[static_cast<unsigned>(AArch64::ArchKind::ID)] \ + .ArchBaseExtensions | \ DEFAULT_EXT) #include "llvm/Support/AArch64TargetParser.def" .Default(AArch64::AEK_INVALID); @@ -444,6 +447,8 @@ bool llvm::AArch64::getExtensionFeatures(unsigned Extensions, Features.push_back("+crc"); if (Extensions & AArch64::AEK_CRYPTO) Features.push_back("+crypto"); + if (Extensions & AArch64::AEK_DOTPROD) + Features.push_back("+dotprod"); if (Extensions & AArch64::AEK_FP16) Features.push_back("+fullfp16"); if (Extensions & AArch64::AEK_PROFILE) @@ -452,8 +457,12 @@ bool llvm::AArch64::getExtensionFeatures(unsigned Extensions, Features.push_back("+ras"); if (Extensions & AArch64::AEK_LSE) Features.push_back("+lse"); + if (Extensions & AArch64::AEK_RDM) + Features.push_back("+rdm"); if (Extensions & AArch64::AEK_SVE) Features.push_back("+sve"); + if (Extensions & AArch64::AEK_RCPC) + Features.push_back("+rcpc"); return true; } @@ -463,41 +472,32 @@ bool llvm::AArch64::getFPUFeatures(unsigned FPUKind, return ARM::getFPUFeatures(FPUKind, Features); } -bool llvm::AArch64::getArchFeatures(unsigned ArchKind, - std::vector<StringRef> &Features) { - if (ArchKind == static_cast<unsigned>(AArch64::ArchKind::AK_ARMV8_1A)) +bool llvm::AArch64::getArchFeatures(AArch64::ArchKind AK, + std::vector<StringRef> &Features) { + if (AK == AArch64::ArchKind::ARMV8_1A) Features.push_back("+v8.1a"); - if (ArchKind == static_cast<unsigned>(AArch64::ArchKind::AK_ARMV8_2A)) + if (AK == AArch64::ArchKind::ARMV8_2A) Features.push_back("+v8.2a"); + if (AK == AArch64::ArchKind::ARMV8_3A) + Features.push_back("+v8.3a"); - return ArchKind > static_cast<unsigned>(AArch64::ArchKind::AK_INVALID) && - ArchKind < static_cast<unsigned>(AArch64::ArchKind::AK_LAST); + return AK != AArch64::ArchKind::INVALID; } -StringRef llvm::AArch64::getArchName(unsigned ArchKind) { - if (ArchKind >= static_cast<unsigned>(AArch64::ArchKind::AK_LAST)) - return StringRef(); - return AArch64ARCHNames[ArchKind].getName(); +StringRef llvm::AArch64::getArchName(ArchKind AK) { + return AArch64ARCHNames[static_cast<unsigned>(AK)].getName(); } -StringRef llvm::AArch64::getCPUAttr(unsigned ArchKind) { - if (ArchKind == static_cast<unsigned>(AArch64::ArchKind::AK_INVALID) || - ArchKind >= static_cast<unsigned>(AArch64::ArchKind::AK_LAST)) - return StringRef(); - return AArch64ARCHNames[ArchKind].getCPUAttr(); +StringRef llvm::AArch64::getCPUAttr(ArchKind AK) { + return AArch64ARCHNames[static_cast<unsigned>(AK)].getCPUAttr(); } -StringRef llvm::AArch64::getSubArch(unsigned ArchKind) { - if (ArchKind == static_cast<unsigned>(AArch64::ArchKind::AK_INVALID) || - ArchKind >= static_cast<unsigned>(AArch64::ArchKind::AK_LAST)) - return StringRef(); - return AArch64ARCHNames[ArchKind].getSubArch(); +StringRef llvm::AArch64::getSubArch(ArchKind AK) { + return AArch64ARCHNames[static_cast<unsigned>(AK)].getSubArch(); } -unsigned llvm::AArch64::getArchAttr(unsigned ArchKind) { - if (ArchKind >= static_cast<unsigned>(AArch64::ArchKind::AK_LAST)) - return ARMBuildAttrs::CPUArch::v8_A; - return AArch64ARCHNames[ArchKind].ArchAttr; +unsigned llvm::AArch64::getArchAttr(ArchKind AK) { + return AArch64ARCHNames[static_cast<unsigned>(AK)].ArchAttr; } StringRef llvm::AArch64::getArchExtName(unsigned ArchExtKind) { @@ -523,13 +523,13 @@ StringRef llvm::AArch64::getArchExtFeature(StringRef ArchExt) { } StringRef llvm::AArch64::getDefaultCPU(StringRef Arch) { - unsigned AK = parseArch(Arch); - if (AK == static_cast<unsigned>(AArch64::ArchKind::AK_INVALID)) + AArch64::ArchKind AK = parseArch(Arch); + if (AK == ArchKind::INVALID) return StringRef(); // Look for multiple AKs to find the default for pair AK+Name. for (const auto &CPU : AArch64CPUNames) - if (static_cast<unsigned>(CPU.ArchID) == AK && CPU.Default) + if (CPU.ArchID == AK && CPU.Default) return CPU.getName(); // If we can't find a default then target the architecture instead @@ -584,6 +584,7 @@ static StringRef getArchSynonym(StringRef Arch) { .Cases("v8", "v8a", "aarch64", "arm64", "v8-a") .Case("v8.1a", "v8.1-a") .Case("v8.2a", "v8.2-a") + .Case("v8.3a", "v8.3-a") .Case("v8r", "v8-r") .Case("v8m.base", "v8-m.base") .Case("v8m.main", "v8-m.main") @@ -662,14 +663,14 @@ unsigned llvm::ARM::parseFPU(StringRef FPU) { } // Allows partial match, ex. "v7a" matches "armv7a". -unsigned llvm::ARM::parseArch(StringRef Arch) { +ARM::ArchKind ARM::parseArch(StringRef Arch) { Arch = getCanonicalArchName(Arch); StringRef Syn = getArchSynonym(Arch); for (const auto A : ARCHNames) { if (A.getName().endswith(Syn)) return A.ID; } - return ARM::AK_INVALID; + return ARM::ArchKind::INVALID; } unsigned llvm::ARM::parseArchExt(StringRef ArchExt) { @@ -680,110 +681,134 @@ unsigned llvm::ARM::parseArchExt(StringRef ArchExt) { return ARM::AEK_INVALID; } -unsigned llvm::ARM::parseCPUArch(StringRef CPU) { +ARM::ArchKind llvm::ARM::parseCPUArch(StringRef CPU) { for (const auto C : CPUNames) { if (CPU == C.getName()) return C.ArchID; } - return ARM::AK_INVALID; + return ARM::ArchKind::INVALID; } // ARM, Thumb, AArch64 -unsigned llvm::ARM::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::IK_INVALID); +ARM::ISAKind ARM::parseArchISA(StringRef Arch) { + return StringSwitch<ARM::ISAKind>(Arch) + .StartsWith("aarch64", ARM::ISAKind::AARCH64) + .StartsWith("arm64", ARM::ISAKind::AARCH64) + .StartsWith("thumb", ARM::ISAKind::THUMB) + .StartsWith("arm", ARM::ISAKind::ARM) + .Default(ARM::ISAKind::INVALID); } // Little/Big endian -unsigned llvm::ARM::parseArchEndian(StringRef Arch) { +ARM::EndianKind ARM::parseArchEndian(StringRef Arch) { if (Arch.startswith("armeb") || Arch.startswith("thumbeb") || Arch.startswith("aarch64_be")) - return ARM::EK_BIG; + return ARM::EndianKind::BIG; if (Arch.startswith("arm") || Arch.startswith("thumb")) { if (Arch.endswith("eb")) - return ARM::EK_BIG; + return ARM::EndianKind::BIG; else - return ARM::EK_LITTLE; + return ARM::EndianKind::LITTLE; } if (Arch.startswith("aarch64")) - return ARM::EK_LITTLE; + return ARM::EndianKind::LITTLE; - return ARM::EK_INVALID; + return ARM::EndianKind::INVALID; } // Profile A/R/M -unsigned llvm::ARM::parseArchProfile(StringRef Arch) { +ARM::ProfileKind ARM::parseArchProfile(StringRef Arch) { Arch = getCanonicalArchName(Arch); switch (parseArch(Arch)) { - case ARM::AK_ARMV6M: - case ARM::AK_ARMV7M: - case ARM::AK_ARMV7EM: - case ARM::AK_ARMV8MMainline: - case ARM::AK_ARMV8MBaseline: - return ARM::PK_M; - case ARM::AK_ARMV7R: - case ARM::AK_ARMV8R: - return ARM::PK_R; - case ARM::AK_ARMV7A: - case ARM::AK_ARMV7VE: - case ARM::AK_ARMV7K: - case ARM::AK_ARMV8A: - case ARM::AK_ARMV8_1A: - case ARM::AK_ARMV8_2A: - return ARM::PK_A; + case ARM::ArchKind::ARMV6M: + case ARM::ArchKind::ARMV7M: + case ARM::ArchKind::ARMV7EM: + case ARM::ArchKind::ARMV8MMainline: + case ARM::ArchKind::ARMV8MBaseline: + return ARM::ProfileKind::M; + case ARM::ArchKind::ARMV7R: + case ARM::ArchKind::ARMV8R: + return ARM::ProfileKind::R; + case ARM::ArchKind::ARMV7A: + case ARM::ArchKind::ARMV7VE: + case ARM::ArchKind::ARMV7K: + case ARM::ArchKind::ARMV8A: + case ARM::ArchKind::ARMV8_1A: + case ARM::ArchKind::ARMV8_2A: + case ARM::ArchKind::ARMV8_3A: + return ARM::ProfileKind::A; + LLVM_FALLTHROUGH; + case ARM::ArchKind::ARMV2: + case ARM::ArchKind::ARMV2A: + case ARM::ArchKind::ARMV3: + case ARM::ArchKind::ARMV3M: + case ARM::ArchKind::ARMV4: + case ARM::ArchKind::ARMV4T: + case ARM::ArchKind::ARMV5T: + case ARM::ArchKind::ARMV5TE: + case ARM::ArchKind::ARMV5TEJ: + case ARM::ArchKind::ARMV6: + case ARM::ArchKind::ARMV6K: + case ARM::ArchKind::ARMV6T2: + case ARM::ArchKind::ARMV6KZ: + case ARM::ArchKind::ARMV7S: + case ARM::ArchKind::IWMMXT: + case ARM::ArchKind::IWMMXT2: + case ARM::ArchKind::XSCALE: + case ARM::ArchKind::INVALID: + return ARM::ProfileKind::INVALID; } - return ARM::PK_INVALID; + llvm_unreachable("Unhandled architecture"); } // Version number (ex. v7 = 7). unsigned llvm::ARM::parseArchVersion(StringRef Arch) { Arch = getCanonicalArchName(Arch); switch (parseArch(Arch)) { - case ARM::AK_ARMV2: - case ARM::AK_ARMV2A: + case ARM::ArchKind::ARMV2: + case ARM::ArchKind::ARMV2A: return 2; - case ARM::AK_ARMV3: - case ARM::AK_ARMV3M: + case ARM::ArchKind::ARMV3: + case ARM::ArchKind::ARMV3M: return 3; - case ARM::AK_ARMV4: - case ARM::AK_ARMV4T: + case ARM::ArchKind::ARMV4: + case ARM::ArchKind::ARMV4T: return 4; - case ARM::AK_ARMV5T: - case ARM::AK_ARMV5TE: - case ARM::AK_IWMMXT: - case ARM::AK_IWMMXT2: - case ARM::AK_XSCALE: - case ARM::AK_ARMV5TEJ: + case ARM::ArchKind::ARMV5T: + case ARM::ArchKind::ARMV5TE: + case ARM::ArchKind::IWMMXT: + case ARM::ArchKind::IWMMXT2: + case ARM::ArchKind::XSCALE: + case ARM::ArchKind::ARMV5TEJ: return 5; - case ARM::AK_ARMV6: - case ARM::AK_ARMV6K: - case ARM::AK_ARMV6T2: - case ARM::AK_ARMV6KZ: - case ARM::AK_ARMV6M: + case ARM::ArchKind::ARMV6: + case ARM::ArchKind::ARMV6K: + case ARM::ArchKind::ARMV6T2: + case ARM::ArchKind::ARMV6KZ: + case ARM::ArchKind::ARMV6M: return 6; - case ARM::AK_ARMV7A: - case ARM::AK_ARMV7VE: - case ARM::AK_ARMV7R: - case ARM::AK_ARMV7M: - case ARM::AK_ARMV7S: - case ARM::AK_ARMV7EM: - case ARM::AK_ARMV7K: + case ARM::ArchKind::ARMV7A: + case ARM::ArchKind::ARMV7VE: + case ARM::ArchKind::ARMV7R: + case ARM::ArchKind::ARMV7M: + case ARM::ArchKind::ARMV7S: + case ARM::ArchKind::ARMV7EM: + case ARM::ArchKind::ARMV7K: return 7; - case ARM::AK_ARMV8A: - case ARM::AK_ARMV8_1A: - case ARM::AK_ARMV8_2A: - case ARM::AK_ARMV8R: - case ARM::AK_ARMV8MBaseline: - case ARM::AK_ARMV8MMainline: + case ARM::ArchKind::ARMV8A: + case ARM::ArchKind::ARMV8_1A: + case ARM::ArchKind::ARMV8_2A: + case ARM::ArchKind::ARMV8_3A: + case ARM::ArchKind::ARMV8R: + case ARM::ArchKind::ARMV8MBaseline: + case ARM::ArchKind::ARMV8MMainline: return 8; + case ARM::ArchKind::INVALID: + return 0; } - return 0; + llvm_unreachable("Unhandled architecture"); } StringRef llvm::ARM::computeDefaultTargetABI(const Triple &TT, StringRef CPU) { @@ -793,7 +818,7 @@ StringRef llvm::ARM::computeDefaultTargetABI(const Triple &TT, StringRef CPU) { if (TT.isOSBinFormatMachO()) { if (TT.getEnvironment() == Triple::EABI || TT.getOS() == Triple::UnknownOS || - llvm::ARM::parseArchProfile(ArchName) == ARM::PK_M) + llvm::ARM::parseArchProfile(ArchName) == ARM::ProfileKind::M) return "aapcs"; if (TT.isWatchABI()) return "aapcs16"; @@ -831,17 +856,17 @@ unsigned llvm::AArch64::parseFPU(StringRef FPU) { } // Allows partial match, ex. "v8a" matches "armv8a". -unsigned llvm::AArch64::parseArch(StringRef Arch) { +AArch64::ArchKind AArch64::parseArch(StringRef Arch) { Arch = getCanonicalArchName(Arch); if (checkArchVersion(Arch) < 8) - return static_cast<unsigned>(AArch64::ArchKind::AK_INVALID); + return ArchKind::INVALID; StringRef Syn = getArchSynonym(Arch); for (const auto A : AArch64ARCHNames) { if (A.getName().endswith(Syn)) - return static_cast<unsigned>(A.ID); + return A.ID; } - return static_cast<unsigned>(AArch64::ArchKind::AK_INVALID); + return ArchKind::INVALID; } unsigned llvm::AArch64::parseArchExt(StringRef ArchExt) { @@ -852,26 +877,26 @@ unsigned llvm::AArch64::parseArchExt(StringRef ArchExt) { return AArch64::AEK_INVALID; } -unsigned llvm::AArch64::parseCPUArch(StringRef CPU) { +AArch64::ArchKind llvm::AArch64::parseCPUArch(StringRef CPU) { for (const auto C : AArch64CPUNames) { if (CPU == C.getName()) - return static_cast<unsigned>(C.ArchID); + return C.ArchID; } - return static_cast<unsigned>(AArch64::ArchKind::AK_INVALID); + return ArchKind::INVALID; } // ARM, Thumb, AArch64 -unsigned llvm::AArch64::parseArchISA(StringRef Arch) { +ARM::ISAKind AArch64::parseArchISA(StringRef Arch) { return ARM::parseArchISA(Arch); } // Little/Big endian -unsigned llvm::AArch64::parseArchEndian(StringRef Arch) { +ARM::EndianKind AArch64::parseArchEndian(StringRef Arch) { return ARM::parseArchEndian(Arch); } // Profile A/R/M -unsigned llvm::AArch64::parseArchProfile(StringRef Arch) { +ARM::ProfileKind AArch64::parseArchProfile(StringRef Arch) { return ARM::parseArchProfile(Arch); } diff --git a/lib/Support/TargetRegistry.cpp b/lib/Support/TargetRegistry.cpp index bed9ed64f802..ed999fce5dad 100644 --- a/lib/Support/TargetRegistry.cpp +++ b/lib/Support/TargetRegistry.cpp @@ -86,9 +86,9 @@ const Target *TargetRegistry::lookupTarget(const std::string &TT, return &*I; } -void TargetRegistry::RegisterTarget(Target &T, - const char *Name, +void TargetRegistry::RegisterTarget(Target &T, const char *Name, const char *ShortDesc, + const char *BackendName, Target::ArchMatchFnTy ArchMatchFn, bool HasJIT) { assert(Name && ShortDesc && ArchMatchFn && @@ -105,6 +105,7 @@ void TargetRegistry::RegisterTarget(Target &T, T.Name = Name; T.ShortDesc = ShortDesc; + T.BackendName = BackendName; T.ArchMatchFn = ArchMatchFn; T.HasJIT = HasJIT; } @@ -114,7 +115,7 @@ static int TargetArraySortFn(const std::pair<StringRef, const Target *> *LHS, return LHS->first.compare(RHS->first); } -void TargetRegistry::printRegisteredTargetsForVersion() { +void TargetRegistry::printRegisteredTargetsForVersion(raw_ostream &OS) { std::vector<std::pair<StringRef, const Target*> > Targets; size_t Width = 0; for (const auto &T : TargetRegistry::targets()) { @@ -123,7 +124,6 @@ void TargetRegistry::printRegisteredTargetsForVersion() { } array_pod_sort(Targets.begin(), Targets.end(), TargetArraySortFn); - raw_ostream &OS = outs(); OS << " Registered Targets:\n"; for (unsigned i = 0, e = Targets.size(); i != e; ++i) { OS << " " << Targets[i].first; diff --git a/lib/Support/ThreadPool.cpp b/lib/Support/ThreadPool.cpp index 22b7550d4971..d0212ca13467 100644 --- a/lib/Support/ThreadPool.cpp +++ b/lib/Support/ThreadPool.cpp @@ -14,14 +14,15 @@ #include "llvm/Support/ThreadPool.h" #include "llvm/Config/llvm-config.h" +#include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; #if LLVM_ENABLE_THREADS -// Default to std::thread::hardware_concurrency -ThreadPool::ThreadPool() : ThreadPool(std::thread::hardware_concurrency()) {} +// Default to hardware_concurrency +ThreadPool::ThreadPool() : ThreadPool(hardware_concurrency()) {} ThreadPool::ThreadPool(unsigned ThreadCount) : ActiveThreads(0), EnableFlag(true) { @@ -46,8 +47,8 @@ ThreadPool::ThreadPool(unsigned ThreadCount) // in order for wait() to properly detect that even if the queue is // empty, there is still a task in flight. { - ++ActiveThreads; std::unique_lock<std::mutex> LockGuard(CompletionLock); + ++ActiveThreads; } Task = std::move(Tasks.front()); Tasks.pop(); diff --git a/lib/Support/Threading.cpp b/lib/Support/Threading.cpp index 6a10b988d464..473c84808af1 100644 --- a/lib/Support/Threading.cpp +++ b/lib/Support/Threading.cpp @@ -47,6 +47,8 @@ void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData, unsigned llvm::heavyweight_hardware_concurrency() { return 1; } +unsigned llvm::hardware_concurrency() { return 1; } + uint64_t llvm::get_threadid() { return 0; } uint32_t llvm::get_max_thread_name_length() { return 0; } @@ -71,6 +73,18 @@ unsigned llvm::heavyweight_hardware_concurrency() { return NumPhysical; } +unsigned llvm::hardware_concurrency() { +#if defined(HAVE_SCHED_GETAFFINITY) && defined(HAVE_CPU_COUNT) + cpu_set_t Set; + if (sched_getaffinity(0, sizeof(Set), &Set)) + return CPU_COUNT(&Set); +#endif + // Guard against std::thread::hardware_concurrency() returning 0. + if (unsigned Val = std::thread::hardware_concurrency()) + return Val; + return 1; +} + // Include the platform-specific parts of this class. #ifdef LLVM_ON_UNIX #include "Unix/Threading.inc" diff --git a/lib/Support/Timer.cpp b/lib/Support/Timer.cpp index 3386f2660f31..0c85faecca84 100644 --- a/lib/Support/Timer.cpp +++ b/lib/Support/Timer.cpp @@ -362,8 +362,10 @@ void TimerGroup::printAll(raw_ostream &OS) { void TimerGroup::printJSONValue(raw_ostream &OS, const PrintRecord &R, const char *suffix, double Value) { - assert(!yaml::needsQuotes(Name) && "TimerGroup name needs no quotes"); - assert(!yaml::needsQuotes(R.Name) && "Timer name needs no quotes"); + assert(yaml::needsQuotes(Name) == yaml::QuotingType::None && + "TimerGroup name needs no quotes"); + assert(yaml::needsQuotes(R.Name) == yaml::QuotingType::None && + "Timer name needs no quotes"); OS << "\t\"time." << Name << '.' << R.Name << suffix << "\": " << Value; } diff --git a/lib/Support/ToolOutputFile.cpp b/lib/Support/ToolOutputFile.cpp index 8ae977db6a14..e12d9e824f7e 100644 --- a/lib/Support/ToolOutputFile.cpp +++ b/lib/Support/ToolOutputFile.cpp @@ -1,4 +1,4 @@ -//===--- ToolOutputFile.cpp - Implement the tool_output_file class --------===// +//===--- ToolOutputFile.cpp - Implement the ToolOutputFile class --------===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This implements the tool_output_file class. +// This implements the ToolOutputFile class. // //===----------------------------------------------------------------------===// @@ -16,14 +16,14 @@ #include "llvm/Support/Signals.h" using namespace llvm; -tool_output_file::CleanupInstaller::CleanupInstaller(StringRef Filename) +ToolOutputFile::CleanupInstaller::CleanupInstaller(StringRef Filename) : Filename(Filename), Keep(false) { // Arrange for the file to be deleted if the process is killed. if (Filename != "-") sys::RemoveFileOnSignal(Filename); } -tool_output_file::CleanupInstaller::~CleanupInstaller() { +ToolOutputFile::CleanupInstaller::~CleanupInstaller() { // Delete the file if the client hasn't told us not to. if (!Keep && Filename != "-") sys::fs::remove(Filename); @@ -34,13 +34,13 @@ tool_output_file::CleanupInstaller::~CleanupInstaller() { sys::DontRemoveFileOnSignal(Filename); } -tool_output_file::tool_output_file(StringRef Filename, std::error_code &EC, - sys::fs::OpenFlags Flags) +ToolOutputFile::ToolOutputFile(StringRef Filename, std::error_code &EC, + sys::fs::OpenFlags Flags) : Installer(Filename), OS(Filename, EC, Flags) { // If open fails, no cleanup is needed. if (EC) Installer.Keep = true; } -tool_output_file::tool_output_file(StringRef Filename, int FD) +ToolOutputFile::ToolOutputFile(StringRef Filename, int FD) : Installer(Filename), OS(FD, true) {} diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp index 2687a67556d3..4f0a30042b76 100644 --- a/lib/Support/Triple.cpp +++ b/lib/Support/Triple.cpp @@ -25,6 +25,7 @@ StringRef Triple::getArchTypeName(ArchType Kind) { case aarch64_be: return "aarch64_be"; case arm: return "arm"; case armeb: return "armeb"; + case arc: return "arc"; case avr: return "avr"; case bpfel: return "bpfel"; case bpfeb: return "bpfeb"; @@ -83,6 +84,8 @@ StringRef Triple::getArchTypePrefix(ArchType Kind) { case aarch64: case aarch64_be: return "aarch64"; + case arc: return "arc"; + case arm: case armeb: case thumb: @@ -194,7 +197,6 @@ StringRef Triple::getOSTypeName(OSType Kind) { case RTEMS: return "rtems"; case NaCl: return "nacl"; case CNK: return "cnk"; - case Bitrig: return "bitrig"; case AIX: return "aix"; case CUDA: return "cuda"; case NVCL: return "nvcl"; @@ -205,6 +207,7 @@ StringRef Triple::getOSTypeName(OSType Kind) { case WatchOS: return "watchos"; case Mesa3D: return "mesa3d"; case Contiki: return "contiki"; + case AMDPAL: return "amdpal"; } llvm_unreachable("Invalid OSType"); @@ -214,6 +217,7 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) { switch (Kind) { case UnknownEnvironment: return "unknown"; case GNU: return "gnu"; + case GNUABIN32: return "gnuabin32"; case GNUABI64: return "gnuabi64"; case GNUEABIHF: return "gnueabihf"; case GNUEABI: return "gnueabi"; @@ -231,6 +235,7 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) { case AMDOpenCL: return "amdopencl"; case CoreCLR: return "coreclr"; case OpenCL: return "opencl"; + case Simulator: return "simulator"; } llvm_unreachable("Invalid EnvironmentType!"); @@ -256,6 +261,7 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { return StringSwitch<Triple::ArchType>(Name) .Case("aarch64", aarch64) .Case("aarch64_be", aarch64_be) + .Case("arc", arc) .Case("arm64", aarch64) // "arm64" is an alias for "aarch64" .Case("arm", arm) .Case("armeb", armeb) @@ -308,39 +314,46 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { } static Triple::ArchType parseARMArch(StringRef ArchName) { - unsigned ISA = ARM::parseArchISA(ArchName); - unsigned ENDIAN = ARM::parseArchEndian(ArchName); + ARM::ISAKind ISA = ARM::parseArchISA(ArchName); + ARM::EndianKind ENDIAN = ARM::parseArchEndian(ArchName); Triple::ArchType arch = Triple::UnknownArch; switch (ENDIAN) { - case ARM::EK_LITTLE: { + case ARM::EndianKind::LITTLE: { switch (ISA) { - case ARM::IK_ARM: + case ARM::ISAKind::ARM: arch = Triple::arm; break; - case ARM::IK_THUMB: + case ARM::ISAKind::THUMB: arch = Triple::thumb; break; - case ARM::IK_AARCH64: + case ARM::ISAKind::AARCH64: arch = Triple::aarch64; break; + case ARM::ISAKind::INVALID: + break; } break; } - case ARM::EK_BIG: { + case ARM::EndianKind::BIG: { switch (ISA) { - case ARM::IK_ARM: + case ARM::ISAKind::ARM: arch = Triple::armeb; break; - case ARM::IK_THUMB: + case ARM::ISAKind::THUMB: arch = Triple::thumbeb; break; - case ARM::IK_AARCH64: + case ARM::ISAKind::AARCH64: arch = Triple::aarch64_be; break; + case ARM::ISAKind::INVALID: + break; } break; } + case ARM::EndianKind::INVALID: { + break; + } } ArchName = ARM::getCanonicalArchName(ArchName); @@ -348,15 +361,15 @@ static Triple::ArchType parseARMArch(StringRef ArchName) { return Triple::UnknownArch; // Thumb only exists in v4+ - if (ISA == ARM::IK_THUMB && + if (ISA == ARM::ISAKind::THUMB && (ArchName.startswith("v2") || ArchName.startswith("v3"))) return Triple::UnknownArch; // Thumb only for v6m - unsigned Profile = ARM::parseArchProfile(ArchName); + ARM::ProfileKind Profile = ARM::parseArchProfile(ArchName); unsigned Version = ARM::parseArchVersion(ArchName); - if (Profile == ARM::PK_M && Version == 6) { - if (ENDIAN == ARM::EK_BIG) + if (Profile == ARM::ProfileKind::M && Version == 6) { + if (ENDIAN == ARM::EndianKind::BIG) return Triple::thumbeb; else return Triple::thumb; @@ -378,6 +391,7 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Case("xscaleeb", Triple::armeb) .Case("aarch64", Triple::aarch64) .Case("aarch64_be", Triple::aarch64_be) + .Case("arc", Triple::arc) .Case("arm64", Triple::aarch64) .Case("arm", Triple::arm) .Case("armeb", Triple::armeb) @@ -477,7 +491,6 @@ static Triple::OSType parseOS(StringRef OSName) { .StartsWith("rtems", Triple::RTEMS) .StartsWith("nacl", Triple::NaCl) .StartsWith("cnk", Triple::CNK) - .StartsWith("bitrig", Triple::Bitrig) .StartsWith("aix", Triple::AIX) .StartsWith("cuda", Triple::CUDA) .StartsWith("nvcl", Triple::NVCL) @@ -488,6 +501,7 @@ static Triple::OSType parseOS(StringRef OSName) { .StartsWith("watchos", Triple::WatchOS) .StartsWith("mesa3d", Triple::Mesa3D) .StartsWith("contiki", Triple::Contiki) + .StartsWith("amdpal", Triple::AMDPAL) .Default(Triple::UnknownOS); } @@ -495,6 +509,7 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { return StringSwitch<Triple::EnvironmentType>(EnvironmentName) .StartsWith("eabihf", Triple::EABIHF) .StartsWith("eabi", Triple::EABI) + .StartsWith("gnuabin32", Triple::GNUABIN32) .StartsWith("gnuabi64", Triple::GNUABI64) .StartsWith("gnueabihf", Triple::GNUEABIHF) .StartsWith("gnueabi", Triple::GNUEABI) @@ -511,6 +526,7 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { .StartsWith("amdopencl", Triple::AMDOpenCL) .StartsWith("coreclr", Triple::CoreCLR) .StartsWith("opencl", Triple::OpenCL) + .StartsWith("simulator", Triple::Simulator) .Default(Triple::UnknownEnvironment); } @@ -536,51 +552,53 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) { // ARM sub arch. switch(ARM::parseArch(ARMSubArch)) { - case ARM::AK_ARMV4: + case ARM::ArchKind::ARMV4: return Triple::NoSubArch; - case ARM::AK_ARMV4T: + case ARM::ArchKind::ARMV4T: return Triple::ARMSubArch_v4t; - case ARM::AK_ARMV5T: + case ARM::ArchKind::ARMV5T: return Triple::ARMSubArch_v5; - case ARM::AK_ARMV5TE: - case ARM::AK_IWMMXT: - case ARM::AK_IWMMXT2: - case ARM::AK_XSCALE: - case ARM::AK_ARMV5TEJ: + case ARM::ArchKind::ARMV5TE: + case ARM::ArchKind::IWMMXT: + case ARM::ArchKind::IWMMXT2: + case ARM::ArchKind::XSCALE: + case ARM::ArchKind::ARMV5TEJ: return Triple::ARMSubArch_v5te; - case ARM::AK_ARMV6: + case ARM::ArchKind::ARMV6: return Triple::ARMSubArch_v6; - case ARM::AK_ARMV6K: - case ARM::AK_ARMV6KZ: + case ARM::ArchKind::ARMV6K: + case ARM::ArchKind::ARMV6KZ: return Triple::ARMSubArch_v6k; - case ARM::AK_ARMV6T2: + case ARM::ArchKind::ARMV6T2: return Triple::ARMSubArch_v6t2; - case ARM::AK_ARMV6M: + case ARM::ArchKind::ARMV6M: return Triple::ARMSubArch_v6m; - case ARM::AK_ARMV7A: - case ARM::AK_ARMV7R: + case ARM::ArchKind::ARMV7A: + case ARM::ArchKind::ARMV7R: return Triple::ARMSubArch_v7; - case ARM::AK_ARMV7VE: + case ARM::ArchKind::ARMV7VE: return Triple::ARMSubArch_v7ve; - case ARM::AK_ARMV7K: + case ARM::ArchKind::ARMV7K: return Triple::ARMSubArch_v7k; - case ARM::AK_ARMV7M: + case ARM::ArchKind::ARMV7M: return Triple::ARMSubArch_v7m; - case ARM::AK_ARMV7S: + case ARM::ArchKind::ARMV7S: return Triple::ARMSubArch_v7s; - case ARM::AK_ARMV7EM: + case ARM::ArchKind::ARMV7EM: return Triple::ARMSubArch_v7em; - case ARM::AK_ARMV8A: + case ARM::ArchKind::ARMV8A: return Triple::ARMSubArch_v8; - case ARM::AK_ARMV8_1A: + case ARM::ArchKind::ARMV8_1A: return Triple::ARMSubArch_v8_1a; - case ARM::AK_ARMV8_2A: + case ARM::ArchKind::ARMV8_2A: return Triple::ARMSubArch_v8_2a; - case ARM::AK_ARMV8R: + case ARM::ArchKind::ARMV8_3A: + return Triple::ARMSubArch_v8_3a; + case ARM::ArchKind::ARMV8R: return Triple::ARMSubArch_v8r; - case ARM::AK_ARMV8MBaseline: + case ARM::ArchKind::ARMV8MBaseline: return Triple::ARMSubArch_v8m_baseline; - case ARM::AK_ARMV8MMainline: + case ARM::ArchKind::ARMV8MMainline: return Triple::ARMSubArch_v8m_mainline; default: return Triple::NoSubArch; @@ -613,6 +631,7 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { return Triple::ELF; case Triple::aarch64_be: + case Triple::arc: case Triple::amdgcn: case Triple::amdil: case Triple::amdil64: @@ -1166,6 +1185,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::msp430: return 16; + case llvm::Triple::arc: case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::hexagon: @@ -1249,6 +1269,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::amdil: case Triple::hsail: case Triple::spir: + case Triple::arc: case Triple::arm: case Triple::armeb: case Triple::hexagon: @@ -1299,6 +1320,7 @@ Triple Triple::get64BitArchVariant() const { Triple T(*this); switch (getArch()) { case Triple::UnknownArch: + case Triple::arc: case Triple::avr: case Triple::hexagon: case Triple::kalimba: @@ -1552,7 +1574,7 @@ StringRef Triple::getARMCPUForArch(StringRef MArch) const { return StringRef(); StringRef CPU = ARM::getDefaultCPU(MArch); - if (!CPU.empty()) + if (!CPU.empty() && !CPU.equals("invalid")) return CPU; // If no specific architecture version is requested, return the minimum CPU diff --git a/lib/Support/Unix/DynamicLibrary.inc b/lib/Support/Unix/DynamicLibrary.inc index f05103ccd1eb..029451f347e8 100644 --- a/lib/Support/Unix/DynamicLibrary.inc +++ b/lib/Support/Unix/DynamicLibrary.inc @@ -71,7 +71,7 @@ void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { // Must declare the symbols in the global namespace. static void *DoSearch(const char* SymbolName) { #define EXPLICIT_SYMBOL(SYM) \ - extern void *SYM; if (!strcmp(SymbolName, #SYM)) return &SYM + extern void *SYM; if (!strcmp(SymbolName, #SYM)) return (void*)&SYM // If this is darwin, it has some funky issues, try to solve them here. Some // important symbols are marked 'private external' which doesn't allow diff --git a/lib/Support/Unix/Memory.inc b/lib/Support/Unix/Memory.inc index dd39ef935bf9..848548d18177 100644 --- a/lib/Support/Unix/Memory.inc +++ b/lib/Support/Unix/Memory.inc @@ -27,7 +27,7 @@ #if defined(__mips__) # if defined(__OpenBSD__) # include <mips64/sysarch.h> -# else +# elif !defined(__FreeBSD__) # include <sys/cachectl.h> # endif #endif @@ -102,6 +102,10 @@ Memory::allocateMappedMemory(size_t NumBytes, int Protect = getPosixProtectionFlags(PFlags); +#if defined(__NetBSD__) && defined(PROT_MPROTECT) + Protect |= PROT_MPROTECT(PROT_READ | PROT_WRITE | PROT_EXEC); +#endif + // Use any near hint and the page size to set a page-aligned starting address uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + NearBlock->size() : 0; @@ -122,8 +126,12 @@ Memory::allocateMappedMemory(size_t NumBytes, Result.Address = Addr; Result.Size = NumPages*PageSize; - if (PFlags & MF_EXEC) - Memory::InvalidateInstructionCache(Result.Address, Result.Size); + // Rely on protectMappedMemory to invalidate instruction cache. + if (PFlags & MF_EXEC) { + EC = Memory::protectMappedMemory (Result, PFlags); + if (EC != std::error_code()) + return MemoryBlock(); + } return Result; } @@ -152,141 +160,34 @@ Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) { return std::error_code(EINVAL, std::generic_category()); int Protect = getPosixProtectionFlags(Flags); - uintptr_t Start = alignAddr((uint8_t *)M.Address - PageSize + 1, PageSize); uintptr_t End = alignAddr((uint8_t *)M.Address + M.Size, PageSize); - int Result = ::mprotect((void *)Start, End - Start, Protect); - - if (Result != 0) - return std::error_code(errno, std::generic_category()); - - if (Flags & MF_EXEC) - Memory::InvalidateInstructionCache(M.Address, M.Size); - - return std::error_code(); -} - -/// AllocateRWX - Allocate a slab of memory with read/write/execute -/// permissions. This is typically used for JIT applications where we want -/// to emit code to the memory then jump to it. Getting this type of memory -/// is very OS specific. -/// -MemoryBlock -Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, - std::string *ErrMsg) { - if (NumBytes == 0) return MemoryBlock(); - - static const size_t PageSize = Process::getPageSize(); - size_t NumPages = (NumBytes+PageSize-1)/PageSize; - - int fd = -1; - - int flags = MAP_PRIVATE | -#ifdef MAP_ANONYMOUS - MAP_ANONYMOUS -#else - MAP_ANON -#endif - ; - - void* start = NearBlock ? (unsigned char*)NearBlock->base() + - NearBlock->size() : nullptr; - -#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__)) - void *pa = ::mmap(start, PageSize*NumPages, PROT_READ|PROT_EXEC, - flags, fd, 0); -#elif defined(__NetBSD__) && defined(PROT_MPROTECT) - void *pa = - ::mmap(start, PageSize * NumPages, - PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC), flags, fd, 0); -#else - void *pa = ::mmap(start, PageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC, - flags, fd, 0); -#endif - if (pa == MAP_FAILED) { - if (NearBlock) //Try again without a near hint - return AllocateRWX(NumBytes, nullptr); - MakeErrMsg(ErrMsg, "Can't allocate RWX Memory"); - return MemoryBlock(); - } + bool InvalidateCache = (Flags & MF_EXEC); -#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__)) - kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)pa, - (vm_size_t)(PageSize*NumPages), 0, - VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); - if (KERN_SUCCESS != kr) { - MakeErrMsg(ErrMsg, "vm_protect max RX failed"); - return MemoryBlock(); - } +#if defined(__arm__) || defined(__aarch64__) + // Certain ARM implementations treat icache clear instruction as a memory read, + // and CPU segfaults on trying to clear cache on !PROT_READ page. Therefore we need + // to temporarily add PROT_READ for the sake of flushing the instruction caches. + if (InvalidateCache && !(Protect & PROT_READ)) { + int Result = ::mprotect((void *)Start, End - Start, Protect | PROT_READ); + if (Result != 0) + return std::error_code(errno, std::generic_category()); - kr = vm_protect(mach_task_self(), (vm_address_t)pa, - (vm_size_t)(PageSize*NumPages), 0, - VM_PROT_READ | VM_PROT_WRITE); - if (KERN_SUCCESS != kr) { - MakeErrMsg(ErrMsg, "vm_protect RW failed"); - return MemoryBlock(); + Memory::InvalidateInstructionCache(M.Address, M.Size); + InvalidateCache = false; } #endif - MemoryBlock result; - result.Address = pa; - result.Size = NumPages*PageSize; - - return result; -} - -bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { - if (M.Address == nullptr || M.Size == 0) return false; - if (0 != ::munmap(M.Address, M.Size)) - return MakeErrMsg(ErrMsg, "Can't release RWX Memory"); - return false; -} - -bool Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) { -#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__)) - if (M.Address == 0 || M.Size == 0) return false; - Memory::InvalidateInstructionCache(M.Address, M.Size); - kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, - (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_WRITE); - return KERN_SUCCESS == kr; -#else - return true; -#endif -} + int Result = ::mprotect((void *)Start, End - Start, Protect); -bool Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { - if (M.Address == nullptr || M.Size == 0) return false; - Memory::InvalidateInstructionCache(M.Address, M.Size); -#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__)) - kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, - (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); - return KERN_SUCCESS == kr; -#else - return true; -#endif -} + if (Result != 0) + return std::error_code(errno, std::generic_category()); -bool Memory::setRangeWritable(const void *Addr, size_t Size) { -#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__)) - kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, - (vm_size_t)Size, 0, - VM_PROT_READ | VM_PROT_WRITE); - return KERN_SUCCESS == kr; -#else - return true; -#endif -} + if (InvalidateCache) + Memory::InvalidateInstructionCache(M.Address, M.Size); -bool Memory::setRangeExecutable(const void *Addr, size_t Size) { -#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__)) - kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, - (vm_size_t)Size, 0, - VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); - return KERN_SUCCESS == kr; -#else - return true; -#endif + return std::error_code(); } /// InvalidateInstructionCache - Before the JIT can run a block of code diff --git a/lib/Support/Unix/Path.inc b/lib/Support/Unix/Path.inc index 45097eb918b7..2ecb97316c87 100644 --- a/lib/Support/Unix/Path.inc +++ b/lib/Support/Unix/Path.inc @@ -108,10 +108,9 @@ using namespace llvm; namespace llvm { namespace sys { namespace fs { -#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ - defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \ - defined(__linux__) || defined(__CYGWIN__) || defined(__DragonFly__) || \ - defined(_AIX) +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ + defined(__minix) || defined(__FreeBSD_kernel__) || defined(__linux__) || \ + defined(__CYGWIN__) || defined(__DragonFly__) || defined(_AIX) static int test_dir(char ret[PATH_MAX], const char *dir, const char *bin) { @@ -180,9 +179,9 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) { if (realpath(exe_path, link_path)) return link_path; } -#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ - defined(__OpenBSD__) || defined(__minix) || defined(__DragonFly__) || \ - defined(__FreeBSD_kernel__) || defined(_AIX) +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ + defined(__minix) || defined(__DragonFly__) || \ + defined(__FreeBSD_kernel__) || defined(_AIX) char exe_path[PATH_MAX]; if (getprogpath(exe_path, argv0) != NULL) @@ -218,11 +217,11 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) { return ""; } -TimePoint<> file_status::getLastAccessedTime() const { +TimePoint<> basic_file_status::getLastAccessedTime() const { return toTimePoint(fs_st_atime); } -TimePoint<> file_status::getLastModificationTime() const { +TimePoint<> basic_file_status::getLastModificationTime() const { return toTimePoint(fs_st_mtime); } @@ -427,7 +426,7 @@ std::error_code resize_file(int FD, uint64_t Size) { // If we have posix_fallocate use it. Unlike ftruncate it always allocates // space, so we get an error if the disk is full. if (int Err = ::posix_fallocate(FD, 0, Size)) { - if (Err != EOPNOTSUPP) + if (Err != EINVAL && Err != EOPNOTSUPP) return std::error_code(Err, std::generic_category()); } #endif @@ -642,15 +641,9 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, return std::error_code(); } -mapped_file_region::mapped_file_region(int fd, mapmode mode, uint64_t length, +mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length, uint64_t offset, std::error_code &ec) : Size(length), Mapping() { - // Make sure that the requested size fits within SIZE_T. - if (length > std::numeric_limits<size_t>::max()) { - ec = make_error_code(errc::invalid_argument); - return; - } - ec = init(fd, offset, mode); if (ec) Mapping = nullptr; @@ -661,7 +654,7 @@ mapped_file_region::~mapped_file_region() { ::munmap(Mapping, Size); } -uint64_t mapped_file_region::size() const { +size_t mapped_file_region::size() const { assert(Mapping && "Mapping failed but used anyway!"); return Size; } @@ -720,6 +713,13 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { return std::error_code(); } +ErrorOr<basic_file_status> directory_entry::status() const { + file_status s; + if (auto EC = fs::status(Path, s, FollowSymlinks)) + return EC; + return s; +} + #if !defined(F_GETPATH) static bool hasProcSelfFD() { // If we have a /proc filesystem mounted, we can quickly establish the @@ -808,53 +808,6 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD, return std::error_code(); } -std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath) { - if (FD < 0) - return make_error_code(errc::bad_file_descriptor); - -#if defined(F_GETPATH) - // When F_GETPATH is availble, it is the quickest way to get - // the path from a file descriptor. - ResultPath.reserve(MAXPATHLEN); - if (::fcntl(FD, F_GETPATH, ResultPath.begin()) == -1) - return std::error_code(errno, std::generic_category()); - - ResultPath.set_size(strlen(ResultPath.begin())); -#else - // If we have a /proc filesystem mounted, we can quickly establish the - // real name of the file with readlink. Otherwise, we don't know how to - // get the filename from a file descriptor. Give up. - if (!fs::hasProcSelfFD()) - return make_error_code(errc::function_not_supported); - - ResultPath.reserve(PATH_MAX); - char ProcPath[64]; - snprintf(ProcPath, sizeof(ProcPath), "/proc/self/fd/%d", FD); - ssize_t CharCount = ::readlink(ProcPath, ResultPath.begin(), ResultPath.capacity()); - if (CharCount < 0) - return std::error_code(errno, std::generic_category()); - - // Was the filename truncated? - if (static_cast<size_t>(CharCount) == ResultPath.capacity()) { - // Use lstat to get the size of the filename - struct stat sb; - if (::lstat(ProcPath, &sb) < 0) - return std::error_code(errno, std::generic_category()); - - ResultPath.reserve(sb.st_size + 1); - CharCount = ::readlink(ProcPath, ResultPath.begin(), ResultPath.capacity()); - if (CharCount < 0) - return std::error_code(errno, std::generic_category()); - - // Test for race condition: did the link size change? - if (CharCount > sb.st_size) - return std::error_code(ENAMETOOLONG, std::generic_category()); - } - ResultPath.set_size(static_cast<size_t>(CharCount)); -#endif - return std::error_code(); -} - template <typename T> static std::error_code remove_directories_impl(const T &Entry, bool IgnoreErrors) { @@ -863,12 +816,11 @@ static std::error_code remove_directories_impl(const T &Entry, directory_iterator End; while (Begin != End) { auto &Item = *Begin; - file_status st; - EC = Item.status(st); - if (EC && !IgnoreErrors) - return EC; + ErrorOr<basic_file_status> st = Item.status(); + if (!st && !IgnoreErrors) + return st.getError(); - if (is_directory(st)) { + if (is_directory(*st)) { EC = remove_directories_impl(Item, IgnoreErrors); if (EC && !IgnoreErrors) return EC; diff --git a/lib/Support/Unix/Process.inc b/lib/Support/Unix/Process.inc index 2d4662094682..e43650d707e3 100644 --- a/lib/Support/Unix/Process.inc +++ b/lib/Support/Unix/Process.inc @@ -32,10 +32,10 @@ #if HAVE_SIGNAL_H #include <signal.h> #endif -// DragonFlyBSD, OpenBSD, and Bitrig have deprecated <malloc.h> for +// DragonFlyBSD, and OpenBSD have deprecated <malloc.h> for // <stdlib.h> instead. Unix.h includes this for us already. #if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) && \ - !defined(__OpenBSD__) && !defined(__Bitrig__) + !defined(__OpenBSD__) #include <malloc.h> #endif #if defined(HAVE_MALLCTL) diff --git a/lib/Support/Unix/Program.inc b/lib/Support/Unix/Program.inc index c866d5b5a84e..4f791991f3e8 100644 --- a/lib/Support/Unix/Program.inc +++ b/lib/Support/Unix/Program.inc @@ -93,7 +93,7 @@ ErrorOr<std::string> sys::findProgramByName(StringRef Name, return errc::no_such_file_or_directory; } -static bool RedirectIO(const StringRef *Path, int FD, std::string* ErrMsg) { +static bool RedirectIO(Optional<StringRef> Path, int FD, std::string* ErrMsg) { if (!Path) // Noop return false; std::string File; @@ -144,8 +144,7 @@ static bool RedirectIO_PS(const std::string *Path, int FD, std::string *ErrMsg, static void TimeOutHandler(int Sig) { } -static void SetMemoryLimits (unsigned size) -{ +static void SetMemoryLimits(unsigned size) { #if HAVE_SYS_RESOURCE_H && HAVE_GETRLIMIT && HAVE_SETRLIMIT struct rlimit r; __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576; @@ -165,9 +164,9 @@ static void SetMemoryLimits (unsigned size) } -static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, - const char **envp, const StringRef **redirects, - unsigned memoryLimit, std::string *ErrMsg) { +static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, + const char **Envp, ArrayRef<Optional<StringRef>> Redirects, + unsigned MemoryLimit, std::string *ErrMsg) { if (!llvm::sys::fs::exists(Program)) { if (ErrMsg) *ErrMsg = std::string("Executable \"") + Program.str() + @@ -178,7 +177,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, // If this OS has posix_spawn and there is no memory limit being implied, use // posix_spawn. It is more efficient than fork/exec. #ifdef HAVE_POSIX_SPAWN - if (memoryLimit == 0) { + if (MemoryLimit == 0) { posix_spawn_file_actions_t FileActionsStore; posix_spawn_file_actions_t *FileActions = nullptr; @@ -187,11 +186,12 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, // so we copy any StringRefs into this variable. std::string RedirectsStorage[3]; - if (redirects) { + if (!Redirects.empty()) { + assert(Redirects.size() == 3); std::string *RedirectsStr[3] = {nullptr, nullptr, nullptr}; for (int I = 0; I < 3; ++I) { - if (redirects[I]) { - RedirectsStorage[I] = *redirects[I]; + if (Redirects[I]) { + RedirectsStorage[I] = *Redirects[I]; RedirectsStr[I] = &RedirectsStorage[I]; } } @@ -203,8 +203,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, if (RedirectIO_PS(RedirectsStr[0], 0, ErrMsg, FileActions) || RedirectIO_PS(RedirectsStr[1], 1, ErrMsg, FileActions)) return false; - if (redirects[1] == nullptr || redirects[2] == nullptr || - *redirects[1] != *redirects[2]) { + if (!Redirects[1] || !Redirects[2] || *Redirects[1] != *Redirects[2]) { // Just redirect stderr if (RedirectIO_PS(RedirectsStr[2], 2, ErrMsg, FileActions)) return false; @@ -216,20 +215,20 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, } } - if (!envp) + if (!Envp) #if !USE_NSGETENVIRON - envp = const_cast<const char **>(environ); + Envp = const_cast<const char **>(environ); #else // environ is missing in dylibs. - envp = const_cast<const char **>(*_NSGetEnviron()); + Envp = const_cast<const char **>(*_NSGetEnviron()); #endif // Explicitly initialized to prevent what appears to be a valgrind false // positive. pid_t PID = 0; int Err = posix_spawn(&PID, Program.str().c_str(), FileActions, - /*attrp*/nullptr, const_cast<char **>(args), - const_cast<char **>(envp)); + /*attrp*/nullptr, const_cast<char **>(Args), + const_cast<char **>(Envp)); if (FileActions) posix_spawn_file_actions_destroy(FileActions); @@ -254,13 +253,12 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, // Child process: Execute the program. case 0: { // Redirect file descriptors... - if (redirects) { + if (!Redirects.empty()) { // Redirect stdin - if (RedirectIO(redirects[0], 0, ErrMsg)) { return false; } + if (RedirectIO(Redirects[0], 0, ErrMsg)) { return false; } // Redirect stdout - if (RedirectIO(redirects[1], 1, ErrMsg)) { return false; } - if (redirects[1] && redirects[2] && - *(redirects[1]) == *(redirects[2])) { + if (RedirectIO(Redirects[1], 1, ErrMsg)) { return false; } + if (Redirects[1] && Redirects[2] && *Redirects[1] == *Redirects[2]) { // If stdout and stderr should go to the same place, redirect stderr // to the FD already open for stdout. if (-1 == dup2(1,2)) { @@ -269,24 +267,24 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, } } else { // Just redirect stderr - if (RedirectIO(redirects[2], 2, ErrMsg)) { return false; } + if (RedirectIO(Redirects[2], 2, ErrMsg)) { return false; } } } // Set memory limits - if (memoryLimit!=0) { - SetMemoryLimits(memoryLimit); + if (MemoryLimit!=0) { + SetMemoryLimits(MemoryLimit); } // Execute! std::string PathStr = Program; - if (envp != nullptr) + if (Envp != nullptr) execve(PathStr.c_str(), - const_cast<char **>(args), - const_cast<char **>(envp)); + const_cast<char **>(Args), + const_cast<char **>(Envp)); else execv(PathStr.c_str(), - const_cast<char **>(args)); + const_cast<char **>(Args)); // If the execve() failed, we should exit. Follow Unix protocol and // return 127 if the executable was not found, and 126 otherwise. // Use _exit rather than exit so that atexit functions and static @@ -433,7 +431,8 @@ llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents, return EC; } -bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, ArrayRef<const char*> Args) { +bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, + ArrayRef<const char *> Args) { static long ArgMax = sysconf(_SC_ARG_MAX); // System says no practical limit. @@ -444,9 +443,8 @@ bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, ArrayRef<co long HalfArgMax = ArgMax / 2; size_t ArgLength = Program.size() + 1; - for (ArrayRef<const char*>::iterator I = Args.begin(), E = Args.end(); - I != E; ++I) { - size_t length = strlen(*I); + for (const char* Arg : Args) { + size_t length = strlen(Arg); // Ensure that we do not exceed the MAX_ARG_STRLEN constant on Linux, which // does not have a constant unlike what the man pages would have you diff --git a/lib/Support/Unix/Threading.inc b/lib/Support/Unix/Threading.inc index 267af388ecdb..7369cff8466c 100644 --- a/lib/Support/Unix/Threading.inc +++ b/lib/Support/Unix/Threading.inc @@ -108,14 +108,14 @@ uint64_t llvm::get_threadid() { static constexpr uint32_t get_max_thread_name_length_impl() { #if defined(__NetBSD__) - return PTHREAD_MAX_NAMELEN_NP; + return PTHREAD_MAX_NAMELEN_NP; #elif defined(__APPLE__) - return 64; + return 64; #elif defined(__linux__) #if HAVE_PTHREAD_SETNAME_NP - return 16; + return 16; #else - return 0; + return 0; #endif #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) return 16; @@ -206,7 +206,7 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) { #if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__) #if HAVE_PTHREAD_GETNAME_NP constexpr uint32_t len = get_max_thread_name_length_impl(); - char Buffer[len]; + char Buffer[len] = {'\0'}; // FIXME: working around MSan false positive. if (0 == ::pthread_getname_np(::pthread_self(), Buffer, len)) Name.append(Buffer, Buffer + strlen(Buffer)); #endif diff --git a/lib/Support/Windows/Memory.inc b/lib/Support/Windows/Memory.inc index 7eab9ff3afd2..318e65aaa9ee 100644 --- a/lib/Support/Windows/Memory.inc +++ b/lib/Support/Windows/Memory.inc @@ -160,85 +160,5 @@ void Memory::InvalidateInstructionCache( FlushInstructionCache(GetCurrentProcess(), Addr, Len); } - -MemoryBlock Memory::AllocateRWX(size_t NumBytes, - const MemoryBlock *NearBlock, - std::string *ErrMsg) { - MemoryBlock MB; - std::error_code EC; - MB = allocateMappedMemory(NumBytes, NearBlock, - MF_READ|MF_WRITE|MF_EXEC, EC); - if (EC != std::error_code() && ErrMsg) { - MakeErrMsg(ErrMsg, EC.message()); - } - return MB; -} - -bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { - std::error_code EC = releaseMappedMemory(M); - if (EC == std::error_code()) - return false; - MakeErrMsg(ErrMsg, EC.message()); - return true; -} - -static DWORD getProtection(const void *addr) { - MEMORY_BASIC_INFORMATION info; - if (sizeof(info) == ::VirtualQuery(addr, &info, sizeof(info))) { - return info.Protect; - } - return 0; -} - -bool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) { - if (!setRangeWritable(M.Address, M.Size)) { - return MakeErrMsg(ErrMsg, "Cannot set memory to writeable"); - } - return true; -} - -bool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) { - if (!setRangeExecutable(M.Address, M.Size)) { - return MakeErrMsg(ErrMsg, "Cannot set memory to executable"); - } - return true; -} - -bool Memory::setRangeWritable(const void *Addr, size_t Size) { - DWORD prot = getProtection(Addr); - if (!prot) - return false; - - if (prot == PAGE_EXECUTE || prot == PAGE_EXECUTE_READ) { - prot = PAGE_EXECUTE_READWRITE; - } else if (prot == PAGE_NOACCESS || prot == PAGE_READONLY) { - prot = PAGE_READWRITE; - } - - DWORD oldProt; - Memory::InvalidateInstructionCache(Addr, Size); - return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) - == TRUE; -} - -bool Memory::setRangeExecutable(const void *Addr, size_t Size) { - DWORD prot = getProtection(Addr); - if (!prot) - return false; - - if (prot == PAGE_NOACCESS) { - prot = PAGE_EXECUTE; - } else if (prot == PAGE_READONLY) { - prot = PAGE_EXECUTE_READ; - } else if (prot == PAGE_READWRITE) { - prot = PAGE_EXECUTE_READWRITE; - } - - DWORD oldProt; - Memory::InvalidateInstructionCache(Addr, Size); - return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) - == TRUE; -} - } // namespace sys } // namespace llvm diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc index b00d3905f658..f81790b17df5 100644 --- a/lib/Support/Windows/Path.inc +++ b/lib/Support/Windows/Path.inc @@ -94,13 +94,16 @@ std::error_code widenPath(const Twine &Path8, return EC; FullPath.append(CurPath); } - // Traverse the requested path, canonicalizing . and .. as we go (because - // the \\?\ prefix is documented to treat them as real components). - // The iterators don't report separators and append() always attaches - // preferred_separator so we don't need to call native() on the result. + // Traverse the requested path, canonicalizing . and .. (because the \\?\ + // prefix is documented to treat them as real components). Ignore + // separators, which can be returned from the iterator if the path has a + // drive name. We don't need to call native() on the result since append() + // always attaches preferred_separator. for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str), E = llvm::sys::path::end(Path8Str); I != E; ++I) { + if (I->size() == 1 && is_separator((*I)[0])) + continue; if (I->size() == 1 && *I == ".") continue; if (I->size() == 2 && *I == "..") @@ -165,14 +168,14 @@ ErrorOr<space_info> disk_space(const Twine &Path) { return SpaceInfo; } -TimePoint<> file_status::getLastAccessedTime() const { +TimePoint<> basic_file_status::getLastAccessedTime() const { FILETIME Time; Time.dwLowDateTime = LastAccessedTimeLow; Time.dwHighDateTime = LastAccessedTimeHigh; return toTimePoint(Time); } -TimePoint<> file_status::getLastModificationTime() const { +TimePoint<> basic_file_status::getLastModificationTime() const { FILETIME Time; Time.dwLowDateTime = LastWriteTimeLow; Time.dwHighDateTime = LastWriteTimeHigh; @@ -250,35 +253,38 @@ std::error_code create_link(const Twine &to, const Twine &from) { } std::error_code create_hard_link(const Twine &to, const Twine &from) { - return create_link(to, from); + return create_link(to, from); } std::error_code remove(const Twine &path, bool IgnoreNonExisting) { SmallVector<wchar_t, 128> path_utf16; - file_status ST; - if (std::error_code EC = status(path, ST)) { - if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) - return EC; - return std::error_code(); - } - if (std::error_code ec = widenPath(path, path_utf16)) return ec; - if (ST.type() == file_type::directory_file) { - if (!::RemoveDirectoryW(c_str(path_utf16))) { - 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))) { + // We don't know whether this is a file or a directory, and remove() can + // accept both. The usual way to delete a file or directory is to use one of + // the DeleteFile or RemoveDirectory functions, but that requires you to know + // which one it is. We could stat() the file to determine that, but that would + // cost us additional system calls, which can be slow in a directory + // containing a large number of files. So instead we call CreateFile directly. + // The important part is the FILE_FLAG_DELETE_ON_CLOSE flag, which causes the + // file to be deleted once it is closed. We also use the flags + // FILE_FLAG_BACKUP_SEMANTICS (which allows us to open directories), and + // FILE_FLAG_OPEN_REPARSE_POINT (don't follow symlinks). + ScopedFileHandle h(::CreateFileW( + c_str(path_utf16), DELETE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_DELETE_ON_CLOSE, + NULL)); + if (!h) { std::error_code EC = mapWindowsError(::GetLastError()); if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) return EC; } + return std::error_code(); } @@ -338,83 +344,261 @@ std::error_code is_local(const Twine &path, bool &result) { return is_local_internal(WidePath, result); } +static std::error_code realPathFromHandle(HANDLE H, + SmallVectorImpl<wchar_t> &Buffer) { + DWORD CountChars = ::GetFinalPathNameByHandleW( + H, Buffer.begin(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); + if (CountChars > Buffer.capacity()) { + // The buffer wasn't big enough, try again. In this case the return value + // *does* indicate the size of the null terminator. + Buffer.reserve(CountChars); + CountChars = ::GetFinalPathNameByHandleW( + H, Buffer.data(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); + } + if (CountChars == 0) + return mapWindowsError(GetLastError()); + Buffer.set_size(CountChars); + return std::error_code(); +} + +static std::error_code realPathFromHandle(HANDLE H, + SmallVectorImpl<char> &RealPath) { + RealPath.clear(); + SmallVector<wchar_t, MAX_PATH> Buffer; + if (std::error_code EC = realPathFromHandle(H, Buffer)) + return EC; + + const wchar_t *Data = Buffer.data(); + DWORD CountChars = Buffer.size(); + if (CountChars >= 4) { + if (0 == ::memcmp(Data, L"\\\\?\\", 8)) { + CountChars -= 4; + Data += 4; + } + } + + // Convert the result from UTF-16 to UTF-8. + return UTF16ToUTF8(Data, CountChars, RealPath); +} + std::error_code is_local(int FD, bool &Result) { SmallVector<wchar_t, 128> FinalPath; HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); - size_t Len = 128; - do { - FinalPath.reserve(Len); - Len = ::GetFinalPathNameByHandleW(Handle, FinalPath.data(), - FinalPath.capacity() - 1, VOLUME_NAME_NT); - if (Len == 0) - return mapWindowsError(::GetLastError()); - } while (Len > FinalPath.capacity()); - - FinalPath.set_size(Len); + if (std::error_code EC = realPathFromHandle(Handle, FinalPath)) + return EC; return is_local_internal(FinalPath, Result); } -std::error_code rename(const Twine &from, const Twine &to) { - // Convert to utf-16. - SmallVector<wchar_t, 128> wide_from; - SmallVector<wchar_t, 128> wide_to; - if (std::error_code ec = widenPath(from, wide_from)) - return ec; - if (std::error_code ec = widenPath(to, wide_to)) - return ec; +static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) { + FILE_DISPOSITION_INFO Disposition; + Disposition.DeleteFile = Delete; + if (!SetFileInformationByHandle(Handle, FileDispositionInfo, &Disposition, + sizeof(Disposition))) + return mapWindowsError(::GetLastError()); + return std::error_code(); +} - std::error_code ec = std::error_code(); +static std::error_code removeFD(int FD) { + HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + return setDeleteDisposition(Handle, true); +} - // Retry while we see recoverable errors. - // System scanners (eg. indexer) might open the source file when it is written - // and closed. +/// In order to handle temporary files we want the following properties +/// +/// * The temporary file is deleted on crashes +/// * We can use (read, rename, etc) the temporary file. +/// * We can cancel the delete to keep the file. +/// +/// Using FILE_DISPOSITION_INFO with DeleteFile=true will create a file that is +/// deleted on close, but it has a few problems: +/// +/// * The file cannot be used. An attempt to open or rename the file will fail. +/// This makes the temporary file almost useless, as it cannot be part of +/// any other CreateFileW call in the current or in another process. +/// * It is not atomic. A crash just after CreateFileW or just after canceling +/// the delete will leave the file on disk. +/// +/// Using FILE_FLAG_DELETE_ON_CLOSE solves the first issues and the first part +/// of the second one, but there is no way to cancel it in place. What works is +/// to create a second handle to prevent the deletion, close the first one and +/// then clear DeleteFile with SetFileInformationByHandle. This requires +/// changing the handle and file descriptor the caller uses. +static std::error_code cancelDeleteOnClose(int &FD) { + HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + SmallVector<wchar_t, MAX_PATH> Name; + if (std::error_code EC = realPathFromHandle(Handle, Name)) + return EC; + HANDLE NewHandle = + ::CreateFileW(Name.data(), GENERIC_READ | GENERIC_WRITE | DELETE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (NewHandle == INVALID_HANDLE_VALUE) + return mapWindowsError(::GetLastError()); + if (close(FD)) + return mapWindowsError(::GetLastError()); - bool TryReplace = true; + if (std::error_code EC = setDeleteDisposition(NewHandle, false)) + return EC; - for (int i = 0; i < 2000; i++) { - if (i > 0) - ::Sleep(1); + FD = ::_open_osfhandle(intptr_t(NewHandle), 0); + if (FD == -1) { + ::CloseHandle(NewHandle); + return mapWindowsError(ERROR_INVALID_HANDLE); + } + return std::error_code(); +} + +static std::error_code rename_internal(HANDLE FromHandle, const Twine &To, + bool ReplaceIfExists) { + SmallVector<wchar_t, 0> ToWide; + if (auto EC = widenPath(To, ToWide)) + return EC; + + std::vector<char> RenameInfoBuf(sizeof(FILE_RENAME_INFO) - sizeof(wchar_t) + + (ToWide.size() * sizeof(wchar_t))); + FILE_RENAME_INFO &RenameInfo = + *reinterpret_cast<FILE_RENAME_INFO *>(RenameInfoBuf.data()); + RenameInfo.ReplaceIfExists = ReplaceIfExists; + RenameInfo.RootDirectory = 0; + RenameInfo.FileNameLength = ToWide.size(); + std::copy(ToWide.begin(), ToWide.end(), &RenameInfo.FileName[0]); + + SetLastError(ERROR_SUCCESS); + if (!SetFileInformationByHandle(FromHandle, FileRenameInfo, &RenameInfo, + RenameInfoBuf.size())) { + unsigned Error = GetLastError(); + if (Error == ERROR_SUCCESS) + Error = ERROR_CALL_NOT_IMPLEMENTED; // Wine doesn't always set error code. + return mapWindowsError(Error); + } - if (TryReplace) { - // Try ReplaceFile first, as it is able to associate a new data stream - // with the destination even if the destination file is currently open. - if (::ReplaceFileW(wide_to.data(), wide_from.data(), NULL, 0, NULL, NULL)) + return std::error_code(); +} + +static std::error_code rename_handle(HANDLE FromHandle, const Twine &To) { + SmallVector<wchar_t, 128> WideTo; + if (std::error_code EC = widenPath(To, WideTo)) + return EC; + + // We normally expect this loop to succeed after a few iterations. If it + // requires more than 200 tries, it's more likely that the failures are due to + // a true error, so stop trying. + for (unsigned Retry = 0; Retry != 200; ++Retry) { + auto EC = rename_internal(FromHandle, To, true); + + if (EC == + std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category())) { + // Wine doesn't support SetFileInformationByHandle in rename_internal. + // Fall back to MoveFileEx. + SmallVector<wchar_t, MAX_PATH> WideFrom; + if (std::error_code EC2 = realPathFromHandle(FromHandle, WideFrom)) + return EC2; + if (::MoveFileExW(WideFrom.begin(), WideTo.begin(), + MOVEFILE_REPLACE_EXISTING)) return std::error_code(); + return mapWindowsError(GetLastError()); + } - DWORD ReplaceError = ::GetLastError(); - ec = mapWindowsError(ReplaceError); + if (!EC || EC != errc::permission_denied) + return EC; - // If ReplaceFileW returned ERROR_UNABLE_TO_MOVE_REPLACEMENT or - // ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, retry but only use MoveFileExW(). - if (ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT || - ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2) { - TryReplace = false; + // The destination file probably exists and is currently open in another + // process, either because the file was opened without FILE_SHARE_DELETE or + // it is mapped into memory (e.g. using MemoryBuffer). Rename it in order to + // move it out of the way of the source file. Use FILE_FLAG_DELETE_ON_CLOSE + // to arrange for the destination file to be deleted when the other process + // closes it. + ScopedFileHandle ToHandle( + ::CreateFileW(WideTo.begin(), GENERIC_READ | DELETE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)); + if (!ToHandle) { + auto EC = mapWindowsError(GetLastError()); + // Another process might have raced with us and moved the existing file + // out of the way before we had a chance to open it. If that happens, try + // to rename the source file again. + if (EC == errc::no_such_file_or_directory) continue; + return EC; + } + + BY_HANDLE_FILE_INFORMATION FI; + if (!GetFileInformationByHandle(ToHandle, &FI)) + return mapWindowsError(GetLastError()); + + // Try to find a unique new name for the destination file. + for (unsigned UniqueId = 0; UniqueId != 200; ++UniqueId) { + std::string TmpFilename = (To + ".tmp" + utostr(UniqueId)).str(); + if (auto EC = rename_internal(ToHandle, TmpFilename, false)) { + if (EC == errc::file_exists || EC == errc::permission_denied) { + // Again, another process might have raced with us and moved the file + // before we could move it. Check whether this is the case, as it + // might have caused the permission denied error. If that was the + // case, we don't need to move it ourselves. + ScopedFileHandle ToHandle2(::CreateFileW( + WideTo.begin(), 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); + if (!ToHandle2) { + auto EC = mapWindowsError(GetLastError()); + if (EC == errc::no_such_file_or_directory) + break; + return EC; + } + BY_HANDLE_FILE_INFORMATION FI2; + if (!GetFileInformationByHandle(ToHandle2, &FI2)) + return mapWindowsError(GetLastError()); + if (FI.nFileIndexHigh != FI2.nFileIndexHigh || + FI.nFileIndexLow != FI2.nFileIndexLow || + FI.dwVolumeSerialNumber != FI2.dwVolumeSerialNumber) + break; + continue; + } + return EC; } - // If ReplaceFileW returned ERROR_UNABLE_TO_REMOVE_REPLACED, retry - // using ReplaceFileW(). - if (ReplaceError == ERROR_UNABLE_TO_REMOVE_REPLACED) - continue; - // We get ERROR_FILE_NOT_FOUND if the destination file is missing. - // MoveFileEx can handle this case. - if (ReplaceError != ERROR_ACCESS_DENIED && - ReplaceError != ERROR_FILE_NOT_FOUND && - ReplaceError != ERROR_SHARING_VIOLATION) - break; + break; } - if (::MoveFileExW(wide_from.begin(), wide_to.begin(), - MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) - return std::error_code(); + // Okay, the old destination file has probably been moved out of the way at + // this point, so try to rename the source file again. Still, another + // process might have raced with us to create and open the destination + // file, so we need to keep doing this until we succeed. + } + + // The most likely root cause. + return errc::permission_denied; +} + +static std::error_code rename_fd(int FromFD, const Twine &To) { + HANDLE FromHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FromFD)); + return rename_handle(FromHandle, To); +} + +std::error_code rename(const Twine &From, const Twine &To) { + // Convert to utf-16. + SmallVector<wchar_t, 128> WideFrom; + if (std::error_code EC = widenPath(From, WideFrom)) + return EC; - DWORD MoveError = ::GetLastError(); - ec = mapWindowsError(MoveError); - if (MoveError != ERROR_ACCESS_DENIED) break; + ScopedFileHandle FromHandle; + // Retry this a few times to defeat badly behaved file system scanners. + for (unsigned Retry = 0; Retry != 200; ++Retry) { + if (Retry != 0) + ::Sleep(10); + FromHandle = + ::CreateFileW(WideFrom.begin(), GENERIC_READ | DELETE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (FromHandle) + break; } + if (!FromHandle) + return mapWindowsError(GetLastError()); - return ec; + return rename_handle(FromHandle, To); } std::error_code resize_file(int FD, uint64_t Size) { @@ -502,6 +686,15 @@ static bool isReservedName(StringRef path) { return false; } +static file_type file_type_from_attrs(DWORD Attrs) { + return (Attrs & FILE_ATTRIBUTE_DIRECTORY) ? file_type::directory_file + : file_type::regular_file; +} + +static perms perms_from_attrs(DWORD Attrs) { + return (Attrs & FILE_ATTRIBUTE_READONLY) ? (all_read | all_exe) : all_all; +} + static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { if (FileHandle == INVALID_HANDLE_VALUE) goto handle_status_error; @@ -530,22 +723,14 @@ static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { if (!::GetFileInformationByHandle(FileHandle, &Info)) goto handle_status_error; - { - file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - ? file_type::directory_file - : file_type::regular_file; - perms Permissions = (Info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) - ? (all_read | all_exe) - : all_all; - Result = file_status( - Type, Permissions, Info.nNumberOfLinks, - Info.ftLastAccessTime.dwHighDateTime, - Info.ftLastAccessTime.dwLowDateTime, - Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime, - Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow, - Info.nFileIndexHigh, Info.nFileIndexLow); - return std::error_code(); - } + Result = file_status( + file_type_from_attrs(Info.dwFileAttributes), + perms_from_attrs(Info.dwFileAttributes), Info.nNumberOfLinks, + Info.ftLastAccessTime.dwHighDateTime, Info.ftLastAccessTime.dwLowDateTime, + Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime, + Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow, + Info.nFileIndexHigh, Info.nFileIndexLow); + return std::error_code(); handle_status_error: DWORD LastError = ::GetLastError(); @@ -637,10 +822,6 @@ std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) { std::error_code mapped_file_region::init(int FD, uint64_t Offset, mapmode Mode) { - // Make sure that the requested size fits within SIZE_T. - if (Size > std::numeric_limits<SIZE_T>::max()) - return make_error_code(errc::invalid_argument); - HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); if (FileHandle == INVALID_HANDLE_VALUE) return make_error_code(errc::bad_file_descriptor); @@ -654,8 +835,8 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, HANDLE FileMappingHandle = ::CreateFileMappingW(FileHandle, 0, flprotect, - (Offset + Size) >> 32, - (Offset + Size) & 0xffffffff, + Hi_32(Size), + Lo_32(Size), 0); if (FileMappingHandle == NULL) { std::error_code ec = mapWindowsError(GetLastError()); @@ -697,7 +878,7 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, return std::error_code(); } -mapped_file_region::mapped_file_region(int fd, mapmode mode, uint64_t length, +mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length, uint64_t offset, std::error_code &ec) : Size(length), Mapping() { ec = init(fd, offset, mode); @@ -710,7 +891,7 @@ mapped_file_region::~mapped_file_region() { ::UnmapViewOfFile(Mapping); } -uint64_t mapped_file_region::size() const { +size_t mapped_file_region::size() const { assert(Mapping && "Mapping failed but used anyway!"); return Size; } @@ -731,6 +912,16 @@ int mapped_file_region::alignment() { return SysInfo.dwAllocationGranularity; } +static basic_file_status status_from_find_data(WIN32_FIND_DATAW *FindData) { + return basic_file_status(file_type_from_attrs(FindData->dwFileAttributes), + perms_from_attrs(FindData->dwFileAttributes), + FindData->ftLastAccessTime.dwHighDateTime, + FindData->ftLastAccessTime.dwLowDateTime, + FindData->ftLastWriteTime.dwHighDateTime, + FindData->ftLastWriteTime.dwLowDateTime, + FindData->nFileSizeHigh, FindData->nFileSizeLow); +} + std::error_code detail::directory_iterator_construct(detail::DirIterState &it, StringRef path, bool follow_symlinks) { @@ -751,7 +942,9 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it, // Get the first directory entry. WIN32_FIND_DATAW FirstFind; - ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind)); + ScopedFindHandle FindHandle(::FindFirstFileExW( + c_str(path_utf16), FindExInfoBasic, &FirstFind, FindExSearchNameMatch, + NULL, FIND_FIRST_EX_LARGE_FETCH)); if (!FindHandle) return mapWindowsError(::GetLastError()); @@ -778,7 +971,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); - it.CurrentEntry = directory_entry(directory_entry_path, follow_symlinks); + it.CurrentEntry = directory_entry(directory_entry_path, follow_symlinks, + status_from_find_data(&FirstFind)); return std::error_code(); } @@ -814,36 +1008,13 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { directory_entry_path_utf8)) return ec; - it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); + it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8), + status_from_find_data(&FindData)); return std::error_code(); } -static std::error_code realPathFromHandle(HANDLE H, - SmallVectorImpl<char> &RealPath) { - RealPath.clear(); - llvm::SmallVector<wchar_t, MAX_PATH> Buffer; - DWORD CountChars = ::GetFinalPathNameByHandleW( - H, Buffer.begin(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); - if (CountChars > Buffer.capacity()) { - // The buffer wasn't big enough, try again. In this case the return value - // *does* indicate the size of the null terminator. - Buffer.reserve(CountChars); - CountChars = ::GetFinalPathNameByHandleW( - H, Buffer.data(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); - } - if (CountChars == 0) - return mapWindowsError(GetLastError()); - - const wchar_t *Data = Buffer.data(); - if (CountChars >= 4) { - if (0 == ::memcmp(Data, L"\\\\?\\", 8)) { - CountChars -= 4; - Data += 4; - } - } - - // Convert the result from UTF-16 to UTF-8. - return UTF16ToUTF8(Data, CountChars, RealPath); +ErrorOr<basic_file_status> directory_entry::status() const { + return Status; } static std::error_code directoryRealPath(const Twine &Name, @@ -922,12 +1093,18 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD, CreationDisposition = CREATE_ALWAYS; DWORD Access = GENERIC_WRITE; + DWORD Attributes = FILE_ATTRIBUTE_NORMAL; if (Flags & F_RW) Access |= GENERIC_READ; + if (Flags & F_Delete) { + Access |= DELETE; + Attributes |= FILE_FLAG_DELETE_ON_CLOSE; + } - HANDLE H = ::CreateFileW(PathUTF16.begin(), Access, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, - CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE H = + ::CreateFileW(PathUTF16.data(), Access, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, CreationDisposition, Attributes, NULL); if (H == INVALID_HANDLE_VALUE) { DWORD LastError = ::GetLastError(); @@ -959,42 +1136,6 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD, return std::error_code(); } -std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath) { - HANDLE FileHandle = reinterpret_cast<HANDLE>(::_get_osfhandle(FD)); - if (FileHandle == INVALID_HANDLE_VALUE) - return make_error_code(errc::bad_file_descriptor); - - DWORD CharCount; - SmallVector<wchar_t, 1024> TempPath; - do { - CharCount = ::GetFinalPathNameByHandleW(FileHandle, TempPath.begin(), - TempPath.capacity(), - FILE_NAME_NORMALIZED); - if (CharCount < TempPath.capacity()) - break; - - // Reserve sufficient space for the path as well as the null character. Even - // though the API does not document that it is required, if we reserve just - // CharCount space, the function call will not store the resulting path and - // still report success. - TempPath.reserve(CharCount + 1); - } while (true); - - if (CharCount == 0) - return mapWindowsError(::GetLastError()); - - TempPath.set_size(CharCount); - - // On earlier Windows releases, the character count includes the terminating - // null. - if (TempPath.back() == L'\0') { - --CharCount; - TempPath.pop_back(); - } - - return windows::UTF16ToUTF8(TempPath.data(), CharCount, ResultPath); -} - std::error_code remove_directories(const Twine &path, bool IgnoreErrors) { // Convert to utf-16. SmallVector<wchar_t, 128> Path16; diff --git a/lib/Support/Windows/Process.inc b/lib/Support/Windows/Process.inc index 18aef610d54a..3fe9f89f1ef5 100644 --- a/lib/Support/Windows/Process.inc +++ b/lib/Support/Windows/Process.inc @@ -129,9 +129,10 @@ Optional<std::string> Process::GetEnv(StringRef Name) { size_t Size = MAX_PATH; do { Buf.reserve(Size); + SetLastError(NO_ERROR); Size = - GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity()); - if (Size == 0) + GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity()); + if (Size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) return None; // Try again with larger buffer. diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc index 721167da5b15..52921cd6a203 100644 --- a/lib/Support/Windows/Program.inc +++ b/lib/Support/Windows/Program.inc @@ -103,9 +103,10 @@ ErrorOr<std::string> sys::findProgramByName(StringRef Name, return std::string(U8Result.begin(), U8Result.end()); } -static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) { +static HANDLE RedirectIO(Optional<StringRef> Path, int fd, + std::string *ErrMsg) { HANDLE h; - if (path == 0) { + if (!Path) { if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), GetCurrentProcess(), &h, 0, TRUE, DUPLICATE_SAME_ACCESS)) @@ -114,10 +115,10 @@ static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) { } std::string fname; - if (path->empty()) + if (Path->empty()) fname = "NUL"; else - fname = *path; + fname = *Path; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); @@ -125,7 +126,7 @@ static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) { sa.bInheritHandle = TRUE; SmallVector<wchar_t, 128> fnameUnicode; - if (path->empty()) { + if (Path->empty()) { // Don't play long-path tricks on "NUL". if (windows::UTF8ToUTF16(fname, fnameUnicode)) return INVALID_HANDLE_VALUE; @@ -207,19 +208,19 @@ static unsigned int ArgLenWithQuotes(const char *Str) { } -static std::unique_ptr<char[]> flattenArgs(const char **args) { +static std::unique_ptr<char[]> flattenArgs(const char **Args) { // First, determine the length of the command line. unsigned len = 0; - for (unsigned i = 0; args[i]; i++) { - len += ArgLenWithQuotes(args[i]) + 1; + for (unsigned i = 0; Args[i]; i++) { + len += ArgLenWithQuotes(Args[i]) + 1; } // Now build the command line. std::unique_ptr<char[]> command(new char[len+1]); char *p = command.get(); - for (unsigned i = 0; args[i]; i++) { - const char *arg = args[i]; + for (unsigned i = 0; Args[i]; i++) { + const char *arg = Args[i]; const char *start = arg; bool needsQuoting = ArgNeedsQuotes(arg); @@ -248,9 +249,9 @@ static std::unique_ptr<char[]> flattenArgs(const char **args) { return command; } -static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, - const char **envp, const StringRef **redirects, - unsigned memoryLimit, std::string *ErrMsg) { +static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, + const char **Envp, ArrayRef<Optional<StringRef>> Redirects, + unsigned MemoryLimit, std::string *ErrMsg) { if (!sys::fs::can_execute(Program)) { if (ErrMsg) *ErrMsg = "program not executable"; @@ -268,18 +269,18 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, // Windows wants a command line, not an array of args, to pass to the new // process. We have to concatenate them all, while quoting the args that // have embedded spaces (or are empty). - std::unique_ptr<char[]> command = flattenArgs(args); + std::unique_ptr<char[]> command = flattenArgs(Args); // The pointer to the environment block for the new process. std::vector<wchar_t> EnvBlock; - if (envp) { + if (Envp) { // An environment block consists of a null-terminated block of // null-terminated strings. Convert the array of environment variables to // an environment block by concatenating them. - for (unsigned i = 0; envp[i]; ++i) { + for (unsigned i = 0; Envp[i]; ++i) { SmallVector<wchar_t, MAX_PATH> EnvString; - if (std::error_code ec = windows::UTF8ToUTF16(envp[i], EnvString)) { + if (std::error_code ec = windows::UTF8ToUTF16(Envp[i], EnvString)) { SetLastError(ec.value()); MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16"); return false; @@ -299,21 +300,21 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, si.hStdOutput = INVALID_HANDLE_VALUE; si.hStdError = INVALID_HANDLE_VALUE; - if (redirects) { + if (!Redirects.empty()) { si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg); + si.hStdInput = RedirectIO(Redirects[0], 0, ErrMsg); if (si.hStdInput == INVALID_HANDLE_VALUE) { MakeErrMsg(ErrMsg, "can't redirect stdin"); return false; } - si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg); + si.hStdOutput = RedirectIO(Redirects[1], 1, ErrMsg); if (si.hStdOutput == INVALID_HANDLE_VALUE) { CloseHandle(si.hStdInput); MakeErrMsg(ErrMsg, "can't redirect stdout"); return false; } - if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { + if (Redirects[1] && Redirects[2] && *Redirects[1] == *Redirects[2]) { // If stdout and stderr should go to the same place, redirect stderr // to the handle already open for stdout. if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput, @@ -326,7 +327,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, } } else { // Just redirect stderr - si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); + si.hStdError = RedirectIO(Redirects[2], 2, ErrMsg); if (si.hStdError == INVALID_HANDLE_VALUE) { CloseHandle(si.hStdInput); CloseHandle(si.hStdOutput); @@ -386,14 +387,14 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, // Assign the process to a job if a memory limit is defined. ScopedJobHandle hJob; - if (memoryLimit != 0) { + if (MemoryLimit != 0) { hJob = CreateJobObjectW(0, 0); bool success = false; if (hJob) { JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; memset(&jeli, 0, sizeof(jeli)); jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; - jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576; + jeli.ProcessMemoryLimit = uintptr_t(MemoryLimit) * 1048576; if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) { if (AssignProcessToJobObject(hJob, pi.hProcess)) @@ -534,16 +535,16 @@ llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents, return EC; } -bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, ArrayRef<const char*> Args) { +bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, + ArrayRef<const char *> Args) { // The documented max length of the command line passed to CreateProcess. static const size_t MaxCommandStringLength = 32768; // Account for the trailing space for the program path and the // trailing NULL of the last argument. size_t ArgLength = ArgLenWithQuotes(Program.str().c_str()) + 2; - for (ArrayRef<const char*>::iterator I = Args.begin(), E = Args.end(); - I != E; ++I) { + for (const char* Arg : Args) { // Account for the trailing space for every arg - ArgLength += ArgLenWithQuotes(*I) + 1; + ArgLength += ArgLenWithQuotes(Arg) + 1; if (ArgLength > MaxCommandStringLength) { return false; } diff --git a/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc index 1ef51888baf3..21dd2dd13754 100644 --- a/lib/Support/Windows/Signals.inc +++ b/lib/Support/Windows/Signals.inc @@ -212,8 +212,14 @@ static StringRef Argv0; enum { #if defined(_M_X64) NativeMachineType = IMAGE_FILE_MACHINE_AMD64 -#else +#elif defined(_M_ARM64) + NativeMachineType = IMAGE_FILE_MACHINE_ARM64 +#elif defined(_M_IX86) NativeMachineType = IMAGE_FILE_MACHINE_I386 +#elif defined(_M_ARM) + NativeMachineType = IMAGE_FILE_MACHINE_ARMNT +#else + NativeMachineType = IMAGE_FILE_MACHINE_UNKNOWN #endif }; @@ -318,18 +324,18 @@ static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess, using namespace llvm; // Print the PC in hexadecimal. DWORD64 PC = StackFrame.AddrPC.Offset; -#if defined(_M_X64) +#if defined(_M_X64) || defined(_M_ARM64) OS << format("0x%016llX", PC); -#elif defined(_M_IX86) +#elif defined(_M_IX86) || defined(_M_ARM) OS << format("0x%08lX", static_cast<DWORD>(PC)); #endif // Print the parameters. Assume there are four. -#if defined(_M_X64) +#if defined(_M_X64) || defined(_M_ARM64) 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) +#elif defined(_M_IX86) || defined(_M_ARM) OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", static_cast<DWORD>(StackFrame.Params[0]), static_cast<DWORD>(StackFrame.Params[1]), @@ -526,10 +532,14 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) { StackFrame.AddrPC.Offset = Context.Rip; StackFrame.AddrStack.Offset = Context.Rsp; StackFrame.AddrFrame.Offset = Context.Rbp; -#else +#elif defined(_M_IX86) StackFrame.AddrPC.Offset = Context.Eip; StackFrame.AddrStack.Offset = Context.Esp; StackFrame.AddrFrame.Offset = Context.Ebp; +#elif defined(_M_ARM64) || defined(_M_ARM) + StackFrame.AddrPC.Offset = Context.Pc; + StackFrame.AddrStack.Offset = Context.Sp; + StackFrame.AddrFrame.Offset = Context.Fp; #endif StackFrame.AddrPC.Mode = AddrModeFlat; StackFrame.AddrStack.Mode = AddrModeFlat; @@ -804,6 +814,13 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { StackFrame.AddrStack.Mode = AddrModeFlat; StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp; StackFrame.AddrFrame.Mode = AddrModeFlat; +#elif defined(_M_ARM64) || defined(_M_ARM) + StackFrame.AddrPC.Offset = ep->ContextRecord->Pc; + StackFrame.AddrPC.Mode = AddrModeFlat; + StackFrame.AddrStack.Offset = ep->ContextRecord->Sp; + StackFrame.AddrStack.Mode = AddrModeFlat; + StackFrame.AddrFrame.Offset = ep->ContextRecord->Fp; + StackFrame.AddrFrame.Mode = AddrModeFlat; #endif HANDLE hProcess = GetCurrentProcess(); diff --git a/lib/Support/YAMLTraits.cpp b/lib/Support/YAMLTraits.cpp index 65eda246a7fe..05ca40f03018 100644 --- a/lib/Support/YAMLTraits.cpp +++ b/lib/Support/YAMLTraits.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/Format.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Unicode.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -160,7 +161,8 @@ bool Input::preflightKey(const char *Key, bool Required, bool, bool &UseDefault, MapHNode *MN = dyn_cast<MapHNode>(CurrentNode); if (!MN) { - setError(CurrentNode, "not a mapping"); + if (Required || !isa<EmptyHNode>(CurrentNode)) + setError(CurrentNode, "not a mapping"); return false; } MN->ValidKeys.push_back(Key); @@ -329,7 +331,7 @@ void Input::endBitSetScalar() { } } -void Input::scalarString(StringRef &S, bool) { +void Input::scalarString(StringRef &S, QuotingType) { if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) { S = SN->value(); } else { @@ -337,7 +339,7 @@ void Input::scalarString(StringRef &S, bool) { } } -void Input::blockScalarString(StringRef &S) { scalarString(S, false); } +void Input::blockScalarString(StringRef &S) { scalarString(S, QuotingType::None); } void Input::setError(HNode *hnode, const Twine &message) { assert(hnode && "HNode must not be NULL"); @@ -374,18 +376,22 @@ std::unique_ptr<Input::HNode> Input::createHNodes(Node *N) { auto mapHNode = llvm::make_unique<MapHNode>(N); for (KeyValueNode &KVN : *Map) { Node *KeyNode = KVN.getKey(); - ScalarNode *KeyScalar = dyn_cast<ScalarNode>(KeyNode); - if (!KeyScalar) { - setError(KeyNode, "Map key must be a scalar"); + ScalarNode *Key = dyn_cast<ScalarNode>(KeyNode); + Node *Value = KVN.getValue(); + if (!Key || !Value) { + if (!Key) + setError(KeyNode, "Map key must be a scalar"); + if (!Value) + setError(KeyNode, "Map value must not be empty"); break; } StringStorage.clear(); - StringRef KeyStr = KeyScalar->getValue(StringStorage); + StringRef KeyStr = Key->getValue(StringStorage); if (!StringStorage.empty()) { // Copy string to permanent storage KeyStr = StringStorage.str().copy(StringAllocator); } - auto ValueHNode = this->createHNodes(KVN.getValue()); + auto ValueHNode = this->createHNodes(Value); if (EC) break; mapHNode->Mapping[KeyStr] = std::move(ValueHNode); @@ -612,7 +618,7 @@ void Output::endBitSetScalar() { this->outputUpToEndOfLine(" ]"); } -void Output::scalarString(StringRef &S, bool MustQuote) { +void Output::scalarString(StringRef &S, QuotingType MustQuote) { this->newLineCheck(); if (S.empty()) { // Print '' for the empty string because leaving the field empty is not @@ -620,27 +626,52 @@ void Output::scalarString(StringRef &S, bool MustQuote) { this->outputUpToEndOfLine("''"); return; } - if (!MustQuote) { + if (MustQuote == QuotingType::None) { // Only quote if we must. this->outputUpToEndOfLine(S); return; } + unsigned i = 0; unsigned j = 0; unsigned End = S.size(); - output("'"); // Starting single quote. const char *Base = S.data(); + + const char *const Quote = MustQuote == QuotingType::Single ? "'" : "\""; + const char QuoteChar = MustQuote == QuotingType::Single ? '\'' : '"'; + + output(Quote); // Starting quote. + + // When using single-quoted strings, any single quote ' must be doubled to be + // escaped. + // When using double-quoted strings, print \x + hex for non-printable ASCII + // characters, and escape double quotes. while (j < End) { - // Escape a single quote by doubling it. - if (S[j] == '\'') { - output(StringRef(&Base[i], j - i + 1)); - output("'"); + if (S[j] == QuoteChar) { // Escape quotes. + output(StringRef(&Base[i], j - i)); // "flush". + if (MustQuote == QuotingType::Double) { // Print it as \" + output(StringLiteral("\\")); + output(StringRef(Quote, 1)); + } else { // Single + output(StringLiteral("''")); // Print it as '' + } + i = j + 1; + } else if (MustQuote == QuotingType::Double && + !sys::unicode::isPrintable(S[j])) { + output(StringRef(&Base[i], j - i)); // "flush" + output(StringLiteral("\\x")); + + // Output the byte 0x0F as \x0f. + auto FormattedHex = format_hex_no_prefix(S[j], 2); + Out << FormattedHex; + Column += 4; // one for the '\', one for the 'x', and two for the hex + i = j + 1; } ++j; } output(StringRef(&Base[i], j - i)); - this->outputUpToEndOfLine("'"); // Ending single quote. + this->outputUpToEndOfLine(Quote); // Ending quote. } void Output::blockScalarString(StringRef &S) { diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp index dd58eccee957..e02611103080 100644 --- a/lib/Support/raw_ostream.cpp +++ b/lib/Support/raw_ostream.cpp @@ -139,6 +139,16 @@ raw_ostream &raw_ostream::write_hex(unsigned long long N) { return *this; } +raw_ostream &raw_ostream::write_uuid(const uuid_t UUID) { + for (int Idx = 0; Idx < 16; ++Idx) { + *this << format("%02" PRIX32, UUID[Idx]); + if (Idx == 3 || Idx == 5 || Idx == 7 || Idx == 9) + *this << "-"; + } + return *this; +} + + raw_ostream &raw_ostream::write_escaped(StringRef Str, bool UseHexEscapes) { for (unsigned char c : Str) { @@ -507,17 +517,18 @@ raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC, /// 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_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose), - Error(false) { + : raw_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose) { if (FD < 0 ) { ShouldClose = false; return; } - // We do not want to close STDOUT as there may have been several uses of it - // such as the case: llc %s -o=- -pass-remarks-output=- -filetype=asm - // which cause multiple closes of STDOUT_FILENO and/or use-after-close of it. - // Using dup() in getFD doesn't work as we end up with original STDOUT_FILENO - // open anyhow. + + // Do not attempt to close stdout or stderr. We used to try to maintain the + // property that tools that support writing file to stdout should not also + // write informational output to stdout, but in practice we were never able to + // maintain this invariant. Many features have been added to LLVM and clang + // (-fdump-record-layouts, optimization remarks, etc) that print to stdout, so + // users must simply be aware that mixed output and remarks is a possibility. if (FD <= STDERR_FILENO) ShouldClose = false; @@ -540,8 +551,10 @@ raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered) raw_fd_ostream::~raw_fd_ostream() { if (FD >= 0) { flush(); - if (ShouldClose && sys::Process::SafelyCloseFileDescriptor(FD)) - error_detected(); + if (ShouldClose) { + if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD)) + error_detected(EC); + } } #ifdef __MINGW32__ @@ -557,31 +570,33 @@ 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.", /*GenCrashDiag=*/false); + report_fatal_error("IO failure on output stream: " + error().message(), + /*GenCrashDiag=*/false); } void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) { assert(FD >= 0 && "File already closed."); pos += Size; -#ifndef LLVM_ON_WIN32 + // The maximum write size is limited to SSIZE_MAX because a write + // greater than SSIZE_MAX is implementation-defined in POSIX. + // Since SSIZE_MAX is not portable, we use SIZE_MAX >> 1 instead. + size_t MaxWriteSize = SIZE_MAX >> 1; + #if defined(__linux__) - bool ShouldWriteInChunks = true; -#else - bool ShouldWriteInChunks = false; -#endif -#else + // It is observed that Linux returns EINVAL for a very large write (>2G). + // Make it a reasonably small value. + MaxWriteSize = 1024 * 1024 * 1024; +#elif defined(LLVM_ON_WIN32) // Writing a large size of output to Windows console returns ENOMEM. It seems // that, prior to Windows 8, WriteFile() is redirecting to WriteConsole(), and // the latter has a size limit (66000 bytes or less, depending on heap usage). - bool ShouldWriteInChunks = !!::_isatty(FD) && !RunningWindows8OrGreater(); + if (::_isatty(FD) && !RunningWindows8OrGreater()) + MaxWriteSize = 32767; #endif do { - size_t ChunkSize = Size; - if (ChunkSize > 32767 && ShouldWriteInChunks) - ChunkSize = 32767; - + size_t ChunkSize = std::min(Size, MaxWriteSize); ssize_t ret = ::write(FD, Ptr, ChunkSize); if (ret < 0) { @@ -601,7 +616,7 @@ void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) { continue; // Otherwise it's a non-recoverable error. Note it and quit. - error_detected(); + error_detected(std::error_code(errno, std::generic_category())); break; } @@ -617,8 +632,8 @@ void raw_fd_ostream::close() { assert(ShouldClose); ShouldClose = false; flush(); - if (sys::Process::SafelyCloseFileDescriptor(FD)) - error_detected(); + if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD)) + error_detected(EC); FD = -1; } @@ -633,7 +648,7 @@ uint64_t raw_fd_ostream::seek(uint64_t off) { pos = ::lseek(FD, off, SEEK_SET); #endif if (pos == (uint64_t)-1) - error_detected(); + error_detected(std::error_code(errno, std::generic_category())); return pos; } @@ -722,10 +737,7 @@ bool raw_fd_ostream::has_colors() const { /// outs() - This returns a reference to a raw_ostream for standard output. /// Use it like: outs() << "foo" << "bar"; raw_ostream &llvm::outs() { - // Set buffer settings to model stdout behavior. Delete the file descriptor - // when the program exits, forcing error detection. This means that if you - // ever call outs(), you can't open another raw_fd_ostream on stdout, as we'll - // close stdout twice and print an error the second time. + // Set buffer settings to model stdout behavior. std::error_code EC; static raw_fd_ostream S("-", EC, sys::fs::F_None); assert(!EC); diff --git a/lib/Support/regcclass.h b/lib/Support/regcclass.h deleted file mode 100644 index 7fd66046cd87..000000000000 --- a/lib/Support/regcclass.h +++ /dev/null @@ -1,75 +0,0 @@ -/*- - * This code is derived from OpenBSD's libc/regex, original license follows: - * - * This code is derived from OpenBSD's libc/regex, original license follows: - * - * Copyright (c) 1992, 1993, 1994 Henry Spencer. - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Henry Spencer. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)cclass.h 8.3 (Berkeley) 3/20/94 - */ - -#ifndef LLVM_SUPPORT_REGCCLASS_H -#define LLVM_SUPPORT_REGCCLASS_H - -/* character-class table */ -static struct cclass { - const char *name; - const char *chars; - const char *multis; -} cclasses[] = { - { "alnum", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ -0123456789", ""} , - { "alpha", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", - ""} , - { "blank", " \t", ""} , - { "cntrl", "\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\ -\25\26\27\30\31\32\33\34\35\36\37\177", ""} , - { "digit", "0123456789", ""} , - { "graph", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ -0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - ""} , - { "lower", "abcdefghijklmnopqrstuvwxyz", - ""} , - { "print", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ -0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ", - ""} , - { "punct", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - ""} , - { "space", "\t\n\v\f\r ", ""} , - { "upper", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", - ""} , - { "xdigit", "0123456789ABCDEFabcdef", - ""} , - { NULL, 0, "" } -}; - -#endif diff --git a/lib/Support/regcname.h b/lib/Support/regcname.h deleted file mode 100644 index 891d25573e8c..000000000000 --- a/lib/Support/regcname.h +++ /dev/null @@ -1,144 +0,0 @@ -/*- - * This code is derived from OpenBSD's libc/regex, original license follows: - * - * Copyright (c) 1992, 1993, 1994 Henry Spencer. - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Henry Spencer. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)cname.h 8.3 (Berkeley) 3/20/94 - */ - -#ifndef LLVM_SUPPORT_REGCNAME_H -#define LLVM_SUPPORT_REGCNAME_H - -/* character-name table */ -static struct cname { - const char *name; - char code; -} cnames[] = { - { "NUL", '\0' }, - { "SOH", '\001' }, - { "STX", '\002' }, - { "ETX", '\003' }, - { "EOT", '\004' }, - { "ENQ", '\005' }, - { "ACK", '\006' }, - { "BEL", '\007' }, - { "alert", '\007' }, - { "BS", '\010' }, - { "backspace", '\b' }, - { "HT", '\011' }, - { "tab", '\t' }, - { "LF", '\012' }, - { "newline", '\n' }, - { "VT", '\013' }, - { "vertical-tab", '\v' }, - { "FF", '\014' }, - { "form-feed", '\f' }, - { "CR", '\015' }, - { "carriage-return", '\r' }, - { "SO", '\016' }, - { "SI", '\017' }, - { "DLE", '\020' }, - { "DC1", '\021' }, - { "DC2", '\022' }, - { "DC3", '\023' }, - { "DC4", '\024' }, - { "NAK", '\025' }, - { "SYN", '\026' }, - { "ETB", '\027' }, - { "CAN", '\030' }, - { "EM", '\031' }, - { "SUB", '\032' }, - { "ESC", '\033' }, - { "IS4", '\034' }, - { "FS", '\034' }, - { "IS3", '\035' }, - { "GS", '\035' }, - { "IS2", '\036' }, - { "RS", '\036' }, - { "IS1", '\037' }, - { "US", '\037' }, - { "space", ' ' }, - { "exclamation-mark", '!' }, - { "quotation-mark", '"' }, - { "number-sign", '#' }, - { "dollar-sign", '$' }, - { "percent-sign", '%' }, - { "ampersand", '&' }, - { "apostrophe", '\'' }, - { "left-parenthesis", '(' }, - { "right-parenthesis", ')' }, - { "asterisk", '*' }, - { "plus-sign", '+' }, - { "comma", ',' }, - { "hyphen", '-' }, - { "hyphen-minus", '-' }, - { "period", '.' }, - { "full-stop", '.' }, - { "slash", '/' }, - { "solidus", '/' }, - { "zero", '0' }, - { "one", '1' }, - { "two", '2' }, - { "three", '3' }, - { "four", '4' }, - { "five", '5' }, - { "six", '6' }, - { "seven", '7' }, - { "eight", '8' }, - { "nine", '9' }, - { "colon", ':' }, - { "semicolon", ';' }, - { "less-than-sign", '<' }, - { "equals-sign", '=' }, - { "greater-than-sign", '>' }, - { "question-mark", '?' }, - { "commercial-at", '@' }, - { "left-square-bracket", '[' }, - { "backslash", '\\' }, - { "reverse-solidus", '\\' }, - { "right-square-bracket", ']' }, - { "circumflex", '^' }, - { "circumflex-accent", '^' }, - { "underscore", '_' }, - { "low-line", '_' }, - { "grave-accent", '`' }, - { "left-brace", '{' }, - { "left-curly-bracket", '{' }, - { "vertical-line", '|' }, - { "right-brace", '}' }, - { "right-curly-bracket", '}' }, - { "tilde", '~' }, - { "DEL", '\177' }, - { NULL, 0 } -}; - -#endif diff --git a/lib/Support/regcomp.c b/lib/Support/regcomp.c index ebde64f9cf75..354e359f676b 100644 --- a/lib/Support/regcomp.c +++ b/lib/Support/regcomp.c @@ -46,9 +46,6 @@ #include "regutils.h" #include "regex2.h" -#include "regcclass.h" -#include "regcname.h" - #include "llvm/Config/config.h" #if HAVE_STDINT_H #include <stdint.h> @@ -57,6 +54,141 @@ #define SIZE_MAX UINT_MAX #endif +/* character-class table */ +static struct cclass { + const char *name; + const char *chars; + const char *multis; +} cclasses[] = { + { "alnum", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789", ""} , + { "alpha", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", + ""} , + { "blank", " \t", ""} , + { "cntrl", "\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\ +\25\26\27\30\31\32\33\34\35\36\37\177", ""} , + { "digit", "0123456789", ""} , + { "graph", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + ""} , + { "lower", "abcdefghijklmnopqrstuvwxyz", + ""} , + { "print", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ", + ""} , + { "punct", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + ""} , + { "space", "\t\n\v\f\r ", ""} , + { "upper", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + ""} , + { "xdigit", "0123456789ABCDEFabcdef", + ""} , + { NULL, 0, "" } +}; + +/* character-name table */ +static struct cname { + const char *name; + char code; +} cnames[] = { + { "NUL", '\0' }, + { "SOH", '\001' }, + { "STX", '\002' }, + { "ETX", '\003' }, + { "EOT", '\004' }, + { "ENQ", '\005' }, + { "ACK", '\006' }, + { "BEL", '\007' }, + { "alert", '\007' }, + { "BS", '\010' }, + { "backspace", '\b' }, + { "HT", '\011' }, + { "tab", '\t' }, + { "LF", '\012' }, + { "newline", '\n' }, + { "VT", '\013' }, + { "vertical-tab", '\v' }, + { "FF", '\014' }, + { "form-feed", '\f' }, + { "CR", '\015' }, + { "carriage-return", '\r' }, + { "SO", '\016' }, + { "SI", '\017' }, + { "DLE", '\020' }, + { "DC1", '\021' }, + { "DC2", '\022' }, + { "DC3", '\023' }, + { "DC4", '\024' }, + { "NAK", '\025' }, + { "SYN", '\026' }, + { "ETB", '\027' }, + { "CAN", '\030' }, + { "EM", '\031' }, + { "SUB", '\032' }, + { "ESC", '\033' }, + { "IS4", '\034' }, + { "FS", '\034' }, + { "IS3", '\035' }, + { "GS", '\035' }, + { "IS2", '\036' }, + { "RS", '\036' }, + { "IS1", '\037' }, + { "US", '\037' }, + { "space", ' ' }, + { "exclamation-mark", '!' }, + { "quotation-mark", '"' }, + { "number-sign", '#' }, + { "dollar-sign", '$' }, + { "percent-sign", '%' }, + { "ampersand", '&' }, + { "apostrophe", '\'' }, + { "left-parenthesis", '(' }, + { "right-parenthesis", ')' }, + { "asterisk", '*' }, + { "plus-sign", '+' }, + { "comma", ',' }, + { "hyphen", '-' }, + { "hyphen-minus", '-' }, + { "period", '.' }, + { "full-stop", '.' }, + { "slash", '/' }, + { "solidus", '/' }, + { "zero", '0' }, + { "one", '1' }, + { "two", '2' }, + { "three", '3' }, + { "four", '4' }, + { "five", '5' }, + { "six", '6' }, + { "seven", '7' }, + { "eight", '8' }, + { "nine", '9' }, + { "colon", ':' }, + { "semicolon", ';' }, + { "less-than-sign", '<' }, + { "equals-sign", '=' }, + { "greater-than-sign", '>' }, + { "question-mark", '?' }, + { "commercial-at", '@' }, + { "left-square-bracket", '[' }, + { "backslash", '\\' }, + { "reverse-solidus", '\\' }, + { "right-square-bracket", ']' }, + { "circumflex", '^' }, + { "circumflex-accent", '^' }, + { "underscore", '_' }, + { "low-line", '_' }, + { "grave-accent", '`' }, + { "left-brace", '{' }, + { "left-curly-bracket", '{' }, + { "vertical-line", '|' }, + { "right-brace", '}' }, + { "right-curly-bracket", '}' }, + { "tilde", '~' }, + { "DEL", '\177' }, + { NULL, 0 } +}; + /* * parse structure, passed up and down to avoid global variables and * other clumsinesses @@ -876,7 +1008,7 @@ p_b_coll_elem(struct parse *p, { char *sp = p->next; struct cname *cp; - int len; + size_t len; while (MORE() && !SEETWO(endc, ']')) NEXT(); @@ -886,7 +1018,7 @@ p_b_coll_elem(struct parse *p, } len = p->next - sp; for (cp = cnames; cp->name != NULL; cp++) - if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0') + if (strncmp(cp->name, sp, len) == 0 && strlen(cp->name) == len) return(cp->code); /* known name */ if (len == 1) return(*sp); /* single character */ diff --git a/lib/Support/regex2.h b/lib/Support/regex2.h index d81bfbc97d02..19d14cd14abb 100644 --- a/lib/Support/regex2.h +++ b/lib/Support/regex2.h @@ -38,6 +38,9 @@ #ifndef LLVM_SUPPORT_REGEX2_H #define LLVM_SUPPORT_REGEX2_H +#include "regutils.h" +#include <stddef.h> + /* * internals of regex_t */ |
