summaryrefslogtreecommitdiff
path: root/lib/Support
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
commit044eb2f6afba375a914ac9d8024f8f5142bb912e (patch)
tree1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /lib/Support
parenteb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff)
Notes
Diffstat (limited to 'lib/Support')
-rw-r--r--lib/Support/AMDGPUMetadata.cpp (renamed from lib/Support/AMDGPUCodeObjectMetadata.cpp)105
-rw-r--r--lib/Support/APFloat.cpp8
-rw-r--r--lib/Support/APInt.cpp10
-rw-r--r--lib/Support/ARMAttributeParser.cpp2
-rw-r--r--lib/Support/Atomic.cpp4
-rw-r--r--lib/Support/BinaryStreamRef.cpp22
-rw-r--r--lib/Support/BinaryStreamWriter.cpp3
-rw-r--r--lib/Support/BlockFrequency.cpp1
-rw-r--r--lib/Support/CMakeLists.txt10
-rw-r--r--lib/Support/CachePruning.cpp70
-rw-r--r--lib/Support/Chrono.cpp40
-rw-r--r--lib/Support/CodeGenCoverage.cpp120
-rw-r--r--lib/Support/CommandLine.cpp54
-rw-r--r--lib/Support/Error.cpp12
-rw-r--r--lib/Support/FileOutputBuffer.cpp213
-rw-r--r--lib/Support/FoldingSet.cpp9
-rw-r--r--lib/Support/FormatVariadic.cpp2
-rw-r--r--lib/Support/GlobPattern.cpp17
-rw-r--r--lib/Support/GraphWriter.cpp4
-rw-r--r--lib/Support/Host.cpp804
-rw-r--r--lib/Support/KnownBits.cpp65
-rw-r--r--lib/Support/LockFileManager.cpp99
-rw-r--r--lib/Support/LowLevelType.cpp2
-rw-r--r--lib/Support/MD5.cpp2
-rw-r--r--lib/Support/Parallel.cpp4
-rw-r--r--lib/Support/Path.cpp173
-rw-r--r--lib/Support/Process.cpp17
-rw-r--r--lib/Support/Program.cpp29
-rw-r--r--lib/Support/RandomNumberGenerator.cpp4
-rw-r--r--lib/Support/ScopedPrinter.cpp1
-rw-r--r--lib/Support/Signals.cpp6
-rw-r--r--lib/Support/SmallPtrSet.cpp20
-rw-r--r--lib/Support/SmallVector.cpp5
-rw-r--r--lib/Support/SourceMgr.cpp5
-rw-r--r--lib/Support/SpecialCaseList.cpp228
-rw-r--r--lib/Support/Statistic.cpp15
-rw-r--r--lib/Support/StringExtras.cpp6
-rw-r--r--lib/Support/StringMap.cpp15
-rw-r--r--lib/Support/StringRef.cpp39
-rw-r--r--lib/Support/TarWriter.cpp62
-rw-r--r--lib/Support/TargetParser.cpp339
-rw-r--r--lib/Support/TargetRegistry.cpp8
-rw-r--r--lib/Support/ThreadPool.cpp7
-rw-r--r--lib/Support/Threading.cpp14
-rw-r--r--lib/Support/Timer.cpp6
-rw-r--r--lib/Support/ToolOutputFile.cpp14
-rw-r--r--lib/Support/Triple.cpp108
-rw-r--r--lib/Support/Unix/DynamicLibrary.inc2
-rw-r--r--lib/Support/Unix/Memory.inc155
-rw-r--r--lib/Support/Unix/Path.inc92
-rw-r--r--lib/Support/Unix/Process.inc4
-rw-r--r--lib/Support/Unix/Program.inc64
-rw-r--r--lib/Support/Unix/Threading.inc10
-rw-r--r--lib/Support/Windows/Memory.inc80
-rw-r--r--lib/Support/Windows/Path.inc479
-rw-r--r--lib/Support/Windows/Process.inc5
-rw-r--r--lib/Support/Windows/Program.inc57
-rw-r--r--lib/Support/Windows/Signals.inc29
-rw-r--r--lib/Support/YAMLTraits.cpp63
-rw-r--r--lib/Support/raw_ostream.cpp70
-rw-r--r--lib/Support/regcclass.h75
-rw-r--r--lib/Support/regcname.h144
-rw-r--r--lib/Support/regcomp.c142
-rw-r--r--lib/Support/regex2.h3
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(), &LT);
+ 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
*/