aboutsummaryrefslogtreecommitdiff
path: root/lib/Support
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Support')
-rw-r--r--lib/Support/AMDGPUMetadata.cpp2
-rw-r--r--lib/Support/APFloat.cpp15
-rw-r--r--lib/Support/APInt.cpp188
-rw-r--r--lib/Support/ARMAttributeParser.cpp1
-rw-r--r--lib/Support/BinaryStreamRef.cpp2
-rw-r--r--lib/Support/BranchProbability.cpp1
-rw-r--r--lib/Support/CMakeLists.txt21
-rw-r--r--lib/Support/COM.cpp4
-rw-r--r--lib/Support/CachePruning.cpp28
-rw-r--r--lib/Support/Chrono.cpp4
-rw-r--r--lib/Support/CodeGenCoverage.cpp13
-rw-r--r--lib/Support/CommandLine.cpp96
-rw-r--r--lib/Support/CrashRecoveryContext.cpp10
-rw-r--r--lib/Support/DAGDeltaAlgorithm.cpp124
-rw-r--r--lib/Support/DJB.cpp86
-rw-r--r--lib/Support/Debug.cpp7
-rw-r--r--lib/Support/DebugCounter.cpp21
-rw-r--r--lib/Support/DynamicLibrary.cpp6
-rw-r--r--lib/Support/Error.cpp4
-rw-r--r--lib/Support/ErrorHandling.cpp35
-rw-r--r--lib/Support/FileOutputBuffer.cpp43
-rw-r--r--lib/Support/FoldingSet.cpp7
-rw-r--r--lib/Support/GraphWriter.cpp70
-rw-r--r--lib/Support/Host.cpp59
-rw-r--r--lib/Support/InitLLVM.cpp52
-rw-r--r--lib/Support/JSON.cpp693
-rw-r--r--lib/Support/Locale.cpp5
-rw-r--r--lib/Support/LockFileManager.cpp95
-rw-r--r--lib/Support/MD5.cpp4
-rw-r--r--lib/Support/ManagedStatic.cpp3
-rw-r--r--lib/Support/Memory.cpp4
-rw-r--r--lib/Support/MemoryBuffer.cpp89
-rw-r--r--lib/Support/Mutex.cpp11
-rw-r--r--lib/Support/NativeFormatting.cpp2
-rw-r--r--lib/Support/Parallel.cpp25
-rw-r--r--lib/Support/Path.cpp192
-rw-r--r--lib/Support/PrettyStackTrace.cpp8
-rw-r--r--lib/Support/Process.cpp4
-rw-r--r--lib/Support/Program.cpp29
-rw-r--r--lib/Support/RWMutex.cpp7
-rw-r--r--lib/Support/RandomNumberGenerator.cpp10
-rw-r--r--lib/Support/Regex.cpp15
-rw-r--r--lib/Support/SHA1.cpp2
-rw-r--r--lib/Support/Signals.cpp90
-rw-r--r--lib/Support/SmallPtrSet.cpp20
-rw-r--r--lib/Support/SmallVector.cpp50
-rw-r--r--lib/Support/SourceMgr.cpp126
-rw-r--r--lib/Support/Statistic.cpp87
-rw-r--r--lib/Support/StringExtras.cpp27
-rw-r--r--lib/Support/StringMap.cpp54
-rw-r--r--lib/Support/StringSaver.cpp7
-rw-r--r--lib/Support/TarWriter.cpp4
-rw-r--r--lib/Support/TargetParser.cpp40
-rw-r--r--lib/Support/ThreadLocal.cpp6
-rw-r--r--lib/Support/Threading.cpp4
-rw-r--r--lib/Support/Timer.cpp35
-rw-r--r--lib/Support/Triple.cpp22
-rw-r--r--lib/Support/Twine.cpp1
-rw-r--r--lib/Support/UnicodeCaseFold.cpp742
-rw-r--r--lib/Support/Unix/Host.inc2
-rw-r--r--lib/Support/Unix/Memory.inc12
-rw-r--r--lib/Support/Unix/Path.inc175
-rw-r--r--lib/Support/Unix/Process.inc31
-rw-r--r--lib/Support/Unix/Program.inc68
-rw-r--r--lib/Support/Unix/Signals.inc302
-rw-r--r--lib/Support/Unix/ThreadLocal.inc2
-rw-r--r--lib/Support/Unix/Threading.inc17
-rw-r--r--lib/Support/Unix/Unix.h2
-rw-r--r--lib/Support/Unix/Watchdog.inc2
-rw-r--r--lib/Support/VersionTuple.cpp110
-rw-r--r--lib/Support/Watchdog.cpp4
-rw-r--r--lib/Support/Windows/DynamicLibrary.inc1
-rw-r--r--lib/Support/Windows/Host.inc2
-rw-r--r--lib/Support/Windows/Path.inc379
-rw-r--r--lib/Support/Windows/Process.inc120
-rw-r--r--lib/Support/Windows/Program.inc215
-rw-r--r--lib/Support/Windows/RWMutex.inc4
-rw-r--r--lib/Support/Windows/Signals.inc49
-rw-r--r--lib/Support/Windows/WindowsSupport.h16
-rw-r--r--lib/Support/WithColor.cpp90
-rw-r--r--lib/Support/YAMLParser.cpp114
-rw-r--r--lib/Support/YAMLTraits.cpp43
-rw-r--r--lib/Support/circular_raw_ostream.cpp2
-rw-r--r--lib/Support/raw_ostream.cpp97
-rw-r--r--lib/Support/regcomp.c7
-rw-r--r--lib/Support/regengine.inc2
-rw-r--r--lib/Support/xxhash.cpp6
87 files changed, 3917 insertions, 1369 deletions
diff --git a/lib/Support/AMDGPUMetadata.cpp b/lib/Support/AMDGPUMetadata.cpp
index ddb25935e0ef..a04bfc2ea299 100644
--- a/lib/Support/AMDGPUMetadata.cpp
+++ b/lib/Support/AMDGPUMetadata.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
/// \file
-/// \brief AMDGPU metadata definitions and in-memory representations.
+/// AMDGPU metadata definitions and in-memory representations.
///
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp
index 3489feb93a02..24005c1890c9 100644
--- a/lib/Support/APFloat.cpp
+++ b/lib/Support/APFloat.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
@@ -3031,27 +3032,29 @@ double IEEEFloat::convertToDouble() const {
/// does not support these bit patterns:
/// exponent = all 1's, integer bit 0, significand 0 ("pseudoinfinity")
/// exponent = all 1's, integer bit 0, significand nonzero ("pseudoNaN")
-/// exponent = 0, integer bit 1 ("pseudodenormal")
/// exponent!=0 nor all 1's, integer bit 0 ("unnormal")
-/// At the moment, the first two are treated as NaNs, the second two as Normal.
+/// exponent = 0, integer bit 1 ("pseudodenormal")
+/// At the moment, the first three are treated as NaNs, the last one as Normal.
void IEEEFloat::initFromF80LongDoubleAPInt(const APInt &api) {
assert(api.getBitWidth()==80);
uint64_t i1 = api.getRawData()[0];
uint64_t i2 = api.getRawData()[1];
uint64_t myexponent = (i2 & 0x7fff);
uint64_t mysignificand = i1;
+ uint8_t myintegerbit = mysignificand >> 63;
initialize(&semX87DoubleExtended);
assert(partCount()==2);
sign = static_cast<unsigned int>(i2>>15);
- if (myexponent==0 && mysignificand==0) {
+ if (myexponent == 0 && mysignificand == 0) {
// exponent, significand meaningless
category = fcZero;
} else if (myexponent==0x7fff && mysignificand==0x8000000000000000ULL) {
// exponent, significand meaningless
category = fcInfinity;
- } else if (myexponent==0x7fff && mysignificand!=0x8000000000000000ULL) {
+ } else if ((myexponent == 0x7fff && mysignificand != 0x8000000000000000ULL) ||
+ (myexponent != 0x7fff && myexponent != 0 && myintegerbit == 0)) {
// exponent meaningless
category = fcNaN;
significandParts()[0] = mysignificand;
@@ -4440,8 +4443,10 @@ APFloat::APFloat(const fltSemantics &Semantics, StringRef S)
APFloat::opStatus APFloat::convert(const fltSemantics &ToSemantics,
roundingMode RM, bool *losesInfo) {
- if (&getSemantics() == &ToSemantics)
+ if (&getSemantics() == &ToSemantics) {
+ *losesInfo = false;
return opOK;
+ }
if (usesLayout<IEEEFloat>(getSemantics()) &&
usesLayout<IEEEFloat>(ToSemantics))
return U.IEEE.convert(ToSemantics, RM, losesInfo);
diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp
index 1ea6319acfad..1fae0e9b8d6d 100644
--- a/lib/Support/APInt.cpp
+++ b/lib/Support/APInt.cpp
@@ -18,6 +18,7 @@
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
@@ -33,8 +34,7 @@ using namespace llvm;
/// A utility function for allocating memory, checking for allocation failures,
/// and ensuring the contents are zeroed.
inline static uint64_t* getClearedMemory(unsigned numWords) {
- uint64_t * result = new uint64_t[numWords];
- assert(result && "APInt memory allocation fails!");
+ uint64_t *result = new uint64_t[numWords];
memset(result, 0, numWords * sizeof(uint64_t));
return result;
}
@@ -42,9 +42,7 @@ inline static uint64_t* getClearedMemory(unsigned numWords) {
/// A utility function for allocating memory and checking for allocation
/// failure. The content is not zeroed.
inline static uint64_t* getMemory(unsigned numWords) {
- uint64_t * result = new uint64_t[numWords];
- assert(result && "APInt memory allocation fails!");
- return result;
+ return new uint64_t[numWords];
}
/// A utility function that converts a character to a digit.
@@ -170,7 +168,7 @@ void APInt::Profile(FoldingSetNodeID& ID) const {
ID.AddInteger(U.pVal[i]);
}
-/// @brief Prefix increment operator. Increments the APInt by one.
+/// Prefix increment operator. Increments the APInt by one.
APInt& APInt::operator++() {
if (isSingleWord())
++U.VAL;
@@ -179,7 +177,7 @@ APInt& APInt::operator++() {
return clearUnusedBits();
}
-/// @brief Prefix decrement operator. Decrements the APInt by one.
+/// Prefix decrement operator. Decrements the APInt by one.
APInt& APInt::operator--() {
if (isSingleWord())
--U.VAL;
@@ -190,7 +188,7 @@ APInt& APInt::operator--() {
/// Adds the RHS APint to this APInt.
/// @returns this, after addition of RHS.
-/// @brief Addition assignment operator.
+/// Addition assignment operator.
APInt& APInt::operator+=(const APInt& RHS) {
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
if (isSingleWord())
@@ -210,7 +208,7 @@ APInt& APInt::operator+=(uint64_t RHS) {
/// Subtracts the RHS APInt from this APInt
/// @returns this, after subtraction
-/// @brief Subtraction assignment operator.
+/// Subtraction assignment operator.
APInt& APInt::operator-=(const APInt& RHS) {
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
if (isSingleWord())
@@ -328,7 +326,7 @@ void APInt::setBitsSlowCase(unsigned loBit, unsigned hiBit) {
U.pVal[word] = WORD_MAX;
}
-/// @brief Toggle every bit to its opposite value.
+/// Toggle every bit to its opposite value.
void APInt::flipAllBitsSlowCase() {
tcComplement(U.pVal, getNumWords());
clearUnusedBits();
@@ -336,7 +334,7 @@ void APInt::flipAllBitsSlowCase() {
/// Toggle a given bit to its opposite value whose position is given
/// as "bitPosition".
-/// @brief Toggles a given bit to its opposite value.
+/// Toggles a given bit to its opposite value.
void APInt::flipBit(unsigned bitPosition) {
assert(bitPosition < BitWidth && "Out of the bit-width range!");
if ((*this)[bitPosition]) clearBit(bitPosition);
@@ -428,11 +426,12 @@ APInt APInt::extractBits(unsigned numBits, unsigned bitPosition) const {
unsigned NumSrcWords = getNumWords();
unsigned NumDstWords = Result.getNumWords();
+ uint64_t *DestPtr = Result.isSingleWord() ? &Result.U.VAL : Result.U.pVal;
for (unsigned word = 0; word < NumDstWords; ++word) {
uint64_t w0 = U.pVal[loWord + word];
uint64_t w1 =
(loWord + word + 1) < NumSrcWords ? U.pVal[loWord + word + 1] : 0;
- Result.U.pVal[word] = (w0 >> loBit) | (w1 << (APINT_BITS_PER_WORD - loBit));
+ DestPtr[word] = (w0 >> loBit) | (w1 << (APINT_BITS_PER_WORD - loBit));
}
return Result.clearUnusedBits();
@@ -909,13 +908,13 @@ APInt APInt::sextOrSelf(unsigned width) const {
}
/// Arithmetic right-shift this APInt by shiftAmt.
-/// @brief Arithmetic right-shift function.
+/// Arithmetic right-shift function.
void APInt::ashrInPlace(const APInt &shiftAmt) {
ashrInPlace((unsigned)shiftAmt.getLimitedValue(BitWidth));
}
/// Arithmetic right-shift this APInt by shiftAmt.
-/// @brief Arithmetic right-shift function.
+/// Arithmetic right-shift function.
void APInt::ashrSlowCase(unsigned ShiftAmt) {
// Don't bother performing a no-op shift.
if (!ShiftAmt)
@@ -924,7 +923,7 @@ void APInt::ashrSlowCase(unsigned ShiftAmt) {
// Save the original sign bit for later.
bool Negative = isNegative();
- // WordShift is the inter-part shift; BitShift is is intra-part shift.
+ // WordShift is the inter-part shift; BitShift is intra-part shift.
unsigned WordShift = ShiftAmt / APINT_BITS_PER_WORD;
unsigned BitShift = ShiftAmt % APINT_BITS_PER_WORD;
@@ -958,19 +957,19 @@ void APInt::ashrSlowCase(unsigned ShiftAmt) {
}
/// Logical right-shift this APInt by shiftAmt.
-/// @brief Logical right-shift function.
+/// Logical right-shift function.
void APInt::lshrInPlace(const APInt &shiftAmt) {
lshrInPlace((unsigned)shiftAmt.getLimitedValue(BitWidth));
}
/// Logical right-shift this APInt by shiftAmt.
-/// @brief Logical right-shift function.
+/// Logical right-shift function.
void APInt::lshrSlowCase(unsigned ShiftAmt) {
tcShiftRight(U.pVal, getNumWords(), ShiftAmt);
}
/// Left-shift this APInt by shiftAmt.
-/// @brief Left-shift function.
+/// Left-shift function.
APInt &APInt::operator<<=(const APInt &shiftAmt) {
// It's undefined behavior in C to shift by BitWidth or greater.
*this <<= (unsigned)shiftAmt.getLimitedValue(BitWidth);
@@ -1254,18 +1253,20 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,
// 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")
+#pragma push_macro("LLVM_DEBUG")
#ifndef KNUTH_DEBUG
-#undef DEBUG
-#define DEBUG(X) do {} while (false)
+#undef LLVM_DEBUG
+#define LLVM_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]);
- DEBUG(dbgs() << " by");
- DEBUG(for (int i = n; i >0; i--) dbgs() << " " << v[i-1]);
- DEBUG(dbgs() << '\n');
+ LLVM_DEBUG(dbgs() << "KnuthDiv: m=" << m << " n=" << n << '\n');
+ LLVM_DEBUG(dbgs() << "KnuthDiv: original:");
+ LLVM_DEBUG(for (int i = m + n; i >= 0; i--) dbgs() << " " << u[i]);
+ LLVM_DEBUG(dbgs() << " by");
+ LLVM_DEBUG(for (int i = n; i > 0; i--) dbgs() << " " << v[i - 1]);
+ LLVM_DEBUG(dbgs() << '\n');
// D1. [Normalize.] Set d = b / (v[n-1] + 1) and multiply all the digits of
// u and v by d. Note that we have taken Knuth's advice here to use a power
// of 2 value for d such that d * v[n-1] >= b/2 (b is the base). A power of
@@ -1291,16 +1292,16 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,
}
u[m+n] = u_carry;
- DEBUG(dbgs() << "KnuthDiv: normal:");
- DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]);
- DEBUG(dbgs() << " by");
- DEBUG(for (int i = n; i >0; i--) dbgs() << " " << v[i-1]);
- DEBUG(dbgs() << '\n');
+ LLVM_DEBUG(dbgs() << "KnuthDiv: normal:");
+ LLVM_DEBUG(for (int i = m + n; i >= 0; i--) dbgs() << " " << u[i]);
+ LLVM_DEBUG(dbgs() << " by");
+ LLVM_DEBUG(for (int i = n; i > 0; i--) dbgs() << " " << v[i - 1]);
+ LLVM_DEBUG(dbgs() << '\n');
// D2. [Initialize j.] Set j to m. This is the loop counter over the places.
int j = m;
do {
- DEBUG(dbgs() << "KnuthDiv: quotient digit #" << j << '\n');
+ LLVM_DEBUG(dbgs() << "KnuthDiv: quotient digit #" << j << '\n');
// D3. [Calculate q'.].
// Set qp = (u[j+n]*b + u[j+n-1]) / v[n-1]. (qp=qprime=q')
// Set rp = (u[j+n]*b + u[j+n-1]) % v[n-1]. (rp=rprime=r')
@@ -1310,7 +1311,7 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,
// value qp is one too large, and it eliminates all cases where qp is two
// too large.
uint64_t dividend = Make_64(u[j+n], u[j+n-1]);
- DEBUG(dbgs() << "KnuthDiv: dividend == " << dividend << '\n');
+ LLVM_DEBUG(dbgs() << "KnuthDiv: dividend == " << dividend << '\n');
uint64_t qp = dividend / v[n-1];
uint64_t rp = dividend % v[n-1];
if (qp == b || qp*v[n-2] > b*rp + u[j+n-2]) {
@@ -1319,7 +1320,7 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,
if (rp < b && (qp == b || qp*v[n-2] > b*rp + u[j+n-2]))
qp--;
}
- DEBUG(dbgs() << "KnuthDiv: qp == " << qp << ", rp == " << rp << '\n');
+ LLVM_DEBUG(dbgs() << "KnuthDiv: qp == " << qp << ", rp == " << rp << '\n');
// D4. [Multiply and subtract.] Replace (u[j+n]u[j+n-1]...u[j]) with
// (u[j+n]u[j+n-1]..u[j]) - qp * (v[n-1]...v[1]v[0]). This computation
@@ -1335,15 +1336,15 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,
int64_t subres = int64_t(u[j+i]) - borrow - Lo_32(p);
u[j+i] = Lo_32(subres);
borrow = Hi_32(p) - Hi_32(subres);
- DEBUG(dbgs() << "KnuthDiv: u[j+i] = " << u[j+i]
- << ", borrow = " << borrow << '\n');
+ LLVM_DEBUG(dbgs() << "KnuthDiv: u[j+i] = " << u[j + i]
+ << ", borrow = " << borrow << '\n');
}
bool isNeg = u[j+n] < borrow;
u[j+n] -= Lo_32(borrow);
- DEBUG(dbgs() << "KnuthDiv: after subtraction:");
- DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]);
- DEBUG(dbgs() << '\n');
+ LLVM_DEBUG(dbgs() << "KnuthDiv: after subtraction:");
+ LLVM_DEBUG(for (int i = m + n; i >= 0; i--) dbgs() << " " << u[i]);
+ LLVM_DEBUG(dbgs() << '\n');
// D5. [Test remainder.] Set q[j] = qp. If the result of step D4 was
// negative, go to step D6; otherwise go on to step D7.
@@ -1364,16 +1365,16 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,
}
u[j+n] += carry;
}
- DEBUG(dbgs() << "KnuthDiv: after correction:");
- DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]);
- DEBUG(dbgs() << "\nKnuthDiv: digit result = " << q[j] << '\n');
+ LLVM_DEBUG(dbgs() << "KnuthDiv: after correction:");
+ LLVM_DEBUG(for (int i = m + n; i >= 0; i--) dbgs() << " " << u[i]);
+ LLVM_DEBUG(dbgs() << "\nKnuthDiv: digit result = " << q[j] << '\n');
- // D7. [Loop on j.] Decrease j by one. Now if j >= 0, go back to D3.
+ // D7. [Loop on j.] Decrease j by one. Now if j >= 0, go back to D3.
} while (--j >= 0);
- DEBUG(dbgs() << "KnuthDiv: quotient:");
- DEBUG(for (int i = m; i >=0; i--) dbgs() <<" " << q[i]);
- DEBUG(dbgs() << '\n');
+ LLVM_DEBUG(dbgs() << "KnuthDiv: quotient:");
+ LLVM_DEBUG(for (int i = m; i >= 0; i--) dbgs() << " " << q[i]);
+ LLVM_DEBUG(dbgs() << '\n');
// D8. [Unnormalize]. Now q[...] is the desired quotient, and the desired
// remainder may be obtained by dividing u[...] by d. If r is non-null we
@@ -1384,23 +1385,23 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,
// shift right here.
if (shift) {
uint32_t carry = 0;
- DEBUG(dbgs() << "KnuthDiv: remainder:");
+ LLVM_DEBUG(dbgs() << "KnuthDiv: remainder:");
for (int i = n-1; i >= 0; i--) {
r[i] = (u[i] >> shift) | carry;
carry = u[i] << (32 - shift);
- DEBUG(dbgs() << " " << r[i]);
+ LLVM_DEBUG(dbgs() << " " << r[i]);
}
} else {
for (int i = n-1; i >= 0; i--) {
r[i] = u[i];
- DEBUG(dbgs() << " " << r[i]);
+ LLVM_DEBUG(dbgs() << " " << r[i]);
}
}
- DEBUG(dbgs() << '\n');
+ LLVM_DEBUG(dbgs() << '\n');
}
- DEBUG(dbgs() << '\n');
+ LLVM_DEBUG(dbgs() << '\n');
-#pragma pop_macro("DEBUG")
+#pragma pop_macro("LLVM_DEBUG")
}
void APInt::divide(const WordType *LHS, unsigned lhsWords, const WordType *RHS,
@@ -1734,25 +1735,25 @@ void APInt::udivrem(const APInt &LHS, const APInt &RHS,
// Check the degenerate cases
if (lhsWords == 0) {
- Quotient = 0; // 0 / Y ===> 0
- Remainder = 0; // 0 % Y ===> 0
+ Quotient = APInt(BitWidth, 0); // 0 / Y ===> 0
+ Remainder = APInt(BitWidth, 0); // 0 % Y ===> 0
return;
}
if (rhsBits == 1) {
- Quotient = LHS; // X / 1 ===> X
- Remainder = 0; // X % 1 ===> 0
+ Quotient = LHS; // X / 1 ===> X
+ Remainder = APInt(BitWidth, 0); // X % 1 ===> 0
}
if (lhsWords < rhsWords || LHS.ult(RHS)) {
- Remainder = LHS; // X % Y ===> X, iff X < Y
- Quotient = 0; // X / Y ===> 0, iff X < Y
+ Remainder = LHS; // X % Y ===> X, iff X < Y
+ Quotient = APInt(BitWidth, 0); // X / Y ===> 0, iff X < Y
return;
}
if (LHS == RHS) {
- Quotient = 1; // X / X ===> 1
- Remainder = 0; // X % X ===> 0;
+ Quotient = APInt(BitWidth, 1); // X / X ===> 1
+ Remainder = APInt(BitWidth, 0); // X % X ===> 0;
return;
}
@@ -1800,25 +1801,26 @@ void APInt::udivrem(const APInt &LHS, uint64_t RHS, APInt &Quotient,
// Check the degenerate cases
if (lhsWords == 0) {
- Quotient = 0; // 0 / Y ===> 0
- Remainder = 0; // 0 % Y ===> 0
+ Quotient = APInt(BitWidth, 0); // 0 / Y ===> 0
+ Remainder = 0; // 0 % Y ===> 0
return;
}
if (RHS == 1) {
- Quotient = LHS; // X / 1 ===> X
- Remainder = 0; // X % 1 ===> 0
+ Quotient = LHS; // X / 1 ===> X
+ Remainder = 0; // X % 1 ===> 0
+ return;
}
if (LHS.ult(RHS)) {
- Remainder = LHS.getZExtValue(); // X % Y ===> X, iff X < Y
- Quotient = 0; // X / Y ===> 0, iff X < Y
+ Remainder = LHS.getZExtValue(); // X % Y ===> X, iff X < Y
+ Quotient = APInt(BitWidth, 0); // X / Y ===> 0, iff X < Y
return;
}
if (LHS == RHS) {
- Quotient = 1; // X / X ===> 1
- Remainder = 0; // X % X ===> 0;
+ Quotient = APInt(BitWidth, 1); // X / X ===> 1
+ Remainder = 0; // X % X ===> 0;
return;
}
@@ -2657,3 +2659,51 @@ void APInt::tcSetLeastSignificantBits(WordType *dst, unsigned parts,
while (i < parts)
dst[i++] = 0;
}
+
+APInt llvm::APIntOps::RoundingUDiv(const APInt &A, const APInt &B,
+ APInt::Rounding RM) {
+ // Currently udivrem always rounds down.
+ switch (RM) {
+ case APInt::Rounding::DOWN:
+ case APInt::Rounding::TOWARD_ZERO:
+ return A.udiv(B);
+ case APInt::Rounding::UP: {
+ APInt Quo, Rem;
+ APInt::udivrem(A, B, Quo, Rem);
+ if (Rem == 0)
+ return Quo;
+ return Quo + 1;
+ }
+ }
+ llvm_unreachable("Unknown APInt::Rounding enum");
+}
+
+APInt llvm::APIntOps::RoundingSDiv(const APInt &A, const APInt &B,
+ APInt::Rounding RM) {
+ switch (RM) {
+ case APInt::Rounding::DOWN:
+ case APInt::Rounding::UP: {
+ APInt Quo, Rem;
+ APInt::sdivrem(A, B, Quo, Rem);
+ if (Rem == 0)
+ return Quo;
+ // This algorithm deals with arbitrary rounding mode used by sdivrem.
+ // We want to check whether the non-integer part of the mathematical value
+ // is negative or not. If the non-integer part is negative, we need to round
+ // down from Quo; otherwise, if it's positive or 0, we return Quo, as it's
+ // already rounded down.
+ if (RM == APInt::Rounding::DOWN) {
+ if (Rem.isNegative() != B.isNegative())
+ return Quo - 1;
+ return Quo;
+ }
+ if (Rem.isNegative() != B.isNegative())
+ return Quo;
+ return Quo + 1;
+ }
+ // Currently sdiv rounds twards zero.
+ case APInt::Rounding::TOWARD_ZERO:
+ return A.sdiv(B);
+ }
+ llvm_unreachable("Unknown APInt::Rounding enum");
+}
diff --git a/lib/Support/ARMAttributeParser.cpp b/lib/Support/ARMAttributeParser.cpp
index e39bddc4e8f2..1f98ac2f40ba 100644
--- a/lib/Support/ARMAttributeParser.cpp
+++ b/lib/Support/ARMAttributeParser.cpp
@@ -705,4 +705,3 @@ void ARMAttributeParser::Parse(ArrayRef<uint8_t> Section, bool isLittle) {
}
}
}
-
diff --git a/lib/Support/BinaryStreamRef.cpp b/lib/Support/BinaryStreamRef.cpp
index 60a03fe9930f..bdc0f54bf25a 100644
--- a/lib/Support/BinaryStreamRef.cpp
+++ b/lib/Support/BinaryStreamRef.cpp
@@ -127,5 +127,5 @@ WritableBinaryStreamRef::operator BinaryStreamRef() const {
return BinaryStreamRef(*BorrowedImpl, ViewOffset, Length);
}
-/// \brief For buffered streams, commits changes to the backing store.
+/// For buffered streams, commits changes to the backing store.
Error WritableBinaryStreamRef::commit() { return BorrowedImpl->commit(); }
diff --git a/lib/Support/BranchProbability.cpp b/lib/Support/BranchProbability.cpp
index 44ad110d456a..31dee9561f49 100644
--- a/lib/Support/BranchProbability.cpp
+++ b/lib/Support/BranchProbability.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/BranchProbability.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt
index 5723f8fcf5bb..5688c1a8aef2 100644
--- a/lib/Support/CMakeLists.txt
+++ b/lib/Support/CMakeLists.txt
@@ -4,7 +4,8 @@ if ( LLVM_ENABLE_ZLIB AND HAVE_LIBZ )
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)
+ # advapi32 required for CryptAcquireContextW in lib/Support/Windows/Path.inc.
+ set(system_libs ${system_libs} psapi shell32 ole32 uuid advapi32)
elseif( CMAKE_HOST_UNIX )
if( HAVE_LIBRT )
set(system_libs ${system_libs} rt)
@@ -12,8 +13,13 @@ elseif( CMAKE_HOST_UNIX )
if( HAVE_LIBDL )
set(system_libs ${system_libs} ${CMAKE_DL_LIBS})
endif()
- if( HAVE_BACKTRACE )
- set(system_libs ${system_libs} ${Backtrace_LIBRARIES})
+ if( HAVE_BACKTRACE AND NOT "${Backtrace_LIBRARIES}" STREQUAL "" )
+ # On BSDs, CMake returns a fully qualified path to the backtrace library.
+ # We need to remove the path and the 'lib' prefix, to make it look like a
+ # regular short library name, suitable for appending to a -l link flag.
+ get_filename_component(Backtrace_LIBFILE ${Backtrace_LIBRARIES} NAME_WE)
+ STRING(REGEX REPLACE "^lib" "" Backtrace_LIBFILE ${Backtrace_LIBFILE})
+ set(system_libs ${system_libs} ${Backtrace_LIBFILE})
endif()
if(LLVM_ENABLE_TERMINFO)
if(HAVE_TERMINFO)
@@ -27,6 +33,9 @@ elseif( CMAKE_HOST_UNIX )
if( UNIX AND NOT (BEOS OR HAIKU) )
set(system_libs ${system_libs} m)
endif()
+ if( FUCHSIA )
+ set(system_libs ${system_libs} zircon)
+ endif()
endif( MSVC OR MINGW )
add_llvm_library(LLVMSupport
@@ -59,6 +68,7 @@ add_llvm_library(LLVMSupport
DebugCounter.cpp
DeltaAlgorithm.cpp
DAGDeltaAlgorithm.cpp
+ DJB.cpp
Error.cpp
ErrorHandling.cpp
FileUtilities.cpp
@@ -69,9 +79,11 @@ add_llvm_library(LLVMSupport
GlobPattern.cpp
GraphWriter.cpp
Hashing.cpp
+ InitLLVM.cpp
IntEqClasses.cpp
IntervalMap.cpp
JamCRC.cpp
+ JSON.cpp
KnownBits.cpp
LEB128.cpp
LineIterator.cpp
@@ -112,6 +124,9 @@ add_llvm_library(LLVMSupport
Triple.cpp
Twine.cpp
Unicode.cpp
+ UnicodeCaseFold.cpp
+ VersionTuple.cpp
+ WithColor.cpp
YAMLParser.cpp
YAMLTraits.cpp
raw_os_ostream.cpp
diff --git a/lib/Support/COM.cpp b/lib/Support/COM.cpp
index cf3a133fd9b4..2e3ff66843d3 100644
--- a/lib/Support/COM.cpp
+++ b/lib/Support/COM.cpp
@@ -13,11 +13,11 @@
#include "llvm/Support/COM.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
// Include the platform-specific parts of this class.
#ifdef LLVM_ON_UNIX
#include "Unix/COM.inc"
-#elif LLVM_ON_WIN32
+#elif _WIN32
#include "Windows/COM.inc"
#endif
diff --git a/lib/Support/CachePruning.cpp b/lib/Support/CachePruning.cpp
index 141573c2a1c7..7326c4fc91fb 100644
--- a/lib/Support/CachePruning.cpp
+++ b/lib/Support/CachePruning.cpp
@@ -146,7 +146,7 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) {
if (Policy.Expiration == seconds(0) &&
Policy.MaxSizePercentageOfAvailableSpace == 0 &&
Policy.MaxSizeBytes == 0 && Policy.MaxSizeFiles == 0) {
- DEBUG(dbgs() << "No pruning settings set, exit early\n");
+ LLVM_DEBUG(dbgs() << "No pruning settings set, exit early\n");
// Nothing will be pruned, early exit
return false;
}
@@ -173,9 +173,9 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) {
const auto TimeStampModTime = FileStatus.getLastModificationTime();
auto TimeStampAge = CurrentTime - TimeStampModTime;
if (TimeStampAge <= *Policy.Interval) {
- DEBUG(dbgs() << "Timestamp file too recent ("
- << duration_cast<seconds>(TimeStampAge).count()
- << "s old), do not prune.\n");
+ LLVM_DEBUG(dbgs() << "Timestamp file too recent ("
+ << duration_cast<seconds>(TimeStampAge).count()
+ << "s old), do not prune.\n");
return false;
}
}
@@ -207,7 +207,7 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) {
// there.
ErrorOr<sys::fs::basic_file_status> StatusOrErr = File->status();
if (!StatusOrErr) {
- DEBUG(dbgs() << "Ignore " << File->path() << " (can't stat)\n");
+ LLVM_DEBUG(dbgs() << "Ignore " << File->path() << " (can't stat)\n");
continue;
}
@@ -215,8 +215,9 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) {
const auto FileAccessTime = StatusOrErr->getLastAccessedTime();
auto FileAge = CurrentTime - FileAccessTime;
if (Policy.Expiration != seconds(0) && FileAge > Policy.Expiration) {
- DEBUG(dbgs() << "Remove " << File->path() << " ("
- << duration_cast<seconds>(FileAge).count() << "s old)\n");
+ LLVM_DEBUG(dbgs() << "Remove " << File->path() << " ("
+ << duration_cast<seconds>(FileAge).count()
+ << "s old)\n");
sys::fs::remove(File->path());
continue;
}
@@ -235,9 +236,9 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) {
// Update size
TotalSize -= FileAndSize->first;
NumFiles--;
- DEBUG(dbgs() << " - Remove " << FileAndSize->second << " (size "
- << FileAndSize->first << "), new occupancy is " << TotalSize
- << "%\n");
+ LLVM_DEBUG(dbgs() << " - Remove " << FileAndSize->second << " (size "
+ << FileAndSize->first << "), new occupancy is "
+ << TotalSize << "%\n");
++FileAndSize;
};
@@ -263,9 +264,10 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) {
AvailableSpace * Policy.MaxSizePercentageOfAvailableSpace / 100ull,
Policy.MaxSizeBytes);
- DEBUG(dbgs() << "Occupancy: " << ((100 * TotalSize) / AvailableSpace)
- << "% target is: " << Policy.MaxSizePercentageOfAvailableSpace
- << "%, " << Policy.MaxSizeBytes << " bytes\n");
+ LLVM_DEBUG(dbgs() << "Occupancy: " << ((100 * TotalSize) / AvailableSpace)
+ << "% target is: "
+ << Policy.MaxSizePercentageOfAvailableSpace << "%, "
+ << Policy.MaxSizeBytes << " bytes\n");
// Remove the oldest accessed files first, till we get below the threshold.
while (TotalSize > TotalSizeTarget && FileAndSize != FileSizes.rend())
diff --git a/lib/Support/Chrono.cpp b/lib/Support/Chrono.cpp
index 84f5aab6fc45..a2626a89eb63 100644
--- a/lib/Support/Chrono.cpp
+++ b/lib/Support/Chrono.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Chrono.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
@@ -32,7 +32,7 @@ static inline struct tm getStructTM(TimePoint<> TP) {
assert(LT);
(void)LT;
#endif
-#if defined(LLVM_ON_WIN32)
+#if defined(_WIN32)
int Error = ::localtime_s(&Storage, &OurTime);
assert(!Error);
(void)Error;
diff --git a/lib/Support/CodeGenCoverage.cpp b/lib/Support/CodeGenCoverage.cpp
index ebfe65a398c3..f0a53db4e32a 100644
--- a/lib/Support/CodeGenCoverage.cpp
+++ b/lib/Support/CodeGenCoverage.cpp
@@ -12,7 +12,7 @@
#include "llvm/Support/CodeGenCoverage.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -22,7 +22,7 @@
#if LLVM_ON_UNIX
#include <unistd.h>
-#elif LLVM_ON_WIN32
+#elif _WIN32
#include <windows.h>
#endif
@@ -38,12 +38,17 @@ void CodeGenCoverage::setCovered(uint64_t RuleID) {
RuleCoverage[RuleID] = true;
}
-bool CodeGenCoverage::isCovered(uint64_t RuleID) {
+bool CodeGenCoverage::isCovered(uint64_t RuleID) const {
if (RuleCoverage.size() <= RuleID)
return false;
return RuleCoverage[RuleID];
}
+iterator_range<CodeGenCoverage::const_covered_iterator>
+CodeGenCoverage::covered() const {
+ return RuleCoverage.set_bits();
+}
+
bool CodeGenCoverage::parse(MemoryBuffer &Buffer, StringRef BackendName) {
const char *CurPtr = Buffer.getBufferStart();
@@ -88,7 +93,7 @@ bool CodeGenCoverage::emit(StringRef CoveragePrefix,
std::string Pid =
#if LLVM_ON_UNIX
llvm::to_string(::getpid());
-#elif LLVM_ON_WIN32
+#elif _WIN32
llvm::to_string(::GetCurrentProcessId());
#else
"";
diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp
index 4caf4a4fdce0..a1e659a01c8e 100644
--- a/lib/Support/CommandLine.cpp
+++ b/lib/Support/CommandLine.cpp
@@ -25,6 +25,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Config/config.h"
#include "llvm/Support/ConvertUTF.h"
@@ -873,6 +874,45 @@ void cl::TokenizeWindowsCommandLine(StringRef Src, StringSaver &Saver,
NewArgv.push_back(nullptr);
}
+void cl::tokenizeConfigFile(StringRef Source, StringSaver &Saver,
+ SmallVectorImpl<const char *> &NewArgv,
+ bool MarkEOLs) {
+ for (const char *Cur = Source.begin(); Cur != Source.end();) {
+ SmallString<128> Line;
+ // Check for comment line.
+ if (isWhitespace(*Cur)) {
+ while (Cur != Source.end() && isWhitespace(*Cur))
+ ++Cur;
+ continue;
+ }
+ if (*Cur == '#') {
+ while (Cur != Source.end() && *Cur != '\n')
+ ++Cur;
+ continue;
+ }
+ // Find end of the current line.
+ const char *Start = Cur;
+ for (const char *End = Source.end(); Cur != End; ++Cur) {
+ if (*Cur == '\\') {
+ if (Cur + 1 != End) {
+ ++Cur;
+ if (*Cur == '\n' ||
+ (*Cur == '\r' && (Cur + 1 != End) && Cur[1] == '\n')) {
+ Line.append(Start, Cur - 1);
+ if (*Cur == '\r')
+ ++Cur;
+ Start = Cur + 1;
+ }
+ }
+ } else if (*Cur == '\n')
+ break;
+ }
+ // Tokenize line.
+ Line.append(Start, Cur);
+ cl::TokenizeGNUCommandLine(Line, Saver, NewArgv, MarkEOLs);
+ }
+}
+
// It is called byte order marker but the UTF-8 BOM is actually not affected
// by the host system's endianness.
static bool hasUTF8ByteOrderMark(ArrayRef<char> S) {
@@ -934,7 +974,7 @@ static bool ExpandResponseFile(StringRef FName, StringSaver &Saver,
return true;
}
-/// \brief Expand response files on a command line recursively using the given
+/// Expand response files on a command line recursively using the given
/// StringSaver and tokenization strategy.
bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
SmallVectorImpl<const char *> &Argv,
@@ -977,6 +1017,15 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
return AllExpanded;
}
+bool cl::readConfigFile(StringRef CfgFile, StringSaver &Saver,
+ SmallVectorImpl<const char *> &Argv) {
+ if (!ExpandResponseFile(CfgFile, Saver, cl::tokenizeConfigFile, Argv,
+ /*MarkEOLs*/ false, /*RelativeNames*/ true))
+ return false;
+ return ExpandResponseFiles(Saver, cl::tokenizeConfigFile, Argv,
+ /*MarkEOLs*/ false, /*RelativeNames*/ true);
+}
+
/// ParseEnvironmentOptions - An alternative entry point to the
/// CommandLine library, which allows you to read the program's name
/// from the caller (as PROGNAME) and its command-line arguments from
@@ -1032,7 +1081,10 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
SmallVector<const char *, 20> newArgv(argv, argv + argc);
BumpPtrAllocator A;
StringSaver Saver(A);
- ExpandResponseFiles(Saver, TokenizeGNUCommandLine, newArgv);
+ ExpandResponseFiles(Saver,
+ Triple(sys::getProcessTriple()).isOSWindows() ?
+ cl::TokenizeWindowsCommandLine : cl::TokenizeGNUCommandLine,
+ newArgv);
argv = &newArgv[0];
argc = static_cast<int>(newArgv.size());
@@ -1218,8 +1270,15 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
// If this is a named positional argument, just remember that it is the
// active one...
- if (Handler->getFormattingFlag() == cl::Positional)
+ if (Handler->getFormattingFlag() == cl::Positional) {
+ if ((Handler->getMiscFlags() & PositionalEatsArgs) && !Value.empty()) {
+ Handler->error("This argument does not take a value.\n"
+ "\tInstead, it consumes any positional arguments until "
+ "the next recognized option.", *Errs);
+ ErrorParsing = true;
+ }
ActivePositionalArg = Handler;
+ }
else
ErrorParsing |= ProvideOption(Handler, ArgName, Value, argc, argv, i);
}
@@ -1323,9 +1382,9 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
// Now that we know if -debug is specified, we can use it.
// Note that if ReadResponseFiles == true, this must be done before the
// memory allocated for the expanded command line is free()d below.
- DEBUG(dbgs() << "Args: ";
- for (int i = 0; i < argc; ++i) dbgs() << argv[i] << ' ';
- dbgs() << '\n';);
+ LLVM_DEBUG(dbgs() << "Args: ";
+ for (int i = 0; i < argc; ++i) dbgs() << argv[i] << ' ';
+ dbgs() << '\n';);
// Free all of the memory allocated to the map. Command line options may only
// be processed once!
@@ -1344,15 +1403,15 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
// Option Base class implementation
//
-bool Option::error(const Twine &Message, StringRef ArgName) {
+bool Option::error(const Twine &Message, StringRef ArgName, raw_ostream &Errs) {
if (!ArgName.data())
ArgName = ArgStr;
if (ArgName.empty())
- errs() << HelpStr; // Be nice for positional arguments
+ Errs << HelpStr; // Be nice for positional arguments
else
- errs() << GlobalParser->ProgramName << ": for the -" << ArgName;
+ Errs << GlobalParser->ProgramName << ": for the -" << ArgName;
- errs() << " option: " << Message << "\n";
+ Errs << " option: " << Message << "\n";
return true;
}
@@ -1422,8 +1481,12 @@ void alias::printOptionInfo(size_t GlobalWidth) const {
size_t basic_parser_impl::getOptionWidth(const Option &O) const {
size_t Len = O.ArgStr.size();
auto ValName = getValueName();
- if (!ValName.empty())
- Len += getValueStr(O, ValName).size() + 3;
+ if (!ValName.empty()) {
+ size_t FormattingLen = 3;
+ if (O.getMiscFlags() & PositionalEatsArgs)
+ FormattingLen = 6;
+ Len += getValueStr(O, ValName).size() + FormattingLen;
+ }
return Len + 6;
}
@@ -1436,8 +1499,13 @@ void basic_parser_impl::printOptionInfo(const Option &O,
outs() << " -" << O.ArgStr;
auto ValName = getValueName();
- if (!ValName.empty())
- outs() << "=<" << getValueStr(O, ValName) << '>';
+ if (!ValName.empty()) {
+ if (O.getMiscFlags() & PositionalEatsArgs) {
+ outs() << " <" << getValueStr(O, ValName) << ">...";
+ } else {
+ outs() << "=<" << getValueStr(O, ValName) << '>';
+ }
+ }
Option::printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O));
}
diff --git a/lib/Support/CrashRecoveryContext.cpp b/lib/Support/CrashRecoveryContext.cpp
index bd38dd88201f..fd5d097d2b7e 100644
--- a/lib/Support/CrashRecoveryContext.cpp
+++ b/lib/Support/CrashRecoveryContext.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/CrashRecoveryContext.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Mutex.h"
@@ -47,7 +47,7 @@ public:
CurrentContext->set(Next);
}
- /// \brief Called when the separate crash-recovery thread was finished, to
+ /// Called when the separate crash-recovery thread was finished, to
/// indicate that we don't need to clear the thread-local CurrentContext.
void setSwitchedThread() {
#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
@@ -189,7 +189,7 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
#else // !_MSC_VER
-#if defined(LLVM_ON_WIN32)
+#if defined(_WIN32)
// This is a non-MSVC compiler, probably mingw gcc or clang without
// -fms-extensions. Use vectored exception handling (VEH).
//
@@ -272,7 +272,7 @@ static void uninstallExceptionOrSignalHandlers() {
}
}
-#else // !LLVM_ON_WIN32
+#else // !_WIN32
// Generic POSIX implementation.
//
@@ -342,7 +342,7 @@ static void uninstallExceptionOrSignalHandlers() {
sigaction(Signals[i], &PrevActions[i], nullptr);
}
-#endif // !LLVM_ON_WIN32
+#endif // !_WIN32
bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
// If crash recovery is disabled, do nothing.
diff --git a/lib/Support/DAGDeltaAlgorithm.cpp b/lib/Support/DAGDeltaAlgorithm.cpp
index f1a334bfc7be..b82aec1423f5 100644
--- a/lib/Support/DAGDeltaAlgorithm.cpp
+++ b/lib/Support/DAGDeltaAlgorithm.cpp
@@ -124,13 +124,13 @@ private:
/// ExecuteOneTest - Execute a single test predicate on the change set \p S.
bool ExecuteOneTest(const changeset_ty &S) {
// Check dependencies invariant.
- DEBUG({
- for (changeset_ty::const_iterator it = S.begin(),
- ie = S.end(); it != ie; ++it)
- for (succ_iterator_ty it2 = succ_begin(*it),
- ie2 = succ_end(*it); it2 != ie2; ++it2)
- assert(S.count(*it2) && "Attempt to run invalid changeset!");
- });
+ LLVM_DEBUG({
+ for (changeset_ty::const_iterator it = S.begin(), ie = S.end(); it != ie;
+ ++it)
+ for (succ_iterator_ty it2 = succ_begin(*it), ie2 = succ_end(*it);
+ it2 != ie2; ++it2)
+ assert(S.count(*it2) && "Attempt to run invalid changeset!");
+ });
return DDA.ExecuteOneTest(S);
}
@@ -224,60 +224,68 @@ DAGDeltaAlgorithmImpl::DAGDeltaAlgorithmImpl(
PredClosure[*it2].insert(*it);
// Dump useful debug info.
- DEBUG({
- llvm::errs() << "-- DAGDeltaAlgorithmImpl --\n";
- llvm::errs() << "Changes: [";
- for (changeset_ty::const_iterator it = Changes.begin(),
- ie = Changes.end(); it != ie; ++it) {
- if (it != Changes.begin()) llvm::errs() << ", ";
- llvm::errs() << *it;
-
- if (succ_begin(*it) != succ_end(*it)) {
- llvm::errs() << "(";
- for (succ_iterator_ty it2 = succ_begin(*it),
- ie2 = succ_end(*it); it2 != ie2; ++it2) {
- if (it2 != succ_begin(*it)) llvm::errs() << ", ";
- llvm::errs() << "->" << *it2;
- }
- llvm::errs() << ")";
+ LLVM_DEBUG({
+ llvm::errs() << "-- DAGDeltaAlgorithmImpl --\n";
+ llvm::errs() << "Changes: [";
+ for (changeset_ty::const_iterator it = Changes.begin(), ie = Changes.end();
+ it != ie; ++it) {
+ if (it != Changes.begin())
+ llvm::errs() << ", ";
+ llvm::errs() << *it;
+
+ if (succ_begin(*it) != succ_end(*it)) {
+ llvm::errs() << "(";
+ for (succ_iterator_ty it2 = succ_begin(*it), ie2 = succ_end(*it);
+ it2 != ie2; ++it2) {
+ if (it2 != succ_begin(*it))
+ llvm::errs() << ", ";
+ llvm::errs() << "->" << *it2;
}
+ llvm::errs() << ")";
}
- llvm::errs() << "]\n";
-
- llvm::errs() << "Roots: [";
- for (std::vector<change_ty>::const_iterator it = Roots.begin(),
- ie = Roots.end(); it != ie; ++it) {
- if (it != Roots.begin()) llvm::errs() << ", ";
- llvm::errs() << *it;
+ }
+ llvm::errs() << "]\n";
+
+ llvm::errs() << "Roots: [";
+ for (std::vector<change_ty>::const_iterator it = Roots.begin(),
+ ie = Roots.end();
+ it != ie; ++it) {
+ if (it != Roots.begin())
+ llvm::errs() << ", ";
+ llvm::errs() << *it;
+ }
+ llvm::errs() << "]\n";
+
+ llvm::errs() << "Predecessor Closure:\n";
+ for (changeset_ty::const_iterator it = Changes.begin(), ie = Changes.end();
+ it != ie; ++it) {
+ llvm::errs() << format(" %-4d: [", *it);
+ for (pred_closure_iterator_ty it2 = pred_closure_begin(*it),
+ ie2 = pred_closure_end(*it);
+ it2 != ie2; ++it2) {
+ if (it2 != pred_closure_begin(*it))
+ llvm::errs() << ", ";
+ llvm::errs() << *it2;
}
llvm::errs() << "]\n";
+ }
- llvm::errs() << "Predecessor Closure:\n";
- for (changeset_ty::const_iterator it = Changes.begin(),
- ie = Changes.end(); it != ie; ++it) {
- llvm::errs() << format(" %-4d: [", *it);
- for (pred_closure_iterator_ty it2 = pred_closure_begin(*it),
- ie2 = pred_closure_end(*it); it2 != ie2; ++it2) {
- if (it2 != pred_closure_begin(*it)) llvm::errs() << ", ";
- llvm::errs() << *it2;
- }
- llvm::errs() << "]\n";
- }
-
- llvm::errs() << "Successor Closure:\n";
- for (changeset_ty::const_iterator it = Changes.begin(),
- ie = Changes.end(); it != ie; ++it) {
- llvm::errs() << format(" %-4d: [", *it);
- for (succ_closure_iterator_ty it2 = succ_closure_begin(*it),
- ie2 = succ_closure_end(*it); it2 != ie2; ++it2) {
- if (it2 != succ_closure_begin(*it)) llvm::errs() << ", ";
- llvm::errs() << *it2;
- }
- llvm::errs() << "]\n";
+ llvm::errs() << "Successor Closure:\n";
+ for (changeset_ty::const_iterator it = Changes.begin(), ie = Changes.end();
+ it != ie; ++it) {
+ llvm::errs() << format(" %-4d: [", *it);
+ for (succ_closure_iterator_ty it2 = succ_closure_begin(*it),
+ ie2 = succ_closure_end(*it);
+ it2 != ie2; ++it2) {
+ if (it2 != succ_closure_begin(*it))
+ llvm::errs() << ", ";
+ llvm::errs() << *it2;
}
+ llvm::errs() << "]\n";
+ }
- llvm::errs() << "\n\n";
- });
+ llvm::errs() << "\n\n";
+ });
}
bool DAGDeltaAlgorithmImpl::GetTestResult(const changeset_ty &Changes,
@@ -312,10 +320,10 @@ DAGDeltaAlgorithmImpl::Run() {
// Invariant: CurrentSet intersect Required == {}
// Invariant: Required == (Required union succ*(Required))
while (!CurrentSet.empty()) {
- DEBUG({
- llvm::errs() << "DAG_DD - " << CurrentSet.size() << " active changes, "
- << Required.size() << " required changes\n";
- });
+ LLVM_DEBUG({
+ llvm::errs() << "DAG_DD - " << CurrentSet.size() << " active changes, "
+ << Required.size() << " required changes\n";
+ });
// Minimize the current set of changes.
DeltaActiveSetHelper Helper(*this, Required);
diff --git a/lib/Support/DJB.cpp b/lib/Support/DJB.cpp
new file mode 100644
index 000000000000..905dcf1b7e81
--- /dev/null
+++ b/lib/Support/DJB.cpp
@@ -0,0 +1,86 @@
+//===-- Support/DJB.cpp ---DJB Hash -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains support for the DJ Bernstein hash function.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/DJB.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Unicode.h"
+
+using namespace llvm;
+
+static UTF32 chopOneUTF32(StringRef &Buffer) {
+ UTF32 C;
+ const UTF8 *const Begin8Const =
+ reinterpret_cast<const UTF8 *>(Buffer.begin());
+ const UTF8 *Begin8 = Begin8Const;
+ UTF32 *Begin32 = &C;
+
+ // In lenient mode we will always end up with a "reasonable" value in C for
+ // non-empty input.
+ assert(!Buffer.empty());
+ ConvertUTF8toUTF32(&Begin8, reinterpret_cast<const UTF8 *>(Buffer.end()),
+ &Begin32, &C + 1, lenientConversion);
+ Buffer = Buffer.drop_front(Begin8 - Begin8Const);
+ return C;
+}
+
+static StringRef toUTF8(UTF32 C, MutableArrayRef<UTF8> Storage) {
+ const UTF32 *Begin32 = &C;
+ UTF8 *Begin8 = Storage.begin();
+
+ // The case-folded output should always be a valid unicode character, so use
+ // strict mode here.
+ ConversionResult CR = ConvertUTF32toUTF8(&Begin32, &C + 1, &Begin8,
+ Storage.end(), strictConversion);
+ assert(CR == conversionOK && "Case folding produced invalid char?");
+ (void)CR;
+ return StringRef(reinterpret_cast<char *>(Storage.begin()),
+ Begin8 - Storage.begin());
+}
+
+static UTF32 foldCharDwarf(UTF32 C) {
+ // DWARF v5 addition to the unicode folding rules.
+ // Fold "Latin Small Letter Dotless I" and "Latin Capital Letter I With Dot
+ // Above" into "i".
+ if (C == 0x130 || C == 0x131)
+ return 'i';
+ return sys::unicode::foldCharSimple(C);
+}
+
+static uint32_t caseFoldingDjbHashCharSlow(StringRef &Buffer, uint32_t H) {
+ UTF32 C = chopOneUTF32(Buffer);
+
+ C = foldCharDwarf(C);
+
+ std::array<UTF8, UNI_MAX_UTF8_BYTES_PER_CODE_POINT> Storage;
+ StringRef Folded = toUTF8(C, Storage);
+ return djbHash(Folded, H);
+}
+
+uint32_t llvm::caseFoldingDjbHash(StringRef Buffer, uint32_t H) {
+ while (!Buffer.empty()) {
+ unsigned char C = Buffer.front();
+ if (LLVM_LIKELY(C <= 0x7f)) {
+ // US-ASCII, encoded as one character in utf-8.
+ // This is by far the most common case, so handle this specially.
+ if (C >= 'A' && C <= 'Z')
+ C = 'a' + (C - 'A'); // fold uppercase into lowercase
+ H = (H << 5) + H + C;
+ Buffer = Buffer.drop_front();
+ continue;
+ }
+ H = caseFoldingDjbHashCharSlow(Buffer, H);
+ }
+ return H;
+}
diff --git a/lib/Support/Debug.cpp b/lib/Support/Debug.cpp
index 9132911479a1..1a70017fee32 100644
--- a/lib/Support/Debug.cpp
+++ b/lib/Support/Debug.cpp
@@ -11,15 +11,16 @@
// code, without it being enabled all of the time, and without having to add
// command line options to enable it.
//
-// In particular, just wrap your code with the DEBUG() macro, and it will be
-// enabled automatically if you specify '-debug' on the command-line.
+// In particular, just wrap your code with the LLVM_DEBUG() macro, and it will
+// be enabled automatically if you specify '-debug' on the command-line.
// Alternatively, you can also use the SET_DEBUG_TYPE("foo") macro to specify
// that your debug code belongs to class "foo". Then, on the command line, you
// can specify '-debug-only=foo' to enable JUST the debug information for the
// foo class.
//
// When compiling without assertions, the -debug-* options and all code in
-// DEBUG() statements disappears, so it does not affect the runtime of the code.
+// LLVM_DEBUG() statements disappears, so it does not affect the runtime of the
+// code.
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Support/DebugCounter.cpp b/lib/Support/DebugCounter.cpp
index 1d46de04ee6a..5a9cecfc56d4 100644
--- a/lib/Support/DebugCounter.cpp
+++ b/lib/Support/DebugCounter.cpp
@@ -45,7 +45,7 @@ private:
// Create our command line option.
static DebugCounterList DebugCounterOption(
- "debug-counter",
+ "debug-counter", cl::Hidden,
cl::desc("Comma separated list of debug counter skip and count"),
cl::CommaSeparated, cl::ZeroOrMore, cl::location(DebugCounter::instance()));
@@ -66,7 +66,7 @@ void DebugCounter::push_back(const std::string &Val) {
}
// Now we have counter=value.
// First, process value.
- long CounterVal;
+ int64_t CounterVal;
if (CounterPair.second.getAsInteger(0, CounterVal)) {
errs() << "DebugCounter Error: " << CounterPair.second
<< " is not a number\n";
@@ -76,26 +76,24 @@ void DebugCounter::push_back(const std::string &Val) {
// add it to the counter values.
if (CounterPair.first.endswith("-skip")) {
auto CounterName = CounterPair.first.drop_back(5);
- unsigned CounterID = RegisteredCounters.idFor(CounterName);
+ unsigned CounterID = getCounterId(CounterName);
if (!CounterID) {
errs() << "DebugCounter Error: " << CounterName
<< " is not a registered counter\n";
return;
}
-
- auto Res = Counters.insert({CounterID, {0, -1}});
- Res.first->second.first = CounterVal;
+ Counters[CounterID].Skip = CounterVal;
+ Counters[CounterID].IsSet = true;
} else if (CounterPair.first.endswith("-count")) {
auto CounterName = CounterPair.first.drop_back(6);
- unsigned CounterID = RegisteredCounters.idFor(CounterName);
+ unsigned CounterID = getCounterId(CounterName);
if (!CounterID) {
errs() << "DebugCounter Error: " << CounterName
<< " is not a registered counter\n";
return;
}
-
- auto Res = Counters.insert({CounterID, {0, -1}});
- Res.first->second.second = CounterVal;
+ Counters[CounterID].StopAfter = CounterVal;
+ Counters[CounterID].IsSet = true;
} else {
errs() << "DebugCounter Error: " << CounterPair.first
<< " does not end with -skip or -count\n";
@@ -106,7 +104,8 @@ void DebugCounter::print(raw_ostream &OS) const {
OS << "Counters and values:\n";
for (const auto &KV : Counters)
OS << left_justify(RegisteredCounters[KV.first], 32) << ": {"
- << KV.second.first << "," << KV.second.second << "}\n";
+ << KV.second.Count << "," << KV.second.Skip << ","
+ << KV.second.StopAfter << "}\n";
}
LLVM_DUMP_METHOD void DebugCounter::dump() const {
diff --git a/lib/Support/DynamicLibrary.cpp b/lib/Support/DynamicLibrary.cpp
index d8422115eae8..530e92d99a90 100644
--- a/lib/Support/DynamicLibrary.cpp
+++ b/lib/Support/DynamicLibrary.cpp
@@ -49,7 +49,7 @@ public:
}
bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true) {
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle.");
#endif
@@ -61,7 +61,7 @@ public:
}
Handles.push_back(Handle);
} else {
-#ifndef LLVM_ON_WIN32
+#ifndef _WIN32
if (Process) {
if (CanClose)
DLClose(Process);
@@ -121,7 +121,7 @@ static llvm::ManagedStatic<DynamicLibrary::HandleSet> OpenedHandles;
static llvm::ManagedStatic<llvm::sys::SmartMutex<true>> SymbolsMutex;
}
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
#include "Windows/DynamicLibrary.inc"
diff --git a/lib/Support/Error.cpp b/lib/Support/Error.cpp
index c43a1fa813e2..83345bf6edb9 100644
--- a/lib/Support/Error.cpp
+++ b/lib/Support/Error.cpp
@@ -112,6 +112,10 @@ std::error_code StringError::convertToErrorCode() const {
return EC;
}
+Error createStringError(std::error_code EC, char const *Msg) {
+ return make_error<StringError>(Msg, EC);
+}
+
void report_fatal_error(Error Err, bool GenCrashDiag) {
assert(Err && "report_fatal_error called with success value");
std::string ErrMsg;
diff --git a/lib/Support/ErrorHandling.cpp b/lib/Support/ErrorHandling.cpp
index fb8ae4c1cd5e..21712c5c039e 100644
--- a/lib/Support/ErrorHandling.cpp
+++ b/lib/Support/ErrorHandling.cpp
@@ -175,6 +175,39 @@ void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
#endif
}
+#ifdef LLVM_ENABLE_EXCEPTIONS
+// Do not set custom new handler if exceptions are enabled. In this case OOM
+// errors are handled by throwing 'std::bad_alloc'.
+void llvm::install_out_of_memory_new_handler() {
+}
+#else
+// Causes crash on allocation failure. It is called prior to the handler set by
+// 'install_bad_alloc_error_handler'.
+static void out_of_memory_new_handler() {
+ llvm::report_bad_alloc_error("Allocation failed");
+}
+
+// Installs new handler that causes crash on allocation failure. It does not
+// need to be called explicitly, if this file is linked to application, because
+// in this case it is called during construction of 'new_handler_installer'.
+void llvm::install_out_of_memory_new_handler() {
+ static bool out_of_memory_new_handler_installed = false;
+ if (!out_of_memory_new_handler_installed) {
+ std::set_new_handler(out_of_memory_new_handler);
+ out_of_memory_new_handler_installed = true;
+ }
+}
+
+// Static object that causes installation of 'out_of_memory_new_handler' before
+// execution of 'main'.
+static class NewHandlerInstaller {
+public:
+ NewHandlerInstaller() {
+ install_out_of_memory_new_handler();
+ }
+} new_handler_installer;
+#endif
+
void llvm::llvm_unreachable_internal(const char *msg, const char *file,
unsigned line) {
// This code intentionally doesn't call the ErrorHandler callback, because
@@ -210,7 +243,7 @@ void LLVMResetFatalErrorHandler() {
remove_fatal_error_handler();
}
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
#include <winerror.h>
diff --git a/lib/Support/FileOutputBuffer.cpp b/lib/Support/FileOutputBuffer.cpp
index c4ff563e5f44..1214b5a0ba1f 100644
--- a/lib/Support/FileOutputBuffer.cpp
+++ b/lib/Support/FileOutputBuffer.cpp
@@ -82,9 +82,11 @@ public:
size_t getBufferSize() const override { return Buffer.size(); }
Error commit() override {
+ using namespace sys::fs;
int FD;
std::error_code EC;
- if (auto EC = openFileForWrite(FinalPath, FD, fs::F_None, Mode))
+ if (auto EC =
+ openFileForWrite(FinalPath, FD, CD_CreateAlways, OF_None, Mode))
return errorCodeToError(EC);
raw_fd_ostream OS(FD, /*shouldClose=*/true, /*unbuffered=*/true);
OS << StringRef((const char *)Buffer.base(), Buffer.size());
@@ -108,24 +110,30 @@ createInMemoryBuffer(StringRef Path, size_t Size, unsigned Mode) {
}
static Expected<std::unique_ptr<OnDiskBuffer>>
-createOnDiskBuffer(StringRef Path, size_t Size, unsigned Mode) {
+createOnDiskBuffer(StringRef Path, size_t Size, bool InitExisting,
+ 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 function.
- if (auto EC = fs::resize_file(File.FD, Size)) {
- consumeError(File.discard());
- return errorCodeToError(EC);
- }
+ if (InitExisting) {
+ if (auto EC = sys::fs::copy_file(Path, File.FD))
+ return errorCodeToError(EC);
+ } else {
+#ifndef _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 function.
+ if (auto EC = fs::resize_file(File.FD, Size)) {
+ consumeError(File.discard());
+ return errorCodeToError(EC);
+ }
#endif
+ }
// Mmap it.
std::error_code EC;
@@ -149,6 +157,15 @@ FileOutputBuffer::create(StringRef Path, size_t Size, unsigned Flags) {
fs::file_status Stat;
fs::status(Path, Stat);
+ if ((Flags & F_modify) && Size == size_t(-1)) {
+ if (Stat.type() == fs::file_type::regular_file)
+ Size = Stat.getSize();
+ else if (Stat.type() == fs::file_type::file_not_found)
+ return errorCodeToError(errc::no_such_file_or_directory);
+ else
+ return errorCodeToError(errc::invalid_argument);
+ }
+
// 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).
@@ -163,7 +180,7 @@ FileOutputBuffer::create(StringRef Path, size_t Size, unsigned Flags) {
case fs::file_type::regular_file:
case fs::file_type::file_not_found:
case fs::file_type::status_error:
- return createOnDiskBuffer(Path, Size, Mode);
+ return createOnDiskBuffer(Path, Size, !!(Flags & F_modify), Mode);
default:
return createInMemoryBuffer(Path, Size, Mode);
}
diff --git a/lib/Support/FoldingSet.cpp b/lib/Support/FoldingSet.cpp
index 942379549039..ec7d57586e8b 100644
--- a/lib/Support/FoldingSet.cpp
+++ b/lib/Support/FoldingSet.cpp
@@ -214,11 +214,8 @@ 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.");
-
+ void **Buckets = static_cast<void**>(safe_calloc(NumBuckets + 1,
+ sizeof(void*)));
// Set the very last bucket to be a non-null "pointer".
Buckets[NumBuckets] = reinterpret_cast<void*>(-1);
return Buckets;
diff --git a/lib/Support/GraphWriter.cpp b/lib/Support/GraphWriter.cpp
index fd7fab08278e..9335daffc3e2 100644
--- a/lib/Support/GraphWriter.cpp
+++ b/lib/Support/GraphWriter.cpp
@@ -66,7 +66,7 @@ std::string llvm::DOT::EscapeString(const std::string &Label) {
return Str;
}
-/// \brief Get a color string for this node number. Simply round-robin selects
+/// Get a color string for this node number. Simply round-robin selects
/// from a reasonable number of colors.
StringRef llvm::DOT::getColorString(unsigned ColorNumber) {
static const int NumColors = 20;
@@ -91,20 +91,18 @@ std::string llvm::createGraphFilename(const Twine &Name, int &FD) {
}
// Execute the graph viewer. Return true if there were errors.
-static bool ExecGraphViewer(StringRef ExecPath, std::vector<const char *> &args,
+static bool ExecGraphViewer(StringRef ExecPath, std::vector<StringRef> &args,
StringRef Filename, bool wait,
std::string &ErrMsg) {
- assert(args.back() == nullptr);
if (wait) {
- if (sys::ExecuteAndWait(ExecPath, args.data(), nullptr, {}, 0, 0,
- &ErrMsg)) {
+ if (sys::ExecuteAndWait(ExecPath, args, None, {}, 0, 0, &ErrMsg)) {
errs() << "Error: " << ErrMsg << "\n";
return true;
}
sys::fs::remove(Filename);
errs() << " done. \n";
} else {
- sys::ExecuteNoWait(ExecPath, args.data(), nullptr, {}, 0, &ErrMsg);
+ sys::ExecuteNoWait(ExecPath, args, None, {}, 0, &ErrMsg);
errs() << "Remember to erase graph file: " << Filename << "\n";
}
return false;
@@ -158,22 +156,20 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait,
#ifdef __APPLE__
wait &= !ViewBackground;
if (S.TryFindProgram("open", ViewerPath)) {
- std::vector<const char *> args;
- args.push_back(ViewerPath.c_str());
+ std::vector<StringRef> args;
+ args.push_back(ViewerPath);
if (wait)
args.push_back("-W");
- args.push_back(Filename.c_str());
- args.push_back(nullptr);
+ args.push_back(Filename);
errs() << "Trying 'open' program... ";
if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg))
return false;
}
#endif
if (S.TryFindProgram("xdg-open", ViewerPath)) {
- std::vector<const char *> args;
- args.push_back(ViewerPath.c_str());
- args.push_back(Filename.c_str());
- args.push_back(nullptr);
+ std::vector<StringRef> args;
+ args.push_back(ViewerPath);
+ args.push_back(Filename);
errs() << "Trying 'xdg-open' program... ";
if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg))
return false;
@@ -181,10 +177,9 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait,
// Graphviz
if (S.TryFindProgram("Graphviz", ViewerPath)) {
- std::vector<const char *> args;
- args.push_back(ViewerPath.c_str());
- args.push_back(Filename.c_str());
- args.push_back(nullptr);
+ std::vector<StringRef> args;
+ args.push_back(ViewerPath);
+ args.push_back(Filename);
errs() << "Running 'Graphviz' program... ";
return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
@@ -192,15 +187,13 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait,
// xdot
if (S.TryFindProgram("xdot|xdot.py", ViewerPath)) {
- std::vector<const char *> args;
- args.push_back(ViewerPath.c_str());
- args.push_back(Filename.c_str());
+ std::vector<StringRef> args;
+ args.push_back(ViewerPath);
+ args.push_back(Filename);
args.push_back("-f");
args.push_back(getProgramName(program));
- args.push_back(nullptr);
-
errs() << "Running 'xdot.py' program... ";
return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
}
@@ -221,7 +214,7 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait,
Viewer = VK_Ghostview;
if (!Viewer && S.TryFindProgram("xdg-open", ViewerPath))
Viewer = VK_XDGOpen;
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
if (!Viewer && S.TryFindProgram("cmd", ViewerPath)) {
Viewer = VK_CmdStart;
}
@@ -235,18 +228,17 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait,
std::string OutputFilename =
Filename + (Viewer == VK_CmdStart ? ".pdf" : ".ps");
- std::vector<const char *> args;
- args.push_back(GeneratorPath.c_str());
+ std::vector<StringRef> args;
+ args.push_back(GeneratorPath);
if (Viewer == VK_CmdStart)
args.push_back("-Tpdf");
else
args.push_back("-Tps");
args.push_back("-Nfontname=Courier");
args.push_back("-Gsize=7.5,10");
- args.push_back(Filename.c_str());
+ args.push_back(Filename);
args.push_back("-o");
- args.push_back(OutputFilename.c_str());
- args.push_back(nullptr);
+ args.push_back(OutputFilename);
errs() << "Running '" << GeneratorPath << "' program... ";
@@ -258,31 +250,30 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait,
std::string StartArg;
args.clear();
- args.push_back(ViewerPath.c_str());
+ args.push_back(ViewerPath);
switch (Viewer) {
case VK_OSXOpen:
args.push_back("-W");
- args.push_back(OutputFilename.c_str());
+ args.push_back(OutputFilename);
break;
case VK_XDGOpen:
wait = false;
- args.push_back(OutputFilename.c_str());
+ args.push_back(OutputFilename);
break;
case VK_Ghostview:
args.push_back("--spartan");
- args.push_back(OutputFilename.c_str());
+ args.push_back(OutputFilename);
break;
case VK_CmdStart:
args.push_back("/S");
args.push_back("/C");
StartArg =
(StringRef("start ") + (wait ? "/WAIT " : "") + OutputFilename).str();
- args.push_back(StartArg.c_str());
+ args.push_back(StartArg);
break;
case VK_None:
llvm_unreachable("Invalid viewer");
}
- args.push_back(nullptr);
ErrMsg.clear();
return ExecGraphViewer(ViewerPath, args, OutputFilename, wait, ErrMsg);
@@ -290,13 +281,12 @@ bool llvm::DisplayGraph(StringRef FilenameRef, bool wait,
// dotty
if (S.TryFindProgram("dotty", ViewerPath)) {
- std::vector<const char *> args;
- args.push_back(ViewerPath.c_str());
- args.push_back(Filename.c_str());
- args.push_back(nullptr);
+ std::vector<StringRef> args;
+ args.push_back(ViewerPath);
+ args.push_back(Filename);
// Dotty spawns another app and doesn't wait until it returns
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
wait = false;
#endif
errs() << "Running 'dotty' program... ";
diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp
index 3dc67ad782af..2c718dd3f5a8 100644
--- a/lib/Support/Host.cpp
+++ b/lib/Support/Host.cpp
@@ -18,7 +18,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -30,7 +30,7 @@
#ifdef LLVM_ON_UNIX
#include "Unix/Host.inc"
#endif
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
#include "Windows/Host.inc"
#endif
#ifdef _MSC_VER
@@ -65,8 +65,7 @@ static std::unique_ptr<llvm::MemoryBuffer>
return std::move(*Text);
}
-StringRef sys::detail::getHostCPUNameForPowerPC(
- const StringRef &ProcCpuinfoContent) {
+StringRef sys::detail::getHostCPUNameForPowerPC(StringRef ProcCpuinfoContent) {
// Access to the Processor Version Register (PVR) on PowerPC is privileged,
// and so we must use an operating-system interface to determine the current
// processor type. On Linux, this is exposed through the /proc/cpuinfo file.
@@ -145,8 +144,7 @@ StringRef sys::detail::getHostCPUNameForPowerPC(
.Default(generic);
}
-StringRef sys::detail::getHostCPUNameForARM(
- const StringRef &ProcCpuinfoContent) {
+StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) {
// The cpuid register on arm is not accessible from user space. On Linux,
// it is exposed through the /proc/cpuinfo file.
@@ -250,8 +248,7 @@ StringRef sys::detail::getHostCPUNameForARM(
return "generic";
}
-StringRef sys::detail::getHostCPUNameForS390x(
- const StringRef &ProcCpuinfoContent) {
+StringRef sys::detail::getHostCPUNameForS390x(StringRef ProcCpuinfoContent) {
// STIDP is a privileged operation, so use /proc/cpuinfo instead.
// The "processor 0:" line comes after a fair amount of other information,
@@ -654,9 +651,11 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
// Goldmont:
case 0x5c: // Apollo Lake
case 0x5f: // Denverton
- case 0x7a: // Gemini Lake
*Type = X86::INTEL_GOLDMONT;
break; // "goldmont"
+ case 0x7a:
+ *Type = X86::INTEL_GOLDMONT_PLUS;
+ break;
case 0x57:
*Type = X86::INTEL_KNL; // knl
break;
@@ -841,9 +840,9 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model,
*Subtype = X86::AMDFAM15H_BDVER3;
break; // "bdver3"; 30h-3Fh: Steamroller
}
- if (Model >= 0x10 && Model <= 0x1f) {
+ if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) {
*Subtype = X86::AMDFAM15H_BDVER2;
- break; // "bdver2"; 10h-1Fh: Piledriver
+ break; // "bdver2"; 02h, 10h-1Fh: Piledriver
}
if (Model <= 0x0f) {
*Subtype = X86::AMDFAM15H_BDVER1;
@@ -1009,7 +1008,7 @@ StringRef sys::getHostCPUName() {
#include "llvm/Support/X86TargetParser.def"
// Now check types.
-#define X86_CPU_SUBTYPE(ARCHNAME, ENUM) \
+#define X86_CPU_TYPE(ARCHNAME, ENUM) \
if (Type == X86::ENUM) \
return ARCHNAME;
#include "llvm/Support/X86TargetParser.def"
@@ -1062,19 +1061,19 @@ StringRef sys::getHostCPUName() {
#elif defined(__linux__) && (defined(__ppc__) || defined(__powerpc__))
StringRef sys::getHostCPUName() {
std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent();
- const StringRef& Content = P ? P->getBuffer() : "";
+ StringRef Content = P ? P->getBuffer() : "";
return detail::getHostCPUNameForPowerPC(Content);
}
#elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__))
StringRef sys::getHostCPUName() {
std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent();
- const StringRef& Content = P ? P->getBuffer() : "";
+ StringRef Content = P ? P->getBuffer() : "";
return detail::getHostCPUNameForARM(Content);
}
#elif defined(__linux__) && defined(__s390x__)
StringRef sys::getHostCPUName() {
std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent();
- const StringRef& Content = P ? P->getBuffer() : "";
+ StringRef Content = P ? P->getBuffer() : "";
return detail::getHostCPUNameForS390x(Content);
}
#else
@@ -1206,6 +1205,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 &&
!getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);
+ Features["sahf"] = HasExtLeaf1 && ((ECX >> 0) & 1);
Features["lzcnt"] = HasExtLeaf1 && ((ECX >> 5) & 1);
Features["sse4a"] = HasExtLeaf1 && ((ECX >> 6) & 1);
Features["prfchw"] = HasExtLeaf1 && ((ECX >> 8) & 1);
@@ -1215,9 +1215,12 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
Features["tbm"] = HasExtLeaf1 && ((ECX >> 21) & 1);
Features["mwaitx"] = HasExtLeaf1 && ((ECX >> 29) & 1);
+ // Miscellaneous memory related features, detected by
+ // using the 0x80000008 leaf of the CPUID instruction
bool HasExtLeaf8 = MaxExtLevel >= 0x80000008 &&
!getX86CpuIDAndInfo(0x80000008, &EAX, &EBX, &ECX, &EDX);
- Features["clzero"] = HasExtLeaf8 && ((EBX >> 0) & 1);
+ Features["clzero"] = HasExtLeaf8 && ((EBX >> 0) & 1);
+ Features["wbnoinvd"] = HasExtLeaf8 && ((EBX >> 9) & 1);
bool HasLeaf7 =
MaxLevel >= 7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX);
@@ -1228,6 +1231,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
// AVX2 is only supported if we have the OS save support from AVX.
Features["avx2"] = HasLeaf7 && ((EBX >> 5) & 1) && HasAVXSave;
Features["bmi2"] = HasLeaf7 && ((EBX >> 8) & 1);
+ Features["invpcid"] = HasLeaf7 && ((EBX >> 10) & 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;
@@ -1247,6 +1251,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
Features["prefetchwt1"] = HasLeaf7 && ((ECX >> 0) & 1);
Features["avx512vbmi"] = HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save;
Features["pku"] = HasLeaf7 && ((ECX >> 4) & 1);
+ Features["waitpkg"] = HasLeaf7 && ((ECX >> 5) & 1);
Features["avx512vbmi2"] = HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save;
Features["shstk"] = HasLeaf7 && ((ECX >> 7) & 1);
Features["gfni"] = HasLeaf7 && ((ECX >> 8) & 1);
@@ -1255,7 +1260,22 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
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);
+ Features["rdpid"] = HasLeaf7 && ((ECX >> 22) & 1);
+ Features["cldemote"] = HasLeaf7 && ((ECX >> 25) & 1);
+ Features["movdiri"] = HasLeaf7 && ((ECX >> 27) & 1);
+ Features["movdir64b"] = HasLeaf7 && ((ECX >> 28) & 1);
+
+ // There are two CPUID leafs which information associated with the pconfig
+ // instruction:
+ // EAX=0x7, ECX=0x0 indicates the availability of the instruction (via the 18th
+ // bit of EDX), while the EAX=0x1b leaf returns information on the
+ // availability of specific pconfig leafs.
+ // The target feature here only refers to the the first of these two.
+ // Users might need to check for the availability of specific pconfig
+ // leaves using cpuid, since that information is ignored while
+ // detecting features using the "-march=native" flag.
+ // For more info, see X86 ISA docs.
+ Features["pconfig"] = HasLeaf7 && ((EDX >> 18) & 1);
bool HasLeafD = MaxLevel >= 0xd &&
!getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX);
@@ -1265,6 +1285,11 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
Features["xsavec"] = HasLeafD && ((EAX >> 1) & 1) && HasAVXSave;
Features["xsaves"] = HasLeafD && ((EAX >> 3) & 1) && HasAVXSave;
+ bool HasLeaf14 = MaxLevel >= 0x14 &&
+ !getX86CpuIDAndInfoEx(0x14, 0x0, &EAX, &EBX, &ECX, &EDX);
+
+ Features["ptwrite"] = HasLeaf14 && ((EBX >> 4) & 1);
+
return true;
}
#elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__))
diff --git a/lib/Support/InitLLVM.cpp b/lib/Support/InitLLVM.cpp
new file mode 100644
index 000000000000..c008d0455c99
--- /dev/null
+++ b/lib/Support/InitLLVM.cpp
@@ -0,0 +1,52 @@
+//===-- InitLLVM.cpp -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include <string>
+
+#ifdef _WIN32
+#include "Windows/WindowsSupport.h"
+#endif
+
+using namespace llvm;
+using namespace llvm::sys;
+
+InitLLVM::InitLLVM(int &Argc, const char **&Argv) : StackPrinter(Argc, Argv) {
+ sys::PrintStackTraceOnErrorSignal(Argv[0]);
+
+#ifdef _WIN32
+ // We use UTF-8 as the internal character encoding. On Windows,
+ // arguments passed to main() may not be encoded in UTF-8. In order
+ // to reliably detect encoding of command line arguments, we use an
+ // Windows API to obtain arguments, convert them to UTF-8, and then
+ // write them back to the Argv vector.
+ //
+ // There's probably other way to do the same thing (e.g. using
+ // wmain() instead of main()), but this way seems less intrusive
+ // than that.
+ std::string Banner = std::string(Argv[0]) + ": ";
+ ExitOnError ExitOnErr(Banner);
+
+ ExitOnErr(errorCodeToError(windows::GetCommandLineArguments(Args, Alloc)));
+
+ // GetCommandLineArguments doesn't terminate the vector with a
+ // nullptr. Do it to make it compatible with the real argv.
+ Args.push_back(nullptr);
+
+ Argc = Args.size() - 1;
+ Argv = Args.data();
+#endif
+}
+
+InitLLVM::~InitLLVM() { llvm_shutdown(); }
diff --git a/lib/Support/JSON.cpp b/lib/Support/JSON.cpp
new file mode 100644
index 000000000000..a5dae7a7c2e0
--- /dev/null
+++ b/lib/Support/JSON.cpp
@@ -0,0 +1,693 @@
+//=== JSON.cpp - JSON value, parsing and serialization - C++ -----------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Format.h"
+#include <cctype>
+
+namespace llvm {
+namespace json {
+
+Value &Object::operator[](const ObjectKey &K) {
+ return try_emplace(K, nullptr).first->getSecond();
+}
+Value &Object::operator[](ObjectKey &&K) {
+ return try_emplace(std::move(K), nullptr).first->getSecond();
+}
+Value *Object::get(StringRef K) {
+ auto I = find(K);
+ if (I == end())
+ return nullptr;
+ return &I->second;
+}
+const Value *Object::get(StringRef K) const {
+ auto I = find(K);
+ if (I == end())
+ return nullptr;
+ return &I->second;
+}
+llvm::Optional<std::nullptr_t> Object::getNull(StringRef K) const {
+ if (auto *V = get(K))
+ return V->getAsNull();
+ return llvm::None;
+}
+llvm::Optional<bool> Object::getBoolean(StringRef K) const {
+ if (auto *V = get(K))
+ return V->getAsBoolean();
+ return llvm::None;
+}
+llvm::Optional<double> Object::getNumber(StringRef K) const {
+ if (auto *V = get(K))
+ return V->getAsNumber();
+ return llvm::None;
+}
+llvm::Optional<int64_t> Object::getInteger(StringRef K) const {
+ if (auto *V = get(K))
+ return V->getAsInteger();
+ return llvm::None;
+}
+llvm::Optional<llvm::StringRef> Object::getString(StringRef K) const {
+ if (auto *V = get(K))
+ return V->getAsString();
+ return llvm::None;
+}
+const json::Object *Object::getObject(StringRef K) const {
+ if (auto *V = get(K))
+ return V->getAsObject();
+ return nullptr;
+}
+json::Object *Object::getObject(StringRef K) {
+ if (auto *V = get(K))
+ return V->getAsObject();
+ return nullptr;
+}
+const json::Array *Object::getArray(StringRef K) const {
+ if (auto *V = get(K))
+ return V->getAsArray();
+ return nullptr;
+}
+json::Array *Object::getArray(StringRef K) {
+ if (auto *V = get(K))
+ return V->getAsArray();
+ return nullptr;
+}
+bool operator==(const Object &LHS, const Object &RHS) {
+ if (LHS.size() != RHS.size())
+ return false;
+ for (const auto &L : LHS) {
+ auto R = RHS.find(L.first);
+ if (R == RHS.end() || L.second != R->second)
+ return false;
+ }
+ return true;
+}
+
+Array::Array(std::initializer_list<Value> Elements) {
+ V.reserve(Elements.size());
+ for (const Value &V : Elements) {
+ emplace_back(nullptr);
+ back().moveFrom(std::move(V));
+ }
+}
+
+Value::Value(std::initializer_list<Value> Elements)
+ : Value(json::Array(Elements)) {}
+
+void Value::copyFrom(const Value &M) {
+ Type = M.Type;
+ switch (Type) {
+ case T_Null:
+ case T_Boolean:
+ case T_Double:
+ case T_Integer:
+ memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer));
+ break;
+ case T_StringRef:
+ create<StringRef>(M.as<StringRef>());
+ break;
+ case T_String:
+ create<std::string>(M.as<std::string>());
+ break;
+ case T_Object:
+ create<json::Object>(M.as<json::Object>());
+ break;
+ case T_Array:
+ create<json::Array>(M.as<json::Array>());
+ break;
+ }
+}
+
+void Value::moveFrom(const Value &&M) {
+ Type = M.Type;
+ switch (Type) {
+ case T_Null:
+ case T_Boolean:
+ case T_Double:
+ case T_Integer:
+ memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer));
+ break;
+ case T_StringRef:
+ create<StringRef>(M.as<StringRef>());
+ break;
+ case T_String:
+ create<std::string>(std::move(M.as<std::string>()));
+ M.Type = T_Null;
+ break;
+ case T_Object:
+ create<json::Object>(std::move(M.as<json::Object>()));
+ M.Type = T_Null;
+ break;
+ case T_Array:
+ create<json::Array>(std::move(M.as<json::Array>()));
+ M.Type = T_Null;
+ break;
+ }
+}
+
+void Value::destroy() {
+ switch (Type) {
+ case T_Null:
+ case T_Boolean:
+ case T_Double:
+ case T_Integer:
+ break;
+ case T_StringRef:
+ as<StringRef>().~StringRef();
+ break;
+ case T_String:
+ as<std::string>().~basic_string();
+ break;
+ case T_Object:
+ as<json::Object>().~Object();
+ break;
+ case T_Array:
+ as<json::Array>().~Array();
+ break;
+ }
+}
+
+bool operator==(const Value &L, const Value &R) {
+ if (L.kind() != R.kind())
+ return false;
+ switch (L.kind()) {
+ case Value::Null:
+ return *L.getAsNull() == *R.getAsNull();
+ case Value::Boolean:
+ return *L.getAsBoolean() == *R.getAsBoolean();
+ case Value::Number:
+ return *L.getAsNumber() == *R.getAsNumber();
+ case Value::String:
+ return *L.getAsString() == *R.getAsString();
+ case Value::Array:
+ return *L.getAsArray() == *R.getAsArray();
+ case Value::Object:
+ return *L.getAsObject() == *R.getAsObject();
+ }
+ llvm_unreachable("Unknown value kind");
+}
+
+namespace {
+// Simple recursive-descent JSON parser.
+class Parser {
+public:
+ Parser(StringRef JSON)
+ : Start(JSON.begin()), P(JSON.begin()), End(JSON.end()) {}
+
+ bool checkUTF8() {
+ size_t ErrOffset;
+ if (isUTF8(StringRef(Start, End - Start), &ErrOffset))
+ return true;
+ P = Start + ErrOffset; // For line/column calculation.
+ return parseError("Invalid UTF-8 sequence");
+ }
+
+ bool parseValue(Value &Out);
+
+ bool assertEnd() {
+ eatWhitespace();
+ if (P == End)
+ return true;
+ return parseError("Text after end of document");
+ }
+
+ Error takeError() {
+ assert(Err);
+ return std::move(*Err);
+ }
+
+private:
+ void eatWhitespace() {
+ while (P != End && (*P == ' ' || *P == '\r' || *P == '\n' || *P == '\t'))
+ ++P;
+ }
+
+ // On invalid syntax, parseX() functions return false and set Err.
+ bool parseNumber(char First, Value &Out);
+ bool parseString(std::string &Out);
+ bool parseUnicode(std::string &Out);
+ bool parseError(const char *Msg); // always returns false
+
+ char next() { return P == End ? 0 : *P++; }
+ char peek() { return P == End ? 0 : *P; }
+ static bool isNumber(char C) {
+ return C == '0' || C == '1' || C == '2' || C == '3' || C == '4' ||
+ C == '5' || C == '6' || C == '7' || C == '8' || C == '9' ||
+ C == 'e' || C == 'E' || C == '+' || C == '-' || C == '.';
+ }
+
+ Optional<Error> Err;
+ const char *Start, *P, *End;
+};
+
+bool Parser::parseValue(Value &Out) {
+ eatWhitespace();
+ if (P == End)
+ return parseError("Unexpected EOF");
+ switch (char C = next()) {
+ // Bare null/true/false are easy - first char identifies them.
+ case 'n':
+ Out = nullptr;
+ return (next() == 'u' && next() == 'l' && next() == 'l') ||
+ parseError("Invalid JSON value (null?)");
+ case 't':
+ Out = true;
+ return (next() == 'r' && next() == 'u' && next() == 'e') ||
+ parseError("Invalid JSON value (true?)");
+ case 'f':
+ Out = false;
+ return (next() == 'a' && next() == 'l' && next() == 's' && next() == 'e') ||
+ parseError("Invalid JSON value (false?)");
+ case '"': {
+ std::string S;
+ if (parseString(S)) {
+ Out = std::move(S);
+ return true;
+ }
+ return false;
+ }
+ case '[': {
+ Out = Array{};
+ Array &A = *Out.getAsArray();
+ eatWhitespace();
+ if (peek() == ']') {
+ ++P;
+ return true;
+ }
+ for (;;) {
+ A.emplace_back(nullptr);
+ if (!parseValue(A.back()))
+ return false;
+ eatWhitespace();
+ switch (next()) {
+ case ',':
+ eatWhitespace();
+ continue;
+ case ']':
+ return true;
+ default:
+ return parseError("Expected , or ] after array element");
+ }
+ }
+ }
+ case '{': {
+ Out = Object{};
+ Object &O = *Out.getAsObject();
+ eatWhitespace();
+ if (peek() == '}') {
+ ++P;
+ return true;
+ }
+ for (;;) {
+ if (next() != '"')
+ return parseError("Expected object key");
+ std::string K;
+ if (!parseString(K))
+ return false;
+ eatWhitespace();
+ if (next() != ':')
+ return parseError("Expected : after object key");
+ eatWhitespace();
+ if (!parseValue(O[std::move(K)]))
+ return false;
+ eatWhitespace();
+ switch (next()) {
+ case ',':
+ eatWhitespace();
+ continue;
+ case '}':
+ return true;
+ default:
+ return parseError("Expected , or } after object property");
+ }
+ }
+ }
+ default:
+ if (isNumber(C))
+ return parseNumber(C, Out);
+ return parseError("Invalid JSON value");
+ }
+}
+
+bool Parser::parseNumber(char First, Value &Out) {
+ // Read the number into a string. (Must be null-terminated for strto*).
+ SmallString<24> S;
+ S.push_back(First);
+ while (isNumber(peek()))
+ S.push_back(next());
+ char *End;
+ // Try first to parse as integer, and if so preserve full 64 bits.
+ // strtoll returns long long >= 64 bits, so check it's in range too.
+ auto I = std::strtoll(S.c_str(), &End, 10);
+ if (End == S.end() && I >= std::numeric_limits<int64_t>::min() &&
+ I <= std::numeric_limits<int64_t>::max()) {
+ Out = int64_t(I);
+ return true;
+ }
+ // If it's not an integer
+ Out = std::strtod(S.c_str(), &End);
+ return End == S.end() || parseError("Invalid JSON value (number?)");
+}
+
+bool Parser::parseString(std::string &Out) {
+ // leading quote was already consumed.
+ for (char C = next(); C != '"'; C = next()) {
+ if (LLVM_UNLIKELY(P == End))
+ return parseError("Unterminated string");
+ if (LLVM_UNLIKELY((C & 0x1f) == C))
+ return parseError("Control character in string");
+ if (LLVM_LIKELY(C != '\\')) {
+ Out.push_back(C);
+ continue;
+ }
+ // Handle escape sequence.
+ switch (C = next()) {
+ case '"':
+ case '\\':
+ case '/':
+ Out.push_back(C);
+ break;
+ case 'b':
+ Out.push_back('\b');
+ break;
+ case 'f':
+ Out.push_back('\f');
+ break;
+ case 'n':
+ Out.push_back('\n');
+ break;
+ case 'r':
+ Out.push_back('\r');
+ break;
+ case 't':
+ Out.push_back('\t');
+ break;
+ case 'u':
+ if (!parseUnicode(Out))
+ return false;
+ break;
+ default:
+ return parseError("Invalid escape sequence");
+ }
+ }
+ return true;
+}
+
+static void encodeUtf8(uint32_t Rune, std::string &Out) {
+ if (Rune < 0x80) {
+ Out.push_back(Rune & 0x7F);
+ } else if (Rune < 0x800) {
+ uint8_t FirstByte = 0xC0 | ((Rune & 0x7C0) >> 6);
+ uint8_t SecondByte = 0x80 | (Rune & 0x3F);
+ Out.push_back(FirstByte);
+ Out.push_back(SecondByte);
+ } else if (Rune < 0x10000) {
+ uint8_t FirstByte = 0xE0 | ((Rune & 0xF000) >> 12);
+ uint8_t SecondByte = 0x80 | ((Rune & 0xFC0) >> 6);
+ uint8_t ThirdByte = 0x80 | (Rune & 0x3F);
+ Out.push_back(FirstByte);
+ Out.push_back(SecondByte);
+ Out.push_back(ThirdByte);
+ } else if (Rune < 0x110000) {
+ uint8_t FirstByte = 0xF0 | ((Rune & 0x1F0000) >> 18);
+ uint8_t SecondByte = 0x80 | ((Rune & 0x3F000) >> 12);
+ uint8_t ThirdByte = 0x80 | ((Rune & 0xFC0) >> 6);
+ uint8_t FourthByte = 0x80 | (Rune & 0x3F);
+ Out.push_back(FirstByte);
+ Out.push_back(SecondByte);
+ Out.push_back(ThirdByte);
+ Out.push_back(FourthByte);
+ } else {
+ llvm_unreachable("Invalid codepoint");
+ }
+}
+
+// Parse a UTF-16 \uNNNN escape sequence. "\u" has already been consumed.
+// May parse several sequential escapes to ensure proper surrogate handling.
+// We do not use ConvertUTF.h, it can't accept and replace unpaired surrogates.
+// These are invalid Unicode but valid JSON (RFC 8259, section 8.2).
+bool Parser::parseUnicode(std::string &Out) {
+ // Invalid UTF is not a JSON error (RFC 8529§8.2). It gets replaced by U+FFFD.
+ auto Invalid = [&] { Out.append(/* UTF-8 */ {'\xef', '\xbf', '\xbd'}); };
+ // Decodes 4 hex digits from the stream into Out, returns false on error.
+ auto Parse4Hex = [this](uint16_t &Out) -> bool {
+ Out = 0;
+ char Bytes[] = {next(), next(), next(), next()};
+ for (unsigned char C : Bytes) {
+ if (!std::isxdigit(C))
+ return parseError("Invalid \\u escape sequence");
+ Out <<= 4;
+ Out |= (C > '9') ? (C & ~0x20) - 'A' + 10 : (C - '0');
+ }
+ return true;
+ };
+ uint16_t First; // UTF-16 code unit from the first \u escape.
+ if (!Parse4Hex(First))
+ return false;
+
+ // We loop to allow proper surrogate-pair error handling.
+ while (true) {
+ // Case 1: the UTF-16 code unit is already a codepoint in the BMP.
+ if (LLVM_LIKELY(First < 0xD800 || First >= 0xE000)) {
+ encodeUtf8(First, Out);
+ return true;
+ }
+
+ // Case 2: it's an (unpaired) trailing surrogate.
+ if (LLVM_UNLIKELY(First >= 0xDC00)) {
+ Invalid();
+ return true;
+ }
+
+ // Case 3: it's a leading surrogate. We expect a trailing one next.
+ // Case 3a: there's no trailing \u escape. Don't advance in the stream.
+ if (LLVM_UNLIKELY(P + 2 > End || *P != '\\' || *(P + 1) != 'u')) {
+ Invalid(); // Leading surrogate was unpaired.
+ return true;
+ }
+ P += 2;
+ uint16_t Second;
+ if (!Parse4Hex(Second))
+ return false;
+ // Case 3b: there was another \u escape, but it wasn't a trailing surrogate.
+ if (LLVM_UNLIKELY(Second < 0xDC00 || Second >= 0xE000)) {
+ Invalid(); // Leading surrogate was unpaired.
+ First = Second; // Second escape still needs to be processed.
+ continue;
+ }
+ // Case 3c: a valid surrogate pair encoding an astral codepoint.
+ encodeUtf8(0x10000 | ((First - 0xD800) << 10) | (Second - 0xDC00), Out);
+ return true;
+ }
+}
+
+bool Parser::parseError(const char *Msg) {
+ int Line = 1;
+ const char *StartOfLine = Start;
+ for (const char *X = Start; X < P; ++X) {
+ if (*X == 0x0A) {
+ ++Line;
+ StartOfLine = X + 1;
+ }
+ }
+ Err.emplace(
+ llvm::make_unique<ParseError>(Msg, Line, P - StartOfLine, P - Start));
+ return false;
+}
+} // namespace
+
+Expected<Value> parse(StringRef JSON) {
+ Parser P(JSON);
+ Value E = nullptr;
+ if (P.checkUTF8())
+ if (P.parseValue(E))
+ if (P.assertEnd())
+ return std::move(E);
+ return P.takeError();
+}
+char ParseError::ID = 0;
+
+static std::vector<const Object::value_type *> sortedElements(const Object &O) {
+ std::vector<const Object::value_type *> Elements;
+ for (const auto &E : O)
+ Elements.push_back(&E);
+ llvm::sort(Elements.begin(), Elements.end(),
+ [](const Object::value_type *L, const Object::value_type *R) {
+ return L->first < R->first;
+ });
+ return Elements;
+}
+
+bool isUTF8(llvm::StringRef S, size_t *ErrOffset) {
+ // Fast-path for ASCII, which is valid UTF-8.
+ if (LLVM_LIKELY(isASCII(S)))
+ return true;
+
+ const UTF8 *Data = reinterpret_cast<const UTF8 *>(S.data()), *Rest = Data;
+ if (LLVM_LIKELY(isLegalUTF8String(&Rest, Data + S.size())))
+ return true;
+
+ if (ErrOffset)
+ *ErrOffset = Rest - Data;
+ return false;
+}
+
+std::string fixUTF8(llvm::StringRef S) {
+ // This isn't particularly efficient, but is only for error-recovery.
+ std::vector<UTF32> Codepoints(S.size()); // 1 codepoint per byte suffices.
+ const UTF8 *In8 = reinterpret_cast<const UTF8 *>(S.data());
+ UTF32 *Out32 = Codepoints.data();
+ ConvertUTF8toUTF32(&In8, In8 + S.size(), &Out32, Out32 + Codepoints.size(),
+ lenientConversion);
+ Codepoints.resize(Out32 - Codepoints.data());
+ std::string Res(4 * Codepoints.size(), 0); // 4 bytes per codepoint suffice
+ const UTF32 *In32 = Codepoints.data();
+ UTF8 *Out8 = reinterpret_cast<UTF8 *>(&Res[0]);
+ ConvertUTF32toUTF8(&In32, In32 + Codepoints.size(), &Out8, Out8 + Res.size(),
+ strictConversion);
+ Res.resize(reinterpret_cast<char *>(Out8) - Res.data());
+ return Res;
+}
+
+} // namespace json
+} // namespace llvm
+
+static void quote(llvm::raw_ostream &OS, llvm::StringRef S) {
+ OS << '\"';
+ for (unsigned char C : S) {
+ if (C == 0x22 || C == 0x5C)
+ OS << '\\';
+ if (C >= 0x20) {
+ OS << C;
+ continue;
+ }
+ OS << '\\';
+ switch (C) {
+ // A few characters are common enough to make short escapes worthwhile.
+ case '\t':
+ OS << 't';
+ break;
+ case '\n':
+ OS << 'n';
+ break;
+ case '\r':
+ OS << 'r';
+ break;
+ default:
+ OS << 'u';
+ llvm::write_hex(OS, C, llvm::HexPrintStyle::Lower, 4);
+ break;
+ }
+ }
+ OS << '\"';
+}
+
+enum IndenterAction {
+ Indent,
+ Outdent,
+ Newline,
+ Space,
+};
+
+// Prints JSON. The indenter can be used to control formatting.
+template <typename Indenter>
+void llvm::json::Value::print(raw_ostream &OS, const Indenter &I) const {
+ switch (Type) {
+ case T_Null:
+ OS << "null";
+ break;
+ case T_Boolean:
+ OS << (as<bool>() ? "true" : "false");
+ break;
+ case T_Double:
+ OS << format("%.*g", std::numeric_limits<double>::max_digits10,
+ as<double>());
+ break;
+ case T_Integer:
+ OS << as<int64_t>();
+ break;
+ case T_StringRef:
+ quote(OS, as<StringRef>());
+ break;
+ case T_String:
+ quote(OS, as<std::string>());
+ break;
+ case T_Object: {
+ bool Comma = false;
+ OS << '{';
+ I(Indent);
+ for (const auto *P : sortedElements(as<json::Object>())) {
+ if (Comma)
+ OS << ',';
+ Comma = true;
+ I(Newline);
+ quote(OS, P->first);
+ OS << ':';
+ I(Space);
+ P->second.print(OS, I);
+ }
+ I(Outdent);
+ if (Comma)
+ I(Newline);
+ OS << '}';
+ break;
+ }
+ case T_Array: {
+ bool Comma = false;
+ OS << '[';
+ I(Indent);
+ for (const auto &E : as<json::Array>()) {
+ if (Comma)
+ OS << ',';
+ Comma = true;
+ I(Newline);
+ E.print(OS, I);
+ }
+ I(Outdent);
+ if (Comma)
+ I(Newline);
+ OS << ']';
+ break;
+ }
+ }
+}
+
+void llvm::format_provider<llvm::json::Value>::format(
+ const llvm::json::Value &E, raw_ostream &OS, StringRef Options) {
+ if (Options.empty()) {
+ OS << E;
+ return;
+ }
+ unsigned IndentAmount = 0;
+ if (Options.getAsInteger(/*Radix=*/10, IndentAmount))
+ llvm_unreachable("json::Value format options should be an integer");
+ unsigned IndentLevel = 0;
+ E.print(OS, [&](IndenterAction A) {
+ switch (A) {
+ case Newline:
+ OS << '\n';
+ OS.indent(IndentLevel);
+ break;
+ case Space:
+ OS << ' ';
+ break;
+ case Indent:
+ IndentLevel += IndentAmount;
+ break;
+ case Outdent:
+ IndentLevel -= IndentAmount;
+ break;
+ };
+ });
+}
+
+llvm::raw_ostream &llvm::json::operator<<(raw_ostream &OS, const Value &E) {
+ E.print(OS, [](IndenterAction A) { /*ignore*/ });
+ return OS;
+}
diff --git a/lib/Support/Locale.cpp b/lib/Support/Locale.cpp
index e24a28be4306..e57d377c9ab5 100644
--- a/lib/Support/Locale.cpp
+++ b/lib/Support/Locale.cpp
@@ -1,6 +1,5 @@
#include "llvm/Support/Locale.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Unicode.h"
namespace llvm {
@@ -8,7 +7,7 @@ namespace sys {
namespace locale {
int columnWidth(StringRef Text) {
-#if LLVM_ON_WIN32
+#if _WIN32
return Text.size();
#else
return llvm::sys::unicode::columnWidthUTF8(Text);
@@ -16,7 +15,7 @@ int columnWidth(StringRef Text) {
}
bool isPrint(int UCS) {
-#if LLVM_ON_WIN32
+#if _WIN32
// Restrict characters that we'll try to print to the lower part of ASCII
// except for the control characters (0x20 - 0x7E). In general one can not
// reliably output code points U+0080 and higher using narrow character C/C++
diff --git a/lib/Support/LockFileManager.cpp b/lib/Support/LockFileManager.cpp
index ec951f33a36a..77baf7ac4bdd 100644
--- a/lib/Support/LockFileManager.cpp
+++ b/lib/Support/LockFileManager.cpp
@@ -24,7 +24,7 @@
#include <sys/types.h>
#include <system_error>
#include <tuple>
-#if LLVM_ON_WIN32
+#if _WIN32
#include <windows.h>
#endif
#if LLVM_ON_UNIX
@@ -43,7 +43,7 @@
using namespace llvm;
-/// \brief Attempt to read the lock file with the given name, if it exists.
+/// Attempt to read the lock file with the given name, if it exists.
///
/// \param LockFileName The name of the lock file to read.
///
@@ -123,21 +123,33 @@ bool LockFileManager::processStillExecuting(StringRef HostID, int PID) {
namespace {
-/// An RAII helper object for cleanups.
-class RAIICleanup {
- std::function<void()> Fn;
- bool Canceled = false;
-
+/// 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;
public:
- RAIICleanup(std::function<void()> Fn) : Fn(Fn) {}
+ RemoveUniqueLockFileOnSignal(StringRef Name)
+ : Filename(Name), RemoveImmediately(true) {
+ sys::RemoveFileOnSignal(Filename, nullptr);
+ }
- ~RAIICleanup() {
- if (Canceled)
+ ~RemoveUniqueLockFileOnSignal() {
+ if (!RemoveImmediately) {
+ // Leave the signal handler enabled. It will be removed when the lock is
+ // released.
return;
- Fn();
+ }
+ sys::fs::remove(Filename);
+ sys::DontRemoveFileOnSignal(Filename);
}
- void cancel() { Canceled = true; }
+ void lockAcquired() { RemoveImmediately = false; }
};
} // end anonymous namespace
@@ -160,22 +172,16 @@ LockFileManager::LockFileManager(StringRef FileName)
return;
// Create a lock file that is unique to this instance.
- 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());
+ 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());
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.
{
@@ -185,46 +191,54 @@ LockFileManager::LockFileManager(StringRef FileName)
return;
}
- raw_fd_ostream Out(UniqueLockFile->FD, /*shouldClose=*/false);
+ raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true);
Out << HostID << ' ';
#if LLVM_ON_UNIX
Out << getpid();
#else
Out << "1";
#endif
- Out.flush();
+ Out.close();
if (Out.has_error()) {
// We failed to write out PID, so report the error, remove the
// unique lock file, and fail.
std::string S("failed to write to ");
- S.append(UniqueLockFile->TmpName);
+ S.append(UniqueLockFileName.str());
setError(Out.error(), S);
+ sys::fs::remove(UniqueLockFileName);
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(UniqueLockFile->TmpName, LockFileName);
+ sys::fs::create_link(UniqueLockFileName, LockFileName);
if (!EC) {
- RemoveTempFile.cancel();
+ RemoveUniqueFile.lockAcquired();
return;
}
if (EC != errc::file_exists) {
std::string S("failed to create link ");
raw_string_ostream OSS(S);
- OSS << LockFileName.str() << " to " << UniqueLockFile->TmpName;
+ OSS << LockFileName.str() << " to " << UniqueLockFileName.str();
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)))
- return; // RemoveTempFile will delete out our unique lock file.
+ if ((Owner = readLockFile(LockFileName))) {
+ // Wipe out our unique lock file (it's useless now)
+ sys::fs::remove(UniqueLockFileName);
+ return;
+ }
if (!sys::fs::exists(LockFileName)) {
// The previous owner released the lock file before we could read it.
@@ -236,7 +250,7 @@ LockFileManager::LockFileManager(StringRef FileName)
// ownership.
if ((EC = sys::fs::remove(LockFileName))) {
std::string S("failed to remove lockfile ");
- S.append(LockFileName.str());
+ S.append(UniqueLockFileName.str());
setError(EC, S);
return;
}
@@ -271,14 +285,17 @@ LockFileManager::~LockFileManager() {
// Since we own the lock, remove the lock file and our own unique lock file.
sys::fs::remove(LockFileName);
- consumeError(UniqueLockFile->discard());
+ 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);
}
LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() {
if (getState() != LFS_Shared)
return Res_Success;
-#if LLVM_ON_WIN32
+#if _WIN32
unsigned long Interval = 1;
#else
struct timespec Interval;
@@ -293,7 +310,7 @@ LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() {
// finish up and remove the lock file.
// FIXME: Should we hook in to system APIs to get a notification when the
// lock file is deleted?
-#if LLVM_ON_WIN32
+#if _WIN32
Sleep(Interval);
#else
nanosleep(&Interval, nullptr);
@@ -312,7 +329,7 @@ LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() {
return Res_OwnerDied;
// Exponentially increase the time we wait for the lock to be removed.
-#if LLVM_ON_WIN32
+#if _WIN32
Interval *= 2;
#else
Interval.tv_sec *= 2;
@@ -323,7 +340,7 @@ LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() {
}
#endif
} while (
-#if LLVM_ON_WIN32
+#if _WIN32
Interval < MaxSeconds * 1000
#else
Interval.tv_sec < (time_t)MaxSeconds
diff --git a/lib/Support/MD5.cpp b/lib/Support/MD5.cpp
index a53172279236..9b02f62912fa 100644
--- a/lib/Support/MD5.cpp
+++ b/lib/Support/MD5.cpp
@@ -74,7 +74,7 @@
using namespace llvm;
-/// \brief This processes one or more 64-byte data blocks, but does NOT update
+/// This processes one or more 64-byte data blocks, but does NOT update
///the bit counters. There are no alignment requirements.
const uint8_t *MD5::body(ArrayRef<uint8_t> Data) {
const uint8_t *ptr;
@@ -229,7 +229,7 @@ void MD5::update(StringRef Str) {
update(SVal);
}
-/// \brief Finish the hash and place the resulting hash into \p result.
+/// Finish the hash and place the resulting hash into \p result.
/// \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/ManagedStatic.cpp b/lib/Support/ManagedStatic.cpp
index fb7cd070c42d..1c884dc70fc9 100644
--- a/lib/Support/ManagedStatic.cpp
+++ b/lib/Support/ManagedStatic.cpp
@@ -28,9 +28,6 @@ static void initializeMutex() {
}
static sys::Mutex* getManagedStaticMutex() {
- // We need to use a function local static here, since this can get called
- // during a static constructor and we need to guarantee that it's initialized
- // correctly.
llvm::call_once(mutex_init_flag, initializeMutex);
return ManagedStaticMutex;
}
diff --git a/lib/Support/Memory.cpp b/lib/Support/Memory.cpp
index f9a4903ad015..c245eedd2c16 100644
--- a/lib/Support/Memory.cpp
+++ b/lib/Support/Memory.cpp
@@ -13,13 +13,13 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Memory.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Valgrind.h"
// Include the platform-specific parts of this class.
#ifdef LLVM_ON_UNIX
#include "Unix/Memory.inc"
#endif
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
#include "Windows/Memory.inc"
#endif
diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp
index c709fc416df6..4428c2f24e32 100644
--- a/lib/Support/MemoryBuffer.cpp
+++ b/lib/Support/MemoryBuffer.cpp
@@ -21,6 +21,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
+#include "llvm/Support/SmallVectorMemoryBuffer.h"
#include <cassert>
#include <cerrno>
#include <cstring>
@@ -139,15 +140,6 @@ MemoryBuffer::getMemBufferCopy(StringRef InputData, const Twine &BufferName) {
return nullptr;
}
-std::unique_ptr<MemoryBuffer>
-MemoryBuffer::getNewMemBuffer(size_t Size, StringRef BufferName) {
- auto SB = WritableMemoryBuffer::getNewUninitMemBuffer(Size, BufferName);
- if (!SB)
- return nullptr;
- memset(SB->getBufferStart(), 0, Size);
- return std::move(SB);
-}
-
ErrorOr<std::unique_ptr<MemoryBuffer>>
MemoryBuffer::getFileOrSTDIN(const Twine &Filename, int64_t FileSize,
bool RequiresNullTerminator) {
@@ -171,7 +163,7 @@ MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize,
//===----------------------------------------------------------------------===//
namespace {
-/// \brief Memory maps a file descriptor using sys::fs::mapped_file_region.
+/// Memory maps a file descriptor using sys::fs::mapped_file_region.
///
/// This handles converting the offset into a legal offset on the platform.
template<typename MB>
@@ -193,10 +185,8 @@ class MemoryBufferMMapFile : public MB {
public:
MemoryBufferMMapFile(bool RequiresNullTerminator, int FD, uint64_t Len,
uint64_t Offset, std::error_code &EC)
- : MFR(FD,
- MB::Writable ? sys::fs::mapped_file_region::priv
- : sys::fs::mapped_file_region::readonly,
- getLegalMapSize(Len, Offset), getLegalMapOffset(Offset), EC) {
+ : MFR(FD, MB::Mapmode, getLegalMapSize(Len, Offset),
+ getLegalMapOffset(Offset), EC) {
if (!EC) {
const char *Start = getStart(Len, Offset);
MemoryBuffer::init(Start, Start + Len, RequiresNullTerminator);
@@ -226,7 +216,7 @@ getMemoryBufferForStream(int FD, const Twine &BufferName) {
// Read into Buffer until we hit EOF.
do {
Buffer.reserve(Buffer.size() + ChunkSize);
- ReadBytes = sys::RetryAfterSignal(-1, read, FD, Buffer.end(), ChunkSize);
+ ReadBytes = sys::RetryAfterSignal(-1, ::read, FD, Buffer.end(), ChunkSize);
if (ReadBytes == -1)
return std::error_code(errno, std::generic_category());
Buffer.set_size(Buffer.size() + ReadBytes);
@@ -254,7 +244,7 @@ static ErrorOr<std::unique_ptr<MB>>
getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize,
uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile) {
int FD;
- std::error_code EC = sys::fs::openFileForRead(Filename, FD);
+ std::error_code EC = sys::fs::openFileForRead(Filename, FD, sys::fs::OF_None);
if (EC)
return EC;
@@ -306,6 +296,15 @@ WritableMemoryBuffer::getNewUninitMemBuffer(size_t Size, const Twine &BufferName
return std::unique_ptr<WritableMemoryBuffer>(Ret);
}
+std::unique_ptr<WritableMemoryBuffer>
+WritableMemoryBuffer::getNewMemBuffer(size_t Size, const Twine &BufferName) {
+ auto SB = WritableMemoryBuffer::getNewUninitMemBuffer(Size, BufferName);
+ if (!SB)
+ return nullptr;
+ memset(SB->getBufferStart(), 0, Size);
+ return SB;
+}
+
static bool shouldUseMmap(int FD,
size_t FileSize,
size_t MapSize,
@@ -361,6 +360,59 @@ static bool shouldUseMmap(int FD,
return true;
}
+static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
+getReadWriteFile(const Twine &Filename, uint64_t FileSize, uint64_t MapSize,
+ uint64_t Offset) {
+ int FD;
+ std::error_code EC = sys::fs::openFileForReadWrite(
+ Filename, FD, sys::fs::CD_OpenExisting, sys::fs::OF_None);
+
+ if (EC)
+ return EC;
+
+ // Default is to map the full file.
+ if (MapSize == uint64_t(-1)) {
+ // If we don't know the file size, use fstat to find out. fstat on an open
+ // file descriptor is cheaper than stat on a random path.
+ if (FileSize == uint64_t(-1)) {
+ sys::fs::file_status Status;
+ std::error_code EC = sys::fs::status(FD, Status);
+ if (EC)
+ return EC;
+
+ // If this not a file or a block device (e.g. it's a named pipe
+ // or character device), we can't mmap it, so error out.
+ sys::fs::file_type Type = Status.type();
+ if (Type != sys::fs::file_type::regular_file &&
+ Type != sys::fs::file_type::block_file)
+ return make_error_code(errc::invalid_argument);
+
+ FileSize = Status.getSize();
+ }
+ MapSize = FileSize;
+ }
+
+ std::unique_ptr<WriteThroughMemoryBuffer> Result(
+ new (NamedBufferAlloc(Filename))
+ MemoryBufferMMapFile<WriteThroughMemoryBuffer>(false, FD, MapSize,
+ Offset, EC));
+ if (EC)
+ return EC;
+ return std::move(Result);
+}
+
+ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
+WriteThroughMemoryBuffer::getFile(const Twine &Filename, int64_t FileSize) {
+ return getReadWriteFile(Filename, FileSize, FileSize, 0);
+}
+
+/// Map a subrange of the specified file as a WritableMemoryBuffer.
+ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
+WriteThroughMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize,
+ uint64_t Offset) {
+ return getReadWriteFile(Filename, -1, MapSize, Offset);
+}
+
template <typename MB>
static ErrorOr<std::unique_ptr<MB>>
getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize,
@@ -466,7 +518,7 @@ ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() {
ErrorOr<std::unique_ptr<MemoryBuffer>>
MemoryBuffer::getFileAsStream(const Twine &Filename) {
int FD;
- std::error_code EC = sys::fs::openFileForRead(Filename, FD);
+ std::error_code EC = sys::fs::openFileForRead(Filename, FD, sys::fs::OF_None);
if (EC)
return EC;
ErrorOr<std::unique_ptr<MemoryBuffer>> Ret =
@@ -480,3 +532,6 @@ MemoryBufferRef MemoryBuffer::getMemBufferRef() const {
StringRef Identifier = getBufferIdentifier();
return MemoryBufferRef(Data, Identifier);
}
+
+void MemoryBuffer::anchor() {}
+void SmallVectorMemoryBuffer::anchor() {}
diff --git a/lib/Support/Mutex.cpp b/lib/Support/Mutex.cpp
index b1d5e7c0d991..7138c7a4b984 100644
--- a/lib/Support/Mutex.cpp
+++ b/lib/Support/Mutex.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Mutex.h"
-#include "llvm/Support/ErrorHandling.h"
#include "llvm/Config/config.h"
+#include "llvm/Support/ErrorHandling.h"
//===----------------------------------------------------------------------===//
//=== WARNING: Implementation here must contain only TRULY operating system
@@ -47,10 +47,7 @@ MutexImpl::MutexImpl( bool recursive)
{
// Declare the pthread_mutex data structures
pthread_mutex_t* mutex =
- static_cast<pthread_mutex_t*>(malloc(sizeof(pthread_mutex_t)));
-
- if (mutex == nullptr)
- report_bad_alloc_error("Mutex allocation failed");
+ static_cast<pthread_mutex_t*>(safe_malloc(sizeof(pthread_mutex_t)));
pthread_mutexattr_t attr;
@@ -119,9 +116,9 @@ MutexImpl::tryacquire()
#elif defined(LLVM_ON_UNIX)
#include "Unix/Mutex.inc"
-#elif defined( LLVM_ON_WIN32)
+#elif defined( _WIN32)
#include "Windows/Mutex.inc"
#else
-#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in Support/Mutex.cpp
+#warning Neither LLVM_ON_UNIX nor _WIN32 was set in Support/Mutex.cpp
#endif
#endif
diff --git a/lib/Support/NativeFormatting.cpp b/lib/Support/NativeFormatting.cpp
index b951a88a38db..85b4bfb81568 100644
--- a/lib/Support/NativeFormatting.cpp
+++ b/lib/Support/NativeFormatting.cpp
@@ -14,6 +14,8 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Format.h"
+#include <float.h>
+
using namespace llvm;
template<typename T, std::size_t N>
diff --git a/lib/Support/Parallel.cpp b/lib/Support/Parallel.cpp
index 010e42916f95..1844003b9d3d 100644
--- a/lib/Support/Parallel.cpp
+++ b/lib/Support/Parallel.cpp
@@ -9,6 +9,9 @@
#include "llvm/Support/Parallel.h"
#include "llvm/Config/llvm-config.h"
+
+#if LLVM_ENABLE_THREADS
+
#include "llvm/Support/Threading.h"
#include <atomic>
@@ -19,7 +22,7 @@ using namespace llvm;
namespace {
-/// \brief An abstract class that takes closures and runs them asynchronously.
+/// An abstract class that takes closures and runs them asynchronously.
class Executor {
public:
virtual ~Executor() = default;
@@ -28,19 +31,8 @@ public:
static Executor *getDefaultExecutor();
};
-#if !LLVM_ENABLE_THREADS
-class SyncExecutor : public Executor {
-public:
- virtual void add(std::function<void()> F) { F(); }
-};
-
-Executor *Executor::getDefaultExecutor() {
- static SyncExecutor Exec;
- return &Exec;
-}
-
-#elif defined(_MSC_VER)
-/// \brief An Executor that runs tasks via ConcRT.
+#if defined(_MSC_VER)
+/// An Executor that runs tasks via ConcRT.
class ConcRTExecutor : public Executor {
struct Taskish {
Taskish(std::function<void()> Task) : Task(Task) {}
@@ -67,7 +59,7 @@ Executor *Executor::getDefaultExecutor() {
}
#else
-/// \brief An implementation of an Executor that runs closures on a thread pool
+/// An implementation of an Executor that runs closures on a thread pool
/// in filo order.
class ThreadPoolExecutor : public Executor {
public:
@@ -127,7 +119,6 @@ Executor *Executor::getDefaultExecutor() {
#endif
}
-#if LLVM_ENABLE_THREADS
void parallel::detail::TaskGroup::spawn(std::function<void()> F) {
L.inc();
Executor::getDefaultExecutor()->add([&, F] {
@@ -135,4 +126,4 @@ void parallel::detail::TaskGroup::spawn(std::function<void()> F) {
L.dec();
});
}
-#endif
+#endif // LLVM_ENABLE_THREADS
diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp
index f229f23a4f84..a806da23ec50 100644
--- a/lib/Support/Path.cpp
+++ b/lib/Support/Path.cpp
@@ -13,6 +13,7 @@
#include "llvm/Support/Path.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
@@ -37,7 +38,7 @@ namespace {
using llvm::sys::path::Style;
inline Style real_style(Style style) {
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
return (style == Style::posix) ? Style::posix : Style::windows;
#else
return (style == Style::windows) ? Style::windows : Style::posix;
@@ -90,10 +91,9 @@ namespace {
return path.substr(0, end);
}
+ // Returns the first character of the filename in str. For paths ending in
+ // '/', it returns the position of the '/'.
size_t filename_pos(StringRef str, Style style) {
- if (str.size() == 2 && is_separator(str[0], style) && str[0] == str[1])
- return 0;
-
if (str.size() > 0 && is_separator(str[str.size() - 1], style))
return str.size() - 1;
@@ -110,6 +110,8 @@ namespace {
return pos + 1;
}
+ // Returns the position of the root directory in str. If there is no root
+ // directory in str, it returns StringRef::npos.
size_t root_dir_start(StringRef str, Style style) {
// case "c:/"
if (real_style(style) == Style::windows) {
@@ -117,10 +119,6 @@ namespace {
return 2;
}
- // case "//"
- if (str.size() == 2 && is_separator(str[0], style) && str[0] == str[1])
- return StringRef::npos;
-
// case "//net"
if (str.size() > 3 && is_separator(str[0], style) && str[0] == str[1] &&
!is_separator(str[2], style)) {
@@ -134,22 +132,29 @@ namespace {
return StringRef::npos;
}
+ // Returns the position past the end of the "parent path" of path. The parent
+ // path will not end in '/', unless the parent is the root directory. If the
+ // path has no parent, 0 is returned.
size_t parent_path_end(StringRef path, Style style) {
size_t end_pos = filename_pos(path, style);
bool filename_was_sep =
path.size() > 0 && is_separator(path[end_pos], style);
- // Skip separators except for root dir.
- size_t root_dir_pos = root_dir_start(path.substr(0, end_pos), style);
-
- while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
+ // Skip separators until we reach root dir (or the start of the string).
+ size_t root_dir_pos = root_dir_start(path, style);
+ while (end_pos > 0 &&
+ (root_dir_pos == StringRef::npos || end_pos > root_dir_pos) &&
is_separator(path[end_pos - 1], style))
--end_pos;
- if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep)
- return StringRef::npos;
+ if (end_pos == root_dir_pos && !filename_was_sep) {
+ // We've reached the root dir and the input path was *not* ending in a
+ // sequence of slashes. Include the root dir in the parent path.
+ return root_dir_pos + 1;
+ }
+ // Otherwise, just include before the last slash.
return end_pos;
}
} // end unnamed namespace
@@ -164,7 +169,7 @@ 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) {
+ sys::fs::OpenFlags Flags = sys::fs::OF_None) {
SmallString<128> ModelStorage;
Model.toVector(ModelStorage);
@@ -196,8 +201,8 @@ retry_random_path:
switch (Type) {
case FS_File: {
if (std::error_code EC =
- sys::fs::openFileForWrite(Twine(ResultPath.begin()), ResultFD,
- Flags | sys::fs::F_Excl, Mode)) {
+ sys::fs::openFileForReadWrite(Twine(ResultPath.begin()), ResultFD,
+ sys::fs::CD_CreateNew, Flags, Mode)) {
if (EC == errc::file_exists)
goto retry_random_path;
return EC;
@@ -281,8 +286,8 @@ const_iterator &const_iterator::operator++() {
++Position;
}
- // Treat trailing '/' as a '.'.
- if (Position == Path.size()) {
+ // Treat trailing '/' as a '.', unless it is the root dir.
+ if (Position == Path.size() && Component != "/") {
--Position;
Component = ".";
return *this;
@@ -321,23 +326,23 @@ reverse_iterator rend(StringRef Path) {
}
reverse_iterator &reverse_iterator::operator++() {
- // If we're at the end and the previous char was a '/', return '.' unless
- // we are the root path.
size_t root_dir_pos = root_dir_start(Path, S);
- if (Position == Path.size() && Path.size() > root_dir_pos + 1 &&
- is_separator(Path[Position - 1], S)) {
- --Position;
- Component = ".";
- return *this;
- }
// Skip separators unless it's the root directory.
size_t end_pos = Position;
-
while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
is_separator(Path[end_pos - 1], S))
--end_pos;
+ // Treat trailing '/' as a '.', unless it is the root dir.
+ if (Position == Path.size() && !Path.empty() &&
+ is_separator(Path.back(), S) &&
+ (root_dir_pos == StringRef::npos || end_pos - 1 > root_dir_pos)) {
+ --Position;
+ Component = ".";
+ return *this;
+ }
+
// Find next separator.
size_t start_pos = filename_pos(Path.substr(0, end_pos), S);
Component = Path.slice(start_pos, end_pos);
@@ -751,51 +756,64 @@ std::error_code getUniqueID(const Twine Path, UniqueID &Result) {
std::error_code createUniqueFile(const Twine &Model, int &ResultFd,
SmallVectorImpl<char> &ResultPath,
- unsigned Mode, sys::fs::OpenFlags Flags) {
+ unsigned Mode) {
+ return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File);
+}
+
+static std::error_code createUniqueFile(const Twine &Model, int &ResultFd,
+ SmallVectorImpl<char> &ResultPath,
+ unsigned Mode, OpenFlags Flags) {
return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File,
Flags);
}
std::error_code createUniqueFile(const Twine &Model,
- SmallVectorImpl<char> &ResultPath) {
- int Dummy;
- return createUniqueEntity(Model, Dummy, ResultPath, false, 0, FS_Name);
+ SmallVectorImpl<char> &ResultPath,
+ unsigned Mode) {
+ int FD;
+ auto EC = createUniqueFile(Model, FD, ResultPath, Mode);
+ if (EC)
+ return EC;
+ // FD is only needed to avoid race conditions. Close it right away.
+ close(FD);
+ return EC;
}
static std::error_code
createTemporaryFile(const Twine &Model, int &ResultFD,
- llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type,
- sys::fs::OpenFlags Flags) {
+ llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) {
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, Flags);
+ owner_read | owner_write, Type);
}
static std::error_code
createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD,
- llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type,
- sys::fs::OpenFlags Flags = sys::fs::F_None) {
+ llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) {
const char *Middle = Suffix.empty() ? "-%%%%%%" : "-%%%%%%.";
return createTemporaryFile(Prefix + Middle + Suffix, ResultFD, ResultPath,
- Type, Flags);
+ Type);
}
std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
int &ResultFD,
- SmallVectorImpl<char> &ResultPath,
- sys::fs::OpenFlags Flags) {
- return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File,
- Flags);
+ SmallVectorImpl<char> &ResultPath) {
+ return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File);
}
std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
SmallVectorImpl<char> &ResultPath) {
- int Dummy;
- return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name);
+ int FD;
+ auto EC = createTemporaryFile(Prefix, Suffix, FD, ResultPath);
+ if (EC)
+ return EC;
+ // FD is only needed to avoid race conditions. Close it right away.
+ close(FD);
+ return EC;
}
@@ -804,8 +822,22 @@ std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
std::error_code createUniqueDirectory(const Twine &Prefix,
SmallVectorImpl<char> &ResultPath) {
int Dummy;
- return createUniqueEntity(Prefix + "-%%%%%%", Dummy, ResultPath,
- true, 0, FS_Dir);
+ return createUniqueEntity(Prefix + "-%%%%%%", Dummy, ResultPath, true, 0,
+ FS_Dir);
+}
+
+std::error_code
+getPotentiallyUniqueFileName(const Twine &Model,
+ SmallVectorImpl<char> &ResultPath) {
+ int Dummy;
+ return createUniqueEntity(Model, Dummy, ResultPath, false, 0, FS_Name);
+}
+
+std::error_code
+getPotentiallyUniqueTempFileName(const Twine &Prefix, StringRef Suffix,
+ SmallVectorImpl<char> &ResultPath) {
+ int Dummy;
+ return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name);
}
static std::error_code make_absolute(const Twine &current_directory,
@@ -895,15 +927,7 @@ std::error_code create_directories(const Twine &Path, bool IgnoreExisting,
return create_directory(P, IgnoreExisting, Perms);
}
-std::error_code copy_file(const Twine &From, const Twine &To) {
- int ReadFD, WriteFD;
- if (std::error_code EC = openFileForRead(From, ReadFD))
- return EC;
- if (std::error_code EC = openFileForWrite(To, WriteFD, F_None)) {
- close(ReadFD);
- return EC;
- }
-
+static std::error_code copy_file_internal(int ReadFD, int WriteFD) {
const size_t BufSize = 4096;
char *Buf = new char[BufSize];
int BytesRead = 0, BytesWritten = 0;
@@ -920,8 +944,6 @@ std::error_code copy_file(const Twine &From, const Twine &To) {
if (BytesWritten < 0)
break;
}
- close(ReadFD);
- close(WriteFD);
delete[] Buf;
if (BytesRead < 0 || BytesWritten < 0)
@@ -929,6 +951,36 @@ std::error_code copy_file(const Twine &From, const Twine &To) {
return std::error_code();
}
+std::error_code copy_file(const Twine &From, const Twine &To) {
+ int ReadFD, WriteFD;
+ if (std::error_code EC = openFileForRead(From, ReadFD, OF_None))
+ return EC;
+ if (std::error_code EC =
+ openFileForWrite(To, WriteFD, CD_CreateAlways, OF_None)) {
+ close(ReadFD);
+ return EC;
+ }
+
+ std::error_code EC = copy_file_internal(ReadFD, WriteFD);
+
+ close(ReadFD);
+ close(WriteFD);
+
+ return EC;
+}
+
+std::error_code copy_file(const Twine &From, int ToFD) {
+ int ReadFD;
+ if (std::error_code EC = openFileForRead(From, ReadFD, OF_None))
+ return EC;
+
+ std::error_code EC = copy_file_internal(ReadFD, ToFD);
+
+ close(ReadFD);
+
+ return EC;
+}
+
ErrorOr<MD5::MD5Result> md5_contents(int FD) {
MD5 Hash;
@@ -951,7 +1003,7 @@ ErrorOr<MD5::MD5Result> md5_contents(int FD) {
ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path) {
int FD;
- if (auto EC = openFileForRead(Path, FD))
+ if (auto EC = openFileForRead(Path, FD, OF_None))
return EC;
auto Result = md5_contents(FD);
@@ -1048,7 +1100,7 @@ ErrorOr<perms> getPermissions(const Twine &Path) {
#if defined(LLVM_ON_UNIX)
#include "Unix/Path.inc"
#endif
-#if defined(LLVM_ON_WIN32)
+#if defined(_WIN32)
#include "Windows/Path.inc"
#endif
@@ -1070,7 +1122,7 @@ Error TempFile::discard() {
Done = true;
std::error_code RemoveEC;
// On windows closing will remove the file.
-#ifndef LLVM_ON_WIN32
+#ifndef _WIN32
// Always try to close and remove.
if (!TmpName.empty()) {
RemoveEC = fs::remove(TmpName);
@@ -1094,14 +1146,15 @@ 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);
+#ifdef _WIN32
+ // If we can't cancel the delete don't rename.
+ auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+ std::error_code RenameEC = setDeleteDisposition(H, false);
if (!RenameEC)
RenameEC = rename_fd(FD, Name);
// If we can't rename, discard the temporary file.
if (RenameEC)
- removeFD(FD);
+ setDeleteDisposition(H, true);
#else
std::error_code RenameEC = fs::rename(TmpName, Name);
// If we can't rename, discard the temporary file.
@@ -1126,8 +1179,9 @@ Error TempFile::keep() {
assert(!Done);
Done = true;
-#ifdef LLVM_ON_WIN32
- if (std::error_code EC = cancelDeleteOnClose(FD))
+#ifdef _WIN32
+ auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+ if (std::error_code EC = setDeleteDisposition(H, false))
return errorCodeToError(EC);
#else
sys::DontRemoveFileOnSignal(TmpName);
@@ -1147,12 +1201,12 @@ Error TempFile::keep() {
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))
+ if (std::error_code EC =
+ createUniqueFile(Model, FD, ResultPath, Mode, OF_Delete))
return errorCodeToError(EC);
TempFile Ret(ResultPath, FD);
-#ifndef LLVM_ON_WIN32
+#ifndef _WIN32
if (sys::RemoveFileOnSignal(ResultPath)) {
// Make sure we delete the file when RemoveFileOnSignal fails.
consumeError(Ret.discard());
diff --git a/lib/Support/PrettyStackTrace.cpp b/lib/Support/PrettyStackTrace.cpp
index a18e9cc50040..f5b6e6f3652d 100644
--- a/lib/Support/PrettyStackTrace.cpp
+++ b/lib/Support/PrettyStackTrace.cpp
@@ -88,7 +88,11 @@ extern "C" {
CRASH_REPORTER_CLIENT_HIDDEN
struct crashreporter_annotations_t gCRAnnotations
__attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION)))
+#if CRASHREPORTER_ANNOTATIONS_VERSION < 5
= { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0 };
+#else
+ = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0, 0 };
+#endif
}
#elif defined(__APPLE__) && HAVE_CRASHREPORTER_INFO
extern "C" const char *__crashreporter_info__
@@ -114,9 +118,9 @@ static void CrashHandler(void *) {
if (!TmpStr.empty()) {
#ifdef HAVE_CRASHREPORTERCLIENT_H
// Cast to void to avoid warning.
- (void)CRSetCrashLogMessage(std::string(TmpStr.str()).c_str());
+ (void)CRSetCrashLogMessage(TmpStr.c_str());
#elif HAVE_CRASHREPORTER_INFO
- __crashreporter_info__ = strdup(std::string(TmpStr.str()).c_str());
+ __crashreporter_info__ = strdup(TmpStr.c_str());
#endif
errs() << TmpStr.str();
}
diff --git a/lib/Support/Process.cpp b/lib/Support/Process.cpp
index 1c8cc6e83ad1..3f5a9d722ca0 100644
--- a/lib/Support/Process.cpp
+++ b/lib/Support/Process.cpp
@@ -14,7 +14,7 @@
#include "llvm/Support/Process.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
@@ -93,6 +93,6 @@ bool Process::AreCoreFilesPrevented() {
#ifdef LLVM_ON_UNIX
#include "Unix/Process.inc"
#endif
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
#include "Windows/Process.inc"
#endif
diff --git a/lib/Support/Program.cpp b/lib/Support/Program.cpp
index 4212323bc0e1..63cdcdaabee9 100644
--- a/lib/Support/Program.cpp
+++ b/lib/Support/Program.cpp
@@ -13,7 +13,7 @@
#include "llvm/Support/Program.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
#include <system_error>
using namespace llvm;
using namespace sys;
@@ -23,17 +23,19 @@ using namespace sys;
//=== independent code.
//===----------------------------------------------------------------------===//
-static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
- const char **Env, ArrayRef<Optional<StringRef>> Redirects,
+static bool Execute(ProcessInfo &PI, StringRef Program,
+ ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env,
+ ArrayRef<Optional<StringRef>> Redirects,
unsigned MemoryLimit, std::string *ErrMsg);
-int sys::ExecuteAndWait(StringRef Program, const char **Args, const char **Envp,
+int sys::ExecuteAndWait(StringRef Program, ArrayRef<StringRef> Args,
+ Optional<ArrayRef<StringRef>> Env,
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, Env, Redirects, MemoryLimit, ErrMsg)) {
if (ExecutionFailed)
*ExecutionFailed = false;
ProcessInfo Result = Wait(
@@ -47,8 +49,8 @@ int sys::ExecuteAndWait(StringRef Program, const char **Args, const char **Envp,
return -1;
}
-ProcessInfo sys::ExecuteNoWait(StringRef Program, const char **Args,
- const char **Envp,
+ProcessInfo sys::ExecuteNoWait(StringRef Program, ArrayRef<StringRef> Args,
+ Optional<ArrayRef<StringRef>> Env,
ArrayRef<Optional<StringRef>> Redirects,
unsigned MemoryLimit, std::string *ErrMsg,
bool *ExecutionFailed) {
@@ -56,17 +58,26 @@ ProcessInfo sys::ExecuteNoWait(StringRef Program, const char **Args,
ProcessInfo PI;
if (ExecutionFailed)
*ExecutionFailed = false;
- if (!Execute(PI, Program, Args, Envp, Redirects, MemoryLimit, ErrMsg))
+ if (!Execute(PI, Program, Args, Env, Redirects, MemoryLimit, ErrMsg))
if (ExecutionFailed)
*ExecutionFailed = true;
return PI;
}
+bool sys::commandLineFitsWithinSystemLimits(StringRef Program,
+ ArrayRef<const char *> Args) {
+ SmallVector<StringRef, 8> StringRefArgs;
+ StringRefArgs.reserve(Args.size());
+ for (const char *A : Args)
+ StringRefArgs.emplace_back(A);
+ return commandLineFitsWithinSystemLimits(Program, StringRefArgs);
+}
+
// Include the platform-specific parts of this class.
#ifdef LLVM_ON_UNIX
#include "Unix/Program.inc"
#endif
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
#include "Windows/Program.inc"
#endif
diff --git a/lib/Support/RWMutex.cpp b/lib/Support/RWMutex.cpp
index 83c6d1d52b4c..8b6d74e49f31 100644
--- a/lib/Support/RWMutex.cpp
+++ b/lib/Support/RWMutex.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/Support/Allocator.h"
#include "llvm/Support/RWMutex.h"
#include "llvm/Config/config.h"
@@ -49,7 +50,7 @@ RWMutexImpl::RWMutexImpl()
{
// Declare the pthread_rwlock data structures
pthread_rwlock_t* rwlock =
- static_cast<pthread_rwlock_t*>(malloc(sizeof(pthread_rwlock_t)));
+ static_cast<pthread_rwlock_t*>(safe_malloc(sizeof(pthread_rwlock_t)));
#ifdef __APPLE__
// Workaround a bug/mis-feature in Darwin's pthread_rwlock_init.
@@ -116,9 +117,9 @@ RWMutexImpl::writer_release()
#elif defined(LLVM_ON_UNIX)
#include "Unix/RWMutex.inc"
-#elif defined( LLVM_ON_WIN32)
+#elif defined( _WIN32)
#include "Windows/RWMutex.inc"
#else
-#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in Support/Mutex.cpp
+#warning Neither LLVM_ON_UNIX nor _WIN32 was set in Support/Mutex.cpp
#endif
#endif
diff --git a/lib/Support/RandomNumberGenerator.cpp b/lib/Support/RandomNumberGenerator.cpp
index 47d20159200b..f1f22af82a81 100644
--- a/lib/Support/RandomNumberGenerator.cpp
+++ b/lib/Support/RandomNumberGenerator.cpp
@@ -17,7 +17,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
#include "Windows/WindowsSupport.h"
#else
#include "Unix/Unix.h"
@@ -36,10 +36,8 @@ static cl::opt<unsigned long long>
cl::desc("Seed for the random number generator"), cl::init(0));
RandomNumberGenerator::RandomNumberGenerator(StringRef Salt) {
- DEBUG(
- if (Seed == 0)
- dbgs() << "Warning! Using unseeded random number generator.\n"
- );
+ LLVM_DEBUG(if (Seed == 0) dbgs()
+ << "Warning! Using unseeded random number generator.\n");
// Combine seed and salts using std::seed_seq.
// Data: Seed-low, Seed-high, Salt
@@ -63,7 +61,7 @@ RandomNumberGenerator::result_type RandomNumberGenerator::operator()() {
// Get random vector of specified size
std::error_code llvm::getRandomBytes(void *Buffer, size_t Size) {
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
HCRYPTPROV hProvider;
if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
diff --git a/lib/Support/Regex.cpp b/lib/Support/Regex.cpp
index b1087fd8853c..48caab131526 100644
--- a/lib/Support/Regex.cpp
+++ b/lib/Support/Regex.cpp
@@ -12,11 +12,16 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Regex.h"
-#include "regex_impl.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include <string>
+
+// Important this comes last because it defines "_REGEX_H_". At least on
+// Darwin, if included before any header that (transitively) includes
+// xlocale.h, this will cause trouble, because of missing regex-related types.
+#include "regex_impl.h"
+
using namespace llvm;
Regex::Regex() : preg(nullptr), error(REG_BADPAT) {}
@@ -25,7 +30,7 @@ Regex::Regex(StringRef regex, unsigned Flags) {
unsigned flags = 0;
preg = new llvm_regex();
preg->re_endp = regex.end();
- if (Flags & IgnoreCase)
+ if (Flags & IgnoreCase)
flags |= REG_ICASE;
if (Flags & Newline)
flags |= REG_NEWLINE;
@@ -51,9 +56,9 @@ Regex::~Regex() {
bool Regex::isValid(std::string &Error) const {
if (!error)
return true;
-
+
size_t len = llvm_regerror(error, preg, nullptr, 0);
-
+
Error.resize(len - 1);
llvm_regerror(error, preg, &Error[0], len);
return false;
@@ -91,7 +96,7 @@ bool Regex::match(StringRef String, SmallVectorImpl<StringRef> *Matches){
if (Matches) { // match position requested
Matches->clear();
-
+
for (unsigned i = 0; i != nmatch; ++i) {
if (pm[i].rm_so == -1) {
// this group didn't match
diff --git a/lib/Support/SHA1.cpp b/lib/Support/SHA1.cpp
index 20f41c5ff447..3007a78d5e22 100644
--- a/lib/Support/SHA1.cpp
+++ b/lib/Support/SHA1.cpp
@@ -1,4 +1,4 @@
-//======- SHA1.h - Private copy of the SHA1 implementation ---*- C++ -* ======//
+//====- SHA1.cpp - Private copy of the SHA1 implementation ---*- C++ -* ======//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/Support/Signals.cpp b/lib/Support/Signals.cpp
index 661f4d649cdd..6534ff69b84c 100644
--- a/lib/Support/Signals.cpp
+++ b/lib/Support/Signals.cpp
@@ -15,7 +15,7 @@
#include "llvm/Support/Signals.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
@@ -36,19 +36,55 @@
using namespace llvm;
-static cl::opt<bool>
+// Use explicit storage to avoid accessing cl::opt in a signal handler.
+static bool DisableSymbolicationFlag = false;
+static cl::opt<bool, true>
DisableSymbolication("disable-symbolication",
cl::desc("Disable symbolizing crash backtraces."),
- cl::init(false), cl::Hidden);
-
-static ManagedStatic<std::vector<std::pair<void (*)(void *), void *>>>
- CallBacksToRun;
+ cl::location(DisableSymbolicationFlag), cl::Hidden);
+
+// Callbacks to run in signal handler must be lock-free because a signal handler
+// could be running as we add new callbacks. We don't add unbounded numbers of
+// callbacks, an array is therefore sufficient.
+struct CallbackAndCookie {
+ sys::SignalHandlerCallback Callback;
+ void *Cookie;
+ enum class Status { Empty, Initializing, Initialized, Executing };
+ std::atomic<Status> Flag;
+};
+static constexpr size_t MaxSignalHandlerCallbacks = 8;
+static CallbackAndCookie CallBacksToRun[MaxSignalHandlerCallbacks];
+
+// Signal-safe.
void sys::RunSignalHandlers() {
- if (!CallBacksToRun.isConstructed())
+ for (size_t I = 0; I < MaxSignalHandlerCallbacks; ++I) {
+ auto &RunMe = CallBacksToRun[I];
+ auto Expected = CallbackAndCookie::Status::Initialized;
+ auto Desired = CallbackAndCookie::Status::Executing;
+ if (!RunMe.Flag.compare_exchange_strong(Expected, Desired))
+ continue;
+ (*RunMe.Callback)(RunMe.Cookie);
+ RunMe.Callback = nullptr;
+ RunMe.Cookie = nullptr;
+ RunMe.Flag.store(CallbackAndCookie::Status::Empty);
+ }
+}
+
+// Signal-safe.
+static void insertSignalHandler(sys::SignalHandlerCallback FnPtr,
+ void *Cookie) {
+ for (size_t I = 0; I < MaxSignalHandlerCallbacks; ++I) {
+ auto &SetMe = CallBacksToRun[I];
+ auto Expected = CallbackAndCookie::Status::Empty;
+ auto Desired = CallbackAndCookie::Status::Initializing;
+ if (!SetMe.Flag.compare_exchange_strong(Expected, Desired))
+ continue;
+ SetMe.Callback = FnPtr;
+ SetMe.Cookie = Cookie;
+ SetMe.Flag.store(CallbackAndCookie::Status::Initialized);
return;
- for (auto &I : *CallBacksToRun)
- I.first(I.second);
- CallBacksToRun->clear();
+ }
+ report_fatal_error("too many signal callbacks already registered");
}
static bool findModulesAndOffsets(void **StackTrace, int Depth,
@@ -64,16 +100,11 @@ static FormattedNumber format_ptr(void *PC) {
return format_hex((uint64_t)PC, PtrWidth);
}
-static bool printSymbolizedStackTrace(StringRef Argv0,
- void **StackTrace, int Depth,
- llvm::raw_ostream &OS)
- LLVM_ATTRIBUTE_USED;
-
/// Helper that launches llvm-symbolizer and symbolizes a backtrace.
-static bool printSymbolizedStackTrace(StringRef Argv0,
- void **StackTrace, int Depth,
- llvm::raw_ostream &OS) {
- if (DisableSymbolication)
+LLVM_ATTRIBUTE_USED
+static bool printSymbolizedStackTrace(StringRef Argv0, void **StackTrace,
+ int Depth, llvm::raw_ostream &OS) {
+ if (DisableSymbolicationFlag)
return false;
// Don't recursively invoke the llvm-symbolizer binary.
@@ -123,17 +154,18 @@ static bool printSymbolizedStackTrace(StringRef Argv0,
}
}
- 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
- // have to add ImageBase from PE file.
- // FIXME: Make this the default for llvm-symbolizer.
- "--relative-address",
+ Optional<StringRef> Redirects[] = {StringRef(InputFile),
+ StringRef(OutputFile), llvm::None};
+ StringRef Args[] = {"llvm-symbolizer", "--functions=linkage", "--inlining",
+#ifdef _WIN32
+ // Pass --relative-address on Windows so that we don't
+ // have to add ImageBase from PE file.
+ // FIXME: Make this the default for llvm-symbolizer.
+ "--relative-address",
#endif
- "--demangle", nullptr};
+ "--demangle"};
int RunResult =
- sys::ExecuteAndWait(LLVMSymbolizerPath, Args, nullptr, Redirects);
+ sys::ExecuteAndWait(LLVMSymbolizerPath, Args, None, Redirects);
if (RunResult != 0)
return false;
@@ -180,6 +212,6 @@ static bool printSymbolizedStackTrace(StringRef Argv0,
#ifdef LLVM_ON_UNIX
#include "Unix/Signals.inc"
#endif
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
#include "Windows/Signals.inc"
#endif
diff --git a/lib/Support/SmallPtrSet.cpp b/lib/Support/SmallPtrSet.cpp
index 119bb871d4c0..fed4a17d6635 100644
--- a/lib/Support/SmallPtrSet.cpp
+++ b/lib/Support/SmallPtrSet.cpp
@@ -32,9 +32,7 @@ void SmallPtrSetImplBase::shrink_and_clear() {
NumNonEmpty = NumTombstones = 0;
// Install the new array. Clear all the buckets to empty.
- CurArray = (const void**)malloc(sizeof(void*) * CurArraySize);
- if (CurArray == nullptr)
- report_bad_alloc_error("Allocation of SmallPtrSet bucket array failed.");
+ CurArray = (const void**)safe_malloc(sizeof(void*) * CurArraySize);
memset(CurArray, -1, CurArraySize*sizeof(void*));
}
@@ -100,9 +98,7 @@ void SmallPtrSetImplBase::Grow(unsigned NewSize) {
bool WasSmall = isSmall();
// Install the new array. Clear all the buckets to empty.
- const void **NewBuckets = (const void**) malloc(sizeof(void*) * NewSize);
- if (NewBuckets == nullptr)
- report_bad_alloc_error("Allocation of SmallPtrSet bucket array failed.");
+ const void **NewBuckets = (const void**) safe_malloc(sizeof(void*) * NewSize);
// Reset member only if memory was allocated successfully
CurArray = NewBuckets;
@@ -132,9 +128,7 @@ SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage,
CurArray = SmallArray;
// Otherwise, allocate new heap space (unless we were the same size)
} else {
- CurArray = (const void**)malloc(sizeof(void*) * that.CurArraySize);
- if (CurArray == nullptr)
- report_bad_alloc_error("Allocation of SmallPtrSet bucket array failed.");
+ CurArray = (const void**)safe_malloc(sizeof(void*) * that.CurArraySize);
}
// Copy over the that array.
@@ -163,16 +157,12 @@ void SmallPtrSetImplBase::CopyFrom(const SmallPtrSetImplBase &RHS) {
// Otherwise, allocate new heap space (unless we were the same size)
} else if (CurArraySize != RHS.CurArraySize) {
if (isSmall())
- CurArray = (const void**)malloc(sizeof(void*) * RHS.CurArraySize);
+ CurArray = (const void**)safe_malloc(sizeof(void*) * RHS.CurArraySize);
else {
- const void **T = (const void**)realloc(CurArray,
+ const void **T = (const void**)safe_realloc(CurArray,
sizeof(void*) * RHS.CurArraySize);
- if (!T)
- free(CurArray);
CurArray = T;
}
- 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 74313151c762..1070c6672edc 100644
--- a/lib/Support/SmallVector.cpp
+++ b/lib/Support/SmallVector.cpp
@@ -14,31 +14,53 @@
#include "llvm/ADT/SmallVector.h"
using namespace llvm;
+// Check that no bytes are wasted and everything is well-aligned.
+namespace {
+struct Struct16B {
+ alignas(16) void *X;
+};
+struct Struct32B {
+ alignas(32) void *X;
+};
+}
+static_assert(sizeof(SmallVector<void *, 0>) ==
+ sizeof(unsigned) * 2 + sizeof(void *),
+ "wasted space in SmallVector size 0");
+static_assert(alignof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
+ "wrong alignment for 16-byte aligned T");
+static_assert(alignof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
+ "wrong alignment for 32-byte aligned T");
+static_assert(sizeof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
+ "missing padding for 16-byte aligned T");
+static_assert(sizeof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
+ "missing padding for 32-byte aligned T");
+static_assert(sizeof(SmallVector<void *, 1>) ==
+ sizeof(unsigned) * 2 + sizeof(void *) * 2,
+ "wasted space in SmallVector size 1");
+
/// grow_pod - This is an implementation of the grow() method which only works
/// on POD-like datatypes and is out of line to reduce code duplication.
-void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSizeInBytes,
+void SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity,
size_t TSize) {
- size_t CurSizeBytes = size_in_bytes();
- size_t NewCapacityInBytes = 2 * capacity_in_bytes() + TSize; // Always grow.
- if (NewCapacityInBytes < MinSizeInBytes)
- NewCapacityInBytes = MinSizeInBytes;
+ // Ensure we can fit the new capacity in 32 bits.
+ if (MinCapacity > UINT32_MAX)
+ report_bad_alloc_error("SmallVector capacity overflow during allocation");
+
+ size_t NewCapacity = 2 * capacity() + 1; // Always grow.
+ NewCapacity =
+ std::min(std::max(NewCapacity, MinCapacity), size_t(UINT32_MAX));
void *NewElts;
if (BeginX == FirstEl) {
- NewElts = malloc(NewCapacityInBytes);
- if (NewElts == nullptr)
- report_bad_alloc_error("Allocation of SmallVector element failed.");
+ NewElts = safe_malloc(NewCapacity * TSize);
// Copy the elements over. No need to run dtors on PODs.
- memcpy(NewElts, this->BeginX, CurSizeBytes);
+ memcpy(NewElts, this->BeginX, size() * TSize);
} 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.");
+ NewElts = safe_realloc(this->BeginX, NewCapacity * TSize);
}
- this->EndX = (char*)NewElts+CurSizeBytes;
this->BeginX = NewElts;
- this->CapacityX = (char*)this->BeginX + NewCapacityInBytes;
+ this->Capacity = NewCapacity;
}
diff --git a/lib/Support/SourceMgr.cpp b/lib/Support/SourceMgr.cpp
index a8f6208a558c..bc15fd4e4014 100644
--- a/lib/Support/SourceMgr.cpp
+++ b/lib/Support/SourceMgr.cpp
@@ -28,6 +28,7 @@
#include <algorithm>
#include <cassert>
#include <cstddef>
+#include <limits>
#include <memory>
#include <string>
#include <utility>
@@ -36,24 +37,6 @@ using namespace llvm;
static const size_t TabStop = 8;
-namespace {
-
- struct LineNoCacheTy {
- const char *LastQuery;
- unsigned LastQueryBufferID;
- unsigned LineNoOfQuery;
- };
-
-} // end anonymous namespace
-
-static LineNoCacheTy *getCache(void *Ptr) {
- return (LineNoCacheTy*)Ptr;
-}
-
-SourceMgr::~SourceMgr() {
- delete getCache(LineNoCache);
-}
-
unsigned SourceMgr::AddIncludeFile(const std::string &Filename,
SMLoc IncludeLoc,
std::string &IncludedFile) {
@@ -85,46 +68,85 @@ unsigned SourceMgr::FindBufferContainingLoc(SMLoc Loc) const {
return 0;
}
-std::pair<unsigned, unsigned>
-SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const {
- if (!BufferID)
- BufferID = FindBufferContainingLoc(Loc);
- assert(BufferID && "Invalid Location!");
+template <typename T>
+unsigned SourceMgr::SrcBuffer::getLineNumber(const char *Ptr) const {
+
+ // Ensure OffsetCache is allocated and populated with offsets of all the
+ // '\n' bytes.
+ std::vector<T> *Offsets = nullptr;
+ if (OffsetCache.isNull()) {
+ Offsets = new std::vector<T>();
+ OffsetCache = Offsets;
+ size_t Sz = Buffer->getBufferSize();
+ assert(Sz <= std::numeric_limits<T>::max());
+ StringRef S = Buffer->getBuffer();
+ for (size_t N = 0; N < Sz; ++N) {
+ if (S[N] == '\n') {
+ Offsets->push_back(static_cast<T>(N));
+ }
+ }
+ } else {
+ Offsets = OffsetCache.get<std::vector<T> *>();
+ }
- const MemoryBuffer *Buff = getMemoryBuffer(BufferID);
+ const char *BufStart = Buffer->getBufferStart();
+ assert(Ptr >= BufStart && Ptr <= Buffer->getBufferEnd());
+ ptrdiff_t PtrDiff = Ptr - BufStart;
+ assert(PtrDiff >= 0 && static_cast<size_t>(PtrDiff) <= std::numeric_limits<T>::max());
+ T PtrOffset = static_cast<T>(PtrDiff);
- // Count the number of \n's between the start of the file and the specified
- // location.
- unsigned LineNo = 1;
+ // std::lower_bound returns the first EOL offset that's not-less-than
+ // PtrOffset, meaning the EOL that _ends the line_ that PtrOffset is on
+ // (including if PtrOffset refers to the EOL itself). If there's no such
+ // EOL, returns end().
+ auto EOL = std::lower_bound(Offsets->begin(), Offsets->end(), PtrOffset);
- const char *BufStart = Buff->getBufferStart();
- const char *Ptr = BufStart;
+ // Lines count from 1, so add 1 to the distance from the 0th line.
+ return (1 + (EOL - Offsets->begin()));
+}
- // If we have a line number cache, and if the query is to a later point in the
- // same file, start searching from the last query location. This optimizes
- // for the case when multiple diagnostics come out of one file in order.
- if (LineNoCacheTy *Cache = getCache(LineNoCache))
- if (Cache->LastQueryBufferID == BufferID &&
- Cache->LastQuery <= Loc.getPointer()) {
- Ptr = Cache->LastQuery;
- LineNo = Cache->LineNoOfQuery;
- }
+SourceMgr::SrcBuffer::SrcBuffer(SourceMgr::SrcBuffer &&Other)
+ : Buffer(std::move(Other.Buffer)),
+ OffsetCache(Other.OffsetCache),
+ IncludeLoc(Other.IncludeLoc) {
+ Other.OffsetCache = nullptr;
+}
- // Scan for the location being queried, keeping track of the number of lines
- // we see.
- for (; SMLoc::getFromPointer(Ptr) != Loc; ++Ptr)
- if (*Ptr == '\n') ++LineNo;
+SourceMgr::SrcBuffer::~SrcBuffer() {
+ if (!OffsetCache.isNull()) {
+ if (OffsetCache.is<std::vector<uint8_t>*>())
+ delete OffsetCache.get<std::vector<uint8_t>*>();
+ else if (OffsetCache.is<std::vector<uint16_t>*>())
+ delete OffsetCache.get<std::vector<uint16_t>*>();
+ else if (OffsetCache.is<std::vector<uint32_t>*>())
+ delete OffsetCache.get<std::vector<uint32_t>*>();
+ else
+ delete OffsetCache.get<std::vector<uint64_t>*>();
+ OffsetCache = nullptr;
+ }
+}
- // Allocate the line number cache if it doesn't exist.
- if (!LineNoCache)
- LineNoCache = new LineNoCacheTy();
+std::pair<unsigned, unsigned>
+SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const {
+ if (!BufferID)
+ BufferID = FindBufferContainingLoc(Loc);
+ assert(BufferID && "Invalid Location!");
- // Update the line # cache.
- LineNoCacheTy &Cache = *getCache(LineNoCache);
- Cache.LastQueryBufferID = BufferID;
- Cache.LastQuery = Ptr;
- Cache.LineNoOfQuery = LineNo;
-
+ auto &SB = getBufferInfo(BufferID);
+ const char *Ptr = Loc.getPointer();
+
+ size_t Sz = SB.Buffer->getBufferSize();
+ unsigned LineNo;
+ if (Sz <= std::numeric_limits<uint8_t>::max())
+ LineNo = SB.getLineNumber<uint8_t>(Ptr);
+ else if (Sz <= std::numeric_limits<uint16_t>::max())
+ LineNo = SB.getLineNumber<uint16_t>(Ptr);
+ else if (Sz <= std::numeric_limits<uint32_t>::max())
+ LineNo = SB.getLineNumber<uint32_t>(Ptr);
+ else
+ LineNo = SB.getLineNumber<uint64_t>(Ptr);
+
+ const char *BufStart = SB.Buffer->getBufferStart();
size_t NewlineOffs = StringRef(BufStart, Ptr-BufStart).find_last_of("\n\r");
if (NewlineOffs == StringRef::npos) NewlineOffs = ~(size_t)0;
return std::make_pair(LineNo, Ptr-BufStart-NewlineOffs);
@@ -247,7 +269,7 @@ SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN,
: SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Kind(Kind),
Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()),
FixIts(Hints.begin(), Hints.end()) {
- std::sort(FixIts.begin(), FixIts.end());
+ llvm::sort(FixIts.begin(), FixIts.end());
}
static void buildFixItLine(std::string &CaretLine, std::string &FixItLine,
diff --git a/lib/Support/Statistic.cpp b/lib/Support/Statistic.cpp
index 544ae2d0983c..d57300a75d1d 100644
--- a/lib/Support/Statistic.cpp
+++ b/lib/Support/Statistic.cpp
@@ -52,11 +52,14 @@ static bool Enabled;
static bool PrintOnExit;
namespace {
-/// StatisticInfo - This class is used in a ManagedStatic so that it is created
-/// on demand (when the first statistic is bumped) and destroyed only when
-/// llvm_shutdown is called. We print statistics from the destructor.
+/// This class is used in a ManagedStatic so that it is created on demand (when
+/// the first statistic is bumped) and destroyed only when llvm_shutdown is
+/// called. We print statistics from the destructor.
+/// This class is also used to look up statistic values from applications that
+/// use LLVM.
class StatisticInfo {
- std::vector<const Statistic*> Stats;
+ std::vector<Statistic*> Stats;
+
friend void llvm::PrintStatistics();
friend void llvm::PrintStatistics(raw_ostream &OS);
friend void llvm::PrintStatisticsJSON(raw_ostream &OS);
@@ -64,14 +67,24 @@ class StatisticInfo {
/// Sort statistics by debugtype,name,description.
void sort();
public:
+ using const_iterator = std::vector<Statistic *>::const_iterator;
+
StatisticInfo();
~StatisticInfo();
- void addStatistic(const Statistic *S) {
+ void addStatistic(Statistic *S) {
Stats.push_back(S);
}
+
+ const_iterator begin() const { return Stats.begin(); }
+ const_iterator end() const { return Stats.end(); }
+ iterator_range<const_iterator> statistics() const {
+ return {begin(), end()};
+ }
+
+ void reset();
};
-}
+} // end anonymous namespace
static ManagedStatic<StatisticInfo> StatInfo;
static ManagedStatic<sys::SmartMutex<true> > StatLock;
@@ -81,17 +94,24 @@ static ManagedStatic<sys::SmartMutex<true> > StatLock;
void Statistic::RegisterStatistic() {
// If stats are enabled, inform StatInfo that this statistic should be
// printed.
- sys::SmartScopedLock<true> Writer(*StatLock);
- if (!Initialized) {
+ // llvm_shutdown calls destructors while holding the ManagedStatic mutex.
+ // These destructors end up calling PrintStatistics, which takes StatLock.
+ // Since dereferencing StatInfo and StatLock can require taking the
+ // ManagedStatic mutex, doing so with StatLock held would lead to a lock
+ // order inversion. To avoid that, we dereference the ManagedStatics first,
+ // and only take StatLock afterwards.
+ if (!Initialized.load(std::memory_order_relaxed)) {
+ sys::SmartMutex<true> &Lock = *StatLock;
+ StatisticInfo &SI = *StatInfo;
+ sys::SmartScopedLock<true> Writer(Lock);
+ // Check Initialized again after acquiring the lock.
+ if (Initialized.load(std::memory_order_relaxed))
+ return;
if (Stats || Enabled)
- StatInfo->addStatistic(this);
+ SI.addStatistic(this);
- TsanHappensBefore(this);
- sys::MemoryFence();
// Remember we have been registered.
- TsanIgnoreWritesBegin();
- Initialized = true;
- TsanIgnoreWritesEnd();
+ Initialized.store(true, std::memory_order_release);
}
}
@@ -128,6 +148,28 @@ void StatisticInfo::sort() {
});
}
+void StatisticInfo::reset() {
+ sys::SmartScopedLock<true> Writer(*StatLock);
+
+ // Tell each statistic that it isn't registered so it has to register
+ // again. We're holding the lock so it won't be able to do so until we're
+ // finished. Once we've forced it to re-register (after we return), then zero
+ // the value.
+ for (auto *Stat : Stats) {
+ // Value updates to a statistic that complete before this statement in the
+ // iteration for that statistic will be lost as intended.
+ Stat->Initialized = false;
+ Stat->Value = 0;
+ }
+
+ // Clear the registration list and release the lock once we're done. Any
+ // pending updates from other threads will safely take effect after we return.
+ // That might not be what the user wants if they're measuring a compilation
+ // but it's their responsibility to prevent concurrent compilations to make
+ // a single compilation measurable.
+ Stats.clear();
+}
+
void llvm::PrintStatistics(raw_ostream &OS) {
StatisticInfo &Stats = *StatInfo;
@@ -159,6 +201,7 @@ void llvm::PrintStatistics(raw_ostream &OS) {
}
void llvm::PrintStatisticsJSON(raw_ostream &OS) {
+ sys::SmartScopedLock<true> Reader(*StatLock);
StatisticInfo &Stats = *StatInfo;
Stats.sort();
@@ -184,7 +227,8 @@ void llvm::PrintStatisticsJSON(raw_ostream &OS) {
}
void llvm::PrintStatistics() {
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
+#if LLVM_ENABLE_STATS
+ sys::SmartScopedLock<true> Reader(*StatLock);
StatisticInfo &Stats = *StatInfo;
// Statistics not enabled?
@@ -209,3 +253,16 @@ void llvm::PrintStatistics() {
}
#endif
}
+
+const std::vector<std::pair<StringRef, unsigned>> llvm::GetStatistics() {
+ sys::SmartScopedLock<true> Reader(*StatLock);
+ std::vector<std::pair<StringRef, unsigned>> ReturnStats;
+
+ for (const auto &Stat : StatInfo->statistics())
+ ReturnStats.emplace_back(Stat->getName(), Stat->getValue());
+ return ReturnStats;
+}
+
+void llvm::ResetStatistics() {
+ StatInfo->reset();
+}
diff --git a/lib/Support/StringExtras.cpp b/lib/Support/StringExtras.cpp
index 21157a14086d..386d74a47983 100644
--- a/lib/Support/StringExtras.cpp
+++ b/lib/Support/StringExtras.cpp
@@ -58,6 +58,33 @@ void llvm::SplitString(StringRef Source,
}
}
+void llvm::printEscapedString(StringRef Name, raw_ostream &Out) {
+ for (unsigned i = 0, e = Name.size(); i != e; ++i) {
+ unsigned char C = Name[i];
+ if (isPrint(C) && C != '\\' && C != '"')
+ Out << C;
+ else
+ Out << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
+ }
+}
+
+void llvm::printHTMLEscaped(StringRef String, raw_ostream &Out) {
+ for (char C : String) {
+ if (C == '&')
+ Out << "&amp;";
+ else if (C == '<')
+ Out << "&lt;";
+ else if (C == '>')
+ Out << "&gt;";
+ else if (C == '\"')
+ Out << "&quot;";
+ else if (C == '\'')
+ Out << "&apos;";
+ else
+ Out << C;
+ }
+}
+
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 4341da2d97bd..c1f707ce50a5 100644
--- a/lib/Support/StringMap.cpp
+++ b/lib/Support/StringMap.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DJB.h"
#include "llvm/Support/MathExtras.h"
#include <cassert>
@@ -32,7 +33,7 @@ static unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
ItemSize = itemSize;
-
+
// If a size is specified, initialize the table with that many buckets.
if (InitSize) {
// The table will grow when the number of entries reach 3/4 of the number of
@@ -41,7 +42,7 @@ StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
init(getMinBucketToReserveForEntries(InitSize));
return;
}
-
+
// Otherwise, initialize it with zero buckets to avoid the allocation.
TheTable = nullptr;
NumBuckets = 0;
@@ -56,13 +57,10 @@ void StringMapImpl::init(unsigned InitSize) {
unsigned NewNumBuckets = InitSize ? InitSize : 16;
NumItems = 0;
NumTombstones = 0;
-
- TheTable = (StringMapEntryBase **)calloc(NewNumBuckets+1,
- sizeof(StringMapEntryBase **) +
- sizeof(unsigned));
- if (TheTable == nullptr)
- report_bad_alloc_error("Allocation of StringMap table failed.");
+ TheTable = static_cast<StringMapEntryBase **>(
+ safe_calloc(NewNumBuckets+1,
+ sizeof(StringMapEntryBase **) + sizeof(unsigned)));
// Set the member only if TheTable was successfully allocated
NumBuckets = NewNumBuckets;
@@ -83,7 +81,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
init(16);
HTSize = NumBuckets;
}
- unsigned FullHashValue = HashString(Name);
+ unsigned FullHashValue = djbHash(Name, 0);
unsigned BucketNo = FullHashValue & (HTSize-1);
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
@@ -99,11 +97,11 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
HashTable[FirstTombstone] = FullHashValue;
return FirstTombstone;
}
-
+
HashTable[BucketNo] = FullHashValue;
return BucketNo;
}
-
+
if (BucketItem == getTombstoneVal()) {
// Skip over tombstones. However, remember the first one we see.
if (FirstTombstone == -1) FirstTombstone = BucketNo;
@@ -112,7 +110,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
// case here is that we are only looking at the buckets (for item info
// being non-null and for the full hash value) not at the items. This
// is important for cache locality.
-
+
// Do the comparison like this because Name isn't necessarily
// null-terminated!
char *ItemStr = (char*)BucketItem+ItemSize;
@@ -121,10 +119,10 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
return BucketNo;
}
}
-
+
// Okay, we didn't find the item. Probe to the next bucket.
BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
-
+
// Use quadratic probing, it has fewer clumping artifacts than linear
// probing and has good cache behavior in the common case.
++ProbeAmt;
@@ -137,7 +135,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
int StringMapImpl::FindKey(StringRef Key) const {
unsigned HTSize = NumBuckets;
if (HTSize == 0) return -1; // Really empty table?
- unsigned FullHashValue = HashString(Key);
+ unsigned FullHashValue = djbHash(Key, 0);
unsigned BucketNo = FullHashValue & (HTSize-1);
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
@@ -147,7 +145,7 @@ int StringMapImpl::FindKey(StringRef Key) const {
// If we found an empty bucket, this key isn't in the table yet, return.
if (LLVM_LIKELY(!BucketItem))
return -1;
-
+
if (BucketItem == getTombstoneVal()) {
// Ignore tombstones.
} else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) {
@@ -155,7 +153,7 @@ int StringMapImpl::FindKey(StringRef Key) const {
// case here is that we are only looking at the buckets (for item info
// being non-null and for the full hash value) not at the items. This
// is important for cache locality.
-
+
// Do the comparison like this because NameStart isn't necessarily
// null-terminated!
char *ItemStr = (char*)BucketItem+ItemSize;
@@ -164,10 +162,10 @@ int StringMapImpl::FindKey(StringRef Key) const {
return BucketNo;
}
}
-
+
// Okay, we didn't find the item. Probe to the next bucket.
BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
-
+
// Use quadratic probing, it has fewer clumping artifacts than linear
// probing and has good cache behavior in the common case.
++ProbeAmt;
@@ -188,7 +186,7 @@ void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) {
int Bucket = FindKey(Key);
if (Bucket == -1) return nullptr;
-
+
StringMapEntryBase *Result = TheTable[Bucket];
TheTable[Bucket] = getTombstoneVal();
--NumItems;
@@ -219,12 +217,8 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
unsigned NewBucketNo = BucketNo;
// Allocate one extra bucket which will always be non-empty. This allows the
// iterators to stop at end.
- StringMapEntryBase **NewTableArray =
- (StringMapEntryBase **)calloc(NewSize+1, sizeof(StringMapEntryBase *) +
- sizeof(unsigned));
-
- if (NewTableArray == nullptr)
- report_bad_alloc_error("Allocation of StringMap hash table failed.");
+ auto NewTableArray = static_cast<StringMapEntryBase **>(
+ safe_calloc(NewSize+1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1);
NewTableArray[NewSize] = (StringMapEntryBase*)2;
@@ -244,13 +238,13 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
NewBucketNo = NewBucket;
continue;
}
-
+
// Otherwise probe for a spot.
unsigned ProbeSize = 1;
do {
NewBucket = (NewBucket + ProbeSize++) & (NewSize-1);
} while (NewTableArray[NewBucket]);
-
+
// Finally found a slot. Fill it in.
NewTableArray[NewBucket] = Bucket;
NewHashArray[NewBucket] = FullHash;
@@ -258,9 +252,9 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
NewBucketNo = NewBucket;
}
}
-
+
free(TheTable);
-
+
TheTable = NewTableArray;
NumBuckets = NewSize;
NumTombstones = 0;
diff --git a/lib/Support/StringSaver.cpp b/lib/Support/StringSaver.cpp
index 335fce3a7bbd..1ded2bdb09de 100644
--- a/lib/Support/StringSaver.cpp
+++ b/lib/Support/StringSaver.cpp
@@ -17,3 +17,10 @@ StringRef StringSaver::save(StringRef S) {
P[S.size()] = '\0';
return StringRef(P, S.size());
}
+
+StringRef UniqueStringSaver::save(StringRef S) {
+ auto R = Unique.insert(S);
+ if (R.second) // cache miss, need to actually save the string
+ *R.first = Strings.save(S); // safe replacement with equal value
+ return *R.first;
+}
diff --git a/lib/Support/TarWriter.cpp b/lib/Support/TarWriter.cpp
index abc46d076576..5b4d554befe4 100644
--- a/lib/Support/TarWriter.cpp
+++ b/lib/Support/TarWriter.cpp
@@ -159,8 +159,10 @@ static void writeUstarHeader(raw_fd_ostream &OS, StringRef Prefix,
// Creates a TarWriter instance and returns it.
Expected<std::unique_ptr<TarWriter>> TarWriter::create(StringRef OutputPath,
StringRef BaseDir) {
+ using namespace sys::fs;
int FD;
- if (std::error_code EC = openFileForWrite(OutputPath, FD, sys::fs::F_None))
+ if (std::error_code EC =
+ openFileForWrite(OutputPath, FD, CD_CreateAlways, OF_None))
return make_error<StringError>("cannot open " + OutputPath, EC);
return std::unique_ptr<TarWriter>(new TarWriter(FD, BaseDir));
}
diff --git a/lib/Support/TargetParser.cpp b/lib/Support/TargetParser.cpp
index b96ca084e9bf..2c167a4d086c 100644
--- a/lib/Support/TargetParser.cpp
+++ b/lib/Support/TargetParser.cpp
@@ -433,6 +433,17 @@ unsigned llvm::AArch64::getDefaultExtensions(StringRef CPU, ArchKind AK) {
.Default(AArch64::AEK_INVALID);
}
+AArch64::ArchKind llvm::AArch64::getCPUArchKind(StringRef CPU) {
+ if (CPU == "generic")
+ return AArch64::ArchKind::ARMV8A;
+
+ return StringSwitch<AArch64::ArchKind>(CPU)
+#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \
+ .Case(NAME, AArch64::ArchKind:: ID)
+#include "llvm/Support/AArch64TargetParser.def"
+ .Default(AArch64::ArchKind::INVALID);
+}
+
bool llvm::AArch64::getExtensionFeatures(unsigned Extensions,
std::vector<StringRef> &Features) {
@@ -480,6 +491,8 @@ bool llvm::AArch64::getArchFeatures(AArch64::ArchKind AK,
Features.push_back("+v8.2a");
if (AK == AArch64::ArchKind::ARMV8_3A)
Features.push_back("+v8.3a");
+ if (AK == AArch64::ArchKind::ARMV8_4A)
+ Features.push_back("+v8.4a");
return AK != AArch64::ArchKind::INVALID;
}
@@ -581,10 +594,11 @@ static StringRef getArchSynonym(StringRef Arch) {
.Case("v7r", "v7-r")
.Case("v7m", "v7-m")
.Case("v7em", "v7e-m")
- .Cases("v8", "v8a", "aarch64", "arm64", "v8-a")
+ .Cases("v8", "v8a", "v8l", "aarch64", "arm64", "v8-a")
.Case("v8.1a", "v8.1-a")
.Case("v8.2a", "v8.2-a")
.Case("v8.3a", "v8.3-a")
+ .Case("v8.4a", "v8.4-a")
.Case("v8r", "v8-r")
.Case("v8m.base", "v8-m.base")
.Case("v8m.main", "v8-m.main")
@@ -689,6 +703,20 @@ ARM::ArchKind llvm::ARM::parseCPUArch(StringRef CPU) {
return ARM::ArchKind::INVALID;
}
+void llvm::ARM::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) {
+ for (const CpuNames<ARM::ArchKind> &Arch : CPUNames) {
+ if (Arch.ArchID != ARM::ArchKind::INVALID)
+ Values.push_back(Arch.getName());
+ }
+}
+
+void llvm::AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) {
+ for (const CpuNames<AArch64::ArchKind> &Arch : AArch64CPUNames) {
+ if (Arch.ArchID != AArch64::ArchKind::INVALID)
+ Values.push_back(Arch.getName());
+ }
+}
+
// ARM, Thumb, AArch64
ARM::ISAKind ARM::parseArchISA(StringRef Arch) {
return StringSwitch<ARM::ISAKind>(Arch)
@@ -738,6 +766,7 @@ ARM::ProfileKind ARM::parseArchProfile(StringRef Arch) {
case ARM::ArchKind::ARMV8_1A:
case ARM::ArchKind::ARMV8_2A:
case ARM::ArchKind::ARMV8_3A:
+ case ARM::ArchKind::ARMV8_4A:
return ARM::ProfileKind::A;
case ARM::ArchKind::ARMV2:
case ARM::ArchKind::ARMV2A:
@@ -800,6 +829,7 @@ unsigned llvm::ARM::parseArchVersion(StringRef Arch) {
case ARM::ArchKind::ARMV8_1A:
case ARM::ArchKind::ARMV8_2A:
case ARM::ArchKind::ARMV8_3A:
+ case ARM::ArchKind::ARMV8_4A:
case ARM::ArchKind::ARMV8R:
case ARM::ArchKind::ARMV8MBaseline:
case ARM::ArchKind::ARMV8MMainline:
@@ -868,10 +898,10 @@ AArch64::ArchKind AArch64::parseArch(StringRef Arch) {
return ArchKind::INVALID;
}
-unsigned llvm::AArch64::parseArchExt(StringRef ArchExt) {
+AArch64::ArchExtKind llvm::AArch64::parseArchExt(StringRef ArchExt) {
for (const auto A : AArch64ARCHExtNames) {
if (ArchExt == A.getName())
- return A.ID;
+ return static_cast<ArchExtKind>(A.ID);
}
return AArch64::AEK_INVALID;
}
@@ -903,3 +933,7 @@ ARM::ProfileKind AArch64::parseArchProfile(StringRef Arch) {
unsigned llvm::AArch64::parseArchVersion(StringRef Arch) {
return ARM::parseArchVersion(Arch);
}
+
+bool llvm::AArch64::isX18ReservedByDefault(const Triple &TT) {
+ return TT.isOSDarwin() || TT.isOSFuchsia() || TT.isOSWindows();
+}
diff --git a/lib/Support/ThreadLocal.cpp b/lib/Support/ThreadLocal.cpp
index 9a75c02b351f..f6e4a652302c 100644
--- a/lib/Support/ThreadLocal.cpp
+++ b/lib/Support/ThreadLocal.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/ThreadLocal.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Compiler.h"
//===----------------------------------------------------------------------===//
@@ -41,8 +41,8 @@ void ThreadLocalImpl::removeInstance() {
}
#elif defined(LLVM_ON_UNIX)
#include "Unix/ThreadLocal.inc"
-#elif defined( LLVM_ON_WIN32)
+#elif defined( _WIN32)
#include "Windows/ThreadLocal.inc"
#else
-#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 set in Support/ThreadLocal.cpp
+#warning Neither LLVM_ON_UNIX nor _WIN32 set in Support/ThreadLocal.cpp
#endif
diff --git a/lib/Support/Threading.cpp b/lib/Support/Threading.cpp
index 473c84808af1..fcb1030e1ab4 100644
--- a/lib/Support/Threading.cpp
+++ b/lib/Support/Threading.cpp
@@ -37,7 +37,7 @@ bool llvm::llvm_is_multithreaded() {
}
#if LLVM_ENABLE_THREADS == 0 || \
- (!defined(LLVM_ON_WIN32) && !defined(HAVE_PTHREAD_H))
+ (!defined(_WIN32) && !defined(HAVE_PTHREAD_H))
// Support for non-Win32, non-pthread implementation.
void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData,
unsigned RequestedStackSize) {
@@ -89,7 +89,7 @@ unsigned llvm::hardware_concurrency() {
#ifdef LLVM_ON_UNIX
#include "Unix/Threading.inc"
#endif
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
#include "Windows/Threading.inc"
#endif
diff --git a/lib/Support/Timer.cpp b/lib/Support/Timer.cpp
index 0c85faecca84..61d3b6c6e319 100644
--- a/lib/Support/Timer.cpp
+++ b/lib/Support/Timer.cpp
@@ -22,6 +22,8 @@
#include "llvm/Support/Process.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
+#include <limits>
+
using namespace llvm;
// This ugly hack is brought to you courtesy of constructor/destructor ordering
@@ -234,6 +236,15 @@ TimerGroup::TimerGroup(StringRef Name, StringRef Description)
TimerGroupList = this;
}
+TimerGroup::TimerGroup(StringRef Name, StringRef Description,
+ const StringMap<TimeRecord> &Records)
+ : TimerGroup(Name, Description) {
+ TimersToPrint.reserve(Records.size());
+ for (const auto &P : Records)
+ TimersToPrint.emplace_back(P.getValue(), P.getKey(), P.getKey());
+ assert(TimersToPrint.size() == Records.size() && "Size mismatch");
+}
+
TimerGroup::~TimerGroup() {
// If the timer group is destroyed before the timers it owns, accumulate and
// print the timing data.
@@ -284,7 +295,7 @@ void TimerGroup::addTimer(Timer &T) {
void TimerGroup::PrintQueuedTimers(raw_ostream &OS) {
// Sort the timers in descending order by amount of time taken.
- std::sort(TimersToPrint.begin(), TimersToPrint.end());
+ llvm::sort(TimersToPrint.begin(), TimersToPrint.end());
TimeRecord Total;
for (const PrintRecord &Record : TimersToPrint)
@@ -336,10 +347,14 @@ void TimerGroup::prepareToPrintList() {
// reset them.
for (Timer *T = FirstTimer; T; T = T->Next) {
if (!T->hasTriggered()) continue;
+ bool WasRunning = T->isRunning();
+ if (WasRunning)
+ T->stopTimer();
+
TimersToPrint.emplace_back(T->Time, T->Name, T->Description);
- // Clear out the time.
- T->clear();
+ if (WasRunning)
+ T->startTimer();
}
}
@@ -363,13 +378,17 @@ void TimerGroup::printAll(raw_ostream &OS) {
void TimerGroup::printJSONValue(raw_ostream &OS, const PrintRecord &R,
const char *suffix, double Value) {
assert(yaml::needsQuotes(Name) == yaml::QuotingType::None &&
- "TimerGroup name needs no quotes");
+ "TimerGroup name should not need quotes");
assert(yaml::needsQuotes(R.Name) == yaml::QuotingType::None &&
- "Timer name needs no quotes");
- OS << "\t\"time." << Name << '.' << R.Name << suffix << "\": " << Value;
+ "Timer name should not need quotes");
+ constexpr auto max_digits10 = std::numeric_limits<double>::max_digits10;
+ OS << "\t\"time." << Name << '.' << R.Name << suffix
+ << "\": " << format("%.*e", max_digits10 - 1, Value);
}
const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) {
+ sys::SmartScopedLock<true> L(*TimerLock);
+
prepareToPrintList();
for (const PrintRecord &R : TimersToPrint) {
OS << delim;
@@ -381,6 +400,10 @@ const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) {
printJSONValue(OS, R, ".user", T.getUserTime());
OS << delim;
printJSONValue(OS, R, ".sys", T.getSystemTime());
+ if (T.getMemUsed()) {
+ OS << delim;
+ printJSONValue(OS, R, ".mem", T.getMemUsed());
+ }
}
TimersToPrint.clear();
return delim;
diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp
index 4f0a30042b76..b14d6492b1ed 100644
--- a/lib/Support/Triple.cpp
+++ b/lib/Support/Triple.cpp
@@ -168,6 +168,7 @@ StringRef Triple::getVendorTypeName(VendorType Kind) {
case AMD: return "amd";
case Mesa: return "mesa";
case SUSE: return "suse";
+ case OpenEmbedded: return "oe";
}
llvm_unreachable("Invalid VendorType!");
@@ -232,9 +233,7 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) {
case MSVC: return "msvc";
case Itanium: return "itanium";
case Cygnus: return "cygnus";
- case AMDOpenCL: return "amdopencl";
case CoreCLR: return "coreclr";
- case OpenCL: return "opencl";
case Simulator: return "simulator";
}
@@ -384,7 +383,7 @@ static Triple::ArchType parseArch(StringRef ArchName) {
// FIXME: Do we need to support these?
.Cases("i786", "i886", "i986", Triple::x86)
.Cases("amd64", "x86_64", "x86_64h", Triple::x86_64)
- .Cases("powerpc", "ppc32", Triple::ppc)
+ .Cases("powerpc", "ppc", "ppc32", Triple::ppc)
.Cases("powerpc64", "ppu", "ppc64", Triple::ppc64)
.Cases("powerpc64le", "ppc64le", Triple::ppc64le)
.Case("xscale", Triple::arm)
@@ -465,6 +464,7 @@ static Triple::VendorType parseVendor(StringRef VendorName) {
.Case("amd", Triple::AMD)
.Case("mesa", Triple::Mesa)
.Case("suse", Triple::SUSE)
+ .Case("oe", Triple::OpenEmbedded)
.Default(Triple::UnknownVendor);
}
@@ -523,9 +523,7 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) {
.StartsWith("msvc", Triple::MSVC)
.StartsWith("itanium", Triple::Itanium)
.StartsWith("cygnus", Triple::Cygnus)
- .StartsWith("amdopencl", Triple::AMDOpenCL)
.StartsWith("coreclr", Triple::CoreCLR)
- .StartsWith("opencl", Triple::OpenCL)
.StartsWith("simulator", Triple::Simulator)
.Default(Triple::UnknownEnvironment);
}
@@ -594,6 +592,8 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) {
return Triple::ARMSubArch_v8_2a;
case ARM::ArchKind::ARMV8_3A:
return Triple::ARMSubArch_v8_3a;
+ case ARM::ArchKind::ARMV8_4A:
+ return Triple::ARMSubArch_v8_4a;
case ARM::ArchKind::ARMV8R:
return Triple::ARMSubArch_v8r;
case ARM::ArchKind::ARMV8MBaseline:
@@ -670,8 +670,6 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) {
case Triple::tce:
case Triple::tcele:
case Triple::thumbeb:
- case Triple::wasm32:
- case Triple::wasm64:
case Triple::xcore:
return Triple::ELF;
@@ -680,11 +678,15 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) {
if (T.isOSDarwin())
return Triple::MachO;
return Triple::ELF;
+
+ case Triple::wasm32:
+ case Triple::wasm64:
+ return Triple::Wasm;
}
llvm_unreachable("unknown architecture");
}
-/// \brief Construct a triple from the string representation provided.
+/// Construct a triple from the string representation provided.
///
/// This stores the string representation and parses the various pieces into
/// enum members.
@@ -713,7 +715,7 @@ Triple::Triple(const Twine &Str)
ObjectFormat = getDefaultFormat(*this);
}
-/// \brief Construct a triple from string representations of the architecture,
+/// Construct a triple from string representations of the architecture,
/// vendor, and OS.
///
/// This joins each argument into a canonical string representation and parses
@@ -729,7 +731,7 @@ Triple::Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr)
ObjectFormat = getDefaultFormat(*this);
}
-/// \brief Construct a triple from string representations of the architecture,
+/// Construct a triple from string representations of the architecture,
/// vendor, OS, and environment.
///
/// This joins each argument into a canonical string representation and parses
diff --git a/lib/Support/Twine.cpp b/lib/Support/Twine.cpp
index d17cd4e66439..4726c8ab7494 100644
--- a/lib/Support/Twine.cpp
+++ b/lib/Support/Twine.cpp
@@ -9,6 +9,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/Support/UnicodeCaseFold.cpp b/lib/Support/UnicodeCaseFold.cpp
new file mode 100644
index 000000000000..b18d49dbafb0
--- /dev/null
+++ b/lib/Support/UnicodeCaseFold.cpp
@@ -0,0 +1,742 @@
+//===---------- Support/UnicodeCaseFold.cpp -------------------------------===//
+//
+// This file was generated by utils/unicode-case-fold.py from the Unicode
+// case folding database at
+// http://www.unicode.org/Public/9.0.0/ucd/CaseFolding.txt
+//
+// To regenerate this file, run:
+// utils/unicode-case-fold.py \
+// "http://www.unicode.org/Public/9.0.0/ucd/CaseFolding.txt" \
+// > lib/Support/UnicodeCaseFold.cpp
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Unicode.h"
+
+int llvm::sys::unicode::foldCharSimple(int C) {
+ if (C < 0x0041)
+ return C;
+ // 26 characters
+ if (C <= 0x005a)
+ return C + 32;
+ // MICRO SIGN
+ if (C == 0x00b5)
+ return 0x03bc;
+ if (C < 0x00c0)
+ return C;
+ // 23 characters
+ if (C <= 0x00d6)
+ return C + 32;
+ if (C < 0x00d8)
+ return C;
+ // 7 characters
+ if (C <= 0x00de)
+ return C + 32;
+ if (C < 0x0100)
+ return C;
+ // 24 characters
+ if (C <= 0x012e)
+ return C | 1;
+ if (C < 0x0132)
+ return C;
+ // 3 characters
+ if (C <= 0x0136)
+ return C | 1;
+ if (C < 0x0139)
+ return C;
+ // 8 characters
+ if (C <= 0x0147 && C % 2 == 1)
+ return C + 1;
+ if (C < 0x014a)
+ return C;
+ // 23 characters
+ if (C <= 0x0176)
+ return C | 1;
+ // LATIN CAPITAL LETTER Y WITH DIAERESIS
+ if (C == 0x0178)
+ return 0x00ff;
+ if (C < 0x0179)
+ return C;
+ // 3 characters
+ if (C <= 0x017d && C % 2 == 1)
+ return C + 1;
+ // LATIN SMALL LETTER LONG S
+ if (C == 0x017f)
+ return 0x0073;
+ // LATIN CAPITAL LETTER B WITH HOOK
+ if (C == 0x0181)
+ return 0x0253;
+ if (C < 0x0182)
+ return C;
+ // 2 characters
+ if (C <= 0x0184)
+ return C | 1;
+ // LATIN CAPITAL LETTER OPEN O
+ if (C == 0x0186)
+ return 0x0254;
+ // LATIN CAPITAL LETTER C WITH HOOK
+ if (C == 0x0187)
+ return 0x0188;
+ if (C < 0x0189)
+ return C;
+ // 2 characters
+ if (C <= 0x018a)
+ return C + 205;
+ // LATIN CAPITAL LETTER D WITH TOPBAR
+ if (C == 0x018b)
+ return 0x018c;
+ // LATIN CAPITAL LETTER REVERSED E
+ if (C == 0x018e)
+ return 0x01dd;
+ // LATIN CAPITAL LETTER SCHWA
+ if (C == 0x018f)
+ return 0x0259;
+ // LATIN CAPITAL LETTER OPEN E
+ if (C == 0x0190)
+ return 0x025b;
+ // LATIN CAPITAL LETTER F WITH HOOK
+ if (C == 0x0191)
+ return 0x0192;
+ // LATIN CAPITAL LETTER G WITH HOOK
+ if (C == 0x0193)
+ return 0x0260;
+ // LATIN CAPITAL LETTER GAMMA
+ if (C == 0x0194)
+ return 0x0263;
+ // LATIN CAPITAL LETTER IOTA
+ if (C == 0x0196)
+ return 0x0269;
+ // LATIN CAPITAL LETTER I WITH STROKE
+ if (C == 0x0197)
+ return 0x0268;
+ // LATIN CAPITAL LETTER K WITH HOOK
+ if (C == 0x0198)
+ return 0x0199;
+ // LATIN CAPITAL LETTER TURNED M
+ if (C == 0x019c)
+ return 0x026f;
+ // LATIN CAPITAL LETTER N WITH LEFT HOOK
+ if (C == 0x019d)
+ return 0x0272;
+ // LATIN CAPITAL LETTER O WITH MIDDLE TILDE
+ if (C == 0x019f)
+ return 0x0275;
+ if (C < 0x01a0)
+ return C;
+ // 3 characters
+ if (C <= 0x01a4)
+ return C | 1;
+ // LATIN LETTER YR
+ if (C == 0x01a6)
+ return 0x0280;
+ // LATIN CAPITAL LETTER TONE TWO
+ if (C == 0x01a7)
+ return 0x01a8;
+ // LATIN CAPITAL LETTER ESH
+ if (C == 0x01a9)
+ return 0x0283;
+ // LATIN CAPITAL LETTER T WITH HOOK
+ if (C == 0x01ac)
+ return 0x01ad;
+ // LATIN CAPITAL LETTER T WITH RETROFLEX HOOK
+ if (C == 0x01ae)
+ return 0x0288;
+ // LATIN CAPITAL LETTER U WITH HORN
+ if (C == 0x01af)
+ return 0x01b0;
+ if (C < 0x01b1)
+ return C;
+ // 2 characters
+ if (C <= 0x01b2)
+ return C + 217;
+ if (C < 0x01b3)
+ return C;
+ // 2 characters
+ if (C <= 0x01b5 && C % 2 == 1)
+ return C + 1;
+ // LATIN CAPITAL LETTER EZH
+ if (C == 0x01b7)
+ return 0x0292;
+ if (C < 0x01b8)
+ return C;
+ // 2 characters
+ if (C <= 0x01bc && C % 4 == 0)
+ return C + 1;
+ // LATIN CAPITAL LETTER DZ WITH CARON
+ if (C == 0x01c4)
+ return 0x01c6;
+ // LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
+ if (C == 0x01c5)
+ return 0x01c6;
+ // LATIN CAPITAL LETTER LJ
+ if (C == 0x01c7)
+ return 0x01c9;
+ // LATIN CAPITAL LETTER L WITH SMALL LETTER J
+ if (C == 0x01c8)
+ return 0x01c9;
+ // LATIN CAPITAL LETTER NJ
+ if (C == 0x01ca)
+ return 0x01cc;
+ if (C < 0x01cb)
+ return C;
+ // 9 characters
+ if (C <= 0x01db && C % 2 == 1)
+ return C + 1;
+ if (C < 0x01de)
+ return C;
+ // 9 characters
+ if (C <= 0x01ee)
+ return C | 1;
+ // LATIN CAPITAL LETTER DZ
+ if (C == 0x01f1)
+ return 0x01f3;
+ if (C < 0x01f2)
+ return C;
+ // 2 characters
+ if (C <= 0x01f4)
+ return C | 1;
+ // LATIN CAPITAL LETTER HWAIR
+ if (C == 0x01f6)
+ return 0x0195;
+ // LATIN CAPITAL LETTER WYNN
+ if (C == 0x01f7)
+ return 0x01bf;
+ if (C < 0x01f8)
+ return C;
+ // 20 characters
+ if (C <= 0x021e)
+ return C | 1;
+ // LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
+ if (C == 0x0220)
+ return 0x019e;
+ if (C < 0x0222)
+ return C;
+ // 9 characters
+ if (C <= 0x0232)
+ return C | 1;
+ // LATIN CAPITAL LETTER A WITH STROKE
+ if (C == 0x023a)
+ return 0x2c65;
+ // LATIN CAPITAL LETTER C WITH STROKE
+ if (C == 0x023b)
+ return 0x023c;
+ // LATIN CAPITAL LETTER L WITH BAR
+ if (C == 0x023d)
+ return 0x019a;
+ // LATIN CAPITAL LETTER T WITH DIAGONAL STROKE
+ if (C == 0x023e)
+ return 0x2c66;
+ // LATIN CAPITAL LETTER GLOTTAL STOP
+ if (C == 0x0241)
+ return 0x0242;
+ // LATIN CAPITAL LETTER B WITH STROKE
+ if (C == 0x0243)
+ return 0x0180;
+ // LATIN CAPITAL LETTER U BAR
+ if (C == 0x0244)
+ return 0x0289;
+ // LATIN CAPITAL LETTER TURNED V
+ if (C == 0x0245)
+ return 0x028c;
+ if (C < 0x0246)
+ return C;
+ // 5 characters
+ if (C <= 0x024e)
+ return C | 1;
+ // COMBINING GREEK YPOGEGRAMMENI
+ if (C == 0x0345)
+ return 0x03b9;
+ if (C < 0x0370)
+ return C;
+ // 2 characters
+ if (C <= 0x0372)
+ return C | 1;
+ // GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA
+ if (C == 0x0376)
+ return 0x0377;
+ // GREEK CAPITAL LETTER YOT
+ if (C == 0x037f)
+ return 0x03f3;
+ // GREEK CAPITAL LETTER ALPHA WITH TONOS
+ if (C == 0x0386)
+ return 0x03ac;
+ if (C < 0x0388)
+ return C;
+ // 3 characters
+ if (C <= 0x038a)
+ return C + 37;
+ // GREEK CAPITAL LETTER OMICRON WITH TONOS
+ if (C == 0x038c)
+ return 0x03cc;
+ if (C < 0x038e)
+ return C;
+ // 2 characters
+ if (C <= 0x038f)
+ return C + 63;
+ if (C < 0x0391)
+ return C;
+ // 17 characters
+ if (C <= 0x03a1)
+ return C + 32;
+ if (C < 0x03a3)
+ return C;
+ // 9 characters
+ if (C <= 0x03ab)
+ return C + 32;
+ // GREEK SMALL LETTER FINAL SIGMA
+ if (C == 0x03c2)
+ return 0x03c3;
+ // GREEK CAPITAL KAI SYMBOL
+ if (C == 0x03cf)
+ return 0x03d7;
+ // GREEK BETA SYMBOL
+ if (C == 0x03d0)
+ return 0x03b2;
+ // GREEK THETA SYMBOL
+ if (C == 0x03d1)
+ return 0x03b8;
+ // GREEK PHI SYMBOL
+ if (C == 0x03d5)
+ return 0x03c6;
+ // GREEK PI SYMBOL
+ if (C == 0x03d6)
+ return 0x03c0;
+ if (C < 0x03d8)
+ return C;
+ // 12 characters
+ if (C <= 0x03ee)
+ return C | 1;
+ // GREEK KAPPA SYMBOL
+ if (C == 0x03f0)
+ return 0x03ba;
+ // GREEK RHO SYMBOL
+ if (C == 0x03f1)
+ return 0x03c1;
+ // GREEK CAPITAL THETA SYMBOL
+ if (C == 0x03f4)
+ return 0x03b8;
+ // GREEK LUNATE EPSILON SYMBOL
+ if (C == 0x03f5)
+ return 0x03b5;
+ // GREEK CAPITAL LETTER SHO
+ if (C == 0x03f7)
+ return 0x03f8;
+ // GREEK CAPITAL LUNATE SIGMA SYMBOL
+ if (C == 0x03f9)
+ return 0x03f2;
+ // GREEK CAPITAL LETTER SAN
+ if (C == 0x03fa)
+ return 0x03fb;
+ if (C < 0x03fd)
+ return C;
+ // 3 characters
+ if (C <= 0x03ff)
+ return C + -130;
+ if (C < 0x0400)
+ return C;
+ // 16 characters
+ if (C <= 0x040f)
+ return C + 80;
+ if (C < 0x0410)
+ return C;
+ // 32 characters
+ if (C <= 0x042f)
+ return C + 32;
+ if (C < 0x0460)
+ return C;
+ // 17 characters
+ if (C <= 0x0480)
+ return C | 1;
+ if (C < 0x048a)
+ return C;
+ // 27 characters
+ if (C <= 0x04be)
+ return C | 1;
+ // CYRILLIC LETTER PALOCHKA
+ if (C == 0x04c0)
+ return 0x04cf;
+ if (C < 0x04c1)
+ return C;
+ // 7 characters
+ if (C <= 0x04cd && C % 2 == 1)
+ return C + 1;
+ if (C < 0x04d0)
+ return C;
+ // 48 characters
+ if (C <= 0x052e)
+ return C | 1;
+ if (C < 0x0531)
+ return C;
+ // 38 characters
+ if (C <= 0x0556)
+ return C + 48;
+ if (C < 0x10a0)
+ return C;
+ // 38 characters
+ if (C <= 0x10c5)
+ return C + 7264;
+ if (C < 0x10c7)
+ return C;
+ // 2 characters
+ if (C <= 0x10cd && C % 6 == 5)
+ return C + 7264;
+ if (C < 0x13f8)
+ return C;
+ // 6 characters
+ if (C <= 0x13fd)
+ return C + -8;
+ // CYRILLIC SMALL LETTER ROUNDED VE
+ if (C == 0x1c80)
+ return 0x0432;
+ // CYRILLIC SMALL LETTER LONG-LEGGED DE
+ if (C == 0x1c81)
+ return 0x0434;
+ // CYRILLIC SMALL LETTER NARROW O
+ if (C == 0x1c82)
+ return 0x043e;
+ if (C < 0x1c83)
+ return C;
+ // 2 characters
+ if (C <= 0x1c84)
+ return C + -6210;
+ // CYRILLIC SMALL LETTER THREE-LEGGED TE
+ if (C == 0x1c85)
+ return 0x0442;
+ // CYRILLIC SMALL LETTER TALL HARD SIGN
+ if (C == 0x1c86)
+ return 0x044a;
+ // CYRILLIC SMALL LETTER TALL YAT
+ if (C == 0x1c87)
+ return 0x0463;
+ // CYRILLIC SMALL LETTER UNBLENDED UK
+ if (C == 0x1c88)
+ return 0xa64b;
+ if (C < 0x1e00)
+ return C;
+ // 75 characters
+ if (C <= 0x1e94)
+ return C | 1;
+ // LATIN SMALL LETTER LONG S WITH DOT ABOVE
+ if (C == 0x1e9b)
+ return 0x1e61;
+ // LATIN CAPITAL LETTER SHARP S
+ if (C == 0x1e9e)
+ return 0x00df;
+ if (C < 0x1ea0)
+ return C;
+ // 48 characters
+ if (C <= 0x1efe)
+ return C | 1;
+ if (C < 0x1f08)
+ return C;
+ // 8 characters
+ if (C <= 0x1f0f)
+ return C + -8;
+ if (C < 0x1f18)
+ return C;
+ // 6 characters
+ if (C <= 0x1f1d)
+ return C + -8;
+ if (C < 0x1f28)
+ return C;
+ // 8 characters
+ if (C <= 0x1f2f)
+ return C + -8;
+ if (C < 0x1f38)
+ return C;
+ // 8 characters
+ if (C <= 0x1f3f)
+ return C + -8;
+ if (C < 0x1f48)
+ return C;
+ // 6 characters
+ if (C <= 0x1f4d)
+ return C + -8;
+ if (C < 0x1f59)
+ return C;
+ // 4 characters
+ if (C <= 0x1f5f && C % 2 == 1)
+ return C + -8;
+ if (C < 0x1f68)
+ return C;
+ // 8 characters
+ if (C <= 0x1f6f)
+ return C + -8;
+ if (C < 0x1f88)
+ return C;
+ // 8 characters
+ if (C <= 0x1f8f)
+ return C + -8;
+ if (C < 0x1f98)
+ return C;
+ // 8 characters
+ if (C <= 0x1f9f)
+ return C + -8;
+ if (C < 0x1fa8)
+ return C;
+ // 8 characters
+ if (C <= 0x1faf)
+ return C + -8;
+ if (C < 0x1fb8)
+ return C;
+ // 2 characters
+ if (C <= 0x1fb9)
+ return C + -8;
+ if (C < 0x1fba)
+ return C;
+ // 2 characters
+ if (C <= 0x1fbb)
+ return C + -74;
+ // GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+ if (C == 0x1fbc)
+ return 0x1fb3;
+ // GREEK PROSGEGRAMMENI
+ if (C == 0x1fbe)
+ return 0x03b9;
+ if (C < 0x1fc8)
+ return C;
+ // 4 characters
+ if (C <= 0x1fcb)
+ return C + -86;
+ // GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+ if (C == 0x1fcc)
+ return 0x1fc3;
+ if (C < 0x1fd8)
+ return C;
+ // 2 characters
+ if (C <= 0x1fd9)
+ return C + -8;
+ if (C < 0x1fda)
+ return C;
+ // 2 characters
+ if (C <= 0x1fdb)
+ return C + -100;
+ if (C < 0x1fe8)
+ return C;
+ // 2 characters
+ if (C <= 0x1fe9)
+ return C + -8;
+ if (C < 0x1fea)
+ return C;
+ // 2 characters
+ if (C <= 0x1feb)
+ return C + -112;
+ // GREEK CAPITAL LETTER RHO WITH DASIA
+ if (C == 0x1fec)
+ return 0x1fe5;
+ if (C < 0x1ff8)
+ return C;
+ // 2 characters
+ if (C <= 0x1ff9)
+ return C + -128;
+ if (C < 0x1ffa)
+ return C;
+ // 2 characters
+ if (C <= 0x1ffb)
+ return C + -126;
+ // GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+ if (C == 0x1ffc)
+ return 0x1ff3;
+ // OHM SIGN
+ if (C == 0x2126)
+ return 0x03c9;
+ // KELVIN SIGN
+ if (C == 0x212a)
+ return 0x006b;
+ // ANGSTROM SIGN
+ if (C == 0x212b)
+ return 0x00e5;
+ // TURNED CAPITAL F
+ if (C == 0x2132)
+ return 0x214e;
+ if (C < 0x2160)
+ return C;
+ // 16 characters
+ if (C <= 0x216f)
+ return C + 16;
+ // ROMAN NUMERAL REVERSED ONE HUNDRED
+ if (C == 0x2183)
+ return 0x2184;
+ if (C < 0x24b6)
+ return C;
+ // 26 characters
+ if (C <= 0x24cf)
+ return C + 26;
+ if (C < 0x2c00)
+ return C;
+ // 47 characters
+ if (C <= 0x2c2e)
+ return C + 48;
+ // LATIN CAPITAL LETTER L WITH DOUBLE BAR
+ if (C == 0x2c60)
+ return 0x2c61;
+ // LATIN CAPITAL LETTER L WITH MIDDLE TILDE
+ if (C == 0x2c62)
+ return 0x026b;
+ // LATIN CAPITAL LETTER P WITH STROKE
+ if (C == 0x2c63)
+ return 0x1d7d;
+ // LATIN CAPITAL LETTER R WITH TAIL
+ if (C == 0x2c64)
+ return 0x027d;
+ if (C < 0x2c67)
+ return C;
+ // 3 characters
+ if (C <= 0x2c6b && C % 2 == 1)
+ return C + 1;
+ // LATIN CAPITAL LETTER ALPHA
+ if (C == 0x2c6d)
+ return 0x0251;
+ // LATIN CAPITAL LETTER M WITH HOOK
+ if (C == 0x2c6e)
+ return 0x0271;
+ // LATIN CAPITAL LETTER TURNED A
+ if (C == 0x2c6f)
+ return 0x0250;
+ // LATIN CAPITAL LETTER TURNED ALPHA
+ if (C == 0x2c70)
+ return 0x0252;
+ if (C < 0x2c72)
+ return C;
+ // 2 characters
+ if (C <= 0x2c75 && C % 3 == 2)
+ return C + 1;
+ if (C < 0x2c7e)
+ return C;
+ // 2 characters
+ if (C <= 0x2c7f)
+ return C + -10815;
+ if (C < 0x2c80)
+ return C;
+ // 50 characters
+ if (C <= 0x2ce2)
+ return C | 1;
+ if (C < 0x2ceb)
+ return C;
+ // 2 characters
+ if (C <= 0x2ced && C % 2 == 1)
+ return C + 1;
+ if (C < 0x2cf2)
+ return C;
+ // 2 characters
+ if (C <= 0xa640 && C % 31054 == 11506)
+ return C + 1;
+ if (C < 0xa642)
+ return C;
+ // 22 characters
+ if (C <= 0xa66c)
+ return C | 1;
+ if (C < 0xa680)
+ return C;
+ // 14 characters
+ if (C <= 0xa69a)
+ return C | 1;
+ if (C < 0xa722)
+ return C;
+ // 7 characters
+ if (C <= 0xa72e)
+ return C | 1;
+ if (C < 0xa732)
+ return C;
+ // 31 characters
+ if (C <= 0xa76e)
+ return C | 1;
+ if (C < 0xa779)
+ return C;
+ // 2 characters
+ if (C <= 0xa77b && C % 2 == 1)
+ return C + 1;
+ // LATIN CAPITAL LETTER INSULAR G
+ if (C == 0xa77d)
+ return 0x1d79;
+ if (C < 0xa77e)
+ return C;
+ // 5 characters
+ if (C <= 0xa786)
+ return C | 1;
+ // LATIN CAPITAL LETTER SALTILLO
+ if (C == 0xa78b)
+ return 0xa78c;
+ // LATIN CAPITAL LETTER TURNED H
+ if (C == 0xa78d)
+ return 0x0265;
+ if (C < 0xa790)
+ return C;
+ // 2 characters
+ if (C <= 0xa792)
+ return C | 1;
+ if (C < 0xa796)
+ return C;
+ // 10 characters
+ if (C <= 0xa7a8)
+ return C | 1;
+ // LATIN CAPITAL LETTER H WITH HOOK
+ if (C == 0xa7aa)
+ return 0x0266;
+ // LATIN CAPITAL LETTER REVERSED OPEN E
+ if (C == 0xa7ab)
+ return 0x025c;
+ // LATIN CAPITAL LETTER SCRIPT G
+ if (C == 0xa7ac)
+ return 0x0261;
+ // LATIN CAPITAL LETTER L WITH BELT
+ if (C == 0xa7ad)
+ return 0x026c;
+ // LATIN CAPITAL LETTER SMALL CAPITAL I
+ if (C == 0xa7ae)
+ return 0x026a;
+ // LATIN CAPITAL LETTER TURNED K
+ if (C == 0xa7b0)
+ return 0x029e;
+ // LATIN CAPITAL LETTER TURNED T
+ if (C == 0xa7b1)
+ return 0x0287;
+ // LATIN CAPITAL LETTER J WITH CROSSED-TAIL
+ if (C == 0xa7b2)
+ return 0x029d;
+ // LATIN CAPITAL LETTER CHI
+ if (C == 0xa7b3)
+ return 0xab53;
+ if (C < 0xa7b4)
+ return C;
+ // 2 characters
+ if (C <= 0xa7b6)
+ return C | 1;
+ if (C < 0xab70)
+ return C;
+ // 80 characters
+ if (C <= 0xabbf)
+ return C + -38864;
+ if (C < 0xff21)
+ return C;
+ // 26 characters
+ if (C <= 0xff3a)
+ return C + 32;
+ if (C < 0x10400)
+ return C;
+ // 40 characters
+ if (C <= 0x10427)
+ return C + 40;
+ if (C < 0x104b0)
+ return C;
+ // 36 characters
+ if (C <= 0x104d3)
+ return C + 40;
+ if (C < 0x10c80)
+ return C;
+ // 51 characters
+ if (C <= 0x10cb2)
+ return C + 64;
+ if (C < 0x118a0)
+ return C;
+ // 32 characters
+ if (C <= 0x118bf)
+ return C + 32;
+ if (C < 0x1e900)
+ return C;
+ // 34 characters
+ if (C <= 0x1e921)
+ return C + 34;
+
+ return C;
+}
diff --git a/lib/Support/Unix/Host.inc b/lib/Support/Unix/Host.inc
index 5580e63893c6..b65f84bf4444 100644
--- a/lib/Support/Unix/Host.inc
+++ b/lib/Support/Unix/Host.inc
@@ -64,5 +64,5 @@ std::string sys::getDefaultTargetTriple() {
TargetTripleString = EnvTriple;
#endif
- return Triple::normalize(TargetTripleString);
+ return TargetTripleString;
}
diff --git a/lib/Support/Unix/Memory.inc b/lib/Support/Unix/Memory.inc
index 848548d18177..adbfff2f59a5 100644
--- a/lib/Support/Unix/Memory.inc
+++ b/lib/Support/Unix/Memory.inc
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Unix.h"
+#include "llvm/Config/config.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Process.h"
@@ -24,6 +25,10 @@
#include <mach/mach.h>
#endif
+#ifdef __Fuchsia__
+#include <zircon/syscalls.h>
+#endif
+
#if defined(__mips__)
# if defined(__OpenBSD__)
# include <mips64/sysarch.h>
@@ -32,7 +37,7 @@
# endif
#endif
-#ifdef __APPLE__
+#if defined(__APPLE__)
extern "C" void sys_icache_invalidate(const void *Addr, size_t len);
#else
extern "C" void __clear_cache(void *, void*);
@@ -205,6 +210,11 @@ void Memory::InvalidateInstructionCache(const void *Addr,
sys_icache_invalidate(const_cast<void *>(Addr), Len);
# endif
+#elif defined(__Fuchsia__)
+
+ zx_status_t Status = zx_cache_flush(Addr, Len, ZX_CACHE_FLUSH_INSN);
+ assert(Status == ZX_OK && "cannot invalidate instruction cache");
+
#else
# if (defined(__POWERPC__) || defined (__ppc__) || \
diff --git a/lib/Support/Unix/Path.inc b/lib/Support/Unix/Path.inc
index 2ecb97316c87..7ad57d892ff1 100644
--- a/lib/Support/Unix/Path.inc
+++ b/lib/Support/Unix/Path.inc
@@ -31,23 +31,8 @@
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
-#if HAVE_DIRENT_H
-# include <dirent.h>
-# define NAMLEN(dirent) strlen((dirent)->d_name)
-#else
-# define dirent direct
-# define NAMLEN(dirent) (dirent)->d_namlen
-# if HAVE_SYS_NDIR_H
-# include <sys/ndir.h>
-# endif
-# if HAVE_SYS_DIR_H
-# include <sys/dir.h>
-# endif
-# if HAVE_NDIR_H
-# include <ndir.h>
-# endif
-#endif
+#include <dirent.h>
#include <pwd.h>
#ifdef __APPLE__
@@ -108,6 +93,9 @@ using namespace llvm;
namespace llvm {
namespace sys {
namespace fs {
+
+const file_t kInvalidFile = -1;
+
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
defined(__minix) || defined(__FreeBSD_kernel__) || defined(__linux__) || \
defined(__CYGWIN__) || defined(__DragonFly__) || defined(_AIX)
@@ -380,6 +368,12 @@ static bool is_local_impl(struct STATVFS &Vfs) {
#elif defined(__CYGWIN__)
// Cygwin doesn't expose this information; would need to use Win32 API.
return false;
+#elif defined(__Fuchsia__)
+ // Fuchsia doesn't yet support remote filesystem mounts.
+ return true;
+#elif defined(__HAIKU__)
+ // Haiku doesn't expose this information.
+ return false;
#elif defined(__sun)
// statvfs::f_basetype contains a null-terminated FSType name of the mounted target
StringRef fstype(Vfs.f_basetype);
@@ -530,7 +524,7 @@ static void expandTildeExpr(SmallVectorImpl<char> &Path) {
}
static std::error_code fillStatus(int StatRet, const struct stat &Status,
- file_status &Result) {
+ file_status &Result) {
if (StatRet != 0) {
std::error_code ec(errno, std::generic_category());
if (ec == errc::no_such_file_or_directory)
@@ -643,7 +637,8 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset,
mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length,
uint64_t offset, std::error_code &ec)
- : Size(length), Mapping() {
+ : Size(length), Mapping(), Mode(mode) {
+ (void)Mode;
ec = init(fd, offset, mode);
if (ec)
Mapping = nullptr;
@@ -702,7 +697,7 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
if (cur_dir == nullptr && errno != 0) {
return std::error_code(errno, std::generic_category());
} else if (cur_dir != nullptr) {
- StringRef name(cur_dir->d_name, NAMLEN(cur_dir));
+ StringRef name(cur_dir->d_name);
if ((name.size() == 1 && name[0] == '.') ||
(name.size() == 2 && name[0] == '.' && name[1] == '.'))
return directory_iterator_increment(it);
@@ -729,21 +724,83 @@ static bool hasProcSelfFD() {
}
#endif
-std::error_code openFileForRead(const Twine &Name, int &ResultFD,
- SmallVectorImpl<char> *RealPath) {
- SmallString<128> Storage;
- StringRef P = Name.toNullTerminatedStringRef(Storage);
- int OpenFlags = O_RDONLY;
+static int nativeOpenFlags(CreationDisposition Disp, OpenFlags Flags,
+ FileAccess Access) {
+ int Result = 0;
+ if (Access == FA_Read)
+ Result |= O_RDONLY;
+ else if (Access == FA_Write)
+ Result |= O_WRONLY;
+ else if (Access == (FA_Read | FA_Write))
+ Result |= O_RDWR;
+
+ // This is for compatibility with old code that assumed F_Append implied
+ // would open an existing file. See Windows/Path.inc for a longer comment.
+ if (Flags & F_Append)
+ Disp = CD_OpenAlways;
+
+ if (Disp == CD_CreateNew) {
+ Result |= O_CREAT; // Create if it doesn't exist.
+ Result |= O_EXCL; // Fail if it does.
+ } else if (Disp == CD_CreateAlways) {
+ Result |= O_CREAT; // Create if it doesn't exist.
+ Result |= O_TRUNC; // Truncate if it does.
+ } else if (Disp == CD_OpenAlways) {
+ Result |= O_CREAT; // Create if it doesn't exist.
+ } else if (Disp == CD_OpenExisting) {
+ // Nothing special, just don't add O_CREAT and we get these semantics.
+ }
+
+ if (Flags & F_Append)
+ Result |= O_APPEND;
+
#ifdef O_CLOEXEC
- OpenFlags |= O_CLOEXEC;
+ if (!(Flags & OF_ChildInherit))
+ Result |= O_CLOEXEC;
#endif
- if ((ResultFD = sys::RetryAfterSignal(-1, open, P.begin(), OpenFlags)) < 0)
+
+ return Result;
+}
+
+std::error_code openFile(const Twine &Name, int &ResultFD,
+ CreationDisposition Disp, FileAccess Access,
+ OpenFlags Flags, unsigned Mode) {
+ int OpenFlags = nativeOpenFlags(Disp, Flags, Access);
+
+ SmallString<128> Storage;
+ StringRef P = Name.toNullTerminatedStringRef(Storage);
+ if ((ResultFD = sys::RetryAfterSignal(-1, ::open, P.begin(), OpenFlags, Mode)) <
+ 0)
return std::error_code(errno, std::generic_category());
#ifndef O_CLOEXEC
- int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC);
- (void)r;
- assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed");
+ if (!(Flags & OF_ChildInherit)) {
+ int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC);
+ (void)r;
+ assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed");
+ }
#endif
+ return std::error_code();
+}
+
+Expected<int> openNativeFile(const Twine &Name, CreationDisposition Disp,
+ FileAccess Access, OpenFlags Flags,
+ unsigned Mode) {
+
+ int FD;
+ std::error_code EC = openFile(Name, FD, Disp, Access, Flags, Mode);
+ if (EC)
+ return errorCodeToError(EC);
+ return FD;
+}
+
+std::error_code openFileForRead(const Twine &Name, int &ResultFD,
+ OpenFlags Flags,
+ SmallVectorImpl<char> *RealPath) {
+ std::error_code EC =
+ openFile(Name, ResultFD, CD_OpenExisting, FA_Read, Flags, 0666);
+ if (EC)
+ return EC;
+
// Attempt to get the real name of the file, if the user asked
if(!RealPath)
return std::error_code();
@@ -763,6 +820,9 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
if (CharCount > 0)
RealPath->append(Buffer, Buffer + CharCount);
} else {
+ SmallString<128> Storage;
+ StringRef P = Name.toNullTerminatedStringRef(Storage);
+
// Use ::realpath to get the real path name
if (::realpath(P.begin(), Buffer) != nullptr)
RealPath->append(Buffer, Buffer + strlen(Buffer));
@@ -771,41 +831,18 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
return std::error_code();
}
-std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
- sys::fs::OpenFlags Flags, unsigned Mode) {
- // Verify that we don't have both "append" and "excl".
- assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) &&
- "Cannot specify both 'excl' and 'append' file creation flags!");
-
- int OpenFlags = O_CREAT;
-
-#ifdef O_CLOEXEC
- OpenFlags |= O_CLOEXEC;
-#endif
-
- if (Flags & F_RW)
- OpenFlags |= O_RDWR;
- else
- OpenFlags |= O_WRONLY;
-
- if (Flags & F_Append)
- OpenFlags |= O_APPEND;
- else
- OpenFlags |= O_TRUNC;
-
- if (Flags & F_Excl)
- OpenFlags |= O_EXCL;
+Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags,
+ SmallVectorImpl<char> *RealPath) {
+ file_t ResultFD;
+ std::error_code EC = openFileForRead(Name, ResultFD, Flags, RealPath);
+ if (EC)
+ return errorCodeToError(EC);
+ return ResultFD;
+}
- SmallString<128> Storage;
- StringRef P = Name.toNullTerminatedStringRef(Storage);
- if ((ResultFD = sys::RetryAfterSignal(-1, open, P.begin(), OpenFlags, Mode)) < 0)
- return std::error_code(errno, std::generic_category());
-#ifndef O_CLOEXEC
- int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC);
- (void)r;
- assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed");
-#endif
- return std::error_code();
+void closeFile(file_t &F) {
+ ::close(F);
+ F = kInvalidFile;
}
template <typename T>
@@ -860,12 +897,12 @@ std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest,
return real_path(Storage, dest, false);
}
- int fd;
- std::error_code EC = openFileForRead(path, fd, &dest);
-
- if (EC)
- return EC;
- ::close(fd);
+ SmallString<128> Storage;
+ StringRef P = path.toNullTerminatedStringRef(Storage);
+ char Buffer[PATH_MAX];
+ if (::realpath(P.begin(), Buffer) == nullptr)
+ return std::error_code(errno, std::generic_category());
+ dest.append(Buffer, Buffer + strlen(Buffer));
return std::error_code();
}
diff --git a/lib/Support/Unix/Process.inc b/lib/Support/Unix/Process.inc
index e43650d707e3..fa515d44f3f2 100644
--- a/lib/Support/Unix/Process.inc
+++ b/lib/Support/Unix/Process.inc
@@ -14,6 +14,7 @@
#include "Unix.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/config.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/MutexGuard.h"
@@ -78,7 +79,7 @@ unsigned Process::getPageSize() {
#elif defined(HAVE_SYSCONF)
static long page_size = ::sysconf(_SC_PAGE_SIZE);
#else
-#warning Cannot get the page size on this machine
+#error Cannot get the page size on this machine
#endif
return static_cast<unsigned>(page_size);
}
@@ -172,15 +173,6 @@ Optional<std::string> Process::GetEnv(StringRef Name) {
return std::string(Val);
}
-std::error_code
-Process::GetArgumentVector(SmallVectorImpl<const char *> &ArgsOut,
- ArrayRef<const char *> ArgsIn,
- SpecificBumpPtrAllocator<char> &) {
- ArgsOut.append(ArgsIn.begin(), ArgsIn.end());
-
- return std::error_code();
-}
-
namespace {
class FDCloser {
public:
@@ -207,7 +199,7 @@ std::error_code Process::FixupStandardFileDescriptors() {
for (int StandardFD : StandardFDs) {
struct stat st;
errno = 0;
- if (RetryAfterSignal(-1, fstat, StandardFD, &st) < 0) {
+ if (RetryAfterSignal(-1, ::fstat, StandardFD, &st) < 0) {
assert(errno && "expected errno to be set if fstat failed!");
// fstat should return EBADF if the file descriptor is closed.
if (errno != EBADF)
@@ -219,7 +211,7 @@ std::error_code Process::FixupStandardFileDescriptors() {
assert(errno == EBADF && "expected errno to have EBADF at this point!");
if (NullFD < 0) {
- if ((NullFD = RetryAfterSignal(-1, open, "/dev/null", O_RDWR)) < 0)
+ if ((NullFD = RetryAfterSignal(-1, ::open, "/dev/null", O_RDWR)) < 0)
return std::error_code(errno, std::generic_category());
}
@@ -369,6 +361,21 @@ static bool terminalHasColors(int fd) {
// Return true if we found a color capabilities for the current terminal.
if (HasColors)
return true;
+#else
+ // When the terminfo database is not available, check if the current terminal
+ // is one of terminals that are known to support ANSI color escape codes.
+ if (const char *TermStr = std::getenv("TERM")) {
+ return StringSwitch<bool>(TermStr)
+ .Case("ansi", true)
+ .Case("cygwin", true)
+ .Case("linux", true)
+ .StartsWith("screen", true)
+ .StartsWith("xterm", true)
+ .StartsWith("vt100", true)
+ .StartsWith("rxvt", true)
+ .EndsWith("color", true)
+ .Default(false);
+ }
#endif
// Otherwise, be conservative.
diff --git a/lib/Support/Unix/Program.inc b/lib/Support/Unix/Program.inc
index 4f791991f3e8..d0abc3763e82 100644
--- a/lib/Support/Unix/Program.inc
+++ b/lib/Support/Unix/Program.inc
@@ -23,6 +23,7 @@
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/StringSaver.h"
#include "llvm/Support/raw_ostream.h"
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
@@ -164,8 +165,18 @@ static void SetMemoryLimits(unsigned size) {
}
-static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
- const char **Envp, ArrayRef<Optional<StringRef>> Redirects,
+static std::vector<const char *>
+toNullTerminatedCStringArray(ArrayRef<StringRef> Strings, StringSaver &Saver) {
+ std::vector<const char *> Result;
+ for (StringRef S : Strings)
+ Result.push_back(Saver.save(S).data());
+ Result.push_back(nullptr);
+ return Result;
+}
+
+static bool Execute(ProcessInfo &PI, StringRef Program,
+ ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env,
+ ArrayRef<Optional<StringRef>> Redirects,
unsigned MemoryLimit, std::string *ErrMsg) {
if (!llvm::sys::fs::exists(Program)) {
if (ErrMsg)
@@ -174,6 +185,18 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
return false;
}
+ BumpPtrAllocator Allocator;
+ StringSaver Saver(Allocator);
+ std::vector<const char *> ArgVector, EnvVector;
+ const char **Argv = nullptr;
+ const char **Envp = nullptr;
+ ArgVector = toNullTerminatedCStringArray(Args, Saver);
+ Argv = ArgVector.data();
+ if (Env) {
+ EnvVector = toNullTerminatedCStringArray(*Env, Saver);
+ Envp = EnvVector.data();
+ }
+
// 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
@@ -227,7 +250,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
// positive.
pid_t PID = 0;
int Err = posix_spawn(&PID, Program.str().c_str(), FileActions,
- /*attrp*/nullptr, const_cast<char **>(Args),
+ /*attrp*/ nullptr, const_cast<char **>(Argv),
const_cast<char **>(Envp));
if (FileActions)
@@ -237,6 +260,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err);
PI.Pid = PID;
+ PI.Process = PID;
return true;
}
@@ -279,12 +303,10 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
// Execute!
std::string PathStr = Program;
if (Envp != nullptr)
- execve(PathStr.c_str(),
- const_cast<char **>(Args),
+ execve(PathStr.c_str(), const_cast<char **>(Argv),
const_cast<char **>(Envp));
else
- execv(PathStr.c_str(),
- const_cast<char **>(Args));
+ execv(PathStr.c_str(), const_cast<char **>(Argv));
// 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
@@ -300,6 +322,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
}
PI.Pid = child;
+ PI.Process = child;
return true;
}
@@ -404,14 +427,14 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
return WaitResult;
}
- std::error_code sys::ChangeStdinToBinary(){
+std::error_code sys::ChangeStdinToBinary() {
// Do nothing, as Unix doesn't differentiate between text and binary.
- return std::error_code();
+ return std::error_code();
}
- std::error_code sys::ChangeStdoutToBinary(){
+std::error_code sys::ChangeStdoutToBinary() {
// Do nothing, as Unix doesn't differentiate between text and binary.
- return std::error_code();
+ return std::error_code();
}
std::error_code
@@ -432,29 +455,38 @@ llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents,
}
bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program,
- ArrayRef<const char *> Args) {
+ ArrayRef<StringRef> Args) {
static long ArgMax = sysconf(_SC_ARG_MAX);
+ // POSIX requires that _POSIX_ARG_MAX is 4096, which is the lowest possible
+ // value for ARG_MAX on a POSIX compliant system.
+ static long ArgMin = _POSIX_ARG_MAX;
+
+ // This the same baseline used by xargs.
+ long EffectiveArgMax = 128 * 1024;
+
+ if (EffectiveArgMax > ArgMax)
+ EffectiveArgMax = ArgMax;
+ else if (EffectiveArgMax < ArgMin)
+ EffectiveArgMax = ArgMin;
// System says no practical limit.
if (ArgMax == -1)
return true;
// Conservatively account for space required by environment variables.
- long HalfArgMax = ArgMax / 2;
+ long HalfArgMax = EffectiveArgMax / 2;
size_t ArgLength = Program.size() + 1;
- for (const char* Arg : Args) {
- size_t length = strlen(Arg);
-
+ for (StringRef Arg : Args) {
// 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
// believe. Since this limit is pretty high, perform the check
// unconditionally rather than trying to be aggressive and limiting it to
// Linux only.
- if (length >= (32 * 4096))
+ if (Arg.size() >= (32 * 4096))
return false;
- ArgLength += length + 1;
+ ArgLength += Arg.size() + 1;
if (ArgLength > size_t(HalfArgMax)) {
return false;
}
diff --git a/lib/Support/Unix/Signals.inc b/lib/Support/Unix/Signals.inc
index aaf760c5b616..de26695d64ea 100644
--- a/lib/Support/Unix/Signals.inc
+++ b/lib/Support/Unix/Signals.inc
@@ -11,9 +11,31 @@
// Unix signals occurring while your program is running.
//
//===----------------------------------------------------------------------===//
+//
+// This file is extremely careful to only do signal-safe things while in a
+// signal handler. In particular, memory allocation and acquiring a mutex
+// while in a signal handler should never occur. ManagedStatic isn't usable from
+// a signal handler for 2 reasons:
+//
+// 1. Creating a new one allocates.
+// 2. The signal handler could fire while llvm_shutdown is being processed, in
+// which case the ManagedStatic is in an unknown state because it could
+// already have been destroyed, or be in the process of being destroyed.
+//
+// Modifying the behavior of the signal handlers (such as registering new ones)
+// can acquire a mutex, but all this guarantees is that the signal handler
+// behavior is only modified by one thread at a time. A signal handler can still
+// fire while this occurs!
+//
+// Adding work to a signal handler requires lock-freedom (and assume atomics are
+// always lock-free) because the signal handler could fire while new work is
+// being added.
+//
+//===----------------------------------------------------------------------===//
#include "Unix.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Config/config.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
@@ -59,24 +81,133 @@ using namespace llvm;
static RETSIGTYPE SignalHandler(int Sig); // defined below.
-static ManagedStatic<sys::SmartMutex<true> > SignalsMutex;
+/// The function to call if ctrl-c is pressed.
+using InterruptFunctionType = void (*)();
+static std::atomic<InterruptFunctionType> InterruptFunction =
+ ATOMIC_VAR_INIT(nullptr);
+
+namespace {
+/// Signal-safe removal of files.
+/// Inserting and erasing from the list isn't signal-safe, but removal of files
+/// themselves is signal-safe. Memory is freed when the head is freed, deletion
+/// is therefore not signal-safe either.
+class FileToRemoveList {
+ std::atomic<char *> Filename = ATOMIC_VAR_INIT(nullptr);
+ std::atomic<FileToRemoveList *> Next = ATOMIC_VAR_INIT(nullptr);
+
+ FileToRemoveList() = default;
+ // Not signal-safe.
+ FileToRemoveList(const std::string &str) : Filename(strdup(str.c_str())) {}
+
+public:
+ // Not signal-safe.
+ ~FileToRemoveList() {
+ if (FileToRemoveList *N = Next.exchange(nullptr))
+ delete N;
+ if (char *F = Filename.exchange(nullptr))
+ free(F);
+ }
+
+ // Not signal-safe.
+ static void insert(std::atomic<FileToRemoveList *> &Head,
+ const std::string &Filename) {
+ // Insert the new file at the end of the list.
+ FileToRemoveList *NewHead = new FileToRemoveList(Filename);
+ std::atomic<FileToRemoveList *> *InsertionPoint = &Head;
+ FileToRemoveList *OldHead = nullptr;
+ while (!InsertionPoint->compare_exchange_strong(OldHead, NewHead)) {
+ InsertionPoint = &OldHead->Next;
+ OldHead = nullptr;
+ }
+ }
+
+ // Not signal-safe.
+ static void erase(std::atomic<FileToRemoveList *> &Head,
+ const std::string &Filename) {
+ // Use a lock to avoid concurrent erase: the comparison would access
+ // free'd memory.
+ static ManagedStatic<sys::SmartMutex<true>> Lock;
+ sys::SmartScopedLock<true> Writer(*Lock);
+
+ for (FileToRemoveList *Current = Head.load(); Current;
+ Current = Current->Next.load()) {
+ if (char *OldFilename = Current->Filename.load()) {
+ if (OldFilename != Filename)
+ continue;
+ // Leave an empty filename.
+ OldFilename = Current->Filename.exchange(nullptr);
+ // The filename might have become null between the time we
+ // compared it and we exchanged it.
+ if (OldFilename)
+ free(OldFilename);
+ }
+ }
+ }
-/// InterruptFunction - The function to call if ctrl-c is pressed.
-static void (*InterruptFunction)() = nullptr;
+ // Signal-safe.
+ static void removeAllFiles(std::atomic<FileToRemoveList *> &Head) {
+ // If cleanup were to occur while we're removing files we'd have a bad time.
+ // Make sure we're OK by preventing cleanup from doing anything while we're
+ // removing files. If cleanup races with us and we win we'll have a leak,
+ // but we won't crash.
+ FileToRemoveList *OldHead = Head.exchange(nullptr);
+
+ for (FileToRemoveList *currentFile = OldHead; currentFile;
+ currentFile = currentFile->Next.load()) {
+ // If erasing was occuring while we're trying to remove files we'd look
+ // at free'd data. Take away the path and put it back when done.
+ if (char *path = currentFile->Filename.exchange(nullptr)) {
+ // Get the status so we can determine if it's a file or directory. If we
+ // can't stat the file, ignore it.
+ struct stat buf;
+ if (stat(path, &buf) != 0)
+ continue;
+
+ // If this is not a regular file, ignore it. We want to prevent removal
+ // of special files like /dev/null, even if the compiler is being run
+ // with the super-user permissions.
+ if (!S_ISREG(buf.st_mode))
+ continue;
+
+ // Otherwise, remove the file. We ignore any errors here as there is
+ // nothing else we can do.
+ unlink(path);
+
+ // We're done removing the file, erasing can safely proceed.
+ currentFile->Filename.exchange(path);
+ }
+ }
-static ManagedStatic<std::vector<std::string>> FilesToRemove;
+ // We're done removing files, cleanup can safely proceed.
+ Head.exchange(OldHead);
+ }
+};
+static std::atomic<FileToRemoveList *> FilesToRemove = ATOMIC_VAR_INIT(nullptr);
+
+/// Clean up the list in a signal-friendly manner.
+/// Recall that signals can fire during llvm_shutdown. If this occurs we should
+/// either clean something up or nothing at all, but we shouldn't crash!
+struct FilesToRemoveCleanup {
+ // Not signal-safe.
+ ~FilesToRemoveCleanup() {
+ FileToRemoveList *Head = FilesToRemove.exchange(nullptr);
+ if (Head)
+ delete Head;
+ }
+};
+} // namespace
static StringRef Argv0;
-// IntSigs - Signals that represent requested termination. There's no bug
-// or failure, or if there is, it's not our direct responsibility. For whatever
-// reason, our continued execution is no longer desirable.
+// Signals that represent requested termination. There's no bug or failure, or
+// if there is, it's not our direct responsibility. For whatever reason, our
+// continued execution is no longer desirable.
static const int IntSigs[] = {
SIGHUP, SIGINT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2
};
-// KillSigs - Signals that represent that we have a bug, and our prompt
-// termination has been ordered.
+// Signals that represent that we have a bug, and our prompt termination has
+// been ordered.
static const int KillSigs[] = {
SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGQUIT
#ifdef SIGSYS
@@ -93,30 +224,12 @@ static const int KillSigs[] = {
#endif
};
-static unsigned NumRegisteredSignals = 0;
+static std::atomic<unsigned> NumRegisteredSignals = ATOMIC_VAR_INIT(0);
static struct {
struct sigaction SA;
int SigNo;
} RegisteredSignalInfo[array_lengthof(IntSigs) + array_lengthof(KillSigs)];
-
-static void RegisterHandler(int Signal) {
- assert(NumRegisteredSignals < array_lengthof(RegisteredSignalInfo) &&
- "Out of space for signal handlers!");
-
- struct sigaction NewHandler;
-
- NewHandler.sa_handler = SignalHandler;
- NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK;
- sigemptyset(&NewHandler.sa_mask);
-
- // Install the new handler, save the old one in RegisteredSignalInfo.
- sigaction(Signal, &NewHandler,
- &RegisteredSignalInfo[NumRegisteredSignals].SA);
- RegisteredSignalInfo[NumRegisteredSignals].SigNo = Signal;
- ++NumRegisteredSignals;
-}
-
#if defined(HAVE_SIGALTSTACK)
// Hold onto both the old and new alternate signal stack so that it's not
// reported as a leak. We don't make any attempt to remove our alt signal
@@ -138,7 +251,7 @@ static void CreateSigAltStack() {
return;
stack_t AltStack = {};
- AltStack.ss_sp = reinterpret_cast<char *>(malloc(AltStackSize));
+ AltStack.ss_sp = static_cast<char *>(safe_malloc(AltStackSize));
NewAltStackPointer = AltStack.ss_sp; // Save to avoid reporting a leak.
AltStack.ss_size = AltStackSize;
if (sigaltstack(&AltStack, &OldAltStack) != 0)
@@ -148,64 +261,59 @@ static void CreateSigAltStack() {
static void CreateSigAltStack() {}
#endif
-static void RegisterHandlers() {
- sys::SmartScopedLock<true> Guard(*SignalsMutex);
+static void RegisterHandlers() { // Not signal-safe.
+ // The mutex prevents other threads from registering handlers while we're
+ // doing it. We also have to protect the handlers and their count because
+ // a signal handler could fire while we're registeting handlers.
+ static ManagedStatic<sys::SmartMutex<true>> SignalHandlerRegistrationMutex;
+ sys::SmartScopedLock<true> Guard(*SignalHandlerRegistrationMutex);
// If the handlers are already registered, we're done.
- if (NumRegisteredSignals != 0) return;
+ if (NumRegisteredSignals.load() != 0)
+ return;
// Create an alternate stack for signal handling. This is necessary for us to
// be able to reliably handle signals due to stack overflow.
CreateSigAltStack();
- for (auto S : IntSigs) RegisterHandler(S);
- for (auto S : KillSigs) RegisterHandler(S);
+ auto registerHandler = [&](int Signal) {
+ unsigned Index = NumRegisteredSignals.load();
+ assert(Index < array_lengthof(RegisteredSignalInfo) &&
+ "Out of space for signal handlers!");
+
+ struct sigaction NewHandler;
+
+ NewHandler.sa_handler = SignalHandler;
+ NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK;
+ sigemptyset(&NewHandler.sa_mask);
+
+ // Install the new handler, save the old one in RegisteredSignalInfo.
+ sigaction(Signal, &NewHandler, &RegisteredSignalInfo[Index].SA);
+ RegisteredSignalInfo[Index].SigNo = Signal;
+ ++NumRegisteredSignals;
+ };
+
+ for (auto S : IntSigs)
+ registerHandler(S);
+ for (auto S : KillSigs)
+ registerHandler(S);
}
static void UnregisterHandlers() {
// Restore all of the signal handlers to how they were before we showed up.
- for (unsigned i = 0, e = NumRegisteredSignals; i != e; ++i)
+ for (unsigned i = 0, e = NumRegisteredSignals.load(); i != e; ++i) {
sigaction(RegisteredSignalInfo[i].SigNo,
&RegisteredSignalInfo[i].SA, nullptr);
- NumRegisteredSignals = 0;
+ --NumRegisteredSignals;
+ }
}
-
-/// RemoveFilesToRemove - Process the FilesToRemove list. This function
-/// should be called with the SignalsMutex lock held.
-/// NB: This must be an async signal safe function. It cannot allocate or free
-/// memory, even in debug builds.
+/// Process the FilesToRemove list.
static void RemoveFilesToRemove() {
- // Avoid constructing ManagedStatic in the signal handler.
- // If FilesToRemove is not constructed, there are no files to remove.
- if (!FilesToRemove.isConstructed())
- return;
-
- // We avoid iterators in case of debug iterators that allocate or release
- // memory.
- std::vector<std::string>& FilesToRemoveRef = *FilesToRemove;
- for (unsigned i = 0, e = FilesToRemoveRef.size(); i != e; ++i) {
- const char *path = FilesToRemoveRef[i].c_str();
-
- // Get the status so we can determine if it's a file or directory. If we
- // can't stat the file, ignore it.
- struct stat buf;
- if (stat(path, &buf) != 0)
- continue;
-
- // If this is not a regular file, ignore it. We want to prevent removal of
- // special files like /dev/null, even if the compiler is being run with the
- // super-user permissions.
- if (!S_ISREG(buf.st_mode))
- continue;
-
- // Otherwise, remove the file. We ignore any errors here as there is nothing
- // else we can do.
- unlink(path);
- }
+ FileToRemoveList::removeAllFiles(FilesToRemove);
}
-// SignalHandler - The signal handler that runs.
+// The signal handler that runs.
static RETSIGTYPE SignalHandler(int Sig) {
// Restore the signal behavior to default, so that the program actually
// crashes when we return and the signal reissues. This also ensures that if
@@ -219,20 +327,13 @@ static RETSIGTYPE SignalHandler(int Sig) {
sigprocmask(SIG_UNBLOCK, &SigMask, nullptr);
{
- unique_lock<sys::SmartMutex<true>> Guard(*SignalsMutex);
RemoveFilesToRemove();
if (std::find(std::begin(IntSigs), std::end(IntSigs), Sig)
!= std::end(IntSigs)) {
- if (InterruptFunction) {
- void (*IF)() = InterruptFunction;
- Guard.unlock();
- InterruptFunction = nullptr;
- IF(); // run the interrupt function.
- return;
- }
+ if (auto OldInterruptFunction = InterruptFunction.exchange(nullptr))
+ return OldInterruptFunction();
- Guard.unlock();
raise(Sig); // Execute the default handler.
return;
}
@@ -252,45 +353,36 @@ static RETSIGTYPE SignalHandler(int Sig) {
}
void llvm::sys::RunInterruptHandlers() {
- sys::SmartScopedLock<true> Guard(*SignalsMutex);
RemoveFilesToRemove();
}
void llvm::sys::SetInterruptFunction(void (*IF)()) {
- {
- sys::SmartScopedLock<true> Guard(*SignalsMutex);
- InterruptFunction = IF;
- }
+ InterruptFunction.exchange(IF);
RegisterHandlers();
}
-// RemoveFileOnSignal - The public API
+// The public API
bool llvm::sys::RemoveFileOnSignal(StringRef Filename,
std::string* ErrMsg) {
- {
- sys::SmartScopedLock<true> Guard(*SignalsMutex);
- FilesToRemove->push_back(Filename);
- }
-
+ // Ensure that cleanup will occur as soon as one file is added.
+ static ManagedStatic<FilesToRemoveCleanup> FilesToRemoveCleanup;
+ *FilesToRemoveCleanup;
+ FileToRemoveList::insert(FilesToRemove, Filename.str());
RegisterHandlers();
return false;
}
-// DontRemoveFileOnSignal - The public API
+// The public API
void llvm::sys::DontRemoveFileOnSignal(StringRef Filename) {
- sys::SmartScopedLock<true> Guard(*SignalsMutex);
- std::vector<std::string>::reverse_iterator RI =
- find(reverse(*FilesToRemove), Filename);
- std::vector<std::string>::iterator I = FilesToRemove->end();
- if (RI != FilesToRemove->rend())
- I = FilesToRemove->erase(RI.base()-1);
+ FileToRemoveList::erase(FilesToRemove, Filename.str());
}
-/// AddSignalHandler - Add a function to be called when a signal is delivered
-/// to the process. The handler can have a cookie passed to it to identify
-/// what instance of the handler it is.
-void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) {
- CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie));
+/// Add a function to be called when a signal is delivered to the process. The
+/// handler can have a cookie passed to it to identify what instance of the
+/// handler it is.
+void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr,
+ void *Cookie) { // Signal-safe.
+ insertSignalHandler(FnPtr, Cookie);
RegisterHandlers();
}
@@ -383,8 +475,8 @@ static int unwindBacktrace(void **StackTrace, int MaxEntries) {
}
#endif
-// PrintStackTrace - In the case of a program crash or fault, print out a stack
-// trace so that the user has an indication of why and where we died.
+// In the case of a program crash or fault, print out a stack trace so that the
+// user has an indication of why and where we died.
//
// On glibc systems we have the 'backtrace' function, which works nicely, but
// doesn't demangle symbols.
@@ -463,8 +555,8 @@ static void PrintStackTraceSignalHandler(void *) {
void llvm::sys::DisableSystemDialogsOnCrash() {}
-/// PrintStackTraceOnErrorSignal - When an error signal (such as SIGABRT or
-/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
+/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
+/// process, print a stack trace and then exit.
void llvm::sys::PrintStackTraceOnErrorSignal(StringRef Argv0,
bool DisableCrashReporting) {
::Argv0 = Argv0;
diff --git a/lib/Support/Unix/ThreadLocal.inc b/lib/Support/Unix/ThreadLocal.inc
index 31c3f3835b29..a6564f0fa281 100644
--- a/lib/Support/Unix/ThreadLocal.inc
+++ b/lib/Support/Unix/ThreadLocal.inc
@@ -16,6 +16,8 @@
//=== is guaranteed to work on *all* UNIX variants.
//===----------------------------------------------------------------------===//
+#include "llvm/Config/config.h"
+
#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_GETSPECIFIC)
#include <cassert>
diff --git a/lib/Support/Unix/Threading.inc b/lib/Support/Unix/Threading.inc
index 7369cff8466c..2d49ce1ad747 100644
--- a/lib/Support/Unix/Threading.inc
+++ b/lib/Support/Unix/Threading.inc
@@ -21,8 +21,8 @@
#include <pthread.h>
-#if defined(__FreeBSD__)
-#include <pthread_np.h> // For pthread_getthreadid_np()
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#include <pthread_np.h> // For pthread_getthreadid_np() / pthread_set_name_np()
#endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -98,8 +98,6 @@ uint64_t llvm::get_threadid() {
return uint64_t(gettid());
#elif defined(__linux__)
return uint64_t(syscall(SYS_gettid));
-#elif defined(LLVM_ON_WIN32)
- return uint64_t(::GetCurrentThreadId());
#else
return uint64_t(pthread_self());
#endif
@@ -119,6 +117,8 @@ static constexpr uint32_t get_max_thread_name_length_impl() {
#endif
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
return 16;
+#elif defined(__OpenBSD__)
+ return 32;
#else
return 0;
#endif
@@ -138,8 +138,9 @@ void llvm::set_thread_name(const Twine &Name) {
// terminated, but additionally the end of a long thread name will usually
// be more unique than the beginning, since a common pattern is for similar
// threads to share a common prefix.
+ // Note that the name length includes the null terminator.
if (get_max_thread_name_length() > 0)
- NameStr = NameStr.take_back(get_max_thread_name_length());
+ NameStr = NameStr.take_back(get_max_thread_name_length() - 1);
(void)NameStr;
#if defined(__linux__)
#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__)
@@ -147,7 +148,7 @@ void llvm::set_thread_name(const Twine &Name) {
::pthread_setname_np(::pthread_self(), NameStr.data());
#endif
#endif
-#elif defined(__FreeBSD__)
+#elif defined(__FreeBSD__) || defined(__OpenBSD__)
::pthread_set_name_np(::pthread_self(), NameStr.data());
#elif defined(__NetBSD__)
::pthread_setname_np(::pthread_self(), "%s",
@@ -175,7 +176,7 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
if (kp == nullptr || (error != 0 && errno == ENOMEM)) {
// Add extra space in case threads are added before next call.
len += sizeof(*kp) + len / 10;
- nkp = (struct kinfo_proc *)realloc(kp, len);
+ nkp = (struct kinfo_proc *)::realloc(kp, len);
if (nkp == nullptr) {
free(kp);
return;
@@ -203,7 +204,6 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
Name.append(buf, buf + strlen(buf));
#elif defined(__linux__)
-#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] = {'\0'}; // FIXME: working around MSan false positive.
@@ -211,5 +211,4 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
Name.append(Buffer, Buffer + strlen(Buffer));
#endif
#endif
-#endif
}
diff --git a/lib/Support/Unix/Unix.h b/lib/Support/Unix/Unix.h
index 239a6d60aaef..0c5d4de556d5 100644
--- a/lib/Support/Unix/Unix.h
+++ b/lib/Support/Unix/Unix.h
@@ -56,7 +56,7 @@
/// This function builds an error message into \p ErrMsg using the \p prefix
/// string and the Unix error number given by \p errnum. If errnum is -1, the
/// default then the value of errno is used.
-/// @brief Make an error message
+/// Make an error message
///
/// If the error number can be converted to a string, it will be
/// separated from prefix by ": ".
diff --git a/lib/Support/Unix/Watchdog.inc b/lib/Support/Unix/Watchdog.inc
index 5d89c0e51b11..f4253391d952 100644
--- a/lib/Support/Unix/Watchdog.inc
+++ b/lib/Support/Unix/Watchdog.inc
@@ -11,6 +11,8 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/Config/config.h"
+
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
diff --git a/lib/Support/VersionTuple.cpp b/lib/Support/VersionTuple.cpp
new file mode 100644
index 000000000000..3f219bfbedfa
--- /dev/null
+++ b/lib/Support/VersionTuple.cpp
@@ -0,0 +1,110 @@
+//===- VersionTuple.cpp - Version Number Handling ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the VersionTuple class, which represents a version in
+// the form major[.minor[.subminor]].
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/Support/VersionTuple.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+std::string VersionTuple::getAsString() const {
+ std::string Result;
+ {
+ llvm::raw_string_ostream Out(Result);
+ Out << *this;
+ }
+ return Result;
+}
+
+raw_ostream &llvm::operator<<(raw_ostream &Out, const VersionTuple &V) {
+ Out << V.getMajor();
+ if (Optional<unsigned> Minor = V.getMinor())
+ Out << '.' << *Minor;
+ if (Optional<unsigned> Subminor = V.getSubminor())
+ Out << '.' << *Subminor;
+ if (Optional<unsigned> Build = V.getBuild())
+ Out << '.' << *Build;
+ return Out;
+}
+
+static bool parseInt(StringRef &input, unsigned &value) {
+ assert(value == 0);
+ if (input.empty())
+ return true;
+
+ char next = input[0];
+ input = input.substr(1);
+ if (next < '0' || next > '9')
+ return true;
+ value = (unsigned)(next - '0');
+
+ while (!input.empty()) {
+ next = input[0];
+ if (next < '0' || next > '9')
+ return false;
+ input = input.substr(1);
+ value = value * 10 + (unsigned)(next - '0');
+ }
+
+ return false;
+}
+
+bool VersionTuple::tryParse(StringRef input) {
+ unsigned major = 0, minor = 0, micro = 0, build = 0;
+
+ // Parse the major version, [0-9]+
+ if (parseInt(input, major))
+ return true;
+
+ if (input.empty()) {
+ *this = VersionTuple(major);
+ return false;
+ }
+
+ // If we're not done, parse the minor version, \.[0-9]+
+ if (input[0] != '.')
+ return true;
+ input = input.substr(1);
+ if (parseInt(input, minor))
+ return true;
+
+ if (input.empty()) {
+ *this = VersionTuple(major, minor);
+ return false;
+ }
+
+ // If we're not done, parse the micro version, \.[0-9]+
+ if (input[0] != '.')
+ return true;
+ input = input.substr(1);
+ if (parseInt(input, micro))
+ return true;
+
+ if (input.empty()) {
+ *this = VersionTuple(major, minor, micro);
+ return false;
+ }
+
+ // If we're not done, parse the micro version, \.[0-9]+
+ if (input[0] != '.')
+ return true;
+ input = input.substr(1);
+ if (parseInt(input, build))
+ return true;
+
+ // If we have characters left over, it's an error.
+ if (!input.empty())
+ return true;
+
+ *this = VersionTuple(major, minor, micro, build);
+ return false;
+}
diff --git a/lib/Support/Watchdog.cpp b/lib/Support/Watchdog.cpp
index 724aa001f16e..be55e3122e70 100644
--- a/lib/Support/Watchdog.cpp
+++ b/lib/Support/Watchdog.cpp
@@ -12,12 +12,12 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Watchdog.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
// Include the platform-specific parts of this class.
#ifdef LLVM_ON_UNIX
#include "Unix/Watchdog.inc"
#endif
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
#include "Windows/Watchdog.inc"
#endif
diff --git a/lib/Support/Windows/DynamicLibrary.inc b/lib/Support/Windows/DynamicLibrary.inc
index 083ea902eeb2..1d47f0848a6d 100644
--- a/lib/Support/Windows/DynamicLibrary.inc
+++ b/lib/Support/Windows/DynamicLibrary.inc
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "WindowsSupport.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/raw_ostream.h"
#include <psapi.h>
diff --git a/lib/Support/Windows/Host.inc b/lib/Support/Windows/Host.inc
index 90a6fb316703..58c4dc5d678f 100644
--- a/lib/Support/Windows/Host.inc
+++ b/lib/Support/Windows/Host.inc
@@ -30,5 +30,5 @@ std::string sys::getDefaultTargetTriple() {
Triple = EnvTriple;
#endif
- return Triple::normalize(Triple);
+ return Triple;
}
diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc
index f81790b17df5..f425d607af47 100644
--- a/lib/Support/Windows/Path.inc
+++ b/lib/Support/Windows/Path.inc
@@ -17,6 +17,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/WindowsError.h"
#include <fcntl.h>
#include <io.h>
@@ -45,6 +46,7 @@ typedef int errno_t;
using namespace llvm;
using llvm::sys::windows::UTF8ToUTF16;
+using llvm::sys::windows::CurCPToUTF16;
using llvm::sys::windows::UTF16ToUTF8;
using llvm::sys::path::widenPath;
@@ -121,6 +123,8 @@ std::error_code widenPath(const Twine &Path8,
namespace fs {
+const file_t kInvalidFile = INVALID_HANDLE_VALUE;
+
std::string getMainExecutable(const char *argv0, void *MainExecAddr) {
SmallVector<wchar_t, MAX_PATH> PathName;
DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity());
@@ -400,56 +404,6 @@ static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) {
return std::error_code();
}
-static std::error_code removeFD(int FD) {
- HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
- return setDeleteDisposition(Handle, true);
-}
-
-/// 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());
-
- if (std::error_code EC = setDeleteDisposition(NewHandle, false))
- return EC;
-
- 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;
@@ -822,8 +776,9 @@ std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {
std::error_code mapped_file_region::init(int FD, uint64_t Offset,
mapmode Mode) {
- HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
- if (FileHandle == INVALID_HANDLE_VALUE)
+ this->Mode = Mode;
+ HANDLE OrigFileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+ if (OrigFileHandle == INVALID_HANDLE_VALUE)
return make_error_code(errc::bad_file_descriptor);
DWORD flprotect;
@@ -834,7 +789,7 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset,
}
HANDLE FileMappingHandle =
- ::CreateFileMappingW(FileHandle, 0, flprotect,
+ ::CreateFileMappingW(OrigFileHandle, 0, flprotect,
Hi_32(Size),
Lo_32(Size),
0);
@@ -872,9 +827,20 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset,
Size = mbi.RegionSize;
}
- // Close all the handles except for the view. It will keep the other handles
- // alive.
+ // Close the file mapping handle, as it's kept alive by the file mapping. But
+ // neither the file mapping nor the file mapping handle keep the file handle
+ // alive, so we need to keep a reference to the file in case all other handles
+ // are closed and the file is deleted, which may cause invalid data to be read
+ // from the file.
::CloseHandle(FileMappingHandle);
+ if (!::DuplicateHandle(::GetCurrentProcess(), OrigFileHandle,
+ ::GetCurrentProcess(), &FileHandle, 0, 0,
+ DUPLICATE_SAME_ACCESS)) {
+ std::error_code ec = mapWindowsError(GetLastError());
+ ::UnmapViewOfFile(Mapping);
+ return ec;
+ }
+
return std::error_code();
}
@@ -887,8 +853,20 @@ mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length,
}
mapped_file_region::~mapped_file_region() {
- if (Mapping)
+ if (Mapping) {
::UnmapViewOfFile(Mapping);
+
+ if (Mode == mapmode::readwrite) {
+ // There is a Windows kernel bug, the exact trigger conditions of which
+ // are not well understood. When triggered, dirty pages are not properly
+ // flushed and subsequent process's attempts to read a file can return
+ // invalid data. Calling FlushFileBuffers on the write handle is
+ // sufficient to ensure that this bug is not triggered.
+ ::FlushFileBuffers(FileHandle);
+ }
+
+ ::CloseHandle(FileHandle);
+ }
}
size_t mapped_file_region::size() const {
@@ -1017,35 +995,82 @@ ErrorOr<basic_file_status> directory_entry::status() const {
return Status;
}
-static std::error_code directoryRealPath(const Twine &Name,
- SmallVectorImpl<char> &RealPath) {
- SmallVector<wchar_t, 128> PathUTF16;
+static std::error_code nativeFileToFd(Expected<HANDLE> H, int &ResultFD,
+ OpenFlags Flags) {
+ int CrtOpenFlags = 0;
+ if (Flags & OF_Append)
+ CrtOpenFlags |= _O_APPEND;
- if (std::error_code EC = widenPath(Name, PathUTF16))
- return EC;
+ if (Flags & OF_Text)
+ CrtOpenFlags |= _O_TEXT;
- HANDLE H =
- ::CreateFileW(PathUTF16.begin(), GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- if (H == INVALID_HANDLE_VALUE)
- return mapWindowsError(GetLastError());
- std::error_code EC = realPathFromHandle(H, RealPath);
- ::CloseHandle(H);
- return EC;
+ ResultFD = -1;
+ if (!H)
+ return errorToErrorCode(H.takeError());
+
+ ResultFD = ::_open_osfhandle(intptr_t(*H), CrtOpenFlags);
+ if (ResultFD == -1) {
+ ::CloseHandle(*H);
+ return mapWindowsError(ERROR_INVALID_HANDLE);
+ }
+ return std::error_code();
}
-std::error_code openFileForRead(const Twine &Name, int &ResultFD,
- SmallVectorImpl<char> *RealPath) {
+static DWORD nativeDisposition(CreationDisposition Disp, OpenFlags Flags) {
+ // This is a compatibility hack. Really we should respect the creation
+ // disposition, but a lot of old code relied on the implicit assumption that
+ // OF_Append implied it would open an existing file. Since the disposition is
+ // now explicit and defaults to CD_CreateAlways, this assumption would cause
+ // any usage of OF_Append to append to a new file, even if the file already
+ // existed. A better solution might have two new creation dispositions:
+ // CD_AppendAlways and CD_AppendNew. This would also address the problem of
+ // OF_Append being used on a read-only descriptor, which doesn't make sense.
+ if (Flags & OF_Append)
+ return OPEN_ALWAYS;
+
+ switch (Disp) {
+ case CD_CreateAlways:
+ return CREATE_ALWAYS;
+ case CD_CreateNew:
+ return CREATE_NEW;
+ case CD_OpenAlways:
+ return OPEN_ALWAYS;
+ case CD_OpenExisting:
+ return OPEN_EXISTING;
+ }
+ llvm_unreachable("unreachable!");
+}
+
+static DWORD nativeAccess(FileAccess Access, OpenFlags Flags) {
+ DWORD Result = 0;
+ if (Access & FA_Read)
+ Result |= GENERIC_READ;
+ if (Access & FA_Write)
+ Result |= GENERIC_WRITE;
+ if (Flags & OF_Delete)
+ Result |= DELETE;
+ if (Flags & OF_UpdateAtime)
+ Result |= FILE_WRITE_ATTRIBUTES;
+ return Result;
+}
+
+static std::error_code openNativeFileInternal(const Twine &Name,
+ file_t &ResultFile, DWORD Disp,
+ DWORD Access, DWORD Flags,
+ bool Inherit = false) {
SmallVector<wchar_t, 128> PathUTF16;
-
if (std::error_code EC = widenPath(Name, PathUTF16))
return EC;
+ SECURITY_ATTRIBUTES SA;
+ SA.nLength = sizeof(SA);
+ SA.lpSecurityDescriptor = nullptr;
+ SA.bInheritHandle = Inherit;
+
HANDLE H =
- ::CreateFileW(PathUTF16.begin(), GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ ::CreateFileW(PathUTF16.begin(), Access,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &SA,
+ Disp, Flags, NULL);
if (H == INVALID_HANDLE_VALUE) {
DWORD LastError = ::GetLastError();
std::error_code EC = mapWindowsError(LastError);
@@ -1058,82 +1083,96 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
return make_error_code(errc::is_a_directory);
return EC;
}
+ ResultFile = H;
+ return std::error_code();
+}
- int FD = ::_open_osfhandle(intptr_t(H), 0);
- if (FD == -1) {
- ::CloseHandle(H);
- return mapWindowsError(ERROR_INVALID_HANDLE);
+Expected<file_t> openNativeFile(const Twine &Name, CreationDisposition Disp,
+ FileAccess Access, OpenFlags Flags,
+ unsigned Mode) {
+ // Verify that we don't have both "append" and "excl".
+ assert((!(Disp == CD_CreateNew) || !(Flags & OF_Append)) &&
+ "Cannot specify both 'CreateNew' and 'Append' file creation flags!");
+
+ DWORD NativeDisp = nativeDisposition(Disp, Flags);
+ DWORD NativeAccess = nativeAccess(Access, Flags);
+
+ bool Inherit = false;
+ if (Flags & OF_ChildInherit)
+ Inherit = true;
+
+ file_t Result;
+ std::error_code EC = openNativeFileInternal(
+ Name, Result, NativeDisp, NativeAccess, FILE_ATTRIBUTE_NORMAL, Inherit);
+ if (EC)
+ return errorCodeToError(EC);
+
+ if (Flags & OF_UpdateAtime) {
+ FILETIME FileTime;
+ SYSTEMTIME SystemTime;
+ GetSystemTime(&SystemTime);
+ if (SystemTimeToFileTime(&SystemTime, &FileTime) == 0 ||
+ SetFileTime(Result, NULL, &FileTime, NULL) == 0) {
+ DWORD LastError = ::GetLastError();
+ ::CloseHandle(Result);
+ return errorCodeToError(mapWindowsError(LastError));
+ }
}
- // Fetch the real name of the file, if the user asked
- if (RealPath)
- realPathFromHandle(H, *RealPath);
-
- ResultFD = FD;
- return std::error_code();
+ if (Flags & OF_Delete) {
+ if ((EC = setDeleteDisposition(Result, true))) {
+ ::CloseHandle(Result);
+ return errorCodeToError(EC);
+ }
+ }
+ return Result;
}
-std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
- sys::fs::OpenFlags Flags, unsigned Mode) {
- // Verify that we don't have both "append" and "excl".
- assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) &&
- "Cannot specify both 'excl' and 'append' file creation flags!");
+std::error_code openFile(const Twine &Name, int &ResultFD,
+ CreationDisposition Disp, FileAccess Access,
+ OpenFlags Flags, unsigned int Mode) {
+ Expected<file_t> Result = openNativeFile(Name, Disp, Access, Flags);
+ if (!Result)
+ return errorToErrorCode(Result.takeError());
- SmallVector<wchar_t, 128> PathUTF16;
+ return nativeFileToFd(*Result, ResultFD, Flags);
+}
- if (std::error_code EC = widenPath(Name, PathUTF16))
+static std::error_code directoryRealPath(const Twine &Name,
+ SmallVectorImpl<char> &RealPath) {
+ file_t File;
+ std::error_code EC = openNativeFileInternal(
+ Name, File, OPEN_EXISTING, GENERIC_READ, FILE_FLAG_BACKUP_SEMANTICS);
+ if (EC)
return EC;
- DWORD CreationDisposition;
- if (Flags & F_Excl)
- CreationDisposition = CREATE_NEW;
- else if (Flags & F_Append)
- CreationDisposition = OPEN_ALWAYS;
- else
- 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.data(), Access,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, CreationDisposition, Attributes, NULL);
+ EC = realPathFromHandle(File, RealPath);
+ ::CloseHandle(File);
+ return EC;
+}
- if (H == INVALID_HANDLE_VALUE) {
- DWORD LastError = ::GetLastError();
- std::error_code EC = mapWindowsError(LastError);
- // Provide a better error message when trying to open directories.
- // This only runs if we failed to open the file, so there is probably
- // no performances issues.
- if (LastError != ERROR_ACCESS_DENIED)
- return EC;
- if (is_directory(Name))
- return make_error_code(errc::is_a_directory);
- return EC;
- }
+std::error_code openFileForRead(const Twine &Name, int &ResultFD,
+ OpenFlags Flags,
+ SmallVectorImpl<char> *RealPath) {
+ Expected<HANDLE> NativeFile = openNativeFileForRead(Name, Flags, RealPath);
+ return nativeFileToFd(std::move(NativeFile), ResultFD, OF_None);
+}
- int OpenFlags = 0;
- if (Flags & F_Append)
- OpenFlags |= _O_APPEND;
+Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags,
+ SmallVectorImpl<char> *RealPath) {
+ Expected<file_t> Result =
+ openNativeFile(Name, CD_OpenExisting, FA_Read, Flags);
- if (Flags & F_Text)
- OpenFlags |= _O_TEXT;
+ // Fetch the real name of the file, if the user asked
+ if (Result && RealPath)
+ realPathFromHandle(*Result, *RealPath);
- int FD = ::_open_osfhandle(intptr_t(H), OpenFlags);
- if (FD == -1) {
- ::CloseHandle(H);
- return mapWindowsError(ERROR_INVALID_HANDLE);
- }
+ return Result;
+}
- ResultFD = FD;
- return std::error_code();
+void closeFile(file_t &F) {
+ ::CloseHandle(F);
+ F = kInvalidFile;
}
std::error_code remove_directories(const Twine &path, bool IgnoreErrors) {
@@ -1204,7 +1243,8 @@ std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest,
return directoryRealPath(path, dest);
int fd;
- if (std::error_code EC = llvm::sys::fs::openFileForRead(path, fd, &dest))
+ if (std::error_code EC =
+ llvm::sys::fs::openFileForRead(path, fd, OF_None, &dest))
return EC;
::close(fd);
return std::error_code();
@@ -1279,23 +1319,26 @@ void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) {
} // end namespace path
namespace windows {
-std::error_code UTF8ToUTF16(llvm::StringRef utf8,
- llvm::SmallVectorImpl<wchar_t> &utf16) {
- if (!utf8.empty()) {
- int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(),
- utf8.size(), utf16.begin(), 0);
-
- if (len == 0)
+std::error_code CodePageToUTF16(unsigned codepage,
+ llvm::StringRef original,
+ llvm::SmallVectorImpl<wchar_t> &utf16) {
+ if (!original.empty()) {
+ int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(),
+ original.size(), utf16.begin(), 0);
+
+ if (len == 0) {
return mapWindowsError(::GetLastError());
+ }
utf16.reserve(len + 1);
utf16.set_size(len);
- len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(),
- utf8.size(), utf16.begin(), utf16.size());
+ len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(),
+ original.size(), utf16.begin(), utf16.size());
- if (len == 0)
+ if (len == 0) {
return mapWindowsError(::GetLastError());
+ }
}
// Make utf16 null terminated.
@@ -1305,32 +1348,44 @@ std::error_code UTF8ToUTF16(llvm::StringRef utf8,
return std::error_code();
}
+std::error_code UTF8ToUTF16(llvm::StringRef utf8,
+ llvm::SmallVectorImpl<wchar_t> &utf16) {
+ return CodePageToUTF16(CP_UTF8, utf8, utf16);
+}
+
+std::error_code CurCPToUTF16(llvm::StringRef curcp,
+ llvm::SmallVectorImpl<wchar_t> &utf16) {
+ return CodePageToUTF16(CP_ACP, curcp, utf16);
+}
+
static
std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16,
size_t utf16_len,
- llvm::SmallVectorImpl<char> &utf8) {
+ llvm::SmallVectorImpl<char> &converted) {
if (utf16_len) {
// Get length.
- int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.begin(),
+ int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.begin(),
0, NULL, NULL);
- if (len == 0)
+ if (len == 0) {
return mapWindowsError(::GetLastError());
+ }
- utf8.reserve(len);
- utf8.set_size(len);
+ converted.reserve(len);
+ converted.set_size(len);
// Now do the actual conversion.
- len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.data(),
- utf8.size(), NULL, NULL);
+ len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.data(),
+ converted.size(), NULL, NULL);
- if (len == 0)
+ if (len == 0) {
return mapWindowsError(::GetLastError());
+ }
}
- // Make utf8 null terminated.
- utf8.push_back(0);
- utf8.pop_back();
+ // Make the new string null terminated.
+ converted.push_back(0);
+ converted.pop_back();
return std::error_code();
}
@@ -1341,8 +1396,8 @@ std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
}
std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
- llvm::SmallVectorImpl<char> &utf8) {
- return UTF16ToCodePage(CP_ACP, utf16, utf16_len, utf8);
+ llvm::SmallVectorImpl<char> &curcp) {
+ return UTF16ToCodePage(CP_ACP, utf16, utf16_len, curcp);
}
} // end namespace windows
diff --git a/lib/Support/Windows/Process.inc b/lib/Support/Windows/Process.inc
index 3fe9f89f1ef5..30126568769c 100644
--- a/lib/Support/Windows/Process.inc
+++ b/lib/Support/Windows/Process.inc
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Allocator.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/WindowsError.h"
#include <malloc.h>
@@ -24,14 +25,7 @@
#include <psapi.h>
#include <shellapi.h>
-#ifdef __MINGW32__
- #if (HAVE_LIBPSAPI != 1)
- #error "libpsapi.a should be present"
- #endif
- #if (HAVE_LIBSHELL32 != 1)
- #error "libshell32.a should be present"
- #endif
-#else
+#if !defined(__MINGW32__)
#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "shell32.lib")
#endif
@@ -146,39 +140,38 @@ Optional<std::string> Process::GetEnv(StringRef Name) {
return std::string(Res.data());
}
-static void AllocateAndPush(const SmallVectorImpl<char> &S,
- SmallVectorImpl<const char *> &Vector,
- SpecificBumpPtrAllocator<char> &Allocator) {
- char *Buffer = Allocator.Allocate(S.size() + 1);
- ::memcpy(Buffer, S.data(), S.size());
- Buffer[S.size()] = '\0';
- Vector.push_back(Buffer);
+static const char *AllocateString(const SmallVectorImpl<char> &S,
+ BumpPtrAllocator &Alloc) {
+ char *Buf = reinterpret_cast<char *>(Alloc.Allocate(S.size() + 1, 1));
+ ::memcpy(Buf, S.data(), S.size());
+ Buf[S.size()] = '\0';
+ return Buf;
}
/// Convert Arg from UTF-16 to UTF-8 and push it onto Args.
-static std::error_code
-ConvertAndPushArg(const wchar_t *Arg, SmallVectorImpl<const char *> &Args,
- SpecificBumpPtrAllocator<char> &Allocator) {
+static std::error_code ConvertAndPushArg(const wchar_t *Arg,
+ SmallVectorImpl<const char *> &Args,
+ BumpPtrAllocator &Alloc) {
SmallVector<char, MAX_PATH> ArgString;
if (std::error_code ec = windows::UTF16ToUTF8(Arg, wcslen(Arg), ArgString))
return ec;
- AllocateAndPush(ArgString, Args, Allocator);
+ Args.push_back(AllocateString(ArgString, Alloc));
return std::error_code();
}
-/// \brief Perform wildcard expansion of Arg, or just push it into Args if it
+/// Perform wildcard expansion of Arg, or just push it into Args if it
/// doesn't have wildcards or doesn't match any files.
-static std::error_code
-WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args,
- SpecificBumpPtrAllocator<char> &Allocator) {
+static std::error_code WildcardExpand(const wchar_t *Arg,
+ SmallVectorImpl<const char *> &Args,
+ BumpPtrAllocator &Alloc) {
if (!wcspbrk(Arg, L"*?")) {
// Arg does not contain any wildcard characters. This is the common case.
- return ConvertAndPushArg(Arg, Args, Allocator);
+ return ConvertAndPushArg(Arg, Args, Alloc);
}
if (wcscmp(Arg, L"/?") == 0 || wcscmp(Arg, L"-?") == 0) {
// Don't wildcard expand /?. Always treat it as an option.
- return ConvertAndPushArg(Arg, Args, Allocator);
+ return ConvertAndPushArg(Arg, Args, Alloc);
}
// Extract any directory part of the argument.
@@ -195,7 +188,7 @@ WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args,
WIN32_FIND_DATAW FileData;
HANDLE FindHandle = FindFirstFileW(Arg, &FileData);
if (FindHandle == INVALID_HANDLE_VALUE) {
- return ConvertAndPushArg(Arg, Args, Allocator);
+ return ConvertAndPushArg(Arg, Args, Alloc);
}
std::error_code ec;
@@ -208,7 +201,7 @@ WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args,
// Append FileName to Dir, and remove it afterwards.
llvm::sys::path::append(Dir, StringRef(FileName.data(), FileName.size()));
- AllocateAndPush(Dir, Args, Allocator);
+ Args.push_back(AllocateString(Dir, Alloc));
Dir.resize(DirSize);
} while (FindNextFileW(FindHandle, &FileData));
@@ -216,56 +209,65 @@ WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args,
return ec;
}
-static std::error_code
-ExpandShortFileName(const wchar_t *Arg, SmallVectorImpl<const char *> &Args,
- SpecificBumpPtrAllocator<char> &Allocator) {
- SmallVector<wchar_t, MAX_PATH> LongPath;
- DWORD Length = GetLongPathNameW(Arg, LongPath.data(), LongPath.capacity());
+static std::error_code GetExecutableName(SmallVectorImpl<char> &Filename) {
+ // The first argument may contain just the name of the executable (e.g.,
+ // "clang") rather than the full path, so swap it with the full path.
+ wchar_t ModuleName[MAX_PATH];
+ size_t Length = ::GetModuleFileNameW(NULL, ModuleName, MAX_PATH);
+ if (Length == 0 || Length == MAX_PATH) {
+ return mapWindowsError(GetLastError());
+ }
+
+ // If the first argument is a shortened (8.3) name (which is possible even
+ // if we got the module name), the driver will have trouble distinguishing it
+ // (e.g., clang.exe v. clang++.exe), so expand it now.
+ Length = GetLongPathNameW(ModuleName, ModuleName, MAX_PATH);
if (Length == 0)
return mapWindowsError(GetLastError());
- if (Length > LongPath.capacity()) {
+ if (Length > MAX_PATH) {
// We're not going to try to deal with paths longer than MAX_PATH, so we'll
// treat this as an error. GetLastError() returns ERROR_SUCCESS, which
// isn't useful, so we'll hardcode an appropriate error value.
return mapWindowsError(ERROR_INSUFFICIENT_BUFFER);
}
- LongPath.set_size(Length);
- return ConvertAndPushArg(LongPath.data(), Args, Allocator);
+
+ std::error_code EC = windows::UTF16ToUTF8(ModuleName, Length, Filename);
+ if (EC)
+ return EC;
+
+ StringRef Base = sys::path::filename(Filename.data());
+ Filename.assign(Base.begin(), Base.end());
+ return std::error_code();
}
std::error_code
-Process::GetArgumentVector(SmallVectorImpl<const char *> &Args,
- ArrayRef<const char *>,
- SpecificBumpPtrAllocator<char> &ArgAllocator) {
+windows::GetCommandLineArguments(SmallVectorImpl<const char *> &Args,
+ BumpPtrAllocator &Alloc) {
int ArgCount;
- wchar_t **UnicodeCommandLine =
- CommandLineToArgvW(GetCommandLineW(), &ArgCount);
+ std::unique_ptr<wchar_t *[], decltype(&LocalFree)> UnicodeCommandLine{
+ CommandLineToArgvW(GetCommandLineW(), &ArgCount), &LocalFree};
if (!UnicodeCommandLine)
return mapWindowsError(::GetLastError());
- Args.reserve(ArgCount);
- std::error_code ec;
+ std::error_code EC;
- // The first argument may contain just the name of the executable (e.g.,
- // "clang") rather than the full path, so swap it with the full path.
- wchar_t ModuleName[MAX_PATH];
- int Length = ::GetModuleFileNameW(NULL, ModuleName, MAX_PATH);
- if (0 < Length && Length < MAX_PATH)
- UnicodeCommandLine[0] = ModuleName;
-
- // If the first argument is a shortened (8.3) name (which is possible even
- // if we got the module name), the driver will have trouble distinguishing it
- // (e.g., clang.exe v. clang++.exe), so expand it now.
- ec = ExpandShortFileName(UnicodeCommandLine[0], Args, ArgAllocator);
+ Args.reserve(ArgCount);
- for (int i = 1; i < ArgCount && !ec; ++i) {
- ec = WildcardExpand(UnicodeCommandLine[i], Args, ArgAllocator);
- if (ec)
- break;
+ for (int I = 0; I < ArgCount; ++I) {
+ EC = WildcardExpand(UnicodeCommandLine[I], Args, Alloc);
+ if (EC)
+ return EC;
}
- LocalFree(UnicodeCommandLine);
- return ec;
+ SmallVector<char, MAX_PATH> Arg0(Args[0], Args[0] + strlen(Args[0]));
+ SmallVector<char, MAX_PATH> Filename;
+ sys::path::remove_filename(Arg0);
+ EC = GetExecutableName(Filename);
+ if (EC)
+ return EC;
+ sys::path::append(Arg0, Filename);
+ Args[0] = AllocateString(Arg0, Alloc);
+ return std::error_code();
}
std::error_code Process::FixupStandardFileDescriptors() {
diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc
index 52921cd6a203..cb68c5b10e52 100644
--- a/lib/Support/Windows/Program.inc
+++ b/lib/Support/Windows/Program.inc
@@ -16,12 +16,14 @@
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/WindowsError.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
#include <fcntl.h>
#include <io.h>
#include <malloc.h>
+#include <numeric>
//===----------------------------------------------------------------------===//
//=== WARNING: Implementation here must contain only Win32 specific code
@@ -30,7 +32,7 @@
namespace llvm {
-ProcessInfo::ProcessInfo() : ProcessHandle(0), Pid(0), ReturnCode(0) {}
+ProcessInfo::ProcessInfo() : Pid(0), Process(0), ReturnCode(0) {}
ErrorOr<std::string> sys::findProgramByName(StringRef Name,
ArrayRef<StringRef> Paths) {
@@ -145,112 +147,11 @@ static HANDLE RedirectIO(Optional<StringRef> Path, int fd,
return h;
}
-/// ArgNeedsQuotes - Check whether argument needs to be quoted when calling
-/// CreateProcess.
-static bool ArgNeedsQuotes(const char *Str) {
- return Str[0] == '\0' || strpbrk(Str, "\t \"&\'()*<>\\`^|") != 0;
}
-/// CountPrecedingBackslashes - Returns the number of backslashes preceding Cur
-/// in the C string Start.
-static unsigned int CountPrecedingBackslashes(const char *Start,
- const char *Cur) {
- unsigned int Count = 0;
- --Cur;
- while (Cur >= Start && *Cur == '\\') {
- ++Count;
- --Cur;
- }
- return Count;
-}
-
-/// EscapePrecedingEscapes - Append a backslash to Dst for every backslash
-/// preceding Cur in the Start string. Assumes Dst has enough space.
-static char *EscapePrecedingEscapes(char *Dst, const char *Start,
- const char *Cur) {
- unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Cur);
- while (PrecedingEscapes > 0) {
- *Dst++ = '\\';
- --PrecedingEscapes;
- }
- return Dst;
-}
-
-/// ArgLenWithQuotes - Check whether argument needs to be quoted when calling
-/// CreateProcess and returns length of quoted arg with escaped quotes
-static unsigned int ArgLenWithQuotes(const char *Str) {
- const char *Start = Str;
- bool Quoted = ArgNeedsQuotes(Str);
- unsigned int len = Quoted ? 2 : 0;
-
- while (*Str != '\0') {
- if (*Str == '\"') {
- // We need to add a backslash, but ensure that it isn't escaped.
- unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Str);
- len += PrecedingEscapes + 1;
- }
- // Note that we *don't* need to escape runs of backslashes that don't
- // precede a double quote! See MSDN:
- // http://msdn.microsoft.com/en-us/library/17w5ykft%28v=vs.85%29.aspx
-
- ++len;
- ++Str;
- }
-
- if (Quoted) {
- // Make sure the closing quote doesn't get escaped by a trailing backslash.
- unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Str);
- len += PrecedingEscapes + 1;
- }
-
- return len;
-}
-
-}
-
-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;
- }
-
- // 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];
- const char *start = arg;
-
- bool needsQuoting = ArgNeedsQuotes(arg);
- if (needsQuoting)
- *p++ = '"';
-
- while (*arg != '\0') {
- if (*arg == '\"') {
- // Escape all preceding escapes (if any), and then escape the quote.
- p = EscapePrecedingEscapes(p, start, arg);
- *p++ = '\\';
- }
-
- *p++ = *arg++;
- }
-
- if (needsQuoting) {
- // Make sure our quote doesn't get escaped by a trailing backslash.
- p = EscapePrecedingEscapes(p, start, arg);
- *p++ = '"';
- }
- *p++ = ' ';
- }
-
- *p = 0;
- return command;
-}
-
-static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
- const char **Envp, ArrayRef<Optional<StringRef>> Redirects,
+static bool Execute(ProcessInfo &PI, StringRef Program,
+ ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env,
+ ArrayRef<Optional<StringRef>> Redirects,
unsigned MemoryLimit, std::string *ErrMsg) {
if (!sys::fs::can_execute(Program)) {
if (ErrMsg)
@@ -269,18 +170,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::string Command = flattenWindowsCommandLine(Args);
// The pointer to the environment block for the new process.
std::vector<wchar_t> EnvBlock;
- if (Envp) {
+ if (Env) {
// 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 (const auto E : *Env) {
SmallVector<wchar_t, MAX_PATH> EnvString;
- if (std::error_code ec = windows::UTF8ToUTF16(Envp[i], EnvString)) {
+ if (std::error_code ec = windows::UTF8ToUTF16(E, EnvString)) {
SetLastError(ec.value());
MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16");
return false;
@@ -352,7 +253,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
}
SmallVector<wchar_t, MAX_PATH> CommandUtf16;
- if (std::error_code ec = windows::UTF8ToUTF16(command.get(), CommandUtf16)) {
+ if (std::error_code ec = windows::UTF8ToUTF16(Command, CommandUtf16)) {
SetLastError(ec.value());
MakeErrMsg(ErrMsg,
std::string("Unable to convert command-line to UTF-16"));
@@ -380,7 +281,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
}
PI.Pid = pi.dwProcessId;
- PI.ProcessHandle = pi.hProcess;
+ PI.Process = pi.hProcess;
// Make sure these get closed no matter what.
ScopedCommonHandle hThread(pi.hThread);
@@ -413,11 +314,67 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
return true;
}
+static bool argNeedsQuotes(StringRef Arg) {
+ if (Arg.empty())
+ return true;
+ return StringRef::npos != Arg.find_first_of("\t \"&\'()*<>\\`^|");
+}
+
+static std::string quoteSingleArg(StringRef Arg) {
+ std::string Result;
+ Result.push_back('"');
+
+ while (!Arg.empty()) {
+ size_t FirstNonBackslash = Arg.find_first_not_of('\\');
+ size_t BackslashCount = FirstNonBackslash;
+ if (FirstNonBackslash == StringRef::npos) {
+ // The entire remainder of the argument is backslashes. Escape all of
+ // them and just early out.
+ BackslashCount = Arg.size();
+ Result.append(BackslashCount * 2, '\\');
+ break;
+ }
+
+ if (Arg[FirstNonBackslash] == '\"') {
+ // This is an embedded quote. Escape all preceding backslashes, then
+ // add one additional backslash to escape the quote.
+ Result.append(BackslashCount * 2 + 1, '\\');
+ Result.push_back('\"');
+ } else {
+ // This is just a normal character. Don't escape any of the preceding
+ // backslashes, just append them as they are and then append the
+ // character.
+ Result.append(BackslashCount, '\\');
+ Result.push_back(Arg[FirstNonBackslash]);
+ }
+
+ // Drop all the backslashes, plus the following character.
+ Arg = Arg.drop_front(FirstNonBackslash + 1);
+ }
+
+ Result.push_back('"');
+ return Result;
+}
+
namespace llvm {
+std::string sys::flattenWindowsCommandLine(ArrayRef<StringRef> Args) {
+ std::string Command;
+ for (StringRef Arg : Args) {
+ if (argNeedsQuotes(Arg))
+ Command += quoteSingleArg(Arg);
+ else
+ Command += Arg;
+
+ Command.push_back(' ');
+ }
+
+ return Command;
+}
+
ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
bool WaitUntilChildTerminates, std::string *ErrMsg) {
assert(PI.Pid && "invalid pid to wait on, process not started?");
- assert(PI.ProcessHandle &&
+ assert((PI.Process && PI.Process != INVALID_HANDLE_VALUE) &&
"invalid process handle to wait on, process not started?");
DWORD milliSecondsToWait = 0;
if (WaitUntilChildTerminates)
@@ -426,20 +383,20 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
milliSecondsToWait = SecondsToWait * 1000;
ProcessInfo WaitResult = PI;
- DWORD WaitStatus = WaitForSingleObject(PI.ProcessHandle, milliSecondsToWait);
+ DWORD WaitStatus = WaitForSingleObject(PI.Process, milliSecondsToWait);
if (WaitStatus == WAIT_TIMEOUT) {
if (SecondsToWait) {
- if (!TerminateProcess(PI.ProcessHandle, 1)) {
+ if (!TerminateProcess(PI.Process, 1)) {
if (ErrMsg)
MakeErrMsg(ErrMsg, "Failed to terminate timed-out program");
// -2 indicates a crash or timeout as opposed to failure to execute.
WaitResult.ReturnCode = -2;
- CloseHandle(PI.ProcessHandle);
+ CloseHandle(PI.Process);
return WaitResult;
}
- WaitForSingleObject(PI.ProcessHandle, INFINITE);
- CloseHandle(PI.ProcessHandle);
+ WaitForSingleObject(PI.Process, INFINITE);
+ CloseHandle(PI.Process);
} else {
// Non-blocking wait.
return ProcessInfo();
@@ -448,10 +405,10 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
// Get its exit status.
DWORD status;
- BOOL rc = GetExitCodeProcess(PI.ProcessHandle, &status);
+ BOOL rc = GetExitCodeProcess(PI.Process, &status);
DWORD err = GetLastError();
if (err != ERROR_INVALID_HANDLE)
- CloseHandle(PI.ProcessHandle);
+ CloseHandle(PI.Process);
if (!rc) {
SetLastError(err);
@@ -495,7 +452,7 @@ std::error_code
llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents,
WindowsEncodingMethod Encoding) {
std::error_code EC;
- llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OpenFlags::F_Text);
+ llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::F_Text);
if (EC)
return EC;
@@ -536,19 +493,13 @@ llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents,
}
bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program,
- ArrayRef<const char *> Args) {
+ ArrayRef<StringRef> 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 (const char* Arg : Args) {
- // Account for the trailing space for every arg
- ArgLength += ArgLenWithQuotes(Arg) + 1;
- if (ArgLength > MaxCommandStringLength) {
- return false;
- }
- }
- return true;
+ SmallVector<StringRef, 8> FullArgs;
+ FullArgs.push_back(Program);
+ FullArgs.append(Args.begin(), Args.end());
+ std::string Result = flattenWindowsCommandLine(FullArgs);
+ return (Result.size() + 1) <= MaxCommandStringLength;
}
}
diff --git a/lib/Support/Windows/RWMutex.inc b/lib/Support/Windows/RWMutex.inc
index ac60c2fc05be..5eb9351eee52 100644
--- a/lib/Support/Windows/RWMutex.inc
+++ b/lib/Support/Windows/RWMutex.inc
@@ -74,10 +74,10 @@ static bool loadSRW() {
sys::RWMutexImpl::RWMutexImpl() {
if (loadSRW()) {
- data_ = calloc(1, sizeof(SRWLOCK));
+ data_ = safe_calloc(1, sizeof(SRWLOCK));
fpInitializeSRWLock(static_cast<PSRWLOCK>(data_));
} else {
- data_ = calloc(1, sizeof(CRITICAL_SECTION));
+ data_ = safe_calloc(1, sizeof(CRITICAL_SECTION));
InitializeCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
}
}
diff --git a/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc
index 21dd2dd13754..41eb5e593aa5 100644
--- a/lib/Support/Windows/Signals.inc
+++ b/lib/Support/Windows/Signals.inc
@@ -10,6 +10,7 @@
// This file provides the Win32 specific implementation of the Signals class.
//
//===----------------------------------------------------------------------===//
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
@@ -36,9 +37,6 @@
#ifdef _MSC_VER
#pragma comment(lib, "psapi.lib")
#elif __MINGW32__
- #if (HAVE_LIBPSAPI != 1)
- #error "libpsapi.a should be present"
- #endif
// The version of g++ that comes with MinGW does *not* properly understand
// the ll format specifier for printf. However, MinGW passes the format
// specifiers on to the MSVCRT entirely, and the CRT understands the ll
@@ -193,7 +191,7 @@ using namespace llvm;
static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep);
static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType);
-// InterruptFunction - The function to call if ctrl-c is pressed.
+// The function to call if ctrl-c is pressed.
static void (*InterruptFunction)() = 0;
static std::vector<std::string> *FilesToRemove = NULL;
@@ -390,9 +388,9 @@ namespace llvm {
//===----------------------------------------------------------------------===//
#ifdef _MSC_VER
-/// AvoidMessageBoxHook - Emulates hitting "retry" from an "abort, retry,
-/// ignore" CRT debug report dialog. "retry" raises an exception which
-/// ultimately triggers our stack dumper.
+/// Emulates hitting "retry" from an "abort, retry, ignore" CRT debug report
+/// dialog. "retry" raises an exception which ultimately triggers our stack
+/// dumper.
static LLVM_ATTRIBUTE_UNUSED int
AvoidMessageBoxHook(int ReportType, char *Message, int *Return) {
// Set *Return to the retry code for the return value of _CrtDbgReport:
@@ -450,7 +448,7 @@ static void RegisterHandler() {
// else multi-threading problems will ensue.
}
-// RemoveFileOnSignal - The public API
+// The public API
bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) {
RegisterHandler();
@@ -469,7 +467,7 @@ bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) {
return false;
}
-// DontRemoveFileOnSignal - The public API
+// The public API
void sys::DontRemoveFileOnSignal(StringRef Filename) {
if (FilesToRemove == NULL)
return;
@@ -503,8 +501,8 @@ void sys::DisableSystemDialogsOnCrash() {
_set_error_mode(_OUT_TO_STDERR);
}
-/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
-/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
+/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
+/// process, print a stack trace and then exit.
void sys::PrintStackTraceOnErrorSignal(StringRef Argv0,
bool DisableCrashReporting) {
::Argv0 = Argv0;
@@ -536,10 +534,14 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) {
StackFrame.AddrPC.Offset = Context.Eip;
StackFrame.AddrStack.Offset = Context.Esp;
StackFrame.AddrFrame.Offset = Context.Ebp;
-#elif defined(_M_ARM64) || defined(_M_ARM)
+#elif defined(_M_ARM64)
StackFrame.AddrPC.Offset = Context.Pc;
StackFrame.AddrStack.Offset = Context.Sp;
StackFrame.AddrFrame.Offset = Context.Fp;
+#elif defined(_M_ARM)
+ StackFrame.AddrPC.Offset = Context.Pc;
+ StackFrame.AddrStack.Offset = Context.Sp;
+ StackFrame.AddrFrame.Offset = Context.R11;
#endif
StackFrame.AddrPC.Mode = AddrModeFlat;
StackFrame.AddrStack.Mode = AddrModeFlat;
@@ -556,11 +558,12 @@ void llvm::sys::SetInterruptFunction(void (*IF)()) {
}
-/// AddSignalHandler - Add a function to be called when a signal is delivered
-/// to the process. The handler can have a cookie passed to it to identify
-/// what instance of the handler it is.
-void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) {
- CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie));
+/// Add a function to be called when a signal is delivered to the process. The
+/// handler can have a cookie passed to it to identify what instance of the
+/// handler it is.
+void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr,
+ void *Cookie) {
+ insertSignalHandler(FnPtr, Cookie);
RegisterHandler();
LeaveCriticalSection(&CriticalSection);
}
@@ -594,7 +597,7 @@ void llvm::sys::RunInterruptHandlers() {
Cleanup();
}
-/// \brief Find the Windows Registry Key for a given location.
+/// Find the Windows Registry Key for a given location.
///
/// \returns a valid HKEY if the location exists, else NULL.
static HKEY FindWERKey(const llvm::Twine &RegistryLocation) {
@@ -607,7 +610,7 @@ static HKEY FindWERKey(const llvm::Twine &RegistryLocation) {
return Key;
}
-/// \brief Populate ResultDirectory with the value for "DumpFolder" for a given
+/// Populate ResultDirectory with the value for "DumpFolder" for a given
/// Windows Registry key.
///
/// \returns true if a valid value for DumpFolder exists, false otherwise.
@@ -648,7 +651,7 @@ static bool GetDumpFolder(HKEY Key,
return true;
}
-/// \brief Populate ResultType with a valid MINIDUMP_TYPE based on the value of
+/// Populate ResultType with a valid MINIDUMP_TYPE based on the value of
/// "DumpType" for a given Windows Registry key.
///
/// According to
@@ -695,7 +698,7 @@ static bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) {
return true;
}
-/// \brief Write a Windows dump file containing process information that can be
+/// Write a Windows dump file containing process information that can be
/// used for post-mortem debugging.
///
/// \returns zero error code if a mini dump created, actual error code
@@ -819,7 +822,11 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
StackFrame.AddrPC.Mode = AddrModeFlat;
StackFrame.AddrStack.Offset = ep->ContextRecord->Sp;
StackFrame.AddrStack.Mode = AddrModeFlat;
+#if defined(_M_ARM64)
StackFrame.AddrFrame.Offset = ep->ContextRecord->Fp;
+#else
+ StackFrame.AddrFrame.Offset = ep->ContextRecord->R11;
+#endif
StackFrame.AddrFrame.Mode = AddrModeFlat;
#endif
diff --git a/lib/Support/Windows/WindowsSupport.h b/lib/Support/Windows/WindowsSupport.h
index d4599dca044e..c2fd6bb982d4 100644
--- a/lib/Support/Windows/WindowsSupport.h
+++ b/lib/Support/Windows/WindowsSupport.h
@@ -247,18 +247,12 @@ inline FILETIME toFILETIME(TimePoint<> TP) {
return Time;
}
-namespace path {
-std::error_code widenPath(const Twine &Path8,
- SmallVectorImpl<wchar_t> &Path16);
-} // end namespace path
-
namespace windows {
-std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
-std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
- SmallVectorImpl<char> &utf8);
-/// Convert from UTF16 to the current code page used in the system
-std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
- SmallVectorImpl<char> &utf8);
+// Returns command line arguments. Unlike arguments given to main(),
+// this function guarantees that the returned arguments are encoded in
+// UTF-8 regardless of the current code page setting.
+std::error_code GetCommandLineArguments(SmallVectorImpl<const char *> &Args,
+ BumpPtrAllocator &Alloc);
} // end namespace windows
} // end namespace sys
} // end namespace llvm.
diff --git a/lib/Support/WithColor.cpp b/lib/Support/WithColor.cpp
new file mode 100644
index 000000000000..d2e13f0e86de
--- /dev/null
+++ b/lib/Support/WithColor.cpp
@@ -0,0 +1,90 @@
+//===- WithColor.cpp ------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+cl::OptionCategory llvm::ColorCategory("Color Options");
+
+static cl::opt<cl::boolOrDefault>
+ UseColor("color", cl::cat(ColorCategory),
+ cl::desc("Use colors in output (default=autodetect)"),
+ cl::init(cl::BOU_UNSET));
+
+bool WithColor::colorsEnabled(raw_ostream &OS) {
+ if (UseColor == cl::BOU_UNSET)
+ return OS.has_colors();
+ return UseColor == cl::BOU_TRUE;
+}
+
+WithColor::WithColor(raw_ostream &OS, HighlightColor Color) : OS(OS) {
+ // Detect color from terminal type unless the user passed the --color option.
+ if (colorsEnabled(OS)) {
+ switch (Color) {
+ case HighlightColor::Address:
+ OS.changeColor(raw_ostream::YELLOW);
+ break;
+ case HighlightColor::String:
+ OS.changeColor(raw_ostream::GREEN);
+ break;
+ case HighlightColor::Tag:
+ OS.changeColor(raw_ostream::BLUE);
+ break;
+ case HighlightColor::Attribute:
+ OS.changeColor(raw_ostream::CYAN);
+ break;
+ case HighlightColor::Enumerator:
+ OS.changeColor(raw_ostream::MAGENTA);
+ break;
+ case HighlightColor::Macro:
+ OS.changeColor(raw_ostream::RED);
+ break;
+ case HighlightColor::Error:
+ OS.changeColor(raw_ostream::RED, true);
+ break;
+ case HighlightColor::Warning:
+ OS.changeColor(raw_ostream::MAGENTA, true);
+ break;
+ case HighlightColor::Note:
+ OS.changeColor(raw_ostream::BLACK, true);
+ break;
+ }
+ }
+}
+
+raw_ostream &WithColor::error() { return error(errs()); }
+
+raw_ostream &WithColor::warning() { return warning(errs()); }
+
+raw_ostream &WithColor::note() { return note(errs()); }
+
+raw_ostream &WithColor::error(raw_ostream &OS, StringRef Prefix) {
+ if (!Prefix.empty())
+ OS << Prefix << ": ";
+ return WithColor(OS, HighlightColor::Error).get() << "error: ";
+}
+
+raw_ostream &WithColor::warning(raw_ostream &OS, StringRef Prefix) {
+ if (!Prefix.empty())
+ OS << Prefix << ": ";
+ return WithColor(OS, HighlightColor::Warning).get() << "warning: ";
+}
+
+raw_ostream &WithColor::note(raw_ostream &OS, StringRef Prefix) {
+ if (!Prefix.empty())
+ OS << Prefix << ": ";
+ return WithColor(OS, HighlightColor::Note).get() << "note: ";
+}
+
+WithColor::~WithColor() {
+ if (colorsEnabled(OS))
+ OS.resetColor();
+}
diff --git a/lib/Support/YAMLParser.cpp b/lib/Support/YAMLParser.cpp
index e2f21a56a810..354b7d0740de 100644
--- a/lib/Support/YAMLParser.cpp
+++ b/lib/Support/YAMLParser.cpp
@@ -26,6 +26,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SMLoc.h"
#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/Unicode.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
@@ -167,7 +168,7 @@ using TokenQueueT = BumpPtrList<Token>;
namespace {
-/// @brief This struct is used to track simple keys.
+/// This struct is used to track simple keys.
///
/// Simple keys are handled by creating an entry in SimpleKeys for each Token
/// which could legally be the start of a simple key. When peekNext is called,
@@ -190,7 +191,7 @@ struct SimpleKey {
} // end anonymous namespace
-/// @brief The Unicode scalar value of a UTF-8 minimal well-formed code unit
+/// The Unicode scalar value of a UTF-8 minimal well-formed code unit
/// subsequence and the subsequence's length in code units (uint8_t).
/// A length of 0 represents an error.
using UTF8Decoded = std::pair<uint32_t, unsigned>;
@@ -248,7 +249,7 @@ static UTF8Decoded decodeUTF8(StringRef Range) {
namespace llvm {
namespace yaml {
-/// @brief Scans YAML tokens from a MemoryBuffer.
+/// Scans YAML tokens from a MemoryBuffer.
class Scanner {
public:
Scanner(StringRef Input, SourceMgr &SM, bool ShowColors = true,
@@ -256,10 +257,10 @@ public:
Scanner(MemoryBufferRef Buffer, SourceMgr &SM_, bool ShowColors = true,
std::error_code *EC = nullptr);
- /// @brief Parse the next token and return it without popping it.
+ /// Parse the next token and return it without popping it.
Token &peekNext();
- /// @brief Parse the next token and pop it from the queue.
+ /// Parse the next token and pop it from the queue.
Token getNext();
void printError(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Message,
@@ -286,7 +287,7 @@ public:
setError(Message, Current);
}
- /// @brief Returns true if an error occurred while parsing.
+ /// Returns true if an error occurred while parsing.
bool failed() {
return Failed;
}
@@ -298,7 +299,7 @@ private:
return StringRef(Current, End - Current);
}
- /// @brief Decode a UTF-8 minimal well-formed code unit subsequence starting
+ /// Decode a UTF-8 minimal well-formed code unit subsequence starting
/// at \a Position.
///
/// If the UTF-8 code units starting at Position do not form a well-formed
@@ -328,7 +329,7 @@ private:
// l-
// A production matching complete line(s).
- /// @brief Skip a single nb-char[27] starting at Position.
+ /// Skip a single nb-char[27] starting at Position.
///
/// A nb-char is 0x9 | [0x20-0x7E] | 0x85 | [0xA0-0xD7FF] | [0xE000-0xFEFE]
/// | [0xFF00-0xFFFD] | [0x10000-0x10FFFF]
@@ -337,7 +338,7 @@ private:
/// nb-char.
StringRef::iterator skip_nb_char(StringRef::iterator Position);
- /// @brief Skip a single b-break[28] starting at Position.
+ /// Skip a single b-break[28] starting at Position.
///
/// A b-break is 0xD 0xA | 0xD | 0xA
///
@@ -353,7 +354,7 @@ private:
/// s-space.
StringRef::iterator skip_s_space(StringRef::iterator Position);
- /// @brief Skip a single s-white[33] starting at Position.
+ /// Skip a single s-white[33] starting at Position.
///
/// A s-white is 0x20 | 0x9
///
@@ -361,7 +362,7 @@ private:
/// s-white.
StringRef::iterator skip_s_white(StringRef::iterator Position);
- /// @brief Skip a single ns-char[34] starting at Position.
+ /// Skip a single ns-char[34] starting at Position.
///
/// A ns-char is nb-char - s-white
///
@@ -371,7 +372,7 @@ private:
using SkipWhileFunc = StringRef::iterator (Scanner::*)(StringRef::iterator);
- /// @brief Skip minimal well-formed code unit subsequences until Func
+ /// Skip minimal well-formed code unit subsequences until Func
/// returns its input.
///
/// @returns The code unit after the last minimal well-formed code unit
@@ -383,20 +384,20 @@ private:
/// input.
void advanceWhile(SkipWhileFunc Func);
- /// @brief Scan ns-uri-char[39]s starting at Cur.
+ /// Scan ns-uri-char[39]s starting at Cur.
///
/// This updates Cur and Column while scanning.
void scan_ns_uri_char();
- /// @brief Consume a minimal well-formed code unit subsequence starting at
+ /// Consume a minimal well-formed code unit subsequence starting at
/// \a Cur. Return false if it is not the same Unicode scalar value as
/// \a Expected. This updates \a Column.
bool consume(uint32_t Expected);
- /// @brief Skip \a Distance UTF-8 code units. Updates \a Cur and \a Column.
+ /// Skip \a Distance UTF-8 code units. Updates \a Cur and \a Column.
void skip(uint32_t Distance);
- /// @brief Return true if the minimal well-formed code unit subsequence at
+ /// Return true if the minimal well-formed code unit subsequence at
/// Pos is whitespace or a new line
bool isBlankOrBreak(StringRef::iterator Position);
@@ -405,77 +406,77 @@ private:
/// Return false if the code unit at the current position isn't a line break.
bool consumeLineBreakIfPresent();
- /// @brief If IsSimpleKeyAllowed, create and push_back a new SimpleKey.
+ /// If IsSimpleKeyAllowed, create and push_back a new SimpleKey.
void saveSimpleKeyCandidate( TokenQueueT::iterator Tok
, unsigned AtColumn
, bool IsRequired);
- /// @brief Remove simple keys that can no longer be valid simple keys.
+ /// Remove simple keys that can no longer be valid simple keys.
///
/// Invalid simple keys are not on the current line or are further than 1024
/// columns back.
void removeStaleSimpleKeyCandidates();
- /// @brief Remove all simple keys on FlowLevel \a Level.
+ /// Remove all simple keys on FlowLevel \a Level.
void removeSimpleKeyCandidatesOnFlowLevel(unsigned Level);
- /// @brief Unroll indentation in \a Indents back to \a Col. Creates BlockEnd
+ /// Unroll indentation in \a Indents back to \a Col. Creates BlockEnd
/// tokens if needed.
bool unrollIndent(int ToColumn);
- /// @brief Increase indent to \a Col. Creates \a Kind token at \a InsertPoint
+ /// Increase indent to \a Col. Creates \a Kind token at \a InsertPoint
/// if needed.
bool rollIndent( int ToColumn
, Token::TokenKind Kind
, TokenQueueT::iterator InsertPoint);
- /// @brief Skip a single-line comment when the comment starts at the current
+ /// Skip a single-line comment when the comment starts at the current
/// position of the scanner.
void skipComment();
- /// @brief Skip whitespace and comments until the start of the next token.
+ /// Skip whitespace and comments until the start of the next token.
void scanToNextToken();
- /// @brief Must be the first token generated.
+ /// Must be the first token generated.
bool scanStreamStart();
- /// @brief Generate tokens needed to close out the stream.
+ /// Generate tokens needed to close out the stream.
bool scanStreamEnd();
- /// @brief Scan a %BLAH directive.
+ /// Scan a %BLAH directive.
bool scanDirective();
- /// @brief Scan a ... or ---.
+ /// Scan a ... or ---.
bool scanDocumentIndicator(bool IsStart);
- /// @brief Scan a [ or { and generate the proper flow collection start token.
+ /// Scan a [ or { and generate the proper flow collection start token.
bool scanFlowCollectionStart(bool IsSequence);
- /// @brief Scan a ] or } and generate the proper flow collection end token.
+ /// Scan a ] or } and generate the proper flow collection end token.
bool scanFlowCollectionEnd(bool IsSequence);
- /// @brief Scan the , that separates entries in a flow collection.
+ /// Scan the , that separates entries in a flow collection.
bool scanFlowEntry();
- /// @brief Scan the - that starts block sequence entries.
+ /// Scan the - that starts block sequence entries.
bool scanBlockEntry();
- /// @brief Scan an explicit ? indicating a key.
+ /// Scan an explicit ? indicating a key.
bool scanKey();
- /// @brief Scan an explicit : indicating a value.
+ /// Scan an explicit : indicating a value.
bool scanValue();
- /// @brief Scan a quoted scalar.
+ /// Scan a quoted scalar.
bool scanFlowScalar(bool IsDoubleQuoted);
- /// @brief Scan an unquoted scalar.
+ /// Scan an unquoted scalar.
bool scanPlainScalar();
- /// @brief Scan an Alias or Anchor starting with * or &.
+ /// Scan an Alias or Anchor starting with * or &.
bool scanAliasOrAnchor(bool IsAlias);
- /// @brief Scan a block scalar starting with | or >.
+ /// Scan a block scalar starting with | or >.
bool scanBlockScalar(bool IsLiteral);
/// Scan a chomping indicator in a block scalar header.
@@ -502,57 +503,57 @@ private:
bool scanBlockScalarIndent(unsigned BlockIndent, unsigned BlockExitIndent,
bool &IsDone);
- /// @brief Scan a tag of the form !stuff.
+ /// Scan a tag of the form !stuff.
bool scanTag();
- /// @brief Dispatch to the next scanning function based on \a *Cur.
+ /// Dispatch to the next scanning function based on \a *Cur.
bool fetchMoreTokens();
- /// @brief The SourceMgr used for diagnostics and buffer management.
+ /// The SourceMgr used for diagnostics and buffer management.
SourceMgr &SM;
- /// @brief The original input.
+ /// The original input.
MemoryBufferRef InputBuffer;
- /// @brief The current position of the scanner.
+ /// The current position of the scanner.
StringRef::iterator Current;
- /// @brief The end of the input (one past the last character).
+ /// The end of the input (one past the last character).
StringRef::iterator End;
- /// @brief Current YAML indentation level in spaces.
+ /// Current YAML indentation level in spaces.
int Indent;
- /// @brief Current column number in Unicode code points.
+ /// Current column number in Unicode code points.
unsigned Column;
- /// @brief Current line number.
+ /// Current line number.
unsigned Line;
- /// @brief How deep we are in flow style containers. 0 Means at block level.
+ /// How deep we are in flow style containers. 0 Means at block level.
unsigned FlowLevel;
- /// @brief Are we at the start of the stream?
+ /// Are we at the start of the stream?
bool IsStartOfStream;
- /// @brief Can the next token be the start of a simple key?
+ /// Can the next token be the start of a simple key?
bool IsSimpleKeyAllowed;
- /// @brief True if an error has occurred.
+ /// True if an error has occurred.
bool Failed;
- /// @brief Should colors be used when printing out the diagnostic messages?
+ /// Should colors be used when printing out the diagnostic messages?
bool ShowColors;
- /// @brief Queue of tokens. This is required to queue up tokens while looking
+ /// Queue of tokens. This is required to queue up tokens while looking
/// for the end of a simple key. And for cases where a single character
/// can produce multiple tokens (e.g. BlockEnd).
TokenQueueT TokenQueue;
- /// @brief Indentation levels.
+ /// Indentation levels.
SmallVector<int, 4> Indents;
- /// @brief Potential simple keys.
+ /// Potential simple keys.
SmallVector<SimpleKey, 4> SimpleKeys;
std::error_code *EC;
@@ -687,7 +688,7 @@ bool yaml::scanTokens(StringRef Input) {
return true;
}
-std::string yaml::escape(StringRef Input) {
+std::string yaml::escape(StringRef Input, bool EscapePrintable) {
std::string EscapedInput;
for (StringRef::iterator i = Input.begin(), e = Input.end(); i != e; ++i) {
if (*i == '\\')
@@ -734,6 +735,9 @@ std::string yaml::escape(StringRef Input) {
EscapedInput += "\\L";
else if (UnicodeScalarValue.first == 0x2029)
EscapedInput += "\\P";
+ else if (!EscapePrintable &&
+ sys::unicode::isPrintable(UnicodeScalarValue.first))
+ EscapedInput += StringRef(i, UnicodeScalarValue.second);
else {
std::string HexStr = utohexstr(UnicodeScalarValue.first);
if (HexStr.size() <= 2)
diff --git a/lib/Support/YAMLTraits.cpp b/lib/Support/YAMLTraits.cpp
index f8a80ba87873..d6345efd00cd 100644
--- a/lib/Support/YAMLTraits.cpp
+++ b/lib/Support/YAMLTraits.cpp
@@ -638,39 +638,22 @@ void Output::scalarString(StringRef &S, QuotingType MustQuote) {
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) {
- 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]) && (S[j] & 0x80) == 0) {
- // If we're double quoting non-printable characters, we prefer printing
- // them as "\x" + their hex representation. Note that special casing is
- // needed for UTF-8, where a byte may be part of a UTF-8 sequence and
- // appear as non-printable, in which case we want to print the correct
- // unicode character and not its hex representation.
- 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
+ // When using double-quoted strings (and only in that case), non-printable characters may be
+ // present, and will be escaped using a variety of unicode-scalar and special short-form
+ // escapes. This is handled in yaml::escape.
+ if (MustQuote == QuotingType::Double) {
+ output(yaml::escape(Base, /* EscapePrintable= */ false));
+ this->outputUpToEndOfLine(Quote);
+ return;
+ }
+ // When using single-quoted strings, any single quote ' must be doubled to be escaped.
+ while (j < End) {
+ if (S[j] == '\'') { // Escape quotes.
+ output(StringRef(&Base[i], j - i)); // "flush".
+ output(StringLiteral("''")); // Print it as ''
i = j + 1;
}
++j;
diff --git a/lib/Support/circular_raw_ostream.cpp b/lib/Support/circular_raw_ostream.cpp
index ca0d30db388c..e768f17cd00d 100644
--- a/lib/Support/circular_raw_ostream.cpp
+++ b/lib/Support/circular_raw_ostream.cpp
@@ -33,7 +33,7 @@ void circular_raw_ostream::write_impl(const char *Ptr, size_t Size) {
Cur = BufferArray;
Filled = true;
}
- }
+ }
}
void circular_raw_ostream::flushBufferWithBanner() {
diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp
index e02611103080..038ad00bd608 100644
--- a/lib/Support/raw_ostream.cpp
+++ b/lib/Support/raw_ostream.cpp
@@ -41,9 +41,6 @@
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif
-#if defined(HAVE_SYS_UIO_H) && defined(HAVE_WRITEV)
-# include <sys/uio.h>
-#endif
#if defined(__CYGWIN__)
#include <io.h>
@@ -62,7 +59,7 @@
#endif
#endif
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
#include "Windows/WindowsSupport.h"
#endif
@@ -78,9 +75,6 @@ raw_ostream::~raw_ostream() {
delete [] OutBufStart;
}
-// An out of line virtual method to provide a home for the class vtable.
-void raw_ostream::handle() {}
-
size_t raw_ostream::preferred_buffer_size() const {
// BUFSIZ is intended to be a reasonable default.
return BUFSIZ;
@@ -166,7 +160,7 @@ raw_ostream &raw_ostream::write_escaped(StringRef Str,
*this << '\\' << '"';
break;
default:
- if (std::isprint(c)) {
+ if (isPrint(c)) {
*this << c;
break;
}
@@ -442,7 +436,7 @@ raw_ostream &raw_ostream::operator<<(const FormattedBytes &FB) {
// Print the ASCII char values for each byte on this line
for (uint8_t Byte : Line) {
- if (isprint(Byte))
+ if (isPrint(Byte))
*this << static_cast<char>(Byte);
else
*this << '.';
@@ -458,25 +452,39 @@ raw_ostream &raw_ostream::operator<<(const FormattedBytes &FB) {
return *this;
}
-/// indent - Insert 'NumSpaces' spaces.
-raw_ostream &raw_ostream::indent(unsigned NumSpaces) {
- static const char Spaces[] = " "
- " "
- " ";
+template <char C>
+static raw_ostream &write_padding(raw_ostream &OS, unsigned NumChars) {
+ static const char Chars[] = {C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
+ C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
+ C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
+ C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
+ C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C};
// Usually the indentation is small, handle it with a fastpath.
- if (NumSpaces < array_lengthof(Spaces))
- return write(Spaces, NumSpaces);
-
- while (NumSpaces) {
- unsigned NumToWrite = std::min(NumSpaces,
- (unsigned)array_lengthof(Spaces)-1);
- write(Spaces, NumToWrite);
- NumSpaces -= NumToWrite;
+ if (NumChars < array_lengthof(Chars))
+ return OS.write(Chars, NumChars);
+
+ while (NumChars) {
+ unsigned NumToWrite = std::min(NumChars,
+ (unsigned)array_lengthof(Chars)-1);
+ OS.write(Chars, NumToWrite);
+ NumChars -= NumToWrite;
}
- return *this;
+ return OS;
+}
+
+/// indent - Insert 'NumSpaces' spaces.
+raw_ostream &raw_ostream::indent(unsigned NumSpaces) {
+ return write_padding<' '>(*this, NumSpaces);
}
+/// write_zeros - Insert 'NumZeros' nulls.
+raw_ostream &raw_ostream::write_zeros(unsigned NumZeros) {
+ return write_padding<'\0'>(*this, NumZeros);
+}
+
+void raw_ostream::anchor() {}
+
//===----------------------------------------------------------------------===//
// Formatted Output
//===----------------------------------------------------------------------===//
@@ -490,29 +498,56 @@ void format_object_base::home() {
//===----------------------------------------------------------------------===//
static int getFD(StringRef Filename, std::error_code &EC,
+ sys::fs::CreationDisposition Disp, sys::fs::FileAccess Access,
sys::fs::OpenFlags Flags) {
+ assert((Access & sys::fs::FA_Write) &&
+ "Cannot make a raw_ostream from a read-only descriptor!");
+
// Handle "-" as stdout. Note that when we do this, we consider ourself
// the owner of stdout and may set the "binary" flag globally based on Flags.
if (Filename == "-") {
EC = std::error_code();
// If user requested binary then put stdout into binary mode if
// possible.
- if (!(Flags & sys::fs::F_Text))
+ if (!(Flags & sys::fs::OF_Text))
sys::ChangeStdoutToBinary();
return STDOUT_FILENO;
}
int FD;
- EC = sys::fs::openFileForWrite(Filename, FD, Flags);
+ if (Access & sys::fs::FA_Read)
+ EC = sys::fs::openFileForReadWrite(Filename, FD, Disp, Flags);
+ else
+ EC = sys::fs::openFileForWrite(Filename, FD, Disp, Flags);
if (EC)
return -1;
return FD;
}
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC)
+ : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, sys::fs::FA_Write,
+ sys::fs::OF_None) {}
+
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::CreationDisposition Disp)
+ : raw_fd_ostream(Filename, EC, Disp, sys::fs::FA_Write, sys::fs::OF_None) {}
+
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::FileAccess Access)
+ : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, Access,
+ sys::fs::OF_None) {}
+
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::OpenFlags Flags)
+ : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, sys::fs::FA_Write,
+ Flags) {}
+
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::CreationDisposition Disp,
+ sys::fs::FileAccess Access,
sys::fs::OpenFlags Flags)
- : raw_fd_ostream(getFD(Filename, EC, Flags), true) {}
+ : raw_fd_ostream(getFD(Filename, EC, Disp, Access, Flags), true) {}
/// FD is the file descriptor that this writes to. If ShouldClose is true, this
/// closes the file when the stream is destroyed.
@@ -534,7 +569,7 @@ raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered)
// Get the starting position.
off_t loc = ::lseek(FD, 0, SEEK_CUR);
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
// MSVCRT's _lseek(SEEK_CUR) doesn't return -1 for pipes.
sys::fs::file_status Status;
std::error_code EC = status(FD, Status);
@@ -587,7 +622,7 @@ void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
// 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)
+#elif defined(_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).
@@ -640,7 +675,7 @@ void raw_fd_ostream::close() {
uint64_t raw_fd_ostream::seek(uint64_t off) {
assert(SupportsSeeking && "Stream does not support seeking!");
flush();
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
pos = ::_lseeki64(FD, off, SEEK_SET);
#elif defined(HAVE_LSEEK64)
pos = ::lseek64(FD, off, SEEK_SET);
@@ -730,6 +765,8 @@ bool raw_fd_ostream::has_colors() const {
return sys::Process::FileDescriptorHasColors(FD);
}
+void raw_fd_ostream::anchor() {}
+
//===----------------------------------------------------------------------===//
// outs(), errs(), nulls()
//===----------------------------------------------------------------------===//
@@ -807,3 +844,5 @@ uint64_t raw_null_ostream::current_pos() const {
void raw_null_ostream::pwrite_impl(const char *Ptr, size_t Size,
uint64_t Offset) {}
+
+void raw_pwrite_stream::anchor() {}
diff --git a/lib/Support/regcomp.c b/lib/Support/regcomp.c
index 354e359f676b..12669ab75d1a 100644
--- a/lib/Support/regcomp.c
+++ b/lib/Support/regcomp.c
@@ -36,6 +36,7 @@
*/
#include <sys/types.h>
+#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
@@ -47,12 +48,6 @@
#include "regex2.h"
#include "llvm/Config/config.h"
-#if HAVE_STDINT_H
-#include <stdint.h>
-#else
-/* Pessimistically bound memory use */
-#define SIZE_MAX UINT_MAX
-#endif
/* character-class table */
static struct cclass {
diff --git a/lib/Support/regengine.inc b/lib/Support/regengine.inc
index 62d8c267f22f..41787aff1242 100644
--- a/lib/Support/regengine.inc
+++ b/lib/Support/regengine.inc
@@ -1013,7 +1013,7 @@ pchar(int ch)
{
static char pbuf[10];
- if (isprint(ch) || ch == ' ')
+ if (isPrint(ch) || ch == ' ')
(void)snprintf(pbuf, sizeof pbuf, "%c", ch);
else
(void)snprintf(pbuf, sizeof pbuf, "\\%o", ch);
diff --git a/lib/Support/xxhash.cpp b/lib/Support/xxhash.cpp
index a7d990bf6a4b..df643f9bd639 100644
--- a/lib/Support/xxhash.cpp
+++ b/lib/Support/xxhash.cpp
@@ -71,12 +71,12 @@ static uint64_t mergeRound(uint64_t Acc, uint64_t Val) {
uint64_t llvm::xxHash64(StringRef Data) {
size_t Len = Data.size();
uint64_t Seed = 0;
- const char *P = Data.data();
- const char *const BEnd = P + Len;
+ const unsigned char *P = Data.bytes_begin();
+ const unsigned char *const BEnd = Data.bytes_end();
uint64_t H64;
if (Len >= 32) {
- const char *const Limit = BEnd - 32;
+ const unsigned char *const Limit = BEnd - 32;
uint64_t V1 = Seed + PRIME64_1 + PRIME64_2;
uint64_t V2 = Seed + PRIME64_2;
uint64_t V3 = Seed + 0;