aboutsummaryrefslogtreecommitdiff
path: root/lib/Support
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-04-16 16:01:22 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-04-16 16:01:22 +0000
commit71d5a2540a98c81f5bcaeb48805e0e2881f530ef (patch)
tree5343938942df402b49ec7300a1c25a2d4ccd5821 /lib/Support
parent31bbf64f3a4974a2d6c8b3b27ad2f519caf74057 (diff)
downloadsrc-71d5a2540a98c81f5bcaeb48805e0e2881f530ef.tar.gz
src-71d5a2540a98c81f5bcaeb48805e0e2881f530ef.zip
Notes
Diffstat (limited to 'lib/Support')
-rw-r--r--lib/Support/APFloat.cpp622
-rw-r--r--lib/Support/APInt.cpp938
-rw-r--r--lib/Support/ARMAttributeParser.cpp708
-rw-r--r--lib/Support/BinaryStreamError.cpp56
-rw-r--r--lib/Support/BinaryStreamReader.cpp95
-rw-r--r--lib/Support/BinaryStreamWriter.cpp68
-rw-r--r--lib/Support/BranchProbability.cpp2
-rw-r--r--lib/Support/CMakeLists.txt13
-rw-r--r--lib/Support/CachePruning.cpp97
-rw-r--r--lib/Support/Chrono.cpp7
-rw-r--r--lib/Support/CommandLine.cpp66
-rw-r--r--lib/Support/Compression.cpp83
-rw-r--r--lib/Support/DebugCounter.cpp108
-rw-r--r--lib/Support/Dwarf.cpp11
-rw-r--r--lib/Support/DynamicLibrary.cpp21
-rw-r--r--lib/Support/FileOutputBuffer.cpp2
-rw-r--r--lib/Support/Host.cpp447
-rw-r--r--lib/Support/LockFileManager.cpp6
-rw-r--r--lib/Support/LowLevelType.cpp47
-rw-r--r--lib/Support/MD5.cpp25
-rw-r--r--lib/Support/ManagedStatic.cpp2
-rw-r--r--lib/Support/MemoryBuffer.cpp34
-rw-r--r--lib/Support/Path.cpp485
-rw-r--r--lib/Support/RWMutex.cpp19
-rw-r--r--lib/Support/Signals.cpp1
-rw-r--r--lib/Support/SourceMgr.cpp27
-rw-r--r--lib/Support/StringRef.cpp13
-rw-r--r--lib/Support/TargetParser.cpp4
-rw-r--r--lib/Support/Threading.cpp123
-rw-r--r--lib/Support/Timer.cpp19
-rw-r--r--lib/Support/Triple.cpp5
-rw-r--r--lib/Support/Twine.cpp4
-rw-r--r--lib/Support/Unix/Path.inc273
-rw-r--r--lib/Support/Unix/Signals.inc18
-rw-r--r--lib/Support/Unix/Threading.inc215
-rw-r--r--lib/Support/Windows/DynamicLibrary.inc34
-rw-r--r--lib/Support/Windows/Mutex.inc11
-rw-r--r--lib/Support/Windows/Path.inc306
-rw-r--r--lib/Support/Windows/Process.inc1
-rw-r--r--lib/Support/Windows/Program.inc1
-rw-r--r--lib/Support/Windows/RWMutex.inc13
-rw-r--r--lib/Support/Windows/Signals.inc2
-rw-r--r--lib/Support/Windows/ThreadLocal.inc11
-rw-r--r--lib/Support/Windows/Threading.inc109
-rw-r--r--lib/Support/YAMLTraits.cpp17
-rw-r--r--lib/Support/raw_ostream.cpp10
46 files changed, 3718 insertions, 1461 deletions
diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp
index 4cfbbf8645e0..9778628911cd 100644
--- a/lib/Support/APFloat.cpp
+++ b/lib/Support/APFloat.cpp
@@ -26,8 +26,21 @@
#include <cstring>
#include <limits.h>
+#define APFLOAT_DISPATCH_ON_SEMANTICS(METHOD_CALL) \
+ do { \
+ if (usesLayout<IEEEFloat>(getSemantics())) \
+ return U.IEEE.METHOD_CALL; \
+ if (usesLayout<DoubleAPFloat>(getSemantics())) \
+ return U.Double.METHOD_CALL; \
+ llvm_unreachable("Unexpected semantics"); \
+ } while (false)
+
using namespace llvm;
+// TODO: Remove these and use APInt qualified types directly.
+typedef APInt::WordType integerPart;
+const unsigned int integerPartWidth = APInt::APINT_BITS_PER_WORD;
+
/// A macro used to combine two fcCategory enums into one key which can be used
/// in a switch statement to classify how the interaction of two APFloat's
/// categories affects an operation.
@@ -66,33 +79,43 @@ namespace llvm {
static const fltSemantics semX87DoubleExtended = {16383, -16382, 64, 80};
static const fltSemantics semBogus = {0, 0, 0, 0};
- /* The PowerPC format consists of two doubles. It does not map cleanly
- onto the usual format above. It is approximated using twice the
- mantissa bits. Note that for exponents near the double minimum,
- we no longer can represent the full 106 mantissa bits, so those
- will be treated as denormal numbers.
-
- FIXME: While this approximation is equivalent to what GCC uses for
- compile-time arithmetic on PPC double-double numbers, it is not able
- to represent all possible values held by a PPC double-double number,
- for example: (long double) 1.0 + (long double) 0x1p-106
- Should this be replaced by a full emulation of PPC double-double?
+ /* The IBM double-double semantics. Such a number consists of a pair of IEEE
+ 64-bit doubles (Hi, Lo), where |Hi| > |Lo|, and if normal,
+ (double)(Hi + Lo) == Hi. The numeric value it's modeling is Hi + Lo.
+ Therefore it has two 53-bit mantissa parts that aren't necessarily adjacent
+ to each other, and two 11-bit exponents.
Note: we need to make the value different from semBogus as otherwise
an unsafe optimization may collapse both values to a single address,
and we heavily rely on them having distinct addresses. */
static const fltSemantics semPPCDoubleDouble = {-1, 0, 0, 0};
- /* There are temporary semantics for the real PPCDoubleDouble implementation.
- Currently, APFloat of PPCDoubleDouble holds one PPCDoubleDoubleImpl as the
- high part of double double, and one IEEEdouble as the low part, so that
- the old operations operate on PPCDoubleDoubleImpl, while the newly added
- operations also populate the IEEEdouble.
+ /* These are legacy semantics for the fallback, inaccrurate implementation of
+ IBM double-double, if the accurate semPPCDoubleDouble doesn't handle the
+ operation. It's equivalent to having an IEEE number with consecutive 106
+ bits of mantissa and 11 bits of exponent.
+
+ It's not equivalent to IBM double-double. For example, a legit IBM
+ double-double, 1 + epsilon:
+
+ 1 + epsilon = 1 + (1 >> 1076)
- TODO: Once all functions support DoubleAPFloat mode, we'll change all
- PPCDoubleDoubleImpl to IEEEdouble and remove PPCDoubleDoubleImpl. */
- static const fltSemantics semPPCDoubleDoubleImpl = {1023, -1022 + 53, 53 + 53,
- 128};
+ is not representable by a consecutive 106 bits of mantissa.
+
+ Currently, these semantics are used in the following way:
+
+ semPPCDoubleDouble -> (IEEEdouble, IEEEdouble) ->
+ (64-bit APInt, 64-bit APInt) -> (128-bit APInt) ->
+ semPPCDoubleDoubleLegacy -> IEEE operations
+
+ We use bitcastToAPInt() to get the bit representation (in APInt) of the
+ underlying IEEEdouble, then use the APInt constructor to construct the
+ legacy IEEE float.
+
+ TODO: Implement all operations in semPPCDoubleDouble, and delete these
+ semantics. */
+ static const fltSemantics semPPCDoubleDoubleLegacy = {1023, -1022 + 53,
+ 53 + 53, 128};
const fltSemantics &APFloatBase::IEEEhalf() {
return semIEEEhalf;
@@ -742,7 +765,7 @@ IEEEFloat &IEEEFloat::operator=(IEEEFloat &&rhs) {
bool IEEEFloat::isDenormal() const {
return isFiniteNonZero() && (exponent == semantics->minExponent) &&
- (APInt::tcExtractBit(significandParts(),
+ (APInt::tcExtractBit(significandParts(),
semantics->precision - 1) == 0);
}
@@ -862,11 +885,6 @@ IEEEFloat::IEEEFloat(IEEEFloat &&rhs) : semantics(&semBogus) {
IEEEFloat::~IEEEFloat() { freeSignificand(); }
-// Profile - This method 'profiles' an APFloat for use with FoldingSet.
-void IEEEFloat::Profile(FoldingSetNodeID &ID) const {
- ID.Add(bitcastToAPInt());
-}
-
unsigned int IEEEFloat::partCount() const {
return partCountForBits(semantics->precision + 1);
}
@@ -966,14 +984,14 @@ lostFraction IEEEFloat::multiplySignificand(const IEEEFloat &rhs,
// rhs = b23 . b22 ... b0 * 2^e2
// the result of multiplication is:
// *this = c48 c47 c46 . c45 ... c0 * 2^(e1+e2)
- // Note that there are three significant bits at the left-hand side of the
+ // Note that there are three significant bits at the left-hand side of the
// radix point: two for the multiplication, and an overflow bit for the
// addition (that will always be zero at this point). Move the radix point
// toward left by two bits, and adjust exponent accordingly.
exponent += 2;
if (addend && addend->isNonZero()) {
- // The intermediate result of the multiplication has "2 * precision"
+ // The intermediate result of the multiplication has "2 * precision"
// signicant bit; adjust the addend to be consistent with mul result.
//
Significand savedSignificand = significand;
@@ -1025,7 +1043,7 @@ lostFraction IEEEFloat::multiplySignificand(const IEEEFloat &rhs,
}
// Convert the result having "2 * precision" significant-bits back to the one
- // having "precision" significant-bits. First, move the radix point from
+ // having "precision" significant-bits. First, move the radix point from
// poision "2*precision - 1" to "precision - 1". The exponent need to be
// adjusted by "2*precision - 1" - "precision - 1" = "precision".
exponent -= precision + 1;
@@ -1611,16 +1629,6 @@ void IEEEFloat::changeSign() {
sign = !sign;
}
-void IEEEFloat::clearSign() {
- /* So is this one. */
- sign = 0;
-}
-
-void IEEEFloat::copySign(const IEEEFloat &rhs) {
- /* And this one. */
- sign = rhs.sign;
-}
-
/* Normalized addition or subtraction. */
IEEEFloat::opStatus IEEEFloat::addOrSubtract(const IEEEFloat &rhs,
roundingMode rounding_mode,
@@ -1712,9 +1720,10 @@ IEEEFloat::opStatus IEEEFloat::remainder(const IEEEFloat &rhs) {
int parts = partCount();
integerPart *x = new integerPart[parts];
bool ignored;
- fs = V.convertToInteger(x, parts * integerPartWidth, true,
- rmNearestTiesToEven, &ignored);
- if (fs==opInvalidOp) {
+ fs = V.convertToInteger(makeMutableArrayRef(x, parts),
+ parts * integerPartWidth, true, rmNearestTiesToEven,
+ &ignored);
+ if (fs == opInvalidOp) {
delete[] x;
return fs;
}
@@ -1735,43 +1744,20 @@ IEEEFloat::opStatus IEEEFloat::remainder(const IEEEFloat &rhs) {
return fs;
}
-/* Normalized llvm frem (C fmod).
- This is not currently correct in all cases. */
+/* Normalized llvm frem (C fmod). */
IEEEFloat::opStatus IEEEFloat::mod(const IEEEFloat &rhs) {
opStatus fs;
fs = modSpecials(rhs);
- if (isFiniteNonZero() && rhs.isFiniteNonZero()) {
- IEEEFloat V = *this;
- unsigned int origSign = sign;
-
- fs = V.divide(rhs, rmNearestTiesToEven);
- if (fs == opDivByZero)
- return fs;
-
- int parts = partCount();
- integerPart *x = new integerPart[parts];
- bool ignored;
- fs = V.convertToInteger(x, parts * integerPartWidth, true,
- rmTowardZero, &ignored);
- if (fs==opInvalidOp) {
- delete[] x;
- return fs;
- }
-
- fs = V.convertFromZeroExtendedInteger(x, parts * integerPartWidth, true,
- rmNearestTiesToEven);
- assert(fs==opOK); // should always work
-
- fs = V.multiply(rhs, rmNearestTiesToEven);
- assert(fs==opOK || fs==opInexact); // should not overflow or underflow
-
+ while (isFiniteNonZero() && rhs.isFiniteNonZero() &&
+ compareAbsoluteValue(rhs) != cmpLessThan) {
+ IEEEFloat V = scalbn(rhs, ilogb(*this) - ilogb(rhs), rmNearestTiesToEven);
+ if (compareAbsoluteValue(V) == cmpLessThan)
+ V = scalbn(V, -1, rmNearestTiesToEven);
+ V.sign = sign;
+
fs = subtract(V, rmNearestTiesToEven);
- assert(fs==opOK || fs==opInexact); // likewise
-
- if (isZero())
- sign = origSign; // IEEE754 requires this
- delete[] x;
+ assert(fs==opOK);
}
return fs;
}
@@ -1840,7 +1826,7 @@ IEEEFloat::opStatus IEEEFloat::roundToIntegral(roundingMode rounding_mode) {
IEEEFloat MagicConstant(*semantics);
fs = MagicConstant.convertFromAPInt(IntegerConstant, false,
rmNearestTiesToEven);
- MagicConstant.copySign(*this);
+ MagicConstant.sign = sign;
if (fs != opOK)
return fs;
@@ -2047,7 +2033,7 @@ IEEEFloat::opStatus IEEEFloat::convert(const fltSemantics &toSemantics,
Note that for conversions to integer type the C standard requires
round-to-zero to always be used. */
IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
- integerPart *parts, unsigned int width, bool isSigned,
+ MutableArrayRef<integerPart> parts, unsigned int width, bool isSigned,
roundingMode rounding_mode, bool *isExact) const {
lostFraction lost_fraction;
const integerPart *src;
@@ -2060,9 +2046,10 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
return opInvalidOp;
dstPartsCount = partCountForBits(width);
+ assert(dstPartsCount <= parts.size() && "Integer too big");
if (category == fcZero) {
- APInt::tcSet(parts, 0, dstPartsCount);
+ APInt::tcSet(parts.data(), 0, dstPartsCount);
// Negative zero can't be represented as an int.
*isExact = !sign;
return opOK;
@@ -2074,7 +2061,7 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
the destination. */
if (exponent < 0) {
/* Our absolute value is less than one; truncate everything. */
- APInt::tcSet(parts, 0, dstPartsCount);
+ APInt::tcSet(parts.data(), 0, dstPartsCount);
/* For exponent -1 the integer bit represents .5, look at that.
For smaller exponents leftmost truncated bit is 0. */
truncatedBits = semantics->precision -1U - exponent;
@@ -2090,11 +2077,13 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
if (bits < semantics->precision) {
/* We truncate (semantics->precision - bits) bits. */
truncatedBits = semantics->precision - bits;
- APInt::tcExtract(parts, dstPartsCount, src, bits, truncatedBits);
+ APInt::tcExtract(parts.data(), dstPartsCount, src, bits, truncatedBits);
} else {
/* We want at least as many bits as are available. */
- APInt::tcExtract(parts, dstPartsCount, src, semantics->precision, 0);
- APInt::tcShiftLeft(parts, dstPartsCount, bits - semantics->precision);
+ APInt::tcExtract(parts.data(), dstPartsCount, src, semantics->precision,
+ 0);
+ APInt::tcShiftLeft(parts.data(), dstPartsCount,
+ bits - semantics->precision);
truncatedBits = 0;
}
}
@@ -2106,7 +2095,7 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
truncatedBits);
if (lost_fraction != lfExactlyZero &&
roundAwayFromZero(rounding_mode, lost_fraction, truncatedBits)) {
- if (APInt::tcIncrement(parts, dstPartsCount))
+ if (APInt::tcIncrement(parts.data(), dstPartsCount))
return opInvalidOp; /* Overflow. */
}
} else {
@@ -2114,7 +2103,7 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
}
/* Step 3: check if we fit in the destination. */
- unsigned int omsb = APInt::tcMSB(parts, dstPartsCount) + 1;
+ unsigned int omsb = APInt::tcMSB(parts.data(), dstPartsCount) + 1;
if (sign) {
if (!isSigned) {
@@ -2125,7 +2114,8 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
/* It takes omsb bits to represent the unsigned integer value.
We lose a bit for the sign, but care is needed as the
maximally negative integer is a special case. */
- if (omsb == width && APInt::tcLSB(parts, dstPartsCount) + 1 != omsb)
+ if (omsb == width &&
+ APInt::tcLSB(parts.data(), dstPartsCount) + 1 != omsb)
return opInvalidOp;
/* This case can happen because of rounding. */
@@ -2133,7 +2123,7 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
return opInvalidOp;
}
- APInt::tcNegate (parts, dstPartsCount);
+ APInt::tcNegate (parts.data(), dstPartsCount);
} else {
if (omsb >= width + !isSigned)
return opInvalidOp;
@@ -2155,11 +2145,10 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
the original value. This is almost equivalent to result==opOK,
except for negative zeroes.
*/
-IEEEFloat::opStatus IEEEFloat::convertToInteger(integerPart *parts,
- unsigned int width,
- bool isSigned,
- roundingMode rounding_mode,
- bool *isExact) const {
+IEEEFloat::opStatus
+IEEEFloat::convertToInteger(MutableArrayRef<integerPart> parts,
+ unsigned int width, bool isSigned,
+ roundingMode rounding_mode, bool *isExact) const {
opStatus fs;
fs = convertToSignExtendedInteger(parts, width, isSigned, rounding_mode,
@@ -2169,6 +2158,7 @@ IEEEFloat::opStatus IEEEFloat::convertToInteger(integerPart *parts,
unsigned int bits, dstPartsCount;
dstPartsCount = partCountForBits(width);
+ assert(dstPartsCount <= parts.size() && "Integer too big");
if (category == fcNaN)
bits = 0;
@@ -2177,30 +2167,14 @@ IEEEFloat::opStatus IEEEFloat::convertToInteger(integerPart *parts,
else
bits = width - isSigned;
- APInt::tcSetLeastSignificantBits(parts, dstPartsCount, bits);
+ APInt::tcSetLeastSignificantBits(parts.data(), dstPartsCount, bits);
if (sign && isSigned)
- APInt::tcShiftLeft(parts, dstPartsCount, width - 1);
+ APInt::tcShiftLeft(parts.data(), dstPartsCount, width - 1);
}
return fs;
}
-/* Same as convertToInteger(integerPart*, ...), except the result is returned in
- an APSInt, whose initial bit-width and signed-ness are used to determine the
- precision of the conversion.
- */
-IEEEFloat::opStatus IEEEFloat::convertToInteger(APSInt &result,
- roundingMode rounding_mode,
- bool *isExact) const {
- unsigned bitWidth = result.getBitWidth();
- SmallVector<uint64_t, 4> parts(result.getNumWords());
- opStatus status = convertToInteger(
- parts.data(), bitWidth, result.isSigned(), rounding_mode, isExact);
- // Keeps the original signed-ness.
- result = APInt(bitWidth, parts);
- return status;
-}
-
/* Convert an unsigned integer SRC to a floating point number,
rounding according to ROUNDING_MODE. The sign of the floating
point number is not modified. */
@@ -2484,7 +2458,7 @@ IEEEFloat::convertFromDecimalString(StringRef str, roundingMode rounding_mode) {
// Test if we have a zero number allowing for strings with no null terminators
// and zero decimals with non-zero exponents.
- //
+ //
// We computed firstSigDigit by ignoring all zeros and dots. Thus if
// D->firstSigDigit equals str.end(), every digit must be a zero and there can
// be at most one dot. On the other hand, if we have a zero with a non-zero
@@ -2852,7 +2826,7 @@ APInt IEEEFloat::convertF80LongDoubleAPFloatToAPInt() const {
}
APInt IEEEFloat::convertPPCDoubleDoubleAPFloatToAPInt() const {
- assert(semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleImpl);
+ assert(semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleLegacy);
assert(partCount()==2);
uint64_t words[2];
@@ -3033,7 +3007,7 @@ APInt IEEEFloat::bitcastToAPInt() const {
if (semantics == (const llvm::fltSemantics*)&semIEEEquad)
return convertQuadrupleAPFloatToAPInt();
- if (semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleImpl)
+ if (semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleLegacy)
return convertPPCDoubleDoubleAPFloatToAPInt();
assert(semantics == (const llvm::fltSemantics*)&semX87DoubleExtended &&
@@ -3103,14 +3077,14 @@ void IEEEFloat::initFromPPCDoubleDoubleAPInt(const APInt &api) {
// Get the first double and convert to our format.
initFromDoubleAPInt(APInt(64, i1));
- fs = convert(semPPCDoubleDoubleImpl, rmNearestTiesToEven, &losesInfo);
+ fs = convert(semPPCDoubleDoubleLegacy, rmNearestTiesToEven, &losesInfo);
assert(fs == opOK && !losesInfo);
(void)fs;
// Unless we have a special case, add in second double.
if (isFiniteNonZero()) {
IEEEFloat v(semIEEEdouble, APInt(64, i2));
- fs = v.convert(semPPCDoubleDoubleImpl, rmNearestTiesToEven, &losesInfo);
+ fs = v.convert(semPPCDoubleDoubleLegacy, rmNearestTiesToEven, &losesInfo);
assert(fs == opOK && !losesInfo);
(void)fs;
@@ -3264,7 +3238,7 @@ void IEEEFloat::initFromAPInt(const fltSemantics *Sem, const APInt &api) {
return initFromF80LongDoubleAPInt(api);
if (Sem == &semIEEEquad)
return initFromQuadrupleAPInt(api);
- if (Sem == &semPPCDoubleDoubleImpl)
+ if (Sem == &semPPCDoubleDoubleLegacy)
return initFromPPCDoubleDoubleAPInt(api);
llvm_unreachable(nullptr);
@@ -3620,7 +3594,7 @@ void IEEEFloat::toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision,
Str.push_back(buffer[NDigits-I-1]);
}
-bool IEEEFloat::getExactInverse(IEEEFloat *inv) const {
+bool IEEEFloat::getExactInverse(APFloat *inv) const {
// Special floats and denormals have no exact inverse.
if (!isFiniteNonZero())
return false;
@@ -3644,7 +3618,7 @@ bool IEEEFloat::getExactInverse(IEEEFloat *inv) const {
reciprocal.significandLSB() == reciprocal.semantics->precision - 1);
if (inv)
- *inv = reciprocal;
+ *inv = APFloat(reciprocal, *semantics);
return true;
}
@@ -3856,28 +3830,29 @@ IEEEFloat frexp(const IEEEFloat &Val, int &Exp, IEEEFloat::roundingMode RM) {
}
DoubleAPFloat::DoubleAPFloat(const fltSemantics &S)
- : Semantics(&S), Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl),
- APFloat(semIEEEdouble)}) {
+ : Semantics(&S),
+ Floats(new APFloat[2]{APFloat(semIEEEdouble), APFloat(semIEEEdouble)}) {
assert(Semantics == &semPPCDoubleDouble);
}
DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, uninitializedTag)
: Semantics(&S),
- Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl, uninitialized),
+ Floats(new APFloat[2]{APFloat(semIEEEdouble, uninitialized),
APFloat(semIEEEdouble, uninitialized)}) {
assert(Semantics == &semPPCDoubleDouble);
}
DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, integerPart I)
- : Semantics(&S), Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl, I),
+ : Semantics(&S), Floats(new APFloat[2]{APFloat(semIEEEdouble, I),
APFloat(semIEEEdouble)}) {
assert(Semantics == &semPPCDoubleDouble);
}
DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, const APInt &I)
- : Semantics(&S), Floats(new APFloat[2]{
- APFloat(semPPCDoubleDoubleImpl, I),
- APFloat(semIEEEdouble, APInt(64, I.getRawData()[1]))}) {
+ : Semantics(&S),
+ Floats(new APFloat[2]{
+ APFloat(semIEEEdouble, APInt(64, I.getRawData()[0])),
+ APFloat(semIEEEdouble, APInt(64, I.getRawData()[1]))}) {
assert(Semantics == &semPPCDoubleDouble);
}
@@ -3886,9 +3861,7 @@ DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, APFloat &&First,
: Semantics(&S),
Floats(new APFloat[2]{std::move(First), std::move(Second)}) {
assert(Semantics == &semPPCDoubleDouble);
- // TODO Check for First == &IEEEdouble once the transition is done.
- assert(&Floats[0].getSemantics() == &semPPCDoubleDoubleImpl ||
- &Floats[0].getSemantics() == &semIEEEdouble);
+ assert(&Floats[0].getSemantics() == &semIEEEdouble);
assert(&Floats[1].getSemantics() == &semIEEEdouble);
}
@@ -3917,6 +3890,7 @@ DoubleAPFloat &DoubleAPFloat::operator=(const DoubleAPFloat &RHS) {
return *this;
}
+// Implement addition, subtraction, multiplication and division based on:
// "Software for Doubled-Precision Floating-Point Computations",
// by Seppo Linnainmaa, ACM TOMS vol 7 no 3, September 1981, pages 272-283.
APFloat::opStatus DoubleAPFloat::addImpl(const APFloat &a, const APFloat &aa,
@@ -3928,7 +3902,7 @@ APFloat::opStatus DoubleAPFloat::addImpl(const APFloat &a, const APFloat &aa,
if (!z.isFinite()) {
if (!z.isInfinity()) {
Floats[0] = std::move(z);
- Floats[1].makeZero(false);
+ Floats[1].makeZero(/* Neg = */ false);
return (opStatus)Status;
}
Status = opOK;
@@ -3946,7 +3920,7 @@ APFloat::opStatus DoubleAPFloat::addImpl(const APFloat &a, const APFloat &aa,
}
if (!z.isFinite()) {
Floats[0] = std::move(z);
- Floats[1].makeZero(false);
+ Floats[1].makeZero(/* Neg = */ false);
return (opStatus)Status;
}
Floats[0] = z;
@@ -3982,13 +3956,13 @@ APFloat::opStatus DoubleAPFloat::addImpl(const APFloat &a, const APFloat &aa,
Status |= zz.add(cc, RM);
if (zz.isZero() && !zz.isNegative()) {
Floats[0] = std::move(z);
- Floats[1].makeZero(false);
+ Floats[1].makeZero(/* Neg = */ false);
return opOK;
}
Floats[0] = z;
Status |= Floats[0].add(zz, RM);
if (!Floats[0].isFinite()) {
- Floats[1].makeZero(false);
+ Floats[1].makeZero(/* Neg = */ false);
return (opStatus)Status;
}
Floats[1] = std::move(z);
@@ -4033,25 +4007,15 @@ APFloat::opStatus DoubleAPFloat::addWithSpecial(const DoubleAPFloat &LHS,
}
assert(LHS.getCategory() == fcNormal && RHS.getCategory() == fcNormal);
- // These conversions will go away once PPCDoubleDoubleImpl goes away.
- // (PPCDoubleDoubleImpl, IEEEDouble) -> (IEEEDouble, IEEEDouble)
- APFloat A(semIEEEdouble,
- APInt(64, LHS.Floats[0].bitcastToAPInt().getRawData()[0])),
- AA(LHS.Floats[1]),
- C(semIEEEdouble, APInt(64, RHS.Floats[0].bitcastToAPInt().getRawData()[0])),
+ APFloat A(LHS.Floats[0]), AA(LHS.Floats[1]), C(RHS.Floats[0]),
CC(RHS.Floats[1]);
+ assert(&A.getSemantics() == &semIEEEdouble);
assert(&AA.getSemantics() == &semIEEEdouble);
+ assert(&C.getSemantics() == &semIEEEdouble);
assert(&CC.getSemantics() == &semIEEEdouble);
- Out.Floats[0] = APFloat(semIEEEdouble);
+ assert(&Out.Floats[0].getSemantics() == &semIEEEdouble);
assert(&Out.Floats[1].getSemantics() == &semIEEEdouble);
-
- auto Ret = Out.addImpl(A, AA, C, CC, RM);
-
- // (IEEEDouble, IEEEDouble) -> (PPCDoubleDoubleImpl, IEEEDouble)
- uint64_t Buffer[] = {Out.Floats[0].bitcastToAPInt().getRawData()[0],
- Out.Floats[1].bitcastToAPInt().getRawData()[0]};
- Out.Floats[0] = APFloat(semPPCDoubleDoubleImpl, APInt(128, 2, Buffer));
- return Ret;
+ return Out.addImpl(A, AA, C, CC, RM);
}
APFloat::opStatus DoubleAPFloat::add(const DoubleAPFloat &RHS,
@@ -4067,6 +4031,140 @@ APFloat::opStatus DoubleAPFloat::subtract(const DoubleAPFloat &RHS,
return Ret;
}
+APFloat::opStatus DoubleAPFloat::multiply(const DoubleAPFloat &RHS,
+ APFloat::roundingMode RM) {
+ const auto &LHS = *this;
+ auto &Out = *this;
+ /* Interesting observation: For special categories, finding the lowest
+ common ancestor of the following layered graph gives the correct
+ return category:
+
+ NaN
+ / \
+ Zero Inf
+ \ /
+ Normal
+
+ e.g. NaN * NaN = NaN
+ Zero * Inf = NaN
+ Normal * Zero = Zero
+ Normal * Inf = Inf
+ */
+ if (LHS.getCategory() == fcNaN) {
+ Out = LHS;
+ return opOK;
+ }
+ if (RHS.getCategory() == fcNaN) {
+ Out = RHS;
+ return opOK;
+ }
+ if ((LHS.getCategory() == fcZero && RHS.getCategory() == fcInfinity) ||
+ (LHS.getCategory() == fcInfinity && RHS.getCategory() == fcZero)) {
+ Out.makeNaN(false, false, nullptr);
+ return opOK;
+ }
+ if (LHS.getCategory() == fcZero || LHS.getCategory() == fcInfinity) {
+ Out = LHS;
+ return opOK;
+ }
+ if (RHS.getCategory() == fcZero || RHS.getCategory() == fcInfinity) {
+ Out = RHS;
+ return opOK;
+ }
+ assert(LHS.getCategory() == fcNormal && RHS.getCategory() == fcNormal &&
+ "Special cases not handled exhaustively");
+
+ int Status = opOK;
+ APFloat A = Floats[0], B = Floats[1], C = RHS.Floats[0], D = RHS.Floats[1];
+ // t = a * c
+ APFloat T = A;
+ Status |= T.multiply(C, RM);
+ if (!T.isFiniteNonZero()) {
+ Floats[0] = T;
+ Floats[1].makeZero(/* Neg = */ false);
+ return (opStatus)Status;
+ }
+
+ // tau = fmsub(a, c, t), that is -fmadd(-a, c, t).
+ APFloat Tau = A;
+ T.changeSign();
+ Status |= Tau.fusedMultiplyAdd(C, T, RM);
+ T.changeSign();
+ {
+ // v = a * d
+ APFloat V = A;
+ Status |= V.multiply(D, RM);
+ // w = b * c
+ APFloat W = B;
+ Status |= W.multiply(C, RM);
+ Status |= V.add(W, RM);
+ // tau += v + w
+ Status |= Tau.add(V, RM);
+ }
+ // u = t + tau
+ APFloat U = T;
+ Status |= U.add(Tau, RM);
+
+ Floats[0] = U;
+ if (!U.isFinite()) {
+ Floats[1].makeZero(/* Neg = */ false);
+ } else {
+ // Floats[1] = (t - u) + tau
+ Status |= T.subtract(U, RM);
+ Status |= T.add(Tau, RM);
+ Floats[1] = T;
+ }
+ return (opStatus)Status;
+}
+
+APFloat::opStatus DoubleAPFloat::divide(const DoubleAPFloat &RHS,
+ APFloat::roundingMode RM) {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+ auto Ret =
+ Tmp.divide(APFloat(semPPCDoubleDoubleLegacy, RHS.bitcastToAPInt()), RM);
+ *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+ return Ret;
+}
+
+APFloat::opStatus DoubleAPFloat::remainder(const DoubleAPFloat &RHS) {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+ auto Ret =
+ Tmp.remainder(APFloat(semPPCDoubleDoubleLegacy, RHS.bitcastToAPInt()));
+ *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+ return Ret;
+}
+
+APFloat::opStatus DoubleAPFloat::mod(const DoubleAPFloat &RHS) {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+ auto Ret = Tmp.mod(APFloat(semPPCDoubleDoubleLegacy, RHS.bitcastToAPInt()));
+ *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+ return Ret;
+}
+
+APFloat::opStatus
+DoubleAPFloat::fusedMultiplyAdd(const DoubleAPFloat &Multiplicand,
+ const DoubleAPFloat &Addend,
+ APFloat::roundingMode RM) {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+ auto Ret = Tmp.fusedMultiplyAdd(
+ APFloat(semPPCDoubleDoubleLegacy, Multiplicand.bitcastToAPInt()),
+ APFloat(semPPCDoubleDoubleLegacy, Addend.bitcastToAPInt()), RM);
+ *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+ return Ret;
+}
+
+APFloat::opStatus DoubleAPFloat::roundToIntegral(APFloat::roundingMode RM) {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+ auto Ret = Tmp.roundToIntegral(RM);
+ *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+ return Ret;
+}
+
void DoubleAPFloat::changeSign() {
Floats[0].changeSign();
Floats[1].changeSign();
@@ -4101,12 +4199,200 @@ bool DoubleAPFloat::isNegative() const { return Floats[0].isNegative(); }
void DoubleAPFloat::makeInf(bool Neg) {
Floats[0].makeInf(Neg);
- Floats[1].makeZero(false);
+ Floats[1].makeZero(/* Neg = */ false);
+}
+
+void DoubleAPFloat::makeZero(bool Neg) {
+ Floats[0].makeZero(Neg);
+ Floats[1].makeZero(/* Neg = */ false);
+}
+
+void DoubleAPFloat::makeLargest(bool Neg) {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ Floats[0] = APFloat(semIEEEdouble, APInt(64, 0x7fefffffffffffffull));
+ Floats[1] = APFloat(semIEEEdouble, APInt(64, 0x7c8ffffffffffffeull));
+ if (Neg)
+ changeSign();
+}
+
+void DoubleAPFloat::makeSmallest(bool Neg) {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ Floats[0].makeSmallest(Neg);
+ Floats[1].makeZero(/* Neg = */ false);
+}
+
+void DoubleAPFloat::makeSmallestNormalized(bool Neg) {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ Floats[0] = APFloat(semIEEEdouble, APInt(64, 0x0360000000000000ull));
+ if (Neg)
+ Floats[0].changeSign();
+ Floats[1].makeZero(/* Neg = */ false);
}
void DoubleAPFloat::makeNaN(bool SNaN, bool Neg, const APInt *fill) {
Floats[0].makeNaN(SNaN, Neg, fill);
- Floats[1].makeZero(false);
+ Floats[1].makeZero(/* Neg = */ false);
+}
+
+APFloat::cmpResult DoubleAPFloat::compare(const DoubleAPFloat &RHS) const {
+ auto Result = Floats[0].compare(RHS.Floats[0]);
+ // |Float[0]| > |Float[1]|
+ if (Result == APFloat::cmpEqual)
+ return Floats[1].compare(RHS.Floats[1]);
+ return Result;
+}
+
+bool DoubleAPFloat::bitwiseIsEqual(const DoubleAPFloat &RHS) const {
+ return Floats[0].bitwiseIsEqual(RHS.Floats[0]) &&
+ Floats[1].bitwiseIsEqual(RHS.Floats[1]);
+}
+
+hash_code hash_value(const DoubleAPFloat &Arg) {
+ if (Arg.Floats)
+ return hash_combine(hash_value(Arg.Floats[0]), hash_value(Arg.Floats[1]));
+ return hash_combine(Arg.Semantics);
+}
+
+APInt DoubleAPFloat::bitcastToAPInt() const {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ uint64_t Data[] = {
+ Floats[0].bitcastToAPInt().getRawData()[0],
+ Floats[1].bitcastToAPInt().getRawData()[0],
+ };
+ return APInt(128, 2, Data);
+}
+
+APFloat::opStatus DoubleAPFloat::convertFromString(StringRef S,
+ roundingMode RM) {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ APFloat Tmp(semPPCDoubleDoubleLegacy);
+ auto Ret = Tmp.convertFromString(S, RM);
+ *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+ return Ret;
+}
+
+APFloat::opStatus DoubleAPFloat::next(bool nextDown) {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+ auto Ret = Tmp.next(nextDown);
+ *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+ return Ret;
+}
+
+APFloat::opStatus
+DoubleAPFloat::convertToInteger(MutableArrayRef<integerPart> Input,
+ unsigned int Width, bool IsSigned,
+ roundingMode RM, bool *IsExact) const {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ return APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt())
+ .convertToInteger(Input, Width, IsSigned, RM, IsExact);
+}
+
+APFloat::opStatus DoubleAPFloat::convertFromAPInt(const APInt &Input,
+ bool IsSigned,
+ roundingMode RM) {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ APFloat Tmp(semPPCDoubleDoubleLegacy);
+ auto Ret = Tmp.convertFromAPInt(Input, IsSigned, RM);
+ *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+ return Ret;
+}
+
+APFloat::opStatus
+DoubleAPFloat::convertFromSignExtendedInteger(const integerPart *Input,
+ unsigned int InputSize,
+ bool IsSigned, roundingMode RM) {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ APFloat Tmp(semPPCDoubleDoubleLegacy);
+ auto Ret = Tmp.convertFromSignExtendedInteger(Input, InputSize, IsSigned, RM);
+ *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+ return Ret;
+}
+
+APFloat::opStatus
+DoubleAPFloat::convertFromZeroExtendedInteger(const integerPart *Input,
+ unsigned int InputSize,
+ bool IsSigned, roundingMode RM) {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ APFloat Tmp(semPPCDoubleDoubleLegacy);
+ auto Ret = Tmp.convertFromZeroExtendedInteger(Input, InputSize, IsSigned, RM);
+ *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+ return Ret;
+}
+
+unsigned int DoubleAPFloat::convertToHexString(char *DST,
+ unsigned int HexDigits,
+ bool UpperCase,
+ roundingMode RM) const {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ return APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt())
+ .convertToHexString(DST, HexDigits, UpperCase, RM);
+}
+
+bool DoubleAPFloat::isDenormal() const {
+ return getCategory() == fcNormal &&
+ (Floats[0].isDenormal() || Floats[1].isDenormal() ||
+ // (double)(Hi + Lo) == Hi defines a normal number.
+ Floats[0].compare(Floats[0] + Floats[1]) != cmpEqual);
+}
+
+bool DoubleAPFloat::isSmallest() const {
+ if (getCategory() != fcNormal)
+ return false;
+ DoubleAPFloat Tmp(*this);
+ Tmp.makeSmallest(this->isNegative());
+ return Tmp.compare(*this) == cmpEqual;
+}
+
+bool DoubleAPFloat::isLargest() const {
+ if (getCategory() != fcNormal)
+ return false;
+ DoubleAPFloat Tmp(*this);
+ Tmp.makeLargest(this->isNegative());
+ return Tmp.compare(*this) == cmpEqual;
+}
+
+bool DoubleAPFloat::isInteger() const {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ APFloat Tmp(semPPCDoubleDoubleLegacy);
+ (void)Tmp.add(Floats[0], rmNearestTiesToEven);
+ (void)Tmp.add(Floats[1], rmNearestTiesToEven);
+ return Tmp.isInteger();
+}
+
+void DoubleAPFloat::toString(SmallVectorImpl<char> &Str,
+ unsigned FormatPrecision,
+ unsigned FormatMaxPadding) const {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt())
+ .toString(Str, FormatPrecision, FormatMaxPadding);
+}
+
+bool DoubleAPFloat::getExactInverse(APFloat *inv) const {
+ assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+ if (!inv)
+ return Tmp.getExactInverse(nullptr);
+ APFloat Inv(semPPCDoubleDoubleLegacy);
+ auto Ret = Tmp.getExactInverse(&Inv);
+ *inv = APFloat(semPPCDoubleDouble, Inv.bitcastToAPInt());
+ return Ret;
+}
+
+DoubleAPFloat scalbn(DoubleAPFloat Arg, int Exp, APFloat::roundingMode RM) {
+ assert(Arg.Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ return DoubleAPFloat(semPPCDoubleDouble, scalbn(Arg.Floats[0], Exp, RM),
+ scalbn(Arg.Floats[1], Exp, RM));
+}
+
+DoubleAPFloat frexp(const DoubleAPFloat &Arg, int &Exp,
+ APFloat::roundingMode RM) {
+ assert(Arg.Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+ APFloat First = frexp(Arg.Floats[0], Exp, RM);
+ APFloat Second = Arg.Floats[1];
+ if (Arg.getCategory() == APFloat::fcNormal)
+ Second = scalbn(Second, -Exp, RM);
+ return DoubleAPFloat(semPPCDoubleDouble, std::move(First), std::move(Second));
}
} // End detail namespace
@@ -4126,10 +4412,16 @@ APFloat::Storage::Storage(IEEEFloat F, const fltSemantics &Semantics) {
}
APFloat::opStatus APFloat::convertFromString(StringRef Str, roundingMode RM) {
- return getIEEE().convertFromString(Str, RM);
+ APFLOAT_DISPATCH_ON_SEMANTICS(convertFromString(Str, RM));
}
-hash_code hash_value(const APFloat &Arg) { return hash_value(Arg.getIEEE()); }
+hash_code hash_value(const APFloat &Arg) {
+ if (APFloat::usesLayout<detail::IEEEFloat>(Arg.getSemantics()))
+ return hash_value(Arg.U.IEEE);
+ if (APFloat::usesLayout<detail::DoubleAPFloat>(Arg.getSemantics()))
+ return hash_value(Arg.U.Double);
+ llvm_unreachable("Unexpected semantics");
+}
APFloat::APFloat(const fltSemantics &Semantics, StringRef S)
: APFloat(Semantics) {
@@ -4146,10 +4438,8 @@ APFloat::opStatus APFloat::convert(const fltSemantics &ToSemantics,
if (usesLayout<IEEEFloat>(getSemantics()) &&
usesLayout<DoubleAPFloat>(ToSemantics)) {
assert(&ToSemantics == &semPPCDoubleDouble);
- auto Ret = U.IEEE.convert(semPPCDoubleDoubleImpl, RM, losesInfo);
- *this = APFloat(DoubleAPFloat(semPPCDoubleDouble, std::move(*this),
- APFloat(semIEEEdouble)),
- ToSemantics);
+ auto Ret = U.IEEE.convert(semPPCDoubleDoubleLegacy, RM, losesInfo);
+ *this = APFloat(ToSemantics, U.IEEE.bitcastToAPInt());
return Ret;
}
if (usesLayout<DoubleAPFloat>(getSemantics()) &&
@@ -4189,6 +4479,30 @@ void APFloat::print(raw_ostream &OS) const {
OS << Buffer << "\n";
}
-void APFloat::dump() const { print(dbgs()); }
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void APFloat::dump() const { print(dbgs()); }
+#endif
+
+void APFloat::Profile(FoldingSetNodeID &NID) const {
+ NID.Add(bitcastToAPInt());
+}
+
+/* Same as convertToInteger(integerPart*, ...), except the result is returned in
+ an APSInt, whose initial bit-width and signed-ness are used to determine the
+ precision of the conversion.
+ */
+APFloat::opStatus APFloat::convertToInteger(APSInt &result,
+ roundingMode rounding_mode,
+ bool *isExact) const {
+ unsigned bitWidth = result.getBitWidth();
+ SmallVector<uint64_t, 4> parts(result.getNumWords());
+ opStatus status = convertToInteger(parts, bitWidth, result.isSigned(),
+ rounding_mode, isExact);
+ // Keeps the original signed-ness.
+ result = APInt(bitWidth, parts);
+ return status;
+}
} // End llvm namespace
+
+#undef APFLOAT_DISPATCH_ON_SEMANTICS
diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp
index fb8b45166a41..0c7da1dad0d2 100644
--- a/lib/Support/APInt.cpp
+++ b/lib/Support/APInt.cpp
@@ -63,7 +63,7 @@ inline static unsigned getDigit(char cdigit, uint8_t radix) {
r = cdigit - 'a';
if (r <= radix - 11U)
return r + 10;
-
+
radix = 10;
}
@@ -76,14 +76,17 @@ inline static unsigned getDigit(char cdigit, uint8_t radix) {
void APInt::initSlowCase(uint64_t val, bool isSigned) {
+ VAL = 0;
pVal = getClearedMemory(getNumWords());
pVal[0] = val;
if (isSigned && int64_t(val) < 0)
for (unsigned i = 1; i < getNumWords(); ++i)
pVal[i] = -1ULL;
+ clearUnusedBits();
}
void APInt::initSlowCase(const APInt& that) {
+ VAL = 0;
pVal = getMemory(getNumWords());
memcpy(pVal, that.pVal, getNumWords() * APINT_WORD_SIZE);
}
@@ -95,6 +98,7 @@ void APInt::initFromArray(ArrayRef<uint64_t> bigVal) {
VAL = bigVal[0];
else {
// Get memory, cleared to 0
+ VAL = 0;
pVal = getClearedMemory(getNumWords());
// Calculate the number of words to copy
unsigned words = std::min<unsigned>(bigVal.size(), getNumWords());
@@ -106,17 +110,17 @@ void APInt::initFromArray(ArrayRef<uint64_t> bigVal) {
}
APInt::APInt(unsigned numBits, ArrayRef<uint64_t> bigVal)
- : BitWidth(numBits), VAL(0) {
+ : BitWidth(numBits) {
initFromArray(bigVal);
}
APInt::APInt(unsigned numBits, unsigned numWords, const uint64_t bigVal[])
- : BitWidth(numBits), VAL(0) {
+ : BitWidth(numBits) {
initFromArray(makeArrayRef(bigVal, numWords));
}
APInt::APInt(unsigned numbits, StringRef Str, uint8_t radix)
- : BitWidth(numbits), VAL(0) {
+ : VAL(0), BitWidth(numbits) {
assert(BitWidth && "Bitwidth too small");
fromString(numbits, Str, radix);
}
@@ -153,16 +157,6 @@ APInt& APInt::AssignSlowCase(const APInt& RHS) {
return clearUnusedBits();
}
-APInt& APInt::operator=(uint64_t RHS) {
- if (isSingleWord())
- VAL = RHS;
- else {
- pVal[0] = RHS;
- memset(pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE);
- }
- return clearUnusedBits();
-}
-
/// This method 'profiles' an APInt for use with FoldingSet.
void APInt::Profile(FoldingSetNodeID& ID) const {
ID.AddInteger(BitWidth);
@@ -177,76 +171,24 @@ void APInt::Profile(FoldingSetNodeID& ID) const {
ID.AddInteger(pVal[i]);
}
-/// This function adds a single "digit" integer, y, to the multiple
-/// "digit" integer array, x[]. x[] is modified to reflect the addition and
-/// 1 is returned if there is a carry out, otherwise 0 is returned.
-/// @returns the carry of the addition.
-static bool add_1(uint64_t dest[], uint64_t x[], unsigned len, uint64_t y) {
- for (unsigned i = 0; i < len; ++i) {
- dest[i] = y + x[i];
- if (dest[i] < y)
- y = 1; // Carry one to next digit.
- else {
- y = 0; // No need to carry so exit early
- break;
- }
- }
- return y;
-}
-
/// @brief Prefix increment operator. Increments the APInt by one.
APInt& APInt::operator++() {
if (isSingleWord())
++VAL;
else
- add_1(pVal, pVal, getNumWords(), 1);
+ tcIncrement(pVal, getNumWords());
return clearUnusedBits();
}
-/// This function subtracts a single "digit" (64-bit word), y, from
-/// the multi-digit integer array, x[], propagating the borrowed 1 value until
-/// no further borrowing is needed or it runs out of "digits" in x. The result
-/// is 1 if "borrowing" exhausted the digits in x, or 0 if x was not exhausted.
-/// In other words, if y > x then this function returns 1, otherwise 0.
-/// @returns the borrow out of the subtraction
-static bool sub_1(uint64_t x[], unsigned len, uint64_t y) {
- for (unsigned i = 0; i < len; ++i) {
- uint64_t X = x[i];
- x[i] -= y;
- if (y > X)
- y = 1; // We have to "borrow 1" from next "digit"
- else {
- y = 0; // No need to borrow
- break; // Remaining digits are unchanged so exit early
- }
- }
- return bool(y);
-}
-
/// @brief Prefix decrement operator. Decrements the APInt by one.
APInt& APInt::operator--() {
if (isSingleWord())
--VAL;
else
- sub_1(pVal, getNumWords(), 1);
+ tcDecrement(pVal, getNumWords());
return clearUnusedBits();
}
-/// This function adds the integer array x to the integer array Y and
-/// places the result in dest.
-/// @returns the carry out from the addition
-/// @brief General addition of 64-bit integer arrays
-static bool add(uint64_t *dest, const uint64_t *x, const uint64_t *y,
- unsigned len) {
- bool carry = false;
- for (unsigned i = 0; i< len; ++i) {
- uint64_t limit = std::min(x[i],y[i]); // must come first in case dest == x
- dest[i] = x[i] + y[i] + carry;
- carry = dest[i] < limit || (carry && dest[i] == limit);
- }
- return carry;
-}
-
/// Adds the RHS APint to this APInt.
/// @returns this, after addition of RHS.
/// @brief Addition assignment operator.
@@ -254,9 +196,8 @@ APInt& APInt::operator+=(const APInt& RHS) {
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
if (isSingleWord())
VAL += RHS.VAL;
- else {
- add(pVal, pVal, RHS.pVal, getNumWords());
- }
+ else
+ tcAdd(pVal, RHS.pVal, 0, getNumWords());
return clearUnusedBits();
}
@@ -264,24 +205,10 @@ APInt& APInt::operator+=(uint64_t RHS) {
if (isSingleWord())
VAL += RHS;
else
- add_1(pVal, pVal, getNumWords(), RHS);
+ tcAddPart(pVal, RHS, getNumWords());
return clearUnusedBits();
}
-/// Subtracts the integer array y from the integer array x
-/// @returns returns the borrow out.
-/// @brief Generalized subtraction of 64-bit integer arrays.
-static bool sub(uint64_t *dest, const uint64_t *x, const uint64_t *y,
- unsigned len) {
- bool borrow = false;
- for (unsigned i = 0; i < len; ++i) {
- uint64_t x_tmp = borrow ? x[i] - 1 : x[i];
- borrow = y[i] > x_tmp || (borrow && x[i] == 0);
- dest[i] = x_tmp - y[i];
- }
- return borrow;
-}
-
/// Subtracts the RHS APInt from this APInt
/// @returns this, after subtraction
/// @brief Subtraction assignment operator.
@@ -290,7 +217,7 @@ APInt& APInt::operator-=(const APInt& RHS) {
if (isSingleWord())
VAL -= RHS.VAL;
else
- sub(pVal, pVal, RHS.pVal, getNumWords());
+ tcSubtract(pVal, RHS.pVal, 0, getNumWords());
return clearUnusedBits();
}
@@ -298,7 +225,7 @@ APInt& APInt::operator-=(uint64_t RHS) {
if (isSingleWord())
VAL -= RHS;
else
- sub_1(pVal, getNumWords(), RHS);
+ tcSubtractPart(pVal, RHS, getNumWords());
return clearUnusedBits();
}
@@ -339,7 +266,7 @@ static uint64_t mul_1(uint64_t dest[], uint64_t x[], unsigned len, uint64_t y) {
/// Multiplies integer array x by integer array y and stores the result into
/// the integer array dest. Note that dest's size must be >= xlen + ylen.
-/// @brief Generalized multiplicate of integer arrays.
+/// @brief Generalized multiplication of integer arrays.
static void mul(uint64_t dest[], uint64_t x[], unsigned xlen, uint64_t y[],
unsigned ylen) {
dest[xlen] = mul_1(dest, x, xlen, y[0]);
@@ -412,69 +339,19 @@ APInt& APInt::operator*=(const APInt& RHS) {
return *this;
}
-APInt& APInt::operator&=(const APInt& RHS) {
- assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
- if (isSingleWord()) {
- VAL &= RHS.VAL;
- return *this;
- }
- unsigned numWords = getNumWords();
- for (unsigned i = 0; i < numWords; ++i)
- pVal[i] &= RHS.pVal[i];
+APInt& APInt::AndAssignSlowCase(const APInt& RHS) {
+ tcAnd(pVal, RHS.pVal, getNumWords());
return *this;
}
-APInt& APInt::operator|=(const APInt& RHS) {
- assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
- if (isSingleWord()) {
- VAL |= RHS.VAL;
- return *this;
- }
- unsigned numWords = getNumWords();
- for (unsigned i = 0; i < numWords; ++i)
- pVal[i] |= RHS.pVal[i];
+APInt& APInt::OrAssignSlowCase(const APInt& RHS) {
+ tcOr(pVal, RHS.pVal, getNumWords());
return *this;
}
-APInt& APInt::operator^=(const APInt& RHS) {
- assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
- if (isSingleWord()) {
- VAL ^= RHS.VAL;
- this->clearUnusedBits();
- return *this;
- }
- unsigned numWords = getNumWords();
- for (unsigned i = 0; i < numWords; ++i)
- pVal[i] ^= RHS.pVal[i];
- return clearUnusedBits();
-}
-
-APInt APInt::AndSlowCase(const APInt& RHS) const {
- unsigned numWords = getNumWords();
- uint64_t* val = getMemory(numWords);
- for (unsigned i = 0; i < numWords; ++i)
- val[i] = pVal[i] & RHS.pVal[i];
- return APInt(val, getBitWidth());
-}
-
-APInt APInt::OrSlowCase(const APInt& RHS) const {
- unsigned numWords = getNumWords();
- uint64_t *val = getMemory(numWords);
- for (unsigned i = 0; i < numWords; ++i)
- val[i] = pVal[i] | RHS.pVal[i];
- return APInt(val, getBitWidth());
-}
-
-APInt APInt::XorSlowCase(const APInt& RHS) const {
- unsigned numWords = getNumWords();
- uint64_t *val = getMemory(numWords);
- for (unsigned i = 0; i < numWords; ++i)
- val[i] = pVal[i] ^ RHS.pVal[i];
-
- APInt Result(val, getBitWidth());
- // 0^0==1 so clear the high bits in case they got set.
- Result.clearUnusedBits();
- return Result;
+APInt& APInt::XorAssignSlowCase(const APInt& RHS) {
+ tcXor(pVal, RHS.pVal, getNumWords());
+ return *this;
}
APInt APInt::operator*(const APInt& RHS) const {
@@ -511,11 +388,11 @@ bool APInt::ult(const APInt& RHS) const {
if (n1 < n2)
return true;
- // If magnitude of RHS is greather than LHS, return false.
+ // If magnitude of RHS is greater than LHS, return false.
if (n2 < n1)
return false;
- // If they bot fit in a word, just compare the low order word
+ // If they both fit in a word, just compare the low order word
if (n1 <= APINT_BITS_PER_WORD && n2 <= APINT_BITS_PER_WORD)
return pVal[0] < RHS.pVal[0];
@@ -545,7 +422,7 @@ bool APInt::slt(const APInt& RHS) const {
if (lhsNeg != rhsNeg)
return lhsNeg;
- // Otherwise we can just use an unsigned comparision, because even negative
+ // Otherwise we can just use an unsigned comparison, because even negative
// numbers compare correctly this way if both have the same signed-ness.
return ult(RHS);
}
@@ -557,6 +434,33 @@ void APInt::setBit(unsigned bitPosition) {
pVal[whichWord(bitPosition)] |= maskBit(bitPosition);
}
+void APInt::setBitsSlowCase(unsigned loBit, unsigned hiBit) {
+ unsigned loWord = whichWord(loBit);
+ unsigned hiWord = whichWord(hiBit);
+
+ // Create an initial mask for the low word with zeros below loBit.
+ uint64_t loMask = UINT64_MAX << whichBit(loBit);
+
+ // If hiBit is not aligned, we need a high mask.
+ unsigned hiShiftAmt = whichBit(hiBit);
+ if (hiShiftAmt != 0) {
+ // Create a high mask with zeros above hiBit.
+ uint64_t hiMask = UINT64_MAX >> (APINT_BITS_PER_WORD - hiShiftAmt);
+ // If loWord and hiWord are equal, then we combine the masks. Otherwise,
+ // set the bits in hiWord.
+ if (hiWord == loWord)
+ loMask &= hiMask;
+ else
+ pVal[hiWord] |= hiMask;
+ }
+ // Apply the mask to the low word.
+ pVal[loWord] |= loMask;
+
+ // Fill any words between loWord and hiWord with all ones.
+ for (unsigned word = loWord + 1; word < hiWord; ++word)
+ pVal[word] = UINT64_MAX;
+}
+
/// Set the given bit to 0 whose position is given as "bitPosition".
/// @brief Set a given bit to 0.
void APInt::clearBit(unsigned bitPosition) {
@@ -567,6 +471,10 @@ void APInt::clearBit(unsigned bitPosition) {
}
/// @brief Toggle every bit to its opposite value.
+void APInt::flipAllBitsSlowCase() {
+ tcComplement(pVal, getNumWords());
+ clearUnusedBits();
+}
/// Toggle a given bit to its opposite value whose position is given
/// as "bitPosition".
@@ -577,9 +485,104 @@ void APInt::flipBit(unsigned bitPosition) {
else setBit(bitPosition);
}
+void APInt::insertBits(const APInt &subBits, unsigned bitPosition) {
+ unsigned subBitWidth = subBits.getBitWidth();
+ assert(0 < subBitWidth && (subBitWidth + bitPosition) <= BitWidth &&
+ "Illegal bit insertion");
+
+ // Insertion is a direct copy.
+ if (subBitWidth == BitWidth) {
+ *this = subBits;
+ return;
+ }
+
+ // Single word result can be done as a direct bitmask.
+ if (isSingleWord()) {
+ uint64_t mask = UINT64_MAX >> (APINT_BITS_PER_WORD - subBitWidth);
+ VAL &= ~(mask << bitPosition);
+ VAL |= (subBits.VAL << bitPosition);
+ return;
+ }
+
+ unsigned loBit = whichBit(bitPosition);
+ unsigned loWord = whichWord(bitPosition);
+ unsigned hi1Word = whichWord(bitPosition + subBitWidth - 1);
+
+ // Insertion within a single word can be done as a direct bitmask.
+ if (loWord == hi1Word) {
+ uint64_t mask = UINT64_MAX >> (APINT_BITS_PER_WORD - subBitWidth);
+ pVal[loWord] &= ~(mask << loBit);
+ pVal[loWord] |= (subBits.VAL << loBit);
+ return;
+ }
+
+ // Insert on word boundaries.
+ if (loBit == 0) {
+ // Direct copy whole words.
+ unsigned numWholeSubWords = subBitWidth / APINT_BITS_PER_WORD;
+ memcpy(pVal + loWord, subBits.getRawData(),
+ numWholeSubWords * APINT_WORD_SIZE);
+
+ // Mask+insert remaining bits.
+ unsigned remainingBits = subBitWidth % APINT_BITS_PER_WORD;
+ if (remainingBits != 0) {
+ uint64_t mask = UINT64_MAX >> (APINT_BITS_PER_WORD - remainingBits);
+ pVal[hi1Word] &= ~mask;
+ pVal[hi1Word] |= subBits.getWord(subBitWidth - 1);
+ }
+ return;
+ }
+
+ // General case - set/clear individual bits in dst based on src.
+ // TODO - there is scope for optimization here, but at the moment this code
+ // path is barely used so prefer readability over performance.
+ for (unsigned i = 0; i != subBitWidth; ++i) {
+ if (subBits[i])
+ setBit(bitPosition + i);
+ else
+ clearBit(bitPosition + i);
+ }
+}
+
+APInt APInt::extractBits(unsigned numBits, unsigned bitPosition) const {
+ assert(numBits > 0 && "Can't extract zero bits");
+ assert(bitPosition < BitWidth && (numBits + bitPosition) <= BitWidth &&
+ "Illegal bit extraction");
+
+ if (isSingleWord())
+ return APInt(numBits, VAL >> bitPosition);
+
+ unsigned loBit = whichBit(bitPosition);
+ unsigned loWord = whichWord(bitPosition);
+ unsigned hiWord = whichWord(bitPosition + numBits - 1);
+
+ // Single word result extracting bits from a single word source.
+ if (loWord == hiWord)
+ return APInt(numBits, pVal[loWord] >> loBit);
+
+ // Extracting bits that start on a source word boundary can be done
+ // as a fast memory copy.
+ if (loBit == 0)
+ return APInt(numBits, makeArrayRef(pVal + loWord, 1 + hiWord - loWord));
+
+ // General case - shift + copy source words directly into place.
+ APInt Result(numBits, 0);
+ unsigned NumSrcWords = getNumWords();
+ unsigned NumDstWords = Result.getNumWords();
+
+ for (unsigned word = 0; word < NumDstWords; ++word) {
+ uint64_t w0 = pVal[loWord + word];
+ uint64_t w1 =
+ (loWord + word + 1) < NumSrcWords ? pVal[loWord + word + 1] : 0;
+ Result.pVal[word] = (w0 >> loBit) | (w1 << (APINT_BITS_PER_WORD - loBit));
+ }
+
+ return Result.clearUnusedBits();
+}
+
unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) {
assert(!str.empty() && "Invalid string length");
- assert((radix == 10 || radix == 8 || radix == 16 || radix == 2 ||
+ assert((radix == 10 || radix == 8 || radix == 16 || radix == 2 ||
radix == 36) &&
"Radix should be 2, 8, 10, 16, or 36!");
@@ -604,7 +607,7 @@ unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) {
return slen * 4 + isNegative;
// FIXME: base 36
-
+
// This is grossly inefficient but accurate. We could probably do something
// with a computation of roughly slen*64/20 and then adjust by the value of
// the first few digits. But, I'm not sure how accurate that could be.
@@ -613,7 +616,7 @@ unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) {
// be too large. This avoids the assertion in the constructor. This
// calculation doesn't work appropriately for the numbers 0-9, so just use 4
// bits in that case.
- unsigned sufficient
+ unsigned sufficient
= radix == 10? (slen == 1 ? 4 : slen * 64/18)
: (slen == 1 ? 7 : slen * 16/3);
@@ -647,19 +650,20 @@ bool APInt::isSplat(unsigned SplatSizeInBits) const {
/// This function returns the high "numBits" bits of this APInt.
APInt APInt::getHiBits(unsigned numBits) const {
- return APIntOps::lshr(*this, BitWidth - numBits);
+ return this->lshr(BitWidth - numBits);
}
/// This function returns the low "numBits" bits of this APInt.
APInt APInt::getLoBits(unsigned numBits) const {
- return APIntOps::lshr(APIntOps::shl(*this, BitWidth - numBits),
- BitWidth - numBits);
+ APInt Result(getLowBitsSet(BitWidth, numBits));
+ Result &= *this;
+ return Result;
}
unsigned APInt::countLeadingZerosSlowCase() const {
unsigned Count = 0;
for (int i = getNumWords()-1; i >= 0; --i) {
- integerPart V = pVal[i];
+ uint64_t V = pVal[i];
if (V == 0)
Count += APINT_BITS_PER_WORD;
else {
@@ -729,18 +733,6 @@ unsigned APInt::countPopulationSlowCase() const {
return Count;
}
-/// Perform a logical right-shift from Src to Dst, which must be equal or
-/// non-overlapping, of Words words, by Shift, which must be less than 64.
-static void lshrNear(uint64_t *Dst, uint64_t *Src, unsigned Words,
- unsigned Shift) {
- uint64_t Carry = 0;
- for (int I = Words - 1; I >= 0; --I) {
- uint64_t Tmp = Src[I];
- Dst[I] = (Tmp >> Shift) | Carry;
- Carry = Tmp << (64 - Shift);
- }
-}
-
APInt APInt::byteSwap() const {
assert(BitWidth >= 16 && BitWidth % 16 == 0 && "Cannot byteswap!");
if (BitWidth == 16)
@@ -761,8 +753,7 @@ APInt APInt::byteSwap() const {
for (unsigned I = 0, N = getNumWords(); I != N; ++I)
Result.pVal[I] = ByteSwap_64(pVal[N - I - 1]);
if (Result.BitWidth != BitWidth) {
- lshrNear(Result.pVal, Result.pVal, getNumWords(),
- Result.BitWidth - BitWidth);
+ Result.lshrInPlace(Result.BitWidth - BitWidth);
Result.BitWidth = BitWidth;
}
return Result;
@@ -798,14 +789,46 @@ APInt APInt::reverseBits() const {
return Reversed;
}
-APInt llvm::APIntOps::GreatestCommonDivisor(const APInt& API1,
- const APInt& API2) {
- APInt A = API1, B = API2;
- while (!!B) {
- APInt T = B;
- B = APIntOps::urem(A, B);
- A = T;
+APInt llvm::APIntOps::GreatestCommonDivisor(APInt A, APInt B) {
+ // Fast-path a common case.
+ if (A == B) return A;
+
+ // Corner cases: if either operand is zero, the other is the gcd.
+ if (!A) return B;
+ if (!B) return A;
+
+ // Count common powers of 2 and remove all other powers of 2.
+ unsigned Pow2;
+ {
+ unsigned Pow2_A = A.countTrailingZeros();
+ unsigned Pow2_B = B.countTrailingZeros();
+ if (Pow2_A > Pow2_B) {
+ A.lshrInPlace(Pow2_A - Pow2_B);
+ Pow2 = Pow2_B;
+ } else if (Pow2_B > Pow2_A) {
+ B.lshrInPlace(Pow2_B - Pow2_A);
+ Pow2 = Pow2_A;
+ } else {
+ Pow2 = Pow2_A;
+ }
+ }
+
+ // Both operands are odd multiples of 2^Pow_2:
+ //
+ // gcd(a, b) = gcd(|a - b| / 2^i, min(a, b))
+ //
+ // This is a modified version of Stein's algorithm, taking advantage of
+ // efficient countTrailingZeros().
+ while (A != B) {
+ if (A.ugt(B)) {
+ A -= B;
+ A.lshrInPlace(A.countTrailingZeros() - Pow2);
+ } else {
+ B -= A;
+ B.lshrInPlace(B.countTrailingZeros() - Pow2);
+ }
}
+
return A;
}
@@ -1117,68 +1140,59 @@ APInt APInt::lshr(const APInt &shiftAmt) const {
return lshr((unsigned)shiftAmt.getLimitedValue(BitWidth));
}
+/// Perform a logical right-shift from Src to Dst of Words words, by Shift,
+/// which must be less than 64. If the source and destination ranges overlap,
+/// we require that Src >= Dst (put another way, we require that the overall
+/// operation is a right shift on the combined range).
+static void lshrWords(APInt::WordType *Dst, APInt::WordType *Src,
+ unsigned Words, unsigned Shift) {
+ assert(Shift < APInt::APINT_BITS_PER_WORD);
+
+ if (!Words)
+ return;
+
+ if (Shift == 0) {
+ std::memmove(Dst, Src, Words * APInt::APINT_WORD_SIZE);
+ return;
+ }
+
+ uint64_t Low = Src[0];
+ for (unsigned I = 1; I != Words; ++I) {
+ uint64_t High = Src[I];
+ Dst[I - 1] =
+ (Low >> Shift) | (High << (APInt::APINT_BITS_PER_WORD - Shift));
+ Low = High;
+ }
+ Dst[Words - 1] = Low >> Shift;
+}
+
/// Logical right-shift this APInt by shiftAmt.
/// @brief Logical right-shift function.
-APInt APInt::lshr(unsigned shiftAmt) const {
+void APInt::lshrInPlace(unsigned shiftAmt) {
if (isSingleWord()) {
if (shiftAmt >= BitWidth)
- return APInt(BitWidth, 0);
+ VAL = 0;
else
- return APInt(BitWidth, this->VAL >> shiftAmt);
- }
-
- // If all the bits were shifted out, the result is 0. This avoids issues
- // with shifting by the size of the integer type, which produces undefined
- // results. We define these "undefined results" to always be 0.
- if (shiftAmt >= BitWidth)
- return APInt(BitWidth, 0);
-
- // If none of the bits are shifted out, the result is *this. This avoids
- // issues with shifting by the size of the integer type, which produces
- // undefined results in the code below. This is also an optimization.
- if (shiftAmt == 0)
- return *this;
-
- // Create some space for the result.
- uint64_t * val = new uint64_t[getNumWords()];
-
- // If we are shifting less than a word, compute the shift with a simple carry
- if (shiftAmt < APINT_BITS_PER_WORD) {
- lshrNear(val, pVal, getNumWords(), shiftAmt);
- APInt Result(val, BitWidth);
- Result.clearUnusedBits();
- return Result;
+ VAL >>= shiftAmt;
+ return;
}
- // Compute some values needed by the remaining shift algorithms
- unsigned wordShift = shiftAmt % APINT_BITS_PER_WORD;
- unsigned offset = shiftAmt / APINT_BITS_PER_WORD;
+ // Don't bother performing a no-op shift.
+ if (!shiftAmt)
+ return;
- // If we are shifting whole words, just move whole words
- if (wordShift == 0) {
- for (unsigned i = 0; i < getNumWords() - offset; ++i)
- val[i] = pVal[i+offset];
- for (unsigned i = getNumWords()-offset; i < getNumWords(); i++)
- val[i] = 0;
- APInt Result(val, BitWidth);
- Result.clearUnusedBits();
- return Result;
- }
+ // Find number of complete words being shifted out and zeroed.
+ const unsigned Words = getNumWords();
+ const unsigned ShiftFullWords =
+ std::min(shiftAmt / APINT_BITS_PER_WORD, Words);
- // Shift the low order words
- unsigned breakWord = getNumWords() - offset -1;
- for (unsigned i = 0; i < breakWord; ++i)
- val[i] = (pVal[i+offset] >> wordShift) |
- (pVal[i+offset+1] << (APINT_BITS_PER_WORD - wordShift));
- // Shift the break word.
- val[breakWord] = pVal[breakWord+offset] >> wordShift;
+ // Fill in first Words - ShiftFullWords by shifting.
+ lshrWords(pVal, pVal + ShiftFullWords, Words - ShiftFullWords,
+ shiftAmt % APINT_BITS_PER_WORD);
- // Remaining words are 0
- for (unsigned i = breakWord+1; i < getNumWords(); ++i)
- val[i] = 0;
- APInt Result(val, BitWidth);
- Result.clearUnusedBits();
- return Result;
+ // The remaining high words are all zero.
+ for (unsigned I = Words - ShiftFullWords; I != Words; ++I)
+ pVal[I] = 0;
}
/// Left-shift this APInt by shiftAmt.
@@ -1244,8 +1258,21 @@ APInt APInt::shlSlowCase(unsigned shiftAmt) const {
return Result;
}
+// Calculate the rotate amount modulo the bit width.
+static unsigned rotateModulo(unsigned BitWidth, const APInt &rotateAmt) {
+ unsigned rotBitWidth = rotateAmt.getBitWidth();
+ APInt rot = rotateAmt;
+ if (rotBitWidth < BitWidth) {
+ // Extend the rotate APInt, so that the urem doesn't divide by 0.
+ // e.g. APInt(1, 32) would give APInt(1, 0).
+ rot = rotateAmt.zext(BitWidth);
+ }
+ rot = rot.urem(APInt(rot.getBitWidth(), BitWidth));
+ return rot.getLimitedValue(BitWidth);
+}
+
APInt APInt::rotl(const APInt &rotateAmt) const {
- return rotl((unsigned)rotateAmt.getLimitedValue(BitWidth));
+ return rotl(rotateModulo(BitWidth, rotateAmt));
}
APInt APInt::rotl(unsigned rotateAmt) const {
@@ -1256,7 +1283,7 @@ APInt APInt::rotl(unsigned rotateAmt) const {
}
APInt APInt::rotr(const APInt &rotateAmt) const {
- return rotr((unsigned)rotateAmt.getLimitedValue(BitWidth));
+ return rotr(rotateModulo(BitWidth, rotateAmt));
}
APInt APInt::rotr(unsigned rotateAmt) const {
@@ -1618,7 +1645,7 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r,
if (r) {
// The value d is expressed by the "shift" value above since we avoided
// multiplication by d by using a shift left. So, all we have to do is
- // shift right here. In order to mak
+ // shift right here.
if (shift) {
unsigned carry = 0;
DEBUG(dbgs() << "KnuthDiv: remainder:");
@@ -2014,7 +2041,7 @@ APInt APInt::sdiv_ov(const APInt &RHS, bool &Overflow) const {
APInt APInt::smul_ov(const APInt &RHS, bool &Overflow) const {
APInt Res = *this * RHS;
-
+
if (*this != 0 && RHS != 0)
Overflow = Res.sdiv(RHS) != *this || Res.sdiv(*this) != RHS;
else
@@ -2041,7 +2068,7 @@ APInt APInt::sshl_ov(const APInt &ShAmt, bool &Overflow) const {
Overflow = ShAmt.uge(countLeadingZeros());
else
Overflow = ShAmt.uge(countLeadingOnes());
-
+
return *this << ShAmt;
}
@@ -2061,7 +2088,7 @@ APInt APInt::ushl_ov(const APInt &ShAmt, bool &Overflow) const {
void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) {
// Check our assumptions here
assert(!str.empty() && "Invalid string length");
- assert((radix == 10 || radix == 8 || radix == 16 || radix == 2 ||
+ assert((radix == 10 || radix == 8 || radix == 16 || radix == 2 ||
radix == 36) &&
"Radix should be 2, 8, 10, 16, or 36!");
@@ -2086,9 +2113,8 @@ void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) {
// Figure out if we can shift instead of multiply
unsigned shift = (radix == 16 ? 4 : radix == 8 ? 3 : radix == 2 ? 1 : 0);
- // Set up an APInt for the digit to add outside the loop so we don't
+ // Set up an APInt for the radix multiplier outside the loop so we don't
// constantly construct/destruct it.
- APInt apdigit(getBitWidth(), 0);
APInt apradix(getBitWidth(), radix);
// Enter digit traversal loop
@@ -2105,11 +2131,7 @@ void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) {
}
// Add in the digit we just interpreted
- if (apdigit.isSingleWord())
- apdigit.VAL = digit;
- else
- apdigit.pVal[0] = digit;
- *this += apdigit;
+ *this += digit;
}
// If its negative, put it in two's complement form
if (isNeg) {
@@ -2120,7 +2142,7 @@ void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) {
void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix,
bool Signed, bool formatAsCLiteral) const {
- assert((Radix == 10 || Radix == 8 || Radix == 16 || Radix == 2 ||
+ assert((Radix == 10 || Radix == 8 || Radix == 16 || Radix == 2 ||
Radix == 36) &&
"Radix should be 2, 8, 10, 16, or 36!");
@@ -2208,7 +2230,7 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix,
// For the 2, 8 and 16 bit cases, we can just shift instead of divide
// because the number of bits per digit (1, 3 and 4 respectively) divides
- // equaly. We just shift until the value is zero.
+ // equally. We just shift until the value is zero.
if (Radix == 2 || Radix == 8 || Radix == 16) {
// Just shift tmp right for each digit width until it becomes zero
unsigned ShiftAmt = (Radix == 16 ? 4 : (Radix == 8 ? 3 : 1));
@@ -2245,14 +2267,15 @@ std::string APInt::toString(unsigned Radix = 10, bool Signed = true) const {
return S.str();
}
-
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void APInt::dump() const {
SmallString<40> S, U;
this->toStringUnsigned(U);
this->toStringSigned(S);
dbgs() << "APInt(" << BitWidth << "b, "
- << U << "u " << S << "s)";
+ << U << "u " << S << "s)\n";
}
+#endif
void APInt::print(raw_ostream &OS, bool isSigned) const {
SmallString<40> S;
@@ -2265,83 +2288,60 @@ void APInt::print(raw_ostream &OS, bool isSigned) const {
// Assumed by lowHalf, highHalf, partMSB and partLSB. A fairly safe
// and unrestricting assumption.
-static_assert(integerPartWidth % 2 == 0, "Part width must be divisible by 2!");
+static_assert(APInt::APINT_BITS_PER_WORD % 2 == 0,
+ "Part width must be divisible by 2!");
/* Some handy functions local to this file. */
-namespace {
- /* Returns the integer part with the least significant BITS set.
- BITS cannot be zero. */
- static inline integerPart
- lowBitMask(unsigned int bits)
- {
- assert(bits != 0 && bits <= integerPartWidth);
+/* Returns the integer part with the least significant BITS set.
+ BITS cannot be zero. */
+static inline APInt::WordType lowBitMask(unsigned bits) {
+ assert(bits != 0 && bits <= APInt::APINT_BITS_PER_WORD);
- return ~(integerPart) 0 >> (integerPartWidth - bits);
- }
+ return ~(APInt::WordType) 0 >> (APInt::APINT_BITS_PER_WORD - bits);
+}
- /* Returns the value of the lower half of PART. */
- static inline integerPart
- lowHalf(integerPart part)
- {
- return part & lowBitMask(integerPartWidth / 2);
- }
+/* Returns the value of the lower half of PART. */
+static inline APInt::WordType lowHalf(APInt::WordType part) {
+ return part & lowBitMask(APInt::APINT_BITS_PER_WORD / 2);
+}
- /* Returns the value of the upper half of PART. */
- static inline integerPart
- highHalf(integerPart part)
- {
- return part >> (integerPartWidth / 2);
- }
+/* Returns the value of the upper half of PART. */
+static inline APInt::WordType highHalf(APInt::WordType part) {
+ return part >> (APInt::APINT_BITS_PER_WORD / 2);
+}
- /* Returns the bit number of the most significant set bit of a part.
- If the input number has no bits set -1U is returned. */
- static unsigned int
- partMSB(integerPart value)
- {
- return findLastSet(value, ZB_Max);
- }
+/* Returns the bit number of the most significant set bit of a part.
+ If the input number has no bits set -1U is returned. */
+static unsigned partMSB(APInt::WordType value) {
+ return findLastSet(value, ZB_Max);
+}
- /* Returns the bit number of the least significant set bit of a
- part. If the input number has no bits set -1U is returned. */
- static unsigned int
- partLSB(integerPart value)
- {
- return findFirstSet(value, ZB_Max);
- }
+/* Returns the bit number of the least significant set bit of a
+ part. If the input number has no bits set -1U is returned. */
+static unsigned partLSB(APInt::WordType value) {
+ return findFirstSet(value, ZB_Max);
}
/* Sets the least significant part of a bignum to the input value, and
zeroes out higher parts. */
-void
-APInt::tcSet(integerPart *dst, integerPart part, unsigned int parts)
-{
- unsigned int i;
-
+void APInt::tcSet(WordType *dst, WordType part, unsigned parts) {
assert(parts > 0);
dst[0] = part;
- for (i = 1; i < parts; i++)
+ for (unsigned i = 1; i < parts; i++)
dst[i] = 0;
}
/* Assign one bignum to another. */
-void
-APInt::tcAssign(integerPart *dst, const integerPart *src, unsigned int parts)
-{
- unsigned int i;
-
- for (i = 0; i < parts; i++)
+void APInt::tcAssign(WordType *dst, const WordType *src, unsigned parts) {
+ for (unsigned i = 0; i < parts; i++)
dst[i] = src[i];
}
/* Returns true if a bignum is zero, false otherwise. */
-bool
-APInt::tcIsZero(const integerPart *src, unsigned int parts)
-{
- unsigned int i;
-
- for (i = 0; i < parts; i++)
+bool APInt::tcIsZero(const WordType *src, unsigned parts) {
+ for (unsigned i = 0; i < parts; i++)
if (src[i])
return false;
@@ -2349,41 +2349,29 @@ APInt::tcIsZero(const integerPart *src, unsigned int parts)
}
/* Extract the given bit of a bignum; returns 0 or 1. */
-int
-APInt::tcExtractBit(const integerPart *parts, unsigned int bit)
-{
- return (parts[bit / integerPartWidth] &
- ((integerPart) 1 << bit % integerPartWidth)) != 0;
+int APInt::tcExtractBit(const WordType *parts, unsigned bit) {
+ return (parts[whichWord(bit)] & maskBit(bit)) != 0;
}
/* Set the given bit of a bignum. */
-void
-APInt::tcSetBit(integerPart *parts, unsigned int bit)
-{
- parts[bit / integerPartWidth] |= (integerPart) 1 << (bit % integerPartWidth);
+void APInt::tcSetBit(WordType *parts, unsigned bit) {
+ parts[whichWord(bit)] |= maskBit(bit);
}
/* Clears the given bit of a bignum. */
-void
-APInt::tcClearBit(integerPart *parts, unsigned int bit)
-{
- parts[bit / integerPartWidth] &=
- ~((integerPart) 1 << (bit % integerPartWidth));
+void APInt::tcClearBit(WordType *parts, unsigned bit) {
+ parts[whichWord(bit)] &= ~maskBit(bit);
}
/* Returns the bit number of the least significant set bit of a
number. If the input number has no bits set -1U is returned. */
-unsigned int
-APInt::tcLSB(const integerPart *parts, unsigned int n)
-{
- unsigned int i, lsb;
-
- for (i = 0; i < n; i++) {
- if (parts[i] != 0) {
- lsb = partLSB(parts[i]);
+unsigned APInt::tcLSB(const WordType *parts, unsigned n) {
+ for (unsigned i = 0; i < n; i++) {
+ if (parts[i] != 0) {
+ unsigned lsb = partLSB(parts[i]);
- return lsb + i * integerPartWidth;
- }
+ return lsb + i * APINT_BITS_PER_WORD;
+ }
}
return -1U;
@@ -2391,18 +2379,14 @@ APInt::tcLSB(const integerPart *parts, unsigned int n)
/* Returns the bit number of the most significant set bit of a number.
If the input number has no bits set -1U is returned. */
-unsigned int
-APInt::tcMSB(const integerPart *parts, unsigned int n)
-{
- unsigned int msb;
-
+unsigned APInt::tcMSB(const WordType *parts, unsigned n) {
do {
--n;
if (parts[n] != 0) {
- msb = partMSB(parts[n]);
+ unsigned msb = partMSB(parts[n]);
- return msb + n * integerPartWidth;
+ return msb + n * APINT_BITS_PER_WORD;
}
} while (n);
@@ -2414,31 +2398,28 @@ APInt::tcMSB(const integerPart *parts, unsigned int n)
the least significant bit of DST. All high bits above srcBITS in
DST are zero-filled. */
void
-APInt::tcExtract(integerPart *dst, unsigned int dstCount,const integerPart *src,
- unsigned int srcBits, unsigned int srcLSB)
-{
- unsigned int firstSrcPart, dstParts, shift, n;
-
- dstParts = (srcBits + integerPartWidth - 1) / integerPartWidth;
+APInt::tcExtract(WordType *dst, unsigned dstCount, const WordType *src,
+ unsigned srcBits, unsigned srcLSB) {
+ unsigned dstParts = (srcBits + APINT_BITS_PER_WORD - 1) / APINT_BITS_PER_WORD;
assert(dstParts <= dstCount);
- firstSrcPart = srcLSB / integerPartWidth;
+ unsigned firstSrcPart = srcLSB / APINT_BITS_PER_WORD;
tcAssign (dst, src + firstSrcPart, dstParts);
- shift = srcLSB % integerPartWidth;
+ unsigned shift = srcLSB % APINT_BITS_PER_WORD;
tcShiftRight (dst, dstParts, shift);
- /* We now have (dstParts * integerPartWidth - shift) bits from SRC
+ /* We now have (dstParts * APINT_BITS_PER_WORD - shift) bits from SRC
in DST. If this is less that srcBits, append the rest, else
clear the high bits. */
- n = dstParts * integerPartWidth - shift;
+ unsigned n = dstParts * APINT_BITS_PER_WORD - shift;
if (n < srcBits) {
- integerPart mask = lowBitMask (srcBits - n);
+ WordType mask = lowBitMask (srcBits - n);
dst[dstParts - 1] |= ((src[firstSrcPart + dstParts] & mask)
- << n % integerPartWidth);
+ << n % APINT_BITS_PER_WORD);
} else if (n > srcBits) {
- if (srcBits % integerPartWidth)
- dst[dstParts - 1] &= lowBitMask (srcBits % integerPartWidth);
+ if (srcBits % APINT_BITS_PER_WORD)
+ dst[dstParts - 1] &= lowBitMask (srcBits % APINT_BITS_PER_WORD);
}
/* Clear high parts. */
@@ -2447,18 +2428,12 @@ APInt::tcExtract(integerPart *dst, unsigned int dstCount,const integerPart *src,
}
/* DST += RHS + C where C is zero or one. Returns the carry flag. */
-integerPart
-APInt::tcAdd(integerPart *dst, const integerPart *rhs,
- integerPart c, unsigned int parts)
-{
- unsigned int i;
-
+APInt::WordType APInt::tcAdd(WordType *dst, const WordType *rhs,
+ WordType c, unsigned parts) {
assert(c <= 1);
- for (i = 0; i < parts; i++) {
- integerPart l;
-
- l = dst[i];
+ for (unsigned i = 0; i < parts; i++) {
+ WordType l = dst[i];
if (c) {
dst[i] += rhs[i] + 1;
c = (dst[i] <= l);
@@ -2471,19 +2446,29 @@ APInt::tcAdd(integerPart *dst, const integerPart *rhs,
return c;
}
-/* DST -= RHS + C where C is zero or one. Returns the carry flag. */
-integerPart
-APInt::tcSubtract(integerPart *dst, const integerPart *rhs,
- integerPart c, unsigned int parts)
-{
- unsigned int i;
+/// This function adds a single "word" integer, src, to the multiple
+/// "word" integer array, dst[]. dst[] is modified to reflect the addition and
+/// 1 is returned if there is a carry out, otherwise 0 is returned.
+/// @returns the carry of the addition.
+APInt::WordType APInt::tcAddPart(WordType *dst, WordType src,
+ unsigned parts) {
+ for (unsigned i = 0; i < parts; ++i) {
+ dst[i] += src;
+ if (dst[i] >= src)
+ return 0; // No need to carry so exit early.
+ src = 1; // Carry one to next digit.
+ }
- assert(c <= 1);
+ return 1;
+}
- for (i = 0; i < parts; i++) {
- integerPart l;
+/* DST -= RHS + C where C is zero or one. Returns the carry flag. */
+APInt::WordType APInt::tcSubtract(WordType *dst, const WordType *rhs,
+ WordType c, unsigned parts) {
+ assert(c <= 1);
- l = dst[i];
+ for (unsigned i = 0; i < parts; i++) {
+ WordType l = dst[i];
if (c) {
dst[i] -= rhs[i] + 1;
c = (dst[i] >= l);
@@ -2496,10 +2481,28 @@ APInt::tcSubtract(integerPart *dst, const integerPart *rhs,
return c;
}
+/// This function subtracts a single "word" (64-bit word), src, from
+/// the multi-word integer array, dst[], propagating the borrowed 1 value until
+/// no further borrowing is needed or it runs out of "words" in dst. The result
+/// is 1 if "borrowing" exhausted the digits in dst, or 0 if dst was not
+/// exhausted. In other words, if src > dst then this function returns 1,
+/// otherwise 0.
+/// @returns the borrow out of the subtraction
+APInt::WordType APInt::tcSubtractPart(WordType *dst, WordType src,
+ unsigned parts) {
+ for (unsigned i = 0; i < parts; ++i) {
+ WordType Dst = dst[i];
+ dst[i] -= src;
+ if (src <= Dst)
+ return 0; // No need to borrow so exit early.
+ src = 1; // We have to "borrow 1" from next "word"
+ }
+
+ return 1;
+}
+
/* Negate a bignum in-place. */
-void
-APInt::tcNegate(integerPart *dst, unsigned int parts)
-{
+void APInt::tcNegate(WordType *dst, unsigned parts) {
tcComplement(dst, parts);
tcIncrement(dst, parts);
}
@@ -2515,23 +2518,20 @@ APInt::tcNegate(integerPart *dst, unsigned int parts)
DSTPARTS parts of the result, and if all of the omitted higher
parts were zero return zero, otherwise overflow occurred and
return one. */
-int
-APInt::tcMultiplyPart(integerPart *dst, const integerPart *src,
- integerPart multiplier, integerPart carry,
- unsigned int srcParts, unsigned int dstParts,
- bool add)
-{
- unsigned int i, n;
-
+int APInt::tcMultiplyPart(WordType *dst, const WordType *src,
+ WordType multiplier, WordType carry,
+ unsigned srcParts, unsigned dstParts,
+ bool add) {
/* Otherwise our writes of DST kill our later reads of SRC. */
assert(dst <= src || dst >= src + srcParts);
assert(dstParts <= srcParts + 1);
/* N loops; minimum of dstParts and srcParts. */
- n = dstParts < srcParts ? dstParts: srcParts;
+ unsigned n = dstParts < srcParts ? dstParts: srcParts;
+ unsigned i;
for (i = 0; i < n; i++) {
- integerPart low, mid, high, srcPart;
+ WordType low, mid, high, srcPart;
/* [ LOW, HIGH ] = MULTIPLIER * SRC[i] + DST[i] + CARRY.
@@ -2543,7 +2543,7 @@ APInt::tcMultiplyPart(integerPart *dst, const integerPart *src,
srcPart = src[i];
- if (multiplier == 0 || srcPart == 0) {
+ if (multiplier == 0 || srcPart == 0) {
low = carry;
high = 0;
} else {
@@ -2552,14 +2552,14 @@ APInt::tcMultiplyPart(integerPart *dst, const integerPart *src,
mid = lowHalf(srcPart) * highHalf(multiplier);
high += highHalf(mid);
- mid <<= integerPartWidth / 2;
+ mid <<= APINT_BITS_PER_WORD / 2;
if (low + mid < low)
high++;
low += mid;
mid = highHalf(srcPart) * lowHalf(multiplier);
high += highHalf(mid);
- mid <<= integerPartWidth / 2;
+ mid <<= APINT_BITS_PER_WORD / 2;
if (low + mid < low)
high++;
low += mid;
@@ -2608,19 +2608,14 @@ APInt::tcMultiplyPart(integerPart *dst, const integerPart *src,
is filled with the least significant parts of the result. Returns
one if overflow occurred, otherwise zero. DST must be disjoint
from both operands. */
-int
-APInt::tcMultiply(integerPart *dst, const integerPart *lhs,
- const integerPart *rhs, unsigned int parts)
-{
- unsigned int i;
- int overflow;
-
+int APInt::tcMultiply(WordType *dst, const WordType *lhs,
+ const WordType *rhs, unsigned parts) {
assert(dst != lhs && dst != rhs);
- overflow = 0;
+ int overflow = 0;
tcSet(dst, 0, parts);
- for (i = 0; i < parts; i++)
+ for (unsigned i = 0; i < parts; i++)
overflow |= tcMultiplyPart(&dst[i], lhs, rhs[i], 0, parts,
parts - i, true);
@@ -2631,25 +2626,21 @@ APInt::tcMultiply(integerPart *dst, const integerPart *lhs,
operands. No overflow occurs. DST must be disjoint from both
operands. Returns the number of parts required to hold the
result. */
-unsigned int
-APInt::tcFullMultiply(integerPart *dst, const integerPart *lhs,
- const integerPart *rhs, unsigned int lhsParts,
- unsigned int rhsParts)
-{
+unsigned APInt::tcFullMultiply(WordType *dst, const WordType *lhs,
+ const WordType *rhs, unsigned lhsParts,
+ unsigned rhsParts) {
/* Put the narrower number on the LHS for less loops below. */
if (lhsParts > rhsParts) {
return tcFullMultiply (dst, rhs, lhs, rhsParts, lhsParts);
} else {
- unsigned int n;
-
assert(dst != lhs && dst != rhs);
tcSet(dst, 0, rhsParts);
- for (n = 0; n < lhsParts; n++)
- tcMultiplyPart(&dst[n], rhs, lhs[n], 0, rhsParts, rhsParts + 1, true);
+ for (unsigned i = 0; i < lhsParts; i++)
+ tcMultiplyPart(&dst[i], rhs, lhs[i], 0, rhsParts, rhsParts + 1, true);
- n = lhsParts + rhsParts;
+ unsigned n = lhsParts + rhsParts;
return n - (dst[n - 1] == 0);
}
@@ -2665,23 +2656,18 @@ APInt::tcFullMultiply(integerPart *dst, const integerPart *lhs,
use by the routine; its contents need not be initialized and are
destroyed. LHS, REMAINDER and SCRATCH must be distinct.
*/
-int
-APInt::tcDivide(integerPart *lhs, const integerPart *rhs,
- integerPart *remainder, integerPart *srhs,
- unsigned int parts)
-{
- unsigned int n, shiftCount;
- integerPart mask;
-
+int APInt::tcDivide(WordType *lhs, const WordType *rhs,
+ WordType *remainder, WordType *srhs,
+ unsigned parts) {
assert(lhs != remainder && lhs != srhs && remainder != srhs);
- shiftCount = tcMSB(rhs, parts) + 1;
+ unsigned shiftCount = tcMSB(rhs, parts) + 1;
if (shiftCount == 0)
return true;
- shiftCount = parts * integerPartWidth - shiftCount;
- n = shiftCount / integerPartWidth;
- mask = (integerPart) 1 << (shiftCount % integerPartWidth);
+ shiftCount = parts * APINT_BITS_PER_WORD - shiftCount;
+ unsigned n = shiftCount / APINT_BITS_PER_WORD;
+ WordType mask = (WordType) 1 << (shiftCount % APINT_BITS_PER_WORD);
tcAssign(srhs, rhs, parts);
tcShiftLeft(srhs, parts, shiftCount);
@@ -2704,7 +2690,7 @@ APInt::tcDivide(integerPart *lhs, const integerPart *rhs,
shiftCount--;
tcShiftRight(srhs, parts, 1);
if ((mask >>= 1) == 0) {
- mask = (integerPart) 1 << (integerPartWidth - 1);
+ mask = (WordType) 1 << (APINT_BITS_PER_WORD - 1);
n--;
}
}
@@ -2714,18 +2700,14 @@ APInt::tcDivide(integerPart *lhs, const integerPart *rhs,
/* Shift a bignum left COUNT bits in-place. Shifted in bits are zero.
There are no restrictions on COUNT. */
-void
-APInt::tcShiftLeft(integerPart *dst, unsigned int parts, unsigned int count)
-{
+void APInt::tcShiftLeft(WordType *dst, unsigned parts, unsigned count) {
if (count) {
- unsigned int jump, shift;
-
/* Jump is the inter-part jump; shift is is intra-part shift. */
- jump = count / integerPartWidth;
- shift = count % integerPartWidth;
+ unsigned jump = count / APINT_BITS_PER_WORD;
+ unsigned shift = count % APINT_BITS_PER_WORD;
while (parts > jump) {
- integerPart part;
+ WordType part;
parts--;
@@ -2735,7 +2717,7 @@ APInt::tcShiftLeft(integerPart *dst, unsigned int parts, unsigned int count)
if (shift) {
part <<= shift;
if (parts >= jump + 1)
- part |= dst[parts - jump - 1] >> (integerPartWidth - shift);
+ part |= dst[parts - jump - 1] >> (APINT_BITS_PER_WORD - shift);
}
dst[parts] = part;
@@ -2748,20 +2730,16 @@ APInt::tcShiftLeft(integerPart *dst, unsigned int parts, unsigned int count)
/* Shift a bignum right COUNT bits in-place. Shifted in bits are
zero. There are no restrictions on COUNT. */
-void
-APInt::tcShiftRight(integerPart *dst, unsigned int parts, unsigned int count)
-{
+void APInt::tcShiftRight(WordType *dst, unsigned parts, unsigned count) {
if (count) {
- unsigned int i, jump, shift;
-
/* Jump is the inter-part jump; shift is is intra-part shift. */
- jump = count / integerPartWidth;
- shift = count % integerPartWidth;
+ unsigned jump = count / APINT_BITS_PER_WORD;
+ unsigned shift = count % APINT_BITS_PER_WORD;
/* Perform the shift. This leaves the most significant COUNT bits
of the result at zero. */
- for (i = 0; i < parts; i++) {
- integerPart part;
+ for (unsigned i = 0; i < parts; i++) {
+ WordType part;
if (i + jump >= parts) {
part = 0;
@@ -2770,7 +2748,7 @@ APInt::tcShiftRight(integerPart *dst, unsigned int parts, unsigned int count)
if (shift) {
part >>= shift;
if (i + jump + 1 < parts)
- part |= dst[i + jump + 1] << (integerPartWidth - shift);
+ part |= dst[i + jump + 1] << (APINT_BITS_PER_WORD - shift);
}
}
@@ -2780,107 +2758,55 @@ APInt::tcShiftRight(integerPart *dst, unsigned int parts, unsigned int count)
}
/* Bitwise and of two bignums. */
-void
-APInt::tcAnd(integerPart *dst, const integerPart *rhs, unsigned int parts)
-{
- unsigned int i;
-
- for (i = 0; i < parts; i++)
+void APInt::tcAnd(WordType *dst, const WordType *rhs, unsigned parts) {
+ for (unsigned i = 0; i < parts; i++)
dst[i] &= rhs[i];
}
/* Bitwise inclusive or of two bignums. */
-void
-APInt::tcOr(integerPart *dst, const integerPart *rhs, unsigned int parts)
-{
- unsigned int i;
-
- for (i = 0; i < parts; i++)
+void APInt::tcOr(WordType *dst, const WordType *rhs, unsigned parts) {
+ for (unsigned i = 0; i < parts; i++)
dst[i] |= rhs[i];
}
/* Bitwise exclusive or of two bignums. */
-void
-APInt::tcXor(integerPart *dst, const integerPart *rhs, unsigned int parts)
-{
- unsigned int i;
-
- for (i = 0; i < parts; i++)
+void APInt::tcXor(WordType *dst, const WordType *rhs, unsigned parts) {
+ for (unsigned i = 0; i < parts; i++)
dst[i] ^= rhs[i];
}
/* Complement a bignum in-place. */
-void
-APInt::tcComplement(integerPart *dst, unsigned int parts)
-{
- unsigned int i;
-
- for (i = 0; i < parts; i++)
+void APInt::tcComplement(WordType *dst, unsigned parts) {
+ for (unsigned i = 0; i < parts; i++)
dst[i] = ~dst[i];
}
/* Comparison (unsigned) of two bignums. */
-int
-APInt::tcCompare(const integerPart *lhs, const integerPart *rhs,
- unsigned int parts)
-{
+int APInt::tcCompare(const WordType *lhs, const WordType *rhs,
+ unsigned parts) {
while (parts) {
- parts--;
- if (lhs[parts] == rhs[parts])
- continue;
+ parts--;
+ if (lhs[parts] == rhs[parts])
+ continue;
- if (lhs[parts] > rhs[parts])
- return 1;
- else
- return -1;
- }
+ return (lhs[parts] > rhs[parts]) ? 1 : -1;
+ }
return 0;
}
-/* Increment a bignum in-place, return the carry flag. */
-integerPart
-APInt::tcIncrement(integerPart *dst, unsigned int parts)
-{
- unsigned int i;
-
- for (i = 0; i < parts; i++)
- if (++dst[i] != 0)
- break;
-
- return i == parts;
-}
-
-/* Decrement a bignum in-place, return the borrow flag. */
-integerPart
-APInt::tcDecrement(integerPart *dst, unsigned int parts) {
- for (unsigned int i = 0; i < parts; i++) {
- // If the current word is non-zero, then the decrement has no effect on the
- // higher-order words of the integer and no borrow can occur. Exit early.
- if (dst[i]--)
- return 0;
- }
- // If every word was zero, then there is a borrow.
- return 1;
-}
-
-
/* Set the least significant BITS bits of a bignum, clear the
rest. */
-void
-APInt::tcSetLeastSignificantBits(integerPart *dst, unsigned int parts,
- unsigned int bits)
-{
- unsigned int i;
-
- i = 0;
- while (bits > integerPartWidth) {
- dst[i++] = ~(integerPart) 0;
- bits -= integerPartWidth;
+void APInt::tcSetLeastSignificantBits(WordType *dst, unsigned parts,
+ unsigned bits) {
+ unsigned i = 0;
+ while (bits > APINT_BITS_PER_WORD) {
+ dst[i++] = ~(WordType) 0;
+ bits -= APINT_BITS_PER_WORD;
}
if (bits)
- dst[i++] = ~(integerPart) 0 >> (integerPartWidth - bits);
+ dst[i++] = ~(WordType) 0 >> (APINT_BITS_PER_WORD - bits);
while (i < parts)
dst[i++] = 0;
diff --git a/lib/Support/ARMAttributeParser.cpp b/lib/Support/ARMAttributeParser.cpp
new file mode 100644
index 000000000000..63e800a5b78b
--- /dev/null
+++ b/lib/Support/ARMAttributeParser.cpp
@@ -0,0 +1,708 @@
+//===--- ARMAttributeParser.cpp - ARM Attribute Information Printer -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ARMAttributeParser.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::ARMBuildAttrs;
+
+
+static const EnumEntry<unsigned> TagNames[] = {
+ { "Tag_File", ARMBuildAttrs::File },
+ { "Tag_Section", ARMBuildAttrs::Section },
+ { "Tag_Symbol", ARMBuildAttrs::Symbol },
+};
+
+namespace llvm {
+#define ATTRIBUTE_HANDLER(Attr_) \
+ { ARMBuildAttrs::Attr_, &ARMAttributeParser::Attr_ }
+
+const ARMAttributeParser::DisplayHandler
+ARMAttributeParser::DisplayRoutines[] = {
+ { ARMBuildAttrs::CPU_raw_name, &ARMAttributeParser::StringAttribute, },
+ { ARMBuildAttrs::CPU_name, &ARMAttributeParser::StringAttribute },
+ ATTRIBUTE_HANDLER(CPU_arch),
+ ATTRIBUTE_HANDLER(CPU_arch_profile),
+ ATTRIBUTE_HANDLER(ARM_ISA_use),
+ ATTRIBUTE_HANDLER(THUMB_ISA_use),
+ ATTRIBUTE_HANDLER(FP_arch),
+ ATTRIBUTE_HANDLER(WMMX_arch),
+ ATTRIBUTE_HANDLER(Advanced_SIMD_arch),
+ ATTRIBUTE_HANDLER(PCS_config),
+ ATTRIBUTE_HANDLER(ABI_PCS_R9_use),
+ ATTRIBUTE_HANDLER(ABI_PCS_RW_data),
+ ATTRIBUTE_HANDLER(ABI_PCS_RO_data),
+ ATTRIBUTE_HANDLER(ABI_PCS_GOT_use),
+ ATTRIBUTE_HANDLER(ABI_PCS_wchar_t),
+ ATTRIBUTE_HANDLER(ABI_FP_rounding),
+ ATTRIBUTE_HANDLER(ABI_FP_denormal),
+ ATTRIBUTE_HANDLER(ABI_FP_exceptions),
+ ATTRIBUTE_HANDLER(ABI_FP_user_exceptions),
+ ATTRIBUTE_HANDLER(ABI_FP_number_model),
+ ATTRIBUTE_HANDLER(ABI_align_needed),
+ ATTRIBUTE_HANDLER(ABI_align_preserved),
+ ATTRIBUTE_HANDLER(ABI_enum_size),
+ ATTRIBUTE_HANDLER(ABI_HardFP_use),
+ ATTRIBUTE_HANDLER(ABI_VFP_args),
+ ATTRIBUTE_HANDLER(ABI_WMMX_args),
+ ATTRIBUTE_HANDLER(ABI_optimization_goals),
+ ATTRIBUTE_HANDLER(ABI_FP_optimization_goals),
+ ATTRIBUTE_HANDLER(compatibility),
+ ATTRIBUTE_HANDLER(CPU_unaligned_access),
+ ATTRIBUTE_HANDLER(FP_HP_extension),
+ ATTRIBUTE_HANDLER(ABI_FP_16bit_format),
+ ATTRIBUTE_HANDLER(MPextension_use),
+ ATTRIBUTE_HANDLER(DIV_use),
+ ATTRIBUTE_HANDLER(DSP_extension),
+ ATTRIBUTE_HANDLER(T2EE_use),
+ ATTRIBUTE_HANDLER(Virtualization_use),
+ ATTRIBUTE_HANDLER(nodefaults)
+};
+
+#undef ATTRIBUTE_HANDLER
+
+uint64_t ARMAttributeParser::ParseInteger(const uint8_t *Data,
+ uint32_t &Offset) {
+ unsigned Length;
+ uint64_t Value = decodeULEB128(Data + Offset, &Length);
+ Offset = Offset + Length;
+ return Value;
+}
+
+StringRef ARMAttributeParser::ParseString(const uint8_t *Data,
+ uint32_t &Offset) {
+ const char *String = reinterpret_cast<const char*>(Data + Offset);
+ size_t Length = std::strlen(String);
+ Offset = Offset + Length + 1;
+ return StringRef(String, Length);
+}
+
+void ARMAttributeParser::IntegerAttribute(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ Attributes.insert(std::make_pair(Tag, Value));
+
+ if (SW)
+ SW->printNumber(ARMBuildAttrs::AttrTypeAsString(Tag), Value);
+}
+
+void ARMAttributeParser::StringAttribute(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false);
+ StringRef ValueDesc = ParseString(Data, Offset);
+
+ if (SW) {
+ DictScope AS(*SW, "Attribute");
+ SW->printNumber("Tag", Tag);
+ if (!TagName.empty())
+ SW->printString("TagName", TagName);
+ SW->printString("Value", ValueDesc);
+ }
+}
+
+void ARMAttributeParser::PrintAttribute(unsigned Tag, unsigned Value,
+ StringRef ValueDesc) {
+ Attributes.insert(std::make_pair(Tag, Value));
+
+ if (SW) {
+ StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag,
+ /*TagPrefix*/false);
+ DictScope AS(*SW, "Attribute");
+ SW->printNumber("Tag", Tag);
+ SW->printNumber("Value", Value);
+ if (!TagName.empty())
+ SW->printString("TagName", TagName);
+ if (!ValueDesc.empty())
+ SW->printString("Description", ValueDesc);
+ }
+}
+
+void ARMAttributeParser::CPU_arch(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "Pre-v4", "ARM v4", "ARM v4T", "ARM v5T", "ARM v5TE", "ARM v5TEJ", "ARM v6",
+ "ARM v6KZ", "ARM v6T2", "ARM v6K", "ARM v7", "ARM v6-M", "ARM v6S-M",
+ "ARM v7E-M", "ARM v8"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::CPU_arch_profile(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ uint64_t Encoded = ParseInteger(Data, Offset);
+
+ StringRef Profile;
+ switch (Encoded) {
+ default: Profile = "Unknown"; break;
+ case 'A': Profile = "Application"; break;
+ case 'R': Profile = "Real-time"; break;
+ case 'M': Profile = "Microcontroller"; break;
+ case 'S': Profile = "Classic"; break;
+ case 0: Profile = "None"; break;
+ }
+
+ PrintAttribute(Tag, Encoded, Profile);
+}
+
+void ARMAttributeParser::ARM_ISA_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = { "Not Permitted", "Permitted" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::THUMB_ISA_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = { "Not Permitted", "Thumb-1", "Thumb-2" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::FP_arch(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "Not Permitted", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16", "VFPv4",
+ "VFPv4-D16", "ARMv8-a FP", "ARMv8-a FP-D16"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::WMMX_arch(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = { "Not Permitted", "WMMXv1", "WMMXv2" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::Advanced_SIMD_arch(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "Not Permitted", "NEONv1", "NEONv2+FMA", "ARMv8-a NEON", "ARMv8.1-a NEON"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::PCS_config(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "None", "Bare Platform", "Linux Application", "Linux DSO", "Palm OS 2004",
+ "Reserved (Palm OS)", "Symbian OS 2004", "Reserved (Symbian OS)"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_PCS_R9_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = { "v6", "Static Base", "TLS", "Unused" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_PCS_RW_data(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "Absolute", "PC-relative", "SB-relative", "Not Permitted"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_PCS_RO_data(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "Absolute", "PC-relative", "Not Permitted"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_PCS_GOT_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "Not Permitted", "Direct", "GOT-Indirect"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_PCS_wchar_t(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "Not Permitted", "Unknown", "2-byte", "Unknown", "4-byte"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_FP_rounding(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = { "IEEE-754", "Runtime" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_FP_denormal(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "Unsupported", "IEEE-754", "Sign Only"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_FP_exceptions(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = { "Not Permitted", "IEEE-754" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_FP_user_exceptions(AttrType Tag,
+ const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = { "Not Permitted", "IEEE-754" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_FP_number_model(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "Not Permitted", "Finite Only", "RTABI", "IEEE-754"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_align_needed(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "Not Permitted", "8-byte alignment", "4-byte alignment", "Reserved"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+
+ std::string Description;
+ if (Value < array_lengthof(Strings))
+ Description = std::string(Strings[Value]);
+ else if (Value <= 12)
+ Description = std::string("8-byte alignment, ") + utostr(1ULL << Value)
+ + std::string("-byte extended alignment");
+ else
+ Description = "Invalid";
+
+ PrintAttribute(Tag, Value, Description);
+}
+
+void ARMAttributeParser::ABI_align_preserved(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "Not Required", "8-byte data alignment", "8-byte data and code alignment",
+ "Reserved"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+
+ std::string Description;
+ if (Value < array_lengthof(Strings))
+ Description = std::string(Strings[Value]);
+ else if (Value <= 12)
+ Description = std::string("8-byte stack alignment, ") +
+ utostr(1ULL << Value) + std::string("-byte data alignment");
+ else
+ Description = "Invalid";
+
+ PrintAttribute(Tag, Value, Description);
+}
+
+void ARMAttributeParser::ABI_enum_size(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "Not Permitted", "Packed", "Int32", "External Int32"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_HardFP_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "Tag_FP_arch", "Single-Precision", "Reserved", "Tag_FP_arch (deprecated)"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_VFP_args(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "AAPCS", "AAPCS VFP", "Custom", "Not Permitted"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_WMMX_args(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = { "AAPCS", "iWMMX", "Custom" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_optimization_goals(AttrType Tag,
+ const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Debugging",
+ "Best Debugging"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_FP_optimization_goals(AttrType Tag,
+ const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Accuracy",
+ "Best Accuracy"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::compatibility(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ uint64_t Integer = ParseInteger(Data, Offset);
+ StringRef String = ParseString(Data, Offset);
+
+ if (SW) {
+ DictScope AS(*SW, "Attribute");
+ SW->printNumber("Tag", Tag);
+ SW->startLine() << "Value: " << Integer << ", " << String << '\n';
+ SW->printString("TagName", AttrTypeAsString(Tag, /*TagPrefix*/false));
+ switch (Integer) {
+ case 0:
+ SW->printString("Description", StringRef("No Specific Requirements"));
+ break;
+ case 1:
+ SW->printString("Description", StringRef("AEABI Conformant"));
+ break;
+ default:
+ SW->printString("Description", StringRef("AEABI Non-Conformant"));
+ break;
+ }
+ }
+}
+
+void ARMAttributeParser::CPU_unaligned_access(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = { "Not Permitted", "v6-style" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::FP_HP_extension(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = { "If Available", "Permitted" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_FP_16bit_format(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = { "Not Permitted", "IEEE-754", "VFPv3" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::MPextension_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = { "Not Permitted", "Permitted" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::DIV_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "If Available", "Not Permitted", "Permitted"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::DSP_extension(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = { "Not Permitted", "Permitted" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::T2EE_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = { "Not Permitted", "Permitted" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::Virtualization_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *const Strings[] = {
+ "Not Permitted", "TrustZone", "Virtualization Extensions",
+ "TrustZone + Virtualization Extensions"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::nodefaults(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ uint64_t Value = ParseInteger(Data, Offset);
+ PrintAttribute(Tag, Value, "Unspecified Tags UNDEFINED");
+}
+
+void ARMAttributeParser::ParseIndexList(const uint8_t *Data, uint32_t &Offset,
+ SmallVectorImpl<uint8_t> &IndexList) {
+ for (;;) {
+ unsigned Length;
+ uint64_t Value = decodeULEB128(Data + Offset, &Length);
+ Offset = Offset + Length;
+ if (Value == 0)
+ break;
+ IndexList.push_back(Value);
+ }
+}
+
+void ARMAttributeParser::ParseAttributeList(const uint8_t *Data,
+ uint32_t &Offset, uint32_t Length) {
+ while (Offset < Length) {
+ unsigned Length;
+ uint64_t Tag = decodeULEB128(Data + Offset, &Length);
+ Offset += Length;
+
+ bool Handled = false;
+ for (unsigned AHI = 0, AHE = array_lengthof(DisplayRoutines);
+ AHI != AHE && !Handled; ++AHI) {
+ if (DisplayRoutines[AHI].Attribute == Tag) {
+ (this->*DisplayRoutines[AHI].Routine)(ARMBuildAttrs::AttrType(Tag),
+ Data, Offset);
+ Handled = true;
+ break;
+ }
+ }
+ if (!Handled) {
+ if (Tag < 32) {
+ errs() << "unhandled AEABI Tag " << Tag
+ << " (" << ARMBuildAttrs::AttrTypeAsString(Tag) << ")\n";
+ continue;
+ }
+
+ if (Tag % 2 == 0)
+ IntegerAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset);
+ else
+ StringAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset);
+ }
+ }
+}
+
+void ARMAttributeParser::ParseSubsection(const uint8_t *Data, uint32_t Length) {
+ uint32_t Offset = sizeof(uint32_t); /* SectionLength */
+
+ const char *VendorName = reinterpret_cast<const char*>(Data + Offset);
+ size_t VendorNameLength = std::strlen(VendorName);
+ Offset = Offset + VendorNameLength + 1;
+
+ if (SW) {
+ SW->printNumber("SectionLength", Length);
+ SW->printString("Vendor", StringRef(VendorName, VendorNameLength));
+ }
+
+ if (StringRef(VendorName, VendorNameLength).lower() != "aeabi") {
+ return;
+ }
+
+ while (Offset < Length) {
+ /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size
+ uint8_t Tag = Data[Offset];
+ Offset = Offset + sizeof(Tag);
+
+ uint32_t Size =
+ *reinterpret_cast<const support::ulittle32_t*>(Data + Offset);
+ Offset = Offset + sizeof(Size);
+
+ if (SW) {
+ SW->printEnum("Tag", Tag, makeArrayRef(TagNames));
+ SW->printNumber("Size", Size);
+ }
+
+ if (Size > Length) {
+ errs() << "subsection length greater than section length\n";
+ return;
+ }
+
+ StringRef ScopeName, IndexName;
+ SmallVector<uint8_t, 8> Indicies;
+ switch (Tag) {
+ case ARMBuildAttrs::File:
+ ScopeName = "FileAttributes";
+ break;
+ case ARMBuildAttrs::Section:
+ ScopeName = "SectionAttributes";
+ IndexName = "Sections";
+ ParseIndexList(Data, Offset, Indicies);
+ break;
+ case ARMBuildAttrs::Symbol:
+ ScopeName = "SymbolAttributes";
+ IndexName = "Symbols";
+ ParseIndexList(Data, Offset, Indicies);
+ break;
+ default:
+ errs() << "unrecognised tag: 0x" << utohexstr(Tag) << '\n';
+ return;
+ }
+
+ if (SW) {
+ DictScope ASS(*SW, ScopeName);
+ if (!Indicies.empty())
+ SW->printList(IndexName, Indicies);
+ ParseAttributeList(Data, Offset, Length);
+ } else {
+ ParseAttributeList(Data, Offset, Length);
+ }
+ }
+}
+
+void ARMAttributeParser::Parse(ArrayRef<uint8_t> Section, bool isLittle) {
+ size_t Offset = 1;
+ unsigned SectionNumber = 0;
+
+ while (Offset < Section.size()) {
+ uint32_t SectionLength = isLittle ?
+ support::endian::read32le(Section.data() + Offset) :
+ support::endian::read32be(Section.data() + Offset);
+
+ if (SW) {
+ SW->startLine() << "Section " << ++SectionNumber << " {\n";
+ SW->indent();
+ }
+
+ ParseSubsection(Section.data() + Offset, SectionLength);
+ Offset = Offset + SectionLength;
+
+ if (SW) {
+ SW->unindent();
+ SW->startLine() << "}\n";
+ }
+ }
+}
+}
+
diff --git a/lib/Support/BinaryStreamError.cpp b/lib/Support/BinaryStreamError.cpp
new file mode 100644
index 000000000000..60f5e21f041a
--- /dev/null
+++ b/lib/Support/BinaryStreamError.cpp
@@ -0,0 +1,56 @@
+//===- BinaryStreamError.cpp - Error extensions for streams -----*- 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/BinaryStreamError.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+char BinaryStreamError::ID = 0;
+
+BinaryStreamError::BinaryStreamError(stream_error_code C)
+ : BinaryStreamError(C, "") {}
+
+BinaryStreamError::BinaryStreamError(StringRef Context)
+ : BinaryStreamError(stream_error_code::unspecified, Context) {}
+
+BinaryStreamError::BinaryStreamError(stream_error_code C, StringRef Context)
+ : Code(C) {
+ ErrMsg = "Stream Error: ";
+ switch (C) {
+ case stream_error_code::unspecified:
+ ErrMsg += "An unspecified error has occurred.";
+ break;
+ case stream_error_code::stream_too_short:
+ ErrMsg += "The stream is too short to perform the requested operation.";
+ break;
+ case stream_error_code::invalid_array_size:
+ ErrMsg += "The buffer size is not a multiple of the array element size.";
+ break;
+ case stream_error_code::invalid_offset:
+ ErrMsg += "The specified offset is invalid for the current stream.";
+ break;
+ case stream_error_code::filesystem_error:
+ ErrMsg += "An I/O error occurred on the file system.";
+ break;
+ }
+
+ if (!Context.empty()) {
+ ErrMsg += " ";
+ ErrMsg += Context;
+ }
+}
+
+void BinaryStreamError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; }
+
+StringRef BinaryStreamError::getErrorMessage() const { return ErrMsg; }
+
+std::error_code BinaryStreamError::convertToErrorCode() const {
+ return inconvertibleErrorCode();
+}
diff --git a/lib/Support/BinaryStreamReader.cpp b/lib/Support/BinaryStreamReader.cpp
new file mode 100644
index 000000000000..c7a2e0ddb179
--- /dev/null
+++ b/lib/Support/BinaryStreamReader.cpp
@@ -0,0 +1,95 @@
+//===- BinaryStreamReader.cpp - Reads objects from a binary stream --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/BinaryStreamReader.h"
+
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/BinaryStreamRef.h"
+
+using namespace llvm;
+
+BinaryStreamReader::BinaryStreamReader(BinaryStreamRef S)
+ : Stream(S), Offset(0) {}
+
+Error BinaryStreamReader::readLongestContiguousChunk(
+ ArrayRef<uint8_t> &Buffer) {
+ if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer))
+ return EC;
+ Offset += Buffer.size();
+ return Error::success();
+}
+
+Error BinaryStreamReader::readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size) {
+ if (auto EC = Stream.readBytes(Offset, Size, Buffer))
+ return EC;
+ Offset += Size;
+ return Error::success();
+}
+
+Error BinaryStreamReader::readCString(StringRef &Dest) {
+ // TODO: This could be made more efficient by using readLongestContiguousChunk
+ // and searching for null terminators in the resulting buffer.
+
+ uint32_t Length = 0;
+ // First compute the length of the string by reading 1 byte at a time.
+ uint32_t OriginalOffset = getOffset();
+ const char *C;
+ while (true) {
+ if (auto EC = readObject(C))
+ return EC;
+ if (*C == '\0')
+ break;
+ ++Length;
+ }
+ // Now go back and request a reference for that many bytes.
+ uint32_t NewOffset = getOffset();
+ setOffset(OriginalOffset);
+
+ if (auto EC = readFixedString(Dest, Length))
+ return EC;
+
+ // Now set the offset back to where it was after we calculated the length.
+ setOffset(NewOffset);
+ return Error::success();
+}
+
+Error BinaryStreamReader::readFixedString(StringRef &Dest, uint32_t Length) {
+ ArrayRef<uint8_t> Bytes;
+ if (auto EC = readBytes(Bytes, Length))
+ return EC;
+ Dest = StringRef(reinterpret_cast<const char *>(Bytes.begin()), Bytes.size());
+ return Error::success();
+}
+
+Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref) {
+ return readStreamRef(Ref, bytesRemaining());
+}
+
+Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref, uint32_t Length) {
+ if (bytesRemaining() < Length)
+ return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
+ Ref = Stream.slice(Offset, Length);
+ Offset += Length;
+ return Error::success();
+}
+
+Error BinaryStreamReader::skip(uint32_t Amount) {
+ if (Amount > bytesRemaining())
+ return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
+ Offset += Amount;
+ return Error::success();
+}
+
+uint8_t BinaryStreamReader::peek() const {
+ ArrayRef<uint8_t> Buffer;
+ auto EC = Stream.readBytes(Offset, 1, Buffer);
+ assert(!EC && "Cannot peek an empty buffer!");
+ llvm::consumeError(std::move(EC));
+ return Buffer[0];
+}
diff --git a/lib/Support/BinaryStreamWriter.cpp b/lib/Support/BinaryStreamWriter.cpp
new file mode 100644
index 000000000000..d60b75642d0f
--- /dev/null
+++ b/lib/Support/BinaryStreamWriter.cpp
@@ -0,0 +1,68 @@
+//===- BinaryStreamWriter.cpp - Writes objects to a BinaryStream ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/BinaryStreamWriter.h"
+
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamRef.h"
+
+using namespace llvm;
+
+BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef S)
+ : Stream(S), Offset(0) {}
+
+Error BinaryStreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) {
+ if (auto EC = Stream.writeBytes(Offset, Buffer))
+ return EC;
+ Offset += Buffer.size();
+ return Error::success();
+}
+
+Error BinaryStreamWriter::writeCString(StringRef Str) {
+ if (auto EC = writeFixedString(Str))
+ return EC;
+ if (auto EC = writeObject('\0'))
+ return EC;
+
+ return Error::success();
+}
+
+Error BinaryStreamWriter::writeFixedString(StringRef Str) {
+ return writeBytes(ArrayRef<uint8_t>(Str.bytes_begin(), Str.bytes_end()));
+}
+
+Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) {
+ return writeStreamRef(Ref, Ref.getLength());
+}
+
+Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_t Length) {
+ BinaryStreamReader SrcReader(Ref.slice(0, Length));
+ // This is a bit tricky. If we just call readBytes, we are requiring that it
+ // return us the entire stream as a contiguous buffer. There is no guarantee
+ // this can be satisfied by returning a reference straight from the buffer, as
+ // an implementation may not store all data in a single contiguous buffer. So
+ // we iterate over each contiguous chunk, writing each one in succession.
+ while (SrcReader.bytesRemaining() > 0) {
+ ArrayRef<uint8_t> Chunk;
+ if (auto EC = SrcReader.readLongestContiguousChunk(Chunk))
+ return EC;
+ if (auto EC = writeBytes(Chunk))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error BinaryStreamWriter::padToAlignment(uint32_t Align) {
+ uint32_t NewOffset = alignTo(Offset, Align);
+ if (NewOffset > getLength())
+ return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
+ Offset = NewOffset;
+ return Error::success();
+}
diff --git a/lib/Support/BranchProbability.cpp b/lib/Support/BranchProbability.cpp
index 1c41659cf8df..44ad110d456a 100644
--- a/lib/Support/BranchProbability.cpp
+++ b/lib/Support/BranchProbability.cpp
@@ -32,7 +32,9 @@ raw_ostream &BranchProbability::print(raw_ostream &OS) const {
Percent);
}
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void BranchProbability::dump() const { print(dbgs()) << '\n'; }
+#endif
BranchProbability::BranchProbability(uint32_t Numerator, uint32_t Denominator) {
assert(Denominator > 0 && "Denominator cannot be 0!");
diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt
index 15418ad2fd06..491614b4bf63 100644
--- a/lib/Support/CMakeLists.txt
+++ b/lib/Support/CMakeLists.txt
@@ -9,6 +9,9 @@ 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})
+ endif()
if(LLVM_ENABLE_TERMINFO)
if(HAVE_TERMINFO)
set(system_libs ${system_libs} ${TERMINFO_LIBS})
@@ -17,7 +20,7 @@ elseif( CMAKE_HOST_UNIX )
if( LLVM_ENABLE_THREADS AND HAVE_LIBATOMIC )
set(system_libs ${system_libs} atomic)
endif()
- set(system_libs ${system_libs} ${PTHREAD_LIB})
+ set(system_libs ${system_libs} ${LLVM_PTHREAD_LIB})
if ( LLVM_ENABLE_ZLIB AND HAVE_LIBZ )
set(system_libs ${system_libs} z)
endif()
@@ -31,8 +34,12 @@ add_llvm_library(LLVMSupport
APInt.cpp
APSInt.cpp
ARMBuildAttrs.cpp
+ ARMAttributeParser.cpp
ARMWinEH.cpp
Allocator.cpp
+ BinaryStreamError.cpp
+ BinaryStreamReader.cpp
+ BinaryStreamWriter.cpp
BlockFrequency.cpp
BranchProbability.cpp
CachePruning.cpp
@@ -46,6 +53,7 @@ add_llvm_library(LLVMSupport
CrashRecoveryContext.cpp
DataExtractor.cpp
Debug.cpp
+ DebugCounter.cpp
DeltaAlgorithm.cpp
DAGDeltaAlgorithm.cpp
Dwarf.cpp
@@ -66,6 +74,7 @@ add_llvm_library(LLVMSupport
LineIterator.cpp
Locale.cpp
LockFileManager.cpp
+ LowLevelType.cpp
ManagedStatic.cpp
MathExtras.cpp
MemoryBuffer.cpp
@@ -134,7 +143,7 @@ add_llvm_library(LLVMSupport
Windows
${LLVM_MAIN_INCLUDE_DIR}/llvm/ADT
${LLVM_MAIN_INCLUDE_DIR}/llvm/Support
-
+ ${Backtrace_INCLUDE_DIRS}
LINK_LIBS ${system_libs}
)
diff --git a/lib/Support/CachePruning.cpp b/lib/Support/CachePruning.cpp
index 3831625962ca..aca123639565 100644
--- a/lib/Support/CachePruning.cpp
+++ b/lib/Support/CachePruning.cpp
@@ -15,6 +15,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -33,8 +34,75 @@ static void writeTimestampFile(StringRef TimestampFile) {
raw_fd_ostream Out(TimestampFile.str(), EC, sys::fs::F_None);
}
+static Expected<std::chrono::seconds> parseDuration(StringRef Duration) {
+ if (Duration.empty())
+ return make_error<StringError>("Duration must not be empty",
+ inconvertibleErrorCode());
+
+ StringRef NumStr = Duration.slice(0, Duration.size()-1);
+ uint64_t Num;
+ if (NumStr.getAsInteger(0, Num))
+ return make_error<StringError>("'" + NumStr + "' not an integer",
+ inconvertibleErrorCode());
+
+ switch (Duration.back()) {
+ case 's':
+ return std::chrono::seconds(Num);
+ case 'm':
+ return std::chrono::minutes(Num);
+ case 'h':
+ return std::chrono::hours(Num);
+ default:
+ return make_error<StringError>("'" + Duration +
+ "' must end with one of 's', 'm' or 'h'",
+ inconvertibleErrorCode());
+ }
+}
+
+Expected<CachePruningPolicy>
+llvm::parseCachePruningPolicy(StringRef PolicyStr) {
+ CachePruningPolicy Policy;
+ std::pair<StringRef, StringRef> P = {"", PolicyStr};
+ while (!P.second.empty()) {
+ P = P.second.split(':');
+
+ StringRef Key, Value;
+ std::tie(Key, Value) = P.first.split('=');
+ if (Key == "prune_interval") {
+ auto DurationOrErr = parseDuration(Value);
+ if (!DurationOrErr)
+ return DurationOrErr.takeError();
+ Policy.Interval = *DurationOrErr;
+ } else if (Key == "prune_after") {
+ auto DurationOrErr = parseDuration(Value);
+ if (!DurationOrErr)
+ return DurationOrErr.takeError();
+ Policy.Expiration = *DurationOrErr;
+ } else if (Key == "cache_size") {
+ if (Value.back() != '%')
+ return make_error<StringError>("'" + Value + "' must be a percentage",
+ inconvertibleErrorCode());
+ StringRef SizeStr = Value.slice(0, Value.size() - 1);
+ uint64_t Size;
+ if (SizeStr.getAsInteger(0, Size))
+ return make_error<StringError>("'" + SizeStr + "' not an integer",
+ inconvertibleErrorCode());
+ if (Size > 100)
+ return make_error<StringError>("'" + SizeStr +
+ "' must be between 0 and 100",
+ inconvertibleErrorCode());
+ Policy.PercentageOfAvailableSpace = Size;
+ } else {
+ return make_error<StringError>("Unknown key: '" + Key + "'",
+ inconvertibleErrorCode());
+ }
+ }
+
+ return Policy;
+}
+
/// Prune the cache of files that haven't been accessed in a long time.
-bool CachePruning::prune() {
+bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) {
using namespace std::chrono;
if (Path.empty())
@@ -47,7 +115,11 @@ bool CachePruning::prune() {
if (!isPathDir)
return false;
- if (Expiration == seconds(0) && PercentageOfAvailableSpace == 0) {
+ Policy.PercentageOfAvailableSpace =
+ std::min(Policy.PercentageOfAvailableSpace, 100u);
+
+ if (Policy.Expiration == seconds(0) &&
+ Policy.PercentageOfAvailableSpace == 0) {
DEBUG(dbgs() << "No pruning settings set, exit early\n");
// Nothing will be pruned, early exit
return false;
@@ -67,12 +139,12 @@ bool CachePruning::prune() {
return false;
}
} else {
- if (Interval == seconds(0)) {
+ if (Policy.Interval == seconds(0)) {
// Check whether the time stamp is older than our pruning interval.
// If not, do nothing.
const auto TimeStampModTime = FileStatus.getLastModificationTime();
auto TimeStampAge = CurrentTime - TimeStampModTime;
- if (TimeStampAge <= Interval) {
+ if (TimeStampAge <= Policy.Interval) {
DEBUG(dbgs() << "Timestamp file too recent ("
<< duration_cast<seconds>(TimeStampAge).count()
<< "s old), do not prune.\n");
@@ -85,7 +157,7 @@ bool CachePruning::prune() {
writeTimestampFile(TimestampFile);
}
- bool ShouldComputeSize = (PercentageOfAvailableSpace > 0);
+ bool ShouldComputeSize = (Policy.PercentageOfAvailableSpace > 0);
// Keep track of space
std::set<std::pair<uint64_t, std::string>> FileSizes;
@@ -108,8 +180,11 @@ bool CachePruning::prune() {
// Walk all of the files within this directory.
for (sys::fs::directory_iterator File(CachePathNative, EC), FileEnd;
File != FileEnd && !EC; File.increment(EC)) {
- // Do not touch the timestamp.
- if (File->path() == TimestampFile)
+ // Ignore any files not beginning with the string "llvmcache-". This
+ // includes the timestamp file as well as any files created by the user.
+ // This acts as a safeguard against data loss if the user specifies the
+ // wrong directory as their cache directory.
+ if (!sys::path::filename(File->path()).startswith("llvmcache-"))
continue;
// Look at this file. If we can't stat it, there's nothing interesting
@@ -122,7 +197,7 @@ bool CachePruning::prune() {
// If the file hasn't been used recently enough, delete it
const auto FileAccessTime = FileStatus.getLastAccessedTime();
auto FileAge = CurrentTime - FileAccessTime;
- if (FileAge > Expiration) {
+ if (FileAge > Policy.Expiration) {
DEBUG(dbgs() << "Remove " << File->path() << " ("
<< duration_cast<seconds>(FileAge).count() << "s old)\n");
sys::fs::remove(File->path());
@@ -143,9 +218,11 @@ bool CachePruning::prune() {
auto AvailableSpace = TotalSize + SpaceInfo.free;
auto FileAndSize = FileSizes.rbegin();
DEBUG(dbgs() << "Occupancy: " << ((100 * TotalSize) / AvailableSpace)
- << "% target is: " << PercentageOfAvailableSpace << "\n");
+ << "% target is: " << Policy.PercentageOfAvailableSpace
+ << "\n");
// Remove the oldest accessed files first, till we get below the threshold
- while (((100 * TotalSize) / AvailableSpace) > PercentageOfAvailableSpace &&
+ while (((100 * TotalSize) / AvailableSpace) >
+ Policy.PercentageOfAvailableSpace &&
FileAndSize != FileSizes.rend()) {
// Remove the file.
sys::fs::remove(FileAndSize->second);
diff --git a/lib/Support/Chrono.cpp b/lib/Support/Chrono.cpp
index cdadbd879979..daccaf1fc103 100644
--- a/lib/Support/Chrono.cpp
+++ b/lib/Support/Chrono.cpp
@@ -16,6 +16,13 @@ namespace llvm {
using namespace sys;
+const char llvm::detail::unit<std::ratio<3600>>::value[] = "h";
+const char llvm::detail::unit<std::ratio<60>>::value[] = "m";
+const char llvm::detail::unit<std::ratio<1>>::value[] = "s";
+const char llvm::detail::unit<std::milli>::value[] = "ms";
+const char llvm::detail::unit<std::micro>::value[] = "us";
+const char llvm::detail::unit<std::nano>::value[] = "ns";
+
static inline struct tm getStructTM(TimePoint<> TP) {
struct tm Storage;
std::time_t OurTime = toTimeT(TP);
diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp
index 3889902eea54..f4a9108b8544 100644
--- a/lib/Support/CommandLine.cpp
+++ b/lib/Support/CommandLine.cpp
@@ -123,7 +123,7 @@ public:
void ResetAllOptionOccurrences();
bool ParseCommandLineOptions(int argc, const char *const *argv,
- StringRef Overview, bool IgnoreErrors);
+ StringRef Overview, raw_ostream *Errs = nullptr);
void addLiteralOption(Option &Opt, SubCommand *SC, StringRef Name) {
if (Opt.hasArgStr())
@@ -1013,9 +1013,9 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar,
}
bool cl::ParseCommandLineOptions(int argc, const char *const *argv,
- StringRef Overview, bool IgnoreErrors) {
+ StringRef Overview, raw_ostream *Errs) {
return GlobalParser->ParseCommandLineOptions(argc, argv, Overview,
- IgnoreErrors);
+ Errs);
}
void CommandLineParser::ResetAllOptionOccurrences() {
@@ -1030,7 +1030,7 @@ void CommandLineParser::ResetAllOptionOccurrences() {
bool CommandLineParser::ParseCommandLineOptions(int argc,
const char *const *argv,
StringRef Overview,
- bool IgnoreErrors) {
+ raw_ostream *Errs) {
assert(hasOptions() && "No options specified!");
// Expand response files.
@@ -1045,6 +1045,9 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
ProgramName = sys::path::filename(StringRef(argv[0]));
ProgramOverview = Overview;
+ bool IgnoreErrors = Errs;
+ if (!Errs)
+ Errs = &errs();
bool ErrorParsing = false;
// Check out the positional arguments to collect information about them.
@@ -1097,15 +1100,14 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
// not specified after an option that eats all extra arguments, or this
// one will never get any!
//
- if (!IgnoreErrors) {
+ if (!IgnoreErrors)
Opt->error("error - option can never match, because "
"another positional argument will match an "
"unbounded number of values, and this option"
" does not require a value!");
- errs() << ProgramName << ": CommandLine Error: Option '"
- << Opt->ArgStr << "' is all messed up!\n";
- errs() << PositionalOpts.size();
- }
+ *Errs << ProgramName << ": CommandLine Error: Option '" << Opt->ArgStr
+ << "' is all messed up!\n";
+ *Errs << PositionalOpts.size();
ErrorParsing = true;
}
UnboundedFound |= EatsUnboundedNumberOfValues(Opt);
@@ -1200,15 +1202,13 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
if (!Handler) {
if (SinkOpts.empty()) {
- if (!IgnoreErrors) {
- errs() << ProgramName << ": Unknown command line argument '"
- << argv[i] << "'. Try: '" << argv[0] << " -help'\n";
-
- if (NearestHandler) {
- // If we know a near match, report it as well.
- errs() << ProgramName << ": Did you mean '-" << NearestHandlerString
- << "'?\n";
- }
+ *Errs << ProgramName << ": Unknown command line argument '" << argv[i]
+ << "'. Try: '" << argv[0] << " -help'\n";
+
+ if (NearestHandler) {
+ // If we know a near match, report it as well.
+ *Errs << ProgramName << ": Did you mean '-" << NearestHandlerString
+ << "'?\n";
}
ErrorParsing = true;
@@ -1231,22 +1231,18 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
// Check and handle positional arguments now...
if (NumPositionalRequired > PositionalVals.size()) {
- if (!IgnoreErrors) {
- errs() << ProgramName
+ *Errs << ProgramName
<< ": Not enough positional command line arguments specified!\n"
<< "Must specify at least " << NumPositionalRequired
<< " positional argument" << (NumPositionalRequired > 1 ? "s" : "")
<< ": See: " << argv[0] << " - help\n";
- }
ErrorParsing = true;
} else if (!HasUnlimitedPositionals &&
PositionalVals.size() > PositionalOpts.size()) {
- if (!IgnoreErrors) {
- errs() << ProgramName << ": Too many positional arguments specified!\n"
- << "Can specify at most " << PositionalOpts.size()
- << " positional arguments: See: " << argv[0] << " -help\n";
- }
+ *Errs << ProgramName << ": Too many positional arguments specified!\n"
+ << "Can specify at most " << PositionalOpts.size()
+ << " positional arguments: See: " << argv[0] << " -help\n";
ErrorParsing = true;
} else if (!ConsumeAfterOpt) {
@@ -1404,8 +1400,8 @@ static StringRef getValueStr(const Option &O, StringRef DefaultMsg) {
// Return the width of the option tag for printing...
size_t alias::getOptionWidth() const { return ArgStr.size() + 6; }
-static void printHelpStr(StringRef HelpStr, size_t Indent,
- size_t FirstLineIndentedBy) {
+void Option::printHelpStr(StringRef HelpStr, size_t Indent,
+ size_t FirstLineIndentedBy) {
std::pair<StringRef, StringRef> Split = HelpStr.split('\n');
outs().indent(Indent - FirstLineIndentedBy) << " - " << Split.first << "\n";
while (!Split.second.empty()) {
@@ -1448,7 +1444,7 @@ void basic_parser_impl::printOptionInfo(const Option &O,
if (!ValName.empty())
outs() << "=<" << getValueStr(O, ValName) << '>';
- printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O));
+ Option::printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O));
}
void basic_parser_impl::printOptionName(const Option &O,
@@ -1587,7 +1583,7 @@ void generic_parser_base::printOptionInfo(const Option &O,
size_t GlobalWidth) const {
if (O.hasArgStr()) {
outs() << " -" << O.ArgStr;
- printHelpStr(O.HelpStr, GlobalWidth, O.ArgStr.size() + 6);
+ Option::printHelpStr(O.HelpStr, GlobalWidth, O.ArgStr.size() + 6);
for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
size_t NumSpaces = GlobalWidth - getOption(i).size() - 8;
@@ -1600,7 +1596,7 @@ void generic_parser_base::printOptionInfo(const Option &O,
for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
auto Option = getOption(i);
outs() << " -" << Option;
- printHelpStr(getDescription(i), GlobalWidth, Option.size() + 8);
+ Option::printHelpStr(getDescription(i), GlobalWidth, Option.size() + 8);
}
}
}
@@ -1856,10 +1852,11 @@ public:
// Helper function for printOptions().
// It shall return a negative value if A's name should be lexicographically
- // ordered before B's name. It returns a value greater equal zero otherwise.
+ // ordered before B's name. It returns a value greater than zero if B's name
+ // should be ordered before A's name, and it returns 0 otherwise.
static int OptionCategoryCompare(OptionCategory *const *A,
OptionCategory *const *B) {
- return (*A)->getName() == (*B)->getName();
+ return (*A)->getName().compare((*B)->getName());
}
// Make sure we inherit our base class's operator=()
@@ -2182,5 +2179,6 @@ void cl::ResetAllOptionOccurrences() {
void LLVMParseCommandLineOptions(int argc, const char *const *argv,
const char *Overview) {
- llvm::cl::ParseCommandLineOptions(argc, argv, StringRef(Overview), true);
+ llvm::cl::ParseCommandLineOptions(argc, argv, StringRef(Overview),
+ &llvm::nulls());
}
diff --git a/lib/Support/Compression.cpp b/lib/Support/Compression.cpp
index 5d556462e89c..c279d10f6c61 100644
--- a/lib/Support/Compression.cpp
+++ b/lib/Support/Compression.cpp
@@ -16,6 +16,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#if LLVM_ENABLE_ZLIB == 1 && HAVE_ZLIB_H
#include <zlib.h>
@@ -24,6 +25,10 @@
using namespace llvm;
#if LLVM_ENABLE_ZLIB == 1 && HAVE_LIBZ
+static Error createError(StringRef Err) {
+ return make_error<StringError>(Err, inconvertibleErrorCode());
+}
+
static int encodeZlibCompressionLevel(zlib::CompressionLevel Level) {
switch (Level) {
case zlib::NoCompression: return 0;
@@ -34,53 +39,59 @@ static int encodeZlibCompressionLevel(zlib::CompressionLevel Level) {
llvm_unreachable("Invalid zlib::CompressionLevel!");
}
-static zlib::Status encodeZlibReturnValue(int ReturnValue) {
- switch (ReturnValue) {
- case Z_OK: return zlib::StatusOK;
- case Z_MEM_ERROR: return zlib::StatusOutOfMemory;
- case Z_BUF_ERROR: return zlib::StatusBufferTooShort;
- case Z_STREAM_ERROR: return zlib::StatusInvalidArg;
- case Z_DATA_ERROR: return zlib::StatusInvalidData;
- default: llvm_unreachable("unknown zlib return status!");
+static StringRef convertZlibCodeToString(int Code) {
+ switch (Code) {
+ case Z_MEM_ERROR:
+ return "zlib error: Z_MEM_ERROR";
+ case Z_BUF_ERROR:
+ return "zlib error: Z_BUF_ERROR";
+ case Z_STREAM_ERROR:
+ return "zlib error: Z_STREAM_ERROR";
+ case Z_DATA_ERROR:
+ return "zlib error: Z_DATA_ERROR";
+ case Z_OK:
+ default:
+ llvm_unreachable("unknown or unexpected zlib status code");
}
}
bool zlib::isAvailable() { return true; }
-zlib::Status zlib::compress(StringRef InputBuffer,
- SmallVectorImpl<char> &CompressedBuffer,
- CompressionLevel Level) {
+
+Error zlib::compress(StringRef InputBuffer,
+ SmallVectorImpl<char> &CompressedBuffer,
+ CompressionLevel Level) {
unsigned long CompressedSize = ::compressBound(InputBuffer.size());
CompressedBuffer.resize(CompressedSize);
int CLevel = encodeZlibCompressionLevel(Level);
- Status Res = encodeZlibReturnValue(::compress2(
- (Bytef *)CompressedBuffer.data(), &CompressedSize,
- (const Bytef *)InputBuffer.data(), InputBuffer.size(), CLevel));
+ int Res = ::compress2((Bytef *)CompressedBuffer.data(), &CompressedSize,
+ (const Bytef *)InputBuffer.data(), InputBuffer.size(),
+ CLevel);
// Tell MemorySanitizer that zlib output buffer is fully initialized.
// This avoids a false report when running LLVM with uninstrumented ZLib.
__msan_unpoison(CompressedBuffer.data(), CompressedSize);
CompressedBuffer.resize(CompressedSize);
- return Res;
+ return Res ? createError(convertZlibCodeToString(Res)) : Error::success();
}
-zlib::Status zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer,
- size_t &UncompressedSize) {
- Status Res = encodeZlibReturnValue(
+Error zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer,
+ size_t &UncompressedSize) {
+ int Res =
::uncompress((Bytef *)UncompressedBuffer, (uLongf *)&UncompressedSize,
- (const Bytef *)InputBuffer.data(), InputBuffer.size()));
+ (const Bytef *)InputBuffer.data(), InputBuffer.size());
// Tell MemorySanitizer that zlib output buffer is fully initialized.
// This avoids a false report when running LLVM with uninstrumented ZLib.
__msan_unpoison(UncompressedBuffer, UncompressedSize);
- return Res;
+ return Res ? createError(convertZlibCodeToString(Res)) : Error::success();
}
-zlib::Status zlib::uncompress(StringRef InputBuffer,
- SmallVectorImpl<char> &UncompressedBuffer,
- size_t UncompressedSize) {
+Error zlib::uncompress(StringRef InputBuffer,
+ SmallVectorImpl<char> &UncompressedBuffer,
+ size_t UncompressedSize) {
UncompressedBuffer.resize(UncompressedSize);
- Status Res =
+ Error E =
uncompress(InputBuffer, UncompressedBuffer.data(), UncompressedSize);
UncompressedBuffer.resize(UncompressedSize);
- return Res;
+ return E;
}
uint32_t zlib::crc32(StringRef Buffer) {
@@ -89,19 +100,19 @@ uint32_t zlib::crc32(StringRef Buffer) {
#else
bool zlib::isAvailable() { return false; }
-zlib::Status zlib::compress(StringRef InputBuffer,
- SmallVectorImpl<char> &CompressedBuffer,
- CompressionLevel Level) {
- return zlib::StatusUnsupported;
+Error zlib::compress(StringRef InputBuffer,
+ SmallVectorImpl<char> &CompressedBuffer,
+ CompressionLevel Level) {
+ llvm_unreachable("zlib::compress is unavailable");
}
-zlib::Status zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer,
- size_t &UncompressedSize) {
- return zlib::StatusUnsupported;
+Error zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer,
+ size_t &UncompressedSize) {
+ llvm_unreachable("zlib::uncompress is unavailable");
}
-zlib::Status zlib::uncompress(StringRef InputBuffer,
- SmallVectorImpl<char> &UncompressedBuffer,
- size_t UncompressedSize) {
- return zlib::StatusUnsupported;
+Error zlib::uncompress(StringRef InputBuffer,
+ SmallVectorImpl<char> &UncompressedBuffer,
+ size_t UncompressedSize) {
+ llvm_unreachable("zlib::uncompress is unavailable");
}
uint32_t zlib::crc32(StringRef Buffer) {
llvm_unreachable("zlib::crc32 is unavailable");
diff --git a/lib/Support/DebugCounter.cpp b/lib/Support/DebugCounter.cpp
new file mode 100644
index 000000000000..29dae8a20f00
--- /dev/null
+++ b/lib/Support/DebugCounter.cpp
@@ -0,0 +1,108 @@
+#include "llvm/Support/DebugCounter.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Options.h"
+
+using namespace llvm;
+
+// This class overrides the default list implementation of printing so we
+// can pretty print the list of debug counter options. This type of
+// dynamic option is pretty rare (basically this and pass lists).
+class DebugCounterList : public cl::list<std::string, DebugCounter> {
+private:
+ using Base = cl::list<std::string, DebugCounter>;
+
+public:
+ template <class... Mods>
+ explicit DebugCounterList(Mods &&... Ms) : Base(std::forward<Mods>(Ms)...) {}
+
+private:
+ void printOptionInfo(size_t GlobalWidth) const override {
+ // This is a variant of from generic_parser_base::printOptionInfo. Sadly,
+ // it's not easy to make it more usable. We could get it to print these as
+ // options if we were a cl::opt and registered them, but lists don't have
+ // options, nor does the parser for std::string. The other mechanisms for
+ // options are global and would pollute the global namespace with our
+ // counters. Rather than go that route, we have just overridden the
+ // printing, which only a few things call anyway.
+ outs() << " -" << ArgStr;
+ // All of the other options in CommandLine.cpp use ArgStr.size() + 6 for
+ // width, so we do the same.
+ Option::printHelpStr(HelpStr, GlobalWidth, ArgStr.size() + 6);
+ const auto &CounterInstance = DebugCounter::instance();
+ for (auto Name : CounterInstance) {
+ const auto Info =
+ CounterInstance.getCounterInfo(CounterInstance.getCounterId(Name));
+ size_t NumSpaces = GlobalWidth - Info.first.size() - 8;
+ outs() << " =" << Info.first;
+ outs().indent(NumSpaces) << " - " << Info.second << '\n';
+ }
+ }
+};
+
+// Create our command line option.
+static DebugCounterList DebugCounterOption(
+ "debug-counter",
+ cl::desc("Comma separated list of debug counter skip and count"),
+ cl::CommaSeparated, cl::ZeroOrMore, cl::location(DebugCounter::instance()));
+
+static ManagedStatic<DebugCounter> DC;
+
+DebugCounter &DebugCounter::instance() { return *DC; }
+
+// This is called by the command line parser when it sees a value for the
+// debug-counter option defined above.
+void DebugCounter::push_back(const std::string &Val) {
+ if (Val.empty())
+ return;
+ // The strings should come in as counter=value
+ auto CounterPair = StringRef(Val).split('=');
+ if (CounterPair.second.empty()) {
+ errs() << "DebugCounter Error: " << Val << " does not have an = in it\n";
+ return;
+ }
+ // Now we have counter=value.
+ // First, process value.
+ long CounterVal;
+ if (CounterPair.second.getAsInteger(0, CounterVal)) {
+ errs() << "DebugCounter Error: " << CounterPair.second
+ << " is not a number\n";
+ return;
+ }
+ // Now we need to see if this is the skip or the count, remove the suffix, and
+ // add it to the counter values.
+ if (CounterPair.first.endswith("-skip")) {
+ auto CounterName = CounterPair.first.drop_back(5);
+ unsigned CounterID = RegisteredCounters.idFor(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;
+ } else if (CounterPair.first.endswith("-count")) {
+ auto CounterName = CounterPair.first.drop_back(6);
+ unsigned CounterID = RegisteredCounters.idFor(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;
+ } else {
+ errs() << "DebugCounter Error: " << CounterPair.first
+ << " does not end with -skip or -count\n";
+ }
+}
+
+void DebugCounter::print(raw_ostream &OS) {
+ OS << "Counters and values:\n";
+ for (const auto &KV : Counters)
+ OS << left_justify(RegisteredCounters[KV.first], 32) << ": {"
+ << KV.second.first << "," << KV.second.second << "}\n";
+}
diff --git a/lib/Support/Dwarf.cpp b/lib/Support/Dwarf.cpp
index 8950e8c919a4..f13da62e4a87 100644
--- a/lib/Support/Dwarf.cpp
+++ b/lib/Support/Dwarf.cpp
@@ -304,6 +304,17 @@ StringRef llvm::dwarf::ApplePropertyString(unsigned Prop) {
}
}
+StringRef llvm::dwarf::UnitTypeString(unsigned UT) {
+ switch (UT) {
+ default:
+ return StringRef();
+#define HANDLE_DW_UT(ID, NAME) \
+ case DW_UT_##NAME: \
+ return "DW_UT_" #NAME;
+#include "llvm/Support/Dwarf.def"
+ }
+}
+
StringRef llvm::dwarf::AtomTypeString(unsigned AT) {
switch (AT) {
case dwarf::DW_ATOM_null:
diff --git a/lib/Support/DynamicLibrary.cpp b/lib/Support/DynamicLibrary.cpp
index ced21e46afe8..92ce6185306a 100644
--- a/lib/Support/DynamicLibrary.cpp
+++ b/lib/Support/DynamicLibrary.cpp
@@ -9,8 +9,6 @@
//
// This file implements the operating system DynamicLibrary concept.
//
-// FIXME: This file leaks ExplicitSymbols and OpenedHandles!
-//
//===----------------------------------------------------------------------===//
#include "llvm/Support/DynamicLibrary.h"
@@ -51,7 +49,7 @@ using namespace llvm::sys;
//=== independent code.
//===----------------------------------------------------------------------===//
-static DenseSet<void *> *OpenedHandles = nullptr;
+static llvm::ManagedStatic<DenseSet<void *> > OpenedHandles;
DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
std::string *errMsg) {
@@ -70,9 +68,6 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
handle = RTLD_DEFAULT;
#endif
- if (!OpenedHandles)
- OpenedHandles = new DenseSet<void *>();
-
// If we've already loaded this library, dlclose() the handle in order to
// keep the internal refcount at +1.
if (!OpenedHandles->insert(handle).second)
@@ -81,6 +76,18 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
return DynamicLibrary(handle);
}
+DynamicLibrary DynamicLibrary::addPermanentLibrary(void *handle,
+ std::string *errMsg) {
+ SmartScopedLock<true> lock(*SymbolsMutex);
+ // If we've already loaded this library, tell the caller.
+ if (!OpenedHandles->insert(handle).second) {
+ if (errMsg) *errMsg = "Library already loaded";
+ return DynamicLibrary();
+ }
+
+ return DynamicLibrary(handle);
+}
+
void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
if (!isValid())
return nullptr;
@@ -121,7 +128,7 @@ void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
#if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN)
// Now search the libraries.
- if (OpenedHandles) {
+ if (OpenedHandles.isConstructed()) {
for (DenseSet<void *>::iterator I = OpenedHandles->begin(),
E = OpenedHandles->end(); I != E; ++I) {
//lt_ptr ptr = lt_dlsym(*I, symbolName);
diff --git a/lib/Support/FileOutputBuffer.cpp b/lib/Support/FileOutputBuffer.cpp
index 57e5a8d7871c..731740d012d9 100644
--- a/lib/Support/FileOutputBuffer.cpp
+++ b/lib/Support/FileOutputBuffer.cpp
@@ -57,6 +57,8 @@ FileOutputBuffer::create(StringRef FilePath, size_t Size, unsigned Flags) {
// FIXME: In posix, you use the access() call to check this.
}
break;
+ case sys::fs::file_type::directory_file:
+ return errc::is_a_directory;
default:
if (EC)
return EC;
diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp
index d1b40412a6fc..970ecfd7df90 100644
--- a/lib/Support/Host.cpp
+++ b/lib/Support/Host.cpp
@@ -52,25 +52,218 @@
using namespace llvm;
-#if defined(__linux__)
-static ssize_t LLVM_ATTRIBUTE_UNUSED readCpuInfo(void *Buf, size_t Size) {
- // Note: We cannot mmap /proc/cpuinfo here and then process the resulting
- // memory buffer because the 'file' has 0 size (it can be read from only
- // as a stream).
-
- int FD;
- std::error_code EC = sys::fs::openFileForRead("/proc/cpuinfo", FD);
- if (EC) {
- DEBUG(dbgs() << "Unable to open /proc/cpuinfo: " << EC.message() << "\n");
- return -1;
+static std::unique_ptr<llvm::MemoryBuffer>
+ LLVM_ATTRIBUTE_UNUSED getProcCpuinfoContent() {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
+ llvm::MemoryBuffer::getFileAsStream("/proc/cpuinfo");
+ if (std::error_code EC = Text.getError()) {
+ llvm::errs() << "Can't read "
+ << "/proc/cpuinfo: " << EC.message() << "\n";
+ return nullptr;
}
- int Ret = read(FD, Buf, Size);
- int CloseStatus = close(FD);
- if (CloseStatus)
- return -1;
- return Ret;
+ return std::move(*Text);
+}
+
+StringRef sys::detail::getHostCPUNameForPowerPC(
+ const 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.
+ const char *generic = "generic";
+
+ // The cpu line is second (after the 'processor: 0' line), so if this
+ // buffer is too small then something has changed (or is wrong).
+ StringRef::const_iterator CPUInfoStart = ProcCpuinfoContent.begin();
+ StringRef::const_iterator CPUInfoEnd = ProcCpuinfoContent.end();
+
+ StringRef::const_iterator CIP = CPUInfoStart;
+
+ StringRef::const_iterator CPUStart = 0;
+ size_t CPULen = 0;
+
+ // We need to find the first line which starts with cpu, spaces, and a colon.
+ // After the colon, there may be some additional spaces and then the cpu type.
+ while (CIP < CPUInfoEnd && CPUStart == 0) {
+ if (CIP < CPUInfoEnd && *CIP == '\n')
+ ++CIP;
+
+ if (CIP < CPUInfoEnd && *CIP == 'c') {
+ ++CIP;
+ if (CIP < CPUInfoEnd && *CIP == 'p') {
+ ++CIP;
+ if (CIP < CPUInfoEnd && *CIP == 'u') {
+ ++CIP;
+ while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t'))
+ ++CIP;
+
+ if (CIP < CPUInfoEnd && *CIP == ':') {
+ ++CIP;
+ while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t'))
+ ++CIP;
+
+ if (CIP < CPUInfoEnd) {
+ CPUStart = CIP;
+ while (CIP < CPUInfoEnd && (*CIP != ' ' && *CIP != '\t' &&
+ *CIP != ',' && *CIP != '\n'))
+ ++CIP;
+ CPULen = CIP - CPUStart;
+ }
+ }
+ }
+ }
+ }
+
+ if (CPUStart == 0)
+ while (CIP < CPUInfoEnd && *CIP != '\n')
+ ++CIP;
+ }
+
+ if (CPUStart == 0)
+ return generic;
+
+ return StringSwitch<const char *>(StringRef(CPUStart, CPULen))
+ .Case("604e", "604e")
+ .Case("604", "604")
+ .Case("7400", "7400")
+ .Case("7410", "7400")
+ .Case("7447", "7400")
+ .Case("7455", "7450")
+ .Case("G4", "g4")
+ .Case("POWER4", "970")
+ .Case("PPC970FX", "970")
+ .Case("PPC970MP", "970")
+ .Case("G5", "g5")
+ .Case("POWER5", "g5")
+ .Case("A2", "a2")
+ .Case("POWER6", "pwr6")
+ .Case("POWER7", "pwr7")
+ .Case("POWER8", "pwr8")
+ .Case("POWER8E", "pwr8")
+ .Case("POWER8NVL", "pwr8")
+ .Case("POWER9", "pwr9")
+ .Default(generic);
+}
+
+StringRef sys::detail::getHostCPUNameForARM(
+ const StringRef &ProcCpuinfoContent) {
+ // The cpuid register on arm is not accessible from user space. On Linux,
+ // it is exposed through the /proc/cpuinfo file.
+
+ // Read 32 lines from /proc/cpuinfo, which should contain the CPU part line
+ // in all cases.
+ SmallVector<StringRef, 32> Lines;
+ ProcCpuinfoContent.split(Lines, "\n");
+
+ // Look for the CPU implementer line.
+ StringRef Implementer;
+ StringRef Hardware;
+ for (unsigned I = 0, E = Lines.size(); I != E; ++I) {
+ if (Lines[I].startswith("CPU implementer"))
+ Implementer = Lines[I].substr(15).ltrim("\t :");
+ if (Lines[I].startswith("Hardware"))
+ Hardware = Lines[I].substr(8).ltrim("\t :");
+ }
+
+ if (Implementer == "0x41") { // ARM Ltd.
+ // MSM8992/8994 may give cpu part for the core that the kernel is running on,
+ // which is undeterministic and wrong. Always return cortex-a53 for these SoC.
+ if (Hardware.endswith("MSM8994") || Hardware.endswith("MSM8996"))
+ return "cortex-a53";
+
+
+ // Look for the CPU part line.
+ for (unsigned I = 0, E = Lines.size(); I != E; ++I)
+ if (Lines[I].startswith("CPU part"))
+ // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The
+ // values correspond to the "Part number" in the CP15/c0 register. The
+ // contents are specified in the various processor manuals.
+ return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :"))
+ .Case("0x926", "arm926ej-s")
+ .Case("0xb02", "mpcore")
+ .Case("0xb36", "arm1136j-s")
+ .Case("0xb56", "arm1156t2-s")
+ .Case("0xb76", "arm1176jz-s")
+ .Case("0xc08", "cortex-a8")
+ .Case("0xc09", "cortex-a9")
+ .Case("0xc0f", "cortex-a15")
+ .Case("0xc20", "cortex-m0")
+ .Case("0xc23", "cortex-m3")
+ .Case("0xc24", "cortex-m4")
+ .Case("0xd04", "cortex-a35")
+ .Case("0xd03", "cortex-a53")
+ .Case("0xd07", "cortex-a57")
+ .Case("0xd08", "cortex-a72")
+ .Case("0xd09", "cortex-a73")
+ .Default("generic");
+ }
+
+ if (Implementer == "0x51") // Qualcomm Technologies, Inc.
+ // Look for the CPU part line.
+ for (unsigned I = 0, E = Lines.size(); I != E; ++I)
+ if (Lines[I].startswith("CPU part"))
+ // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The
+ // values correspond to the "Part number" in the CP15/c0 register. The
+ // contents are specified in the various processor manuals.
+ return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :"))
+ .Case("0x06f", "krait") // APQ8064
+ .Case("0x201", "kryo")
+ .Case("0x205", "kryo")
+ .Default("generic");
+
+ return "generic";
+}
+
+StringRef sys::detail::getHostCPUNameForS390x(
+ const StringRef &ProcCpuinfoContent) {
+ // STIDP is a privileged operation, so use /proc/cpuinfo instead.
+
+ // The "processor 0:" line comes after a fair amount of other information,
+ // including a cache breakdown, but this should be plenty.
+ SmallVector<StringRef, 32> Lines;
+ ProcCpuinfoContent.split(Lines, "\n");
+
+ // Look for the CPU features.
+ SmallVector<StringRef, 32> CPUFeatures;
+ for (unsigned I = 0, E = Lines.size(); I != E; ++I)
+ if (Lines[I].startswith("features")) {
+ size_t Pos = Lines[I].find(":");
+ if (Pos != StringRef::npos) {
+ Lines[I].drop_front(Pos + 1).split(CPUFeatures, ' ');
+ break;
+ }
+ }
+
+ // We need to check for the presence of vector support independently of
+ // the machine type, since we may only use the vector register set when
+ // supported by the kernel (and hypervisor).
+ bool HaveVectorSupport = false;
+ for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) {
+ if (CPUFeatures[I] == "vx")
+ HaveVectorSupport = true;
+ }
+
+ // Now check the processor machine type.
+ for (unsigned I = 0, E = Lines.size(); I != E; ++I) {
+ if (Lines[I].startswith("processor ")) {
+ size_t Pos = Lines[I].find("machine = ");
+ if (Pos != StringRef::npos) {
+ Pos += sizeof("machine = ") - 1;
+ unsigned int Id;
+ if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) {
+ if (Id >= 2964 && HaveVectorSupport)
+ return "z13";
+ if (Id >= 2827)
+ return "zEC12";
+ if (Id >= 2817)
+ return "z196";
+ }
+ }
+ break;
+ }
+ }
+
+ return "generic";
}
-#endif
#if defined(__i386__) || defined(_M_IX86) || \
defined(__x86_64__) || defined(_M_X64)
@@ -1020,201 +1213,21 @@ StringRef sys::getHostCPUName() {
}
#elif defined(__linux__) && (defined(__ppc__) || defined(__powerpc__))
StringRef sys::getHostCPUName() {
- // 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.
- const char *generic = "generic";
-
- // The cpu line is second (after the 'processor: 0' line), so if this
- // buffer is too small then something has changed (or is wrong).
- char buffer[1024];
- ssize_t CPUInfoSize = readCpuInfo(buffer, sizeof(buffer));
- if (CPUInfoSize == -1)
- return generic;
-
- const char *CPUInfoStart = buffer;
- const char *CPUInfoEnd = buffer + CPUInfoSize;
-
- const char *CIP = CPUInfoStart;
-
- const char *CPUStart = 0;
- size_t CPULen = 0;
-
- // We need to find the first line which starts with cpu, spaces, and a colon.
- // After the colon, there may be some additional spaces and then the cpu type.
- while (CIP < CPUInfoEnd && CPUStart == 0) {
- if (CIP < CPUInfoEnd && *CIP == '\n')
- ++CIP;
-
- if (CIP < CPUInfoEnd && *CIP == 'c') {
- ++CIP;
- if (CIP < CPUInfoEnd && *CIP == 'p') {
- ++CIP;
- if (CIP < CPUInfoEnd && *CIP == 'u') {
- ++CIP;
- while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t'))
- ++CIP;
-
- if (CIP < CPUInfoEnd && *CIP == ':') {
- ++CIP;
- while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t'))
- ++CIP;
-
- if (CIP < CPUInfoEnd) {
- CPUStart = CIP;
- while (CIP < CPUInfoEnd && (*CIP != ' ' && *CIP != '\t' &&
- *CIP != ',' && *CIP != '\n'))
- ++CIP;
- CPULen = CIP - CPUStart;
- }
- }
- }
- }
- }
-
- if (CPUStart == 0)
- while (CIP < CPUInfoEnd && *CIP != '\n')
- ++CIP;
- }
-
- if (CPUStart == 0)
- return generic;
-
- return StringSwitch<const char *>(StringRef(CPUStart, CPULen))
- .Case("604e", "604e")
- .Case("604", "604")
- .Case("7400", "7400")
- .Case("7410", "7400")
- .Case("7447", "7400")
- .Case("7455", "7450")
- .Case("G4", "g4")
- .Case("POWER4", "970")
- .Case("PPC970FX", "970")
- .Case("PPC970MP", "970")
- .Case("G5", "g5")
- .Case("POWER5", "g5")
- .Case("A2", "a2")
- .Case("POWER6", "pwr6")
- .Case("POWER7", "pwr7")
- .Case("POWER8", "pwr8")
- .Case("POWER8E", "pwr8")
- .Case("POWER8NVL", "pwr8")
- .Case("POWER9", "pwr9")
- .Default(generic);
+ std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent();
+ const StringRef& Content = P ? P->getBuffer() : "";
+ return detail::getHostCPUNameForPowerPC(Content);
}
-#elif defined(__linux__) && defined(__arm__)
+#elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__))
StringRef sys::getHostCPUName() {
- // The cpuid register on arm is not accessible from user space. On Linux,
- // it is exposed through the /proc/cpuinfo file.
-
- // Read 1024 bytes from /proc/cpuinfo, which should contain the CPU part line
- // in all cases.
- char buffer[1024];
- ssize_t CPUInfoSize = readCpuInfo(buffer, sizeof(buffer));
- if (CPUInfoSize == -1)
- return "generic";
-
- StringRef Str(buffer, CPUInfoSize);
-
- SmallVector<StringRef, 32> Lines;
- Str.split(Lines, "\n");
-
- // Look for the CPU implementer line.
- StringRef Implementer;
- for (unsigned I = 0, E = Lines.size(); I != E; ++I)
- if (Lines[I].startswith("CPU implementer"))
- Implementer = Lines[I].substr(15).ltrim("\t :");
-
- if (Implementer == "0x41") // ARM Ltd.
- // Look for the CPU part line.
- for (unsigned I = 0, E = Lines.size(); I != E; ++I)
- if (Lines[I].startswith("CPU part"))
- // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The
- // values correspond to the "Part number" in the CP15/c0 register. The
- // contents are specified in the various processor manuals.
- return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :"))
- .Case("0x926", "arm926ej-s")
- .Case("0xb02", "mpcore")
- .Case("0xb36", "arm1136j-s")
- .Case("0xb56", "arm1156t2-s")
- .Case("0xb76", "arm1176jz-s")
- .Case("0xc08", "cortex-a8")
- .Case("0xc09", "cortex-a9")
- .Case("0xc0f", "cortex-a15")
- .Case("0xc20", "cortex-m0")
- .Case("0xc23", "cortex-m3")
- .Case("0xc24", "cortex-m4")
- .Default("generic");
-
- if (Implementer == "0x51") // Qualcomm Technologies, Inc.
- // Look for the CPU part line.
- for (unsigned I = 0, E = Lines.size(); I != E; ++I)
- if (Lines[I].startswith("CPU part"))
- // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The
- // values correspond to the "Part number" in the CP15/c0 register. The
- // contents are specified in the various processor manuals.
- return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :"))
- .Case("0x06f", "krait") // APQ8064
- .Default("generic");
-
- return "generic";
+ std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent();
+ const StringRef& Content = P ? P->getBuffer() : "";
+ return detail::getHostCPUNameForARM(Content);
}
#elif defined(__linux__) && defined(__s390x__)
StringRef sys::getHostCPUName() {
- // STIDP is a privileged operation, so use /proc/cpuinfo instead.
-
- // The "processor 0:" line comes after a fair amount of other information,
- // including a cache breakdown, but this should be plenty.
- char buffer[2048];
- ssize_t CPUInfoSize = readCpuInfo(buffer, sizeof(buffer));
- if (CPUInfoSize == -1)
- return "generic";
-
- StringRef Str(buffer, CPUInfoSize);
- SmallVector<StringRef, 32> Lines;
- Str.split(Lines, "\n");
-
- // Look for the CPU features.
- SmallVector<StringRef, 32> CPUFeatures;
- for (unsigned I = 0, E = Lines.size(); I != E; ++I)
- if (Lines[I].startswith("features")) {
- size_t Pos = Lines[I].find(":");
- if (Pos != StringRef::npos) {
- Lines[I].drop_front(Pos + 1).split(CPUFeatures, ' ');
- break;
- }
- }
-
- // We need to check for the presence of vector support independently of
- // the machine type, since we may only use the vector register set when
- // supported by the kernel (and hypervisor).
- bool HaveVectorSupport = false;
- for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) {
- if (CPUFeatures[I] == "vx")
- HaveVectorSupport = true;
- }
-
- // Now check the processor machine type.
- for (unsigned I = 0, E = Lines.size(); I != E; ++I) {
- if (Lines[I].startswith("processor ")) {
- size_t Pos = Lines[I].find("machine = ");
- if (Pos != StringRef::npos) {
- Pos += sizeof("machine = ") - 1;
- unsigned int Id;
- if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) {
- if (Id >= 2964 && HaveVectorSupport)
- return "z13";
- if (Id >= 2827)
- return "zEC12";
- if (Id >= 2817)
- return "z196";
- }
- }
- break;
- }
- }
-
- return "generic";
+ std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent();
+ const StringRef& Content = P ? P->getBuffer() : "";
+ return detail::getHostCPUNameForS390x(Content);
}
#else
StringRef sys::getHostCPUName() { return "generic"; }
@@ -1232,6 +1245,7 @@ static int computeHostNumPhysicalCores() {
if (std::error_code EC = Text.getError()) {
llvm::errs() << "Can't read "
<< "/proc/cpuinfo: " << EC.message() << "\n";
+ return -1;
}
SmallVector<StringRef, 8> strs;
(*Text)->getBuffer().split(strs, "\n", /*MaxSplit=*/-1,
@@ -1353,6 +1367,10 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
Features["tbm"] = HasExtLeaf1 && ((ECX >> 21) & 1);
Features["mwaitx"] = HasExtLeaf1 && ((ECX >> 29) & 1);
+ bool HasExtLeaf8 = MaxExtLevel >= 0x80000008 &&
+ !getX86CpuIDAndInfoEx(0x80000008,0x0, &EAX, &EBX, &ECX, &EDX);
+ Features["clzero"] = HasExtLeaf8 && ((EBX >> 0) & 1);
+
bool HasLeaf7 =
MaxLevel >= 7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX);
@@ -1362,14 +1380,10 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
Features["fsgsbase"] = HasLeaf7 && ((EBX >> 0) & 1);
Features["sgx"] = HasLeaf7 && ((EBX >> 2) & 1);
Features["bmi"] = HasLeaf7 && ((EBX >> 3) & 1);
- Features["hle"] = HasLeaf7 && ((EBX >> 4) & 1);
Features["bmi2"] = HasLeaf7 && ((EBX >> 8) & 1);
- Features["invpcid"] = HasLeaf7 && ((EBX >> 10) & 1);
Features["rtm"] = HasLeaf7 && ((EBX >> 11) & 1);
Features["rdseed"] = HasLeaf7 && ((EBX >> 18) & 1);
Features["adx"] = HasLeaf7 && ((EBX >> 19) & 1);
- Features["smap"] = HasLeaf7 && ((EBX >> 20) & 1);
- Features["pcommit"] = HasLeaf7 && ((EBX >> 22) & 1);
Features["clflushopt"] = HasLeaf7 && ((EBX >> 23) & 1);
Features["clwb"] = HasLeaf7 && ((EBX >> 24) & 1);
Features["sha"] = HasLeaf7 && ((EBX >> 29) & 1);
@@ -1401,17 +1415,12 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
}
#elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__))
bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
- // Read 1024 bytes from /proc/cpuinfo, which should contain the Features line
- // in all cases.
- char buffer[1024];
- ssize_t CPUInfoSize = readCpuInfo(buffer, sizeof(buffer));
- if (CPUInfoSize == -1)
+ std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent();
+ if (!P)
return false;
- StringRef Str(buffer, CPUInfoSize);
-
SmallVector<StringRef, 32> Lines;
- Str.split(Lines, "\n");
+ P->getBuffer().split(Lines, "\n");
SmallVector<StringRef, 32> CPUFeatures;
diff --git a/lib/Support/LockFileManager.cpp b/lib/Support/LockFileManager.cpp
index 444aaa37c8c8..8be9879fbc24 100644
--- a/lib/Support/LockFileManager.cpp
+++ b/lib/Support/LockFileManager.cpp
@@ -304,9 +304,9 @@ LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() {
Interval.tv_sec = 0;
Interval.tv_nsec = 1000000;
#endif
- // Don't wait more than five minutes per iteration. Total timeout for the file
- // to appear is ~8.5 mins.
- const unsigned MaxSeconds = 5*60;
+ // Don't wait more than 40s per iteration. Total timeout for the file
+ // to appear is ~1.5 minutes.
+ const unsigned MaxSeconds = 40;
do {
// Sleep for the designated interval, to allow the owning process time to
// finish up and remove the lock file.
diff --git a/lib/Support/LowLevelType.cpp b/lib/Support/LowLevelType.cpp
new file mode 100644
index 000000000000..4290d69cd197
--- /dev/null
+++ b/lib/Support/LowLevelType.cpp
@@ -0,0 +1,47 @@
+//===-- llvm/Support/LowLevelType.cpp -------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file This file implements the more header-heavy bits of the LLT class to
+/// avoid polluting users' namespaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/LowLevelTypeImpl.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+LLT::LLT(MVT VT) {
+ if (VT.isVector()) {
+ SizeInBits = VT.getVectorElementType().getSizeInBits();
+ ElementsOrAddrSpace = VT.getVectorNumElements();
+ Kind = ElementsOrAddrSpace == 1 ? Scalar : Vector;
+ } else if (VT.isValid()) {
+ // Aggregates are no different from real scalars as far as GlobalISel is
+ // concerned.
+ Kind = Scalar;
+ SizeInBits = VT.getSizeInBits();
+ ElementsOrAddrSpace = 1;
+ assert(SizeInBits != 0 && "invalid zero-sized type");
+ } else {
+ Kind = Invalid;
+ SizeInBits = ElementsOrAddrSpace = 0;
+ }
+}
+
+void LLT::print(raw_ostream &OS) const {
+ if (isVector())
+ OS << "<" << ElementsOrAddrSpace << " x s" << SizeInBits << ">";
+ else if (isPointer())
+ OS << "p" << getAddressSpace();
+ else if (isValid()) {
+ assert(isScalar() && "unexpected type");
+ OS << "s" << getScalarSizeInBits();
+ } else
+ llvm_unreachable("trying to print an invalid type");
+}
diff --git a/lib/Support/MD5.cpp b/lib/Support/MD5.cpp
index 942571eab0f3..bdbf1d677938 100644
--- a/lib/Support/MD5.cpp
+++ b/lib/Support/MD5.cpp
@@ -38,9 +38,13 @@
*/
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Endian.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/raw_ostream.h"
+#include <array>
+#include <cstdint>
#include <cstring>
// The basic MD5 functions.
@@ -68,7 +72,7 @@
((MD5_u32plus) ptr[(n) * 4 + 3] << 24))
#define GET(n) (block[(n)])
-namespace llvm {
+using namespace llvm;
/// \brief This processes one or more 64-byte data blocks, but does NOT update
///the bit counters. There are no alignment requirements.
@@ -179,9 +183,7 @@ const uint8_t *MD5::body(ArrayRef<uint8_t> Data) {
return ptr;
}
-MD5::MD5()
- : a(0x67452301), b(0xefcdab89), c(0x98badcfe), d(0x10325476), hi(0), lo(0) {
-}
+MD5::MD5() = default;
/// Incrementally add the bytes in \p Data to the hash.
void MD5::update(ArrayRef<uint8_t> Data) {
@@ -259,10 +261,16 @@ void MD5::final(MD5Result &Result) {
support::endian::write32le(&Result[12], d);
}
-void MD5::stringifyResult(MD5Result &Result, SmallString<32> &Str) {
+SmallString<32> MD5::MD5Result::digest() const {
+ SmallString<32> Str;
raw_svector_ostream Res(Str);
for (int i = 0; i < 16; ++i)
- Res << format("%.2x", Result[i]);
+ Res << format("%.2x", Bytes[i]);
+ return Str;
+}
+
+void MD5::stringifyResult(MD5Result &Result, SmallString<32> &Str) {
+ Str = Result.digest();
}
std::array<uint8_t, 16> MD5::hash(ArrayRef<uint8_t> Data) {
@@ -271,8 +279,5 @@ std::array<uint8_t, 16> MD5::hash(ArrayRef<uint8_t> Data) {
MD5::MD5Result Res;
Hash.final(Res);
- std::array<uint8_t, 16> Arr;
- memcpy(Arr.data(), Res, sizeof(Res));
- return Arr;
-}
+ return Res;
}
diff --git a/lib/Support/ManagedStatic.cpp b/lib/Support/ManagedStatic.cpp
index 7dd31315f90d..fb7cd070c42d 100644
--- a/lib/Support/ManagedStatic.cpp
+++ b/lib/Support/ManagedStatic.cpp
@@ -21,7 +21,7 @@ using namespace llvm;
static const ManagedStaticBase *StaticList = nullptr;
static sys::Mutex *ManagedStaticMutex = nullptr;
-LLVM_DEFINE_ONCE_FLAG(mutex_init_flag);
+static llvm::once_flag mutex_init_flag;
static void initializeMutex() {
ManagedStaticMutex = new sys::Mutex();
diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp
index a3a18c9283ce..227e792d83dc 100644
--- a/lib/Support/MemoryBuffer.cpp
+++ b/lib/Support/MemoryBuffer.cpp
@@ -103,7 +103,7 @@ public:
static ErrorOr<std::unique_ptr<MemoryBuffer>>
getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize,
- uint64_t Offset, bool RequiresNullTerminator, bool IsVolatileSize);
+ uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile);
std::unique_ptr<MemoryBuffer>
MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName,
@@ -178,8 +178,8 @@ MemoryBuffer::getFileOrSTDIN(const Twine &Filename, int64_t FileSize,
ErrorOr<std::unique_ptr<MemoryBuffer>>
MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize,
- uint64_t Offset) {
- return getFileAux(FilePath, -1, MapSize, Offset, false, false);
+ uint64_t Offset, bool IsVolatile) {
+ return getFileAux(FilePath, -1, MapSize, Offset, false, IsVolatile);
}
@@ -254,19 +254,19 @@ getMemoryBufferForStream(int FD, const Twine &BufferName) {
ErrorOr<std::unique_ptr<MemoryBuffer>>
MemoryBuffer::getFile(const Twine &Filename, int64_t FileSize,
- bool RequiresNullTerminator, bool IsVolatileSize) {
+ bool RequiresNullTerminator, bool IsVolatile) {
return getFileAux(Filename, FileSize, FileSize, 0,
- RequiresNullTerminator, IsVolatileSize);
+ RequiresNullTerminator, IsVolatile);
}
static ErrorOr<std::unique_ptr<MemoryBuffer>>
getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize,
uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator,
- bool IsVolatileSize);
+ bool IsVolatile);
static ErrorOr<std::unique_ptr<MemoryBuffer>>
getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize,
- uint64_t Offset, bool RequiresNullTerminator, bool IsVolatileSize) {
+ uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile) {
int FD;
std::error_code EC = sys::fs::openFileForRead(Filename, FD);
if (EC)
@@ -274,7 +274,7 @@ getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize,
ErrorOr<std::unique_ptr<MemoryBuffer>> Ret =
getOpenFileImpl(FD, Filename, FileSize, MapSize, Offset,
- RequiresNullTerminator, IsVolatileSize);
+ RequiresNullTerminator, IsVolatile);
close(FD);
return Ret;
}
@@ -285,11 +285,11 @@ static bool shouldUseMmap(int FD,
off_t Offset,
bool RequiresNullTerminator,
int PageSize,
- bool IsVolatileSize) {
+ bool IsVolatile) {
// mmap may leave the buffer without null terminator if the file size changed
// by the time the last page is mapped in, so avoid it if the file size is
// likely to change.
- if (IsVolatileSize)
+ if (IsVolatile)
return false;
// We don't use mmap for small files because this can severely fragment our
@@ -300,7 +300,6 @@ static bool shouldUseMmap(int FD,
if (!RequiresNullTerminator)
return true;
-
// If we don't know the file size, use fstat to find out. fstat on an open
// file descriptor is cheaper than stat on a random path.
// FIXME: this chunk of code is duplicated, but it avoids a fstat when
@@ -338,7 +337,7 @@ static bool shouldUseMmap(int FD,
static ErrorOr<std::unique_ptr<MemoryBuffer>>
getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize,
uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator,
- bool IsVolatileSize) {
+ bool IsVolatile) {
static int PageSize = sys::Process::getPageSize();
// Default is to map the full file.
@@ -365,7 +364,7 @@ getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize,
}
if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator,
- PageSize, IsVolatileSize)) {
+ PageSize, IsVolatile)) {
std::error_code EC;
std::unique_ptr<MemoryBuffer> Result(
new (NamedBufferAlloc(Filename))
@@ -415,17 +414,16 @@ getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize,
ErrorOr<std::unique_ptr<MemoryBuffer>>
MemoryBuffer::getOpenFile(int FD, const Twine &Filename, uint64_t FileSize,
- bool RequiresNullTerminator, bool IsVolatileSize) {
+ bool RequiresNullTerminator, bool IsVolatile) {
return getOpenFileImpl(FD, Filename, FileSize, FileSize, 0,
- RequiresNullTerminator, IsVolatileSize);
+ RequiresNullTerminator, IsVolatile);
}
ErrorOr<std::unique_ptr<MemoryBuffer>>
MemoryBuffer::getOpenFileSlice(int FD, const Twine &Filename, uint64_t MapSize,
- int64_t Offset) {
+ int64_t Offset, bool IsVolatile) {
assert(MapSize != uint64_t(-1));
- return getOpenFileImpl(FD, Filename, -1, MapSize, Offset, false,
- /*IsVolatileSize*/ false);
+ return getOpenFileImpl(FD, Filename, -1, MapSize, Offset, false, IsVolatile);
}
ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() {
diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp
index 4bb035eeccca..9fd6652ce4b8 100644
--- a/lib/Support/Path.cpp
+++ b/lib/Support/Path.cpp
@@ -11,13 +11,14 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/Support/Path.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/COFF.h"
-#include "llvm/Support/MachO.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
+#include "llvm/Support/MachO.h"
#include "llvm/Support/Process.h"
#include <cctype>
#include <cstring>
@@ -34,16 +35,29 @@ using namespace llvm::support::endian;
namespace {
using llvm::StringRef;
using llvm::sys::path::is_separator;
+ using llvm::sys::path::Style;
+ inline Style real_style(Style style) {
#ifdef LLVM_ON_WIN32
- const char *separators = "\\/";
- const char preferred_separator = '\\';
+ return (style == Style::posix) ? Style::posix : Style::windows;
#else
- const char separators = '/';
- const char preferred_separator = '/';
+ return (style == Style::windows) ? Style::windows : Style::posix;
#endif
+ }
- StringRef find_first_component(StringRef path) {
+ inline const char *separators(Style style) {
+ if (real_style(style) == Style::windows)
+ return "\\/";
+ return "/";
+ }
+
+ inline char preferred_separator(Style style) {
+ if (real_style(style) == Style::windows)
+ return '\\';
+ return '/';
+ }
+
+ StringRef find_first_component(StringRef path, Style style) {
// Look for this first component in the following order.
// * empty (in this case we return an empty string)
// * either C: or {//,\\}net.
@@ -53,96 +67,85 @@ namespace {
if (path.empty())
return path;
-#ifdef LLVM_ON_WIN32
- // C:
- if (path.size() >= 2 && std::isalpha(static_cast<unsigned char>(path[0])) &&
- path[1] == ':')
- return path.substr(0, 2);
-#endif
+ if (real_style(style) == Style::windows) {
+ // C:
+ if (path.size() >= 2 &&
+ std::isalpha(static_cast<unsigned char>(path[0])) && path[1] == ':')
+ return path.substr(0, 2);
+ }
// //net
- if ((path.size() > 2) &&
- is_separator(path[0]) &&
- path[0] == path[1] &&
- !is_separator(path[2])) {
+ if ((path.size() > 2) && is_separator(path[0], style) &&
+ path[0] == path[1] && !is_separator(path[2], style)) {
// Find the next directory separator.
- size_t end = path.find_first_of(separators, 2);
+ size_t end = path.find_first_of(separators(style), 2);
return path.substr(0, end);
}
// {/,\}
- if (is_separator(path[0]))
+ if (is_separator(path[0], style))
return path.substr(0, 1);
// * {file,directory}name
- size_t end = path.find_first_of(separators);
+ size_t end = path.find_first_of(separators(style));
return path.substr(0, end);
}
- size_t filename_pos(StringRef str) {
- if (str.size() == 2 &&
- is_separator(str[0]) &&
- str[0] == str[1])
+ 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]))
+ if (str.size() > 0 && is_separator(str[str.size() - 1], style))
return str.size() - 1;
- size_t pos = str.find_last_of(separators, str.size() - 1);
+ size_t pos = str.find_last_of(separators(style), str.size() - 1);
-#ifdef LLVM_ON_WIN32
- if (pos == StringRef::npos)
- pos = str.find_last_of(':', str.size() - 2);
-#endif
+ if (real_style(style) == Style::windows) {
+ if (pos == StringRef::npos)
+ pos = str.find_last_of(':', str.size() - 2);
+ }
- if (pos == StringRef::npos ||
- (pos == 1 && is_separator(str[0])))
+ if (pos == StringRef::npos || (pos == 1 && is_separator(str[0], style)))
return 0;
return pos + 1;
}
- size_t root_dir_start(StringRef str) {
+ size_t root_dir_start(StringRef str, Style style) {
// case "c:/"
-#ifdef LLVM_ON_WIN32
- if (str.size() > 2 &&
- str[1] == ':' &&
- is_separator(str[2]))
- return 2;
-#endif
+ if (real_style(style) == Style::windows) {
+ if (str.size() > 2 && str[1] == ':' && is_separator(str[2], style))
+ return 2;
+ }
// case "//"
- if (str.size() == 2 &&
- is_separator(str[0]) &&
- str[0] == str[1])
+ 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]) &&
- str[0] == str[1] &&
- !is_separator(str[2])) {
- return str.find_first_of(separators, 2);
+ if (str.size() > 3 && is_separator(str[0], style) && str[0] == str[1] &&
+ !is_separator(str[2], style)) {
+ return str.find_first_of(separators(style), 2);
}
// case "/"
- if (str.size() > 0 && is_separator(str[0]))
+ if (str.size() > 0 && is_separator(str[0], style))
return 0;
return StringRef::npos;
}
- size_t parent_path_end(StringRef path) {
- size_t end_pos = filename_pos(path);
+ 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]);
+ 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));
+ size_t root_dir_pos = root_dir_start(path.substr(0, end_pos), style);
- while(end_pos > 0 &&
- (end_pos - 1) != root_dir_pos &&
- is_separator(path[end_pos - 1]))
+ while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
+ is_separator(path[end_pos - 1], style))
--end_pos;
if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep)
@@ -230,11 +233,12 @@ namespace llvm {
namespace sys {
namespace path {
-const_iterator begin(StringRef path) {
+const_iterator begin(StringRef path, Style style) {
const_iterator i;
i.Path = path;
- i.Component = find_first_component(path);
+ i.Component = find_first_component(path, style);
i.Position = 0;
+ i.S = style;
return i;
}
@@ -259,27 +263,21 @@ const_iterator &const_iterator::operator++() {
// Both POSIX and Windows treat paths that begin with exactly two separators
// specially.
- bool was_net = Component.size() > 2 &&
- is_separator(Component[0]) &&
- Component[1] == Component[0] &&
- !is_separator(Component[2]);
+ bool was_net = Component.size() > 2 && is_separator(Component[0], S) &&
+ Component[1] == Component[0] && !is_separator(Component[2], S);
// Handle separators.
- if (is_separator(Path[Position])) {
+ if (is_separator(Path[Position], S)) {
// Root dir.
- if (was_net
-#ifdef LLVM_ON_WIN32
+ if (was_net ||
// c:/
- || Component.endswith(":")
-#endif
- ) {
+ (real_style(S) == Style::windows && Component.endswith(":"))) {
Component = Path.substr(Position, 1);
return *this;
}
// Skip extra separators.
- while (Position != Path.size() &&
- is_separator(Path[Position])) {
+ while (Position != Path.size() && is_separator(Path[Position], S)) {
++Position;
}
@@ -292,7 +290,7 @@ const_iterator &const_iterator::operator++() {
}
// Find next component.
- size_t end_pos = Path.find_first_of(separators, Position);
+ size_t end_pos = Path.find_first_of(separators(S), Position);
Component = Path.slice(Position, end_pos);
return *this;
@@ -306,10 +304,11 @@ ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const {
return Position - RHS.Position;
}
-reverse_iterator rbegin(StringRef Path) {
+reverse_iterator rbegin(StringRef Path, Style style) {
reverse_iterator I;
I.Path = Path;
I.Position = Path.size();
+ I.S = style;
return ++I;
}
@@ -324,10 +323,9 @@ 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);
- if (Position == Path.size() &&
- Path.size() > root_dir_pos + 1 &&
- is_separator(Path[Position - 1])) {
+ 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;
@@ -336,13 +334,12 @@ reverse_iterator &reverse_iterator::operator++() {
// 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]))
+ while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
+ is_separator(Path[end_pos - 1], S))
--end_pos;
// Find next separator.
- size_t start_pos = filename_pos(Path.substr(0, end_pos));
+ size_t start_pos = filename_pos(Path.substr(0, end_pos), S);
Component = Path.slice(start_pos, end_pos);
Position = start_pos;
return *this;
@@ -357,21 +354,15 @@ ptrdiff_t reverse_iterator::operator-(const reverse_iterator &RHS) const {
return Position - RHS.Position;
}
-StringRef root_path(StringRef path) {
- const_iterator b = begin(path),
- pos = b,
- e = end(path);
+StringRef root_path(StringRef path, Style style) {
+ const_iterator b = begin(path, style), pos = b, e = end(path);
if (b != e) {
- bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
- bool has_drive =
-#ifdef LLVM_ON_WIN32
- b->endswith(":");
-#else
- false;
-#endif
+ bool has_net =
+ b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
+ bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
if (has_net || has_drive) {
- if ((++pos != e) && is_separator((*pos)[0])) {
+ if ((++pos != e) && is_separator((*pos)[0], style)) {
// {C:/,//net/}, so get the first two components.
return path.substr(0, b->size() + pos->size());
} else {
@@ -381,7 +372,7 @@ StringRef root_path(StringRef path) {
}
// POSIX style root directory.
- if (is_separator((*b)[0])) {
+ if (is_separator((*b)[0], style)) {
return *b;
}
}
@@ -389,17 +380,12 @@ StringRef root_path(StringRef path) {
return StringRef();
}
-StringRef root_name(StringRef path) {
- const_iterator b = begin(path),
- e = end(path);
+StringRef root_name(StringRef path, Style style) {
+ const_iterator b = begin(path, style), e = end(path);
if (b != e) {
- bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
- bool has_drive =
-#ifdef LLVM_ON_WIN32
- b->endswith(":");
-#else
- false;
-#endif
+ bool has_net =
+ b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
+ bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
if (has_net || has_drive) {
// just {C:,//net}, return the first component.
@@ -411,27 +397,21 @@ StringRef root_name(StringRef path) {
return StringRef();
}
-StringRef root_directory(StringRef path) {
- const_iterator b = begin(path),
- pos = b,
- e = end(path);
+StringRef root_directory(StringRef path, Style style) {
+ const_iterator b = begin(path, style), pos = b, e = end(path);
if (b != e) {
- bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
- bool has_drive =
-#ifdef LLVM_ON_WIN32
- b->endswith(":");
-#else
- false;
-#endif
+ bool has_net =
+ b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
+ bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
if ((has_net || has_drive) &&
// {C:,//net}, skip to the next component.
- (++pos != e) && is_separator((*pos)[0])) {
+ (++pos != e) && is_separator((*pos)[0], style)) {
return *pos;
}
// POSIX style root directory.
- if (!has_net && is_separator((*b)[0])) {
+ if (!has_net && is_separator((*b)[0], style)) {
return *b;
}
}
@@ -440,15 +420,13 @@ StringRef root_directory(StringRef path) {
return StringRef();
}
-StringRef relative_path(StringRef path) {
- StringRef root = root_path(path);
+StringRef relative_path(StringRef path, Style style) {
+ StringRef root = root_path(path, style);
return path.substr(root.size());
}
-void append(SmallVectorImpl<char> &path, const Twine &a,
- const Twine &b,
- const Twine &c,
- const Twine &d) {
+void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
+ const Twine &b, const Twine &c, const Twine &d) {
SmallString<32> a_storage;
SmallString<32> b_storage;
SmallString<32> c_storage;
@@ -461,13 +439,15 @@ void append(SmallVectorImpl<char> &path, const Twine &a,
if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage));
for (auto &component : components) {
- bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]);
- bool component_has_sep = !component.empty() && is_separator(component[0]);
- bool is_root_name = has_root_name(component);
+ bool path_has_sep =
+ !path.empty() && is_separator(path[path.size() - 1], style);
+ bool component_has_sep =
+ !component.empty() && is_separator(component[0], style);
+ bool is_root_name = has_root_name(component, style);
if (path_has_sep) {
// Strip separators from beginning of component.
- size_t loc = component.find_first_not_of(separators);
+ size_t loc = component.find_first_not_of(separators(style));
StringRef c = component.substr(loc);
// Append it.
@@ -477,41 +457,47 @@ void append(SmallVectorImpl<char> &path, const Twine &a,
if (!component_has_sep && !(path.empty() || is_root_name)) {
// Add a separator.
- path.push_back(preferred_separator);
+ path.push_back(preferred_separator(style));
}
path.append(component.begin(), component.end());
}
}
-void append(SmallVectorImpl<char> &path,
- const_iterator begin, const_iterator end) {
+void append(SmallVectorImpl<char> &path, const Twine &a, const Twine &b,
+ const Twine &c, const Twine &d) {
+ append(path, Style::native, a, b, c, d);
+}
+
+void append(SmallVectorImpl<char> &path, const_iterator begin,
+ const_iterator end, Style style) {
for (; begin != end; ++begin)
- path::append(path, *begin);
+ path::append(path, style, *begin);
}
-StringRef parent_path(StringRef path) {
- size_t end_pos = parent_path_end(path);
+StringRef parent_path(StringRef path, Style style) {
+ size_t end_pos = parent_path_end(path, style);
if (end_pos == StringRef::npos)
return StringRef();
else
return path.substr(0, end_pos);
}
-void remove_filename(SmallVectorImpl<char> &path) {
- size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()));
+void remove_filename(SmallVectorImpl<char> &path, Style style) {
+ size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()), style);
if (end_pos != StringRef::npos)
path.set_size(end_pos);
}
-void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) {
+void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
+ Style style) {
StringRef p(path.begin(), path.size());
SmallString<32> ext_storage;
StringRef ext = extension.toStringRef(ext_storage);
// Erase existing extension.
size_t pos = p.find_last_of('.');
- if (pos != StringRef::npos && pos >= filename_pos(p))
+ if (pos != StringRef::npos && pos >= filename_pos(p, style))
path.set_size(pos);
// Append '.' if needed.
@@ -523,8 +509,8 @@ void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) {
}
void replace_path_prefix(SmallVectorImpl<char> &Path,
- const StringRef &OldPrefix,
- const StringRef &NewPrefix) {
+ const StringRef &OldPrefix, const StringRef &NewPrefix,
+ Style style) {
if (OldPrefix.empty() && NewPrefix.empty())
return;
@@ -540,53 +526,58 @@ void replace_path_prefix(SmallVectorImpl<char> &Path,
StringRef RelPath = OrigPath.substr(OldPrefix.size());
SmallString<256> NewPath;
- path::append(NewPath, NewPrefix);
- path::append(NewPath, RelPath);
+ path::append(NewPath, style, NewPrefix);
+ path::append(NewPath, style, RelPath);
Path.swap(NewPath);
}
-void native(const Twine &path, SmallVectorImpl<char> &result) {
+void native(const Twine &path, SmallVectorImpl<char> &result, Style style) {
assert((!path.isSingleStringRef() ||
path.getSingleStringRef().data() != result.data()) &&
"path and result are not allowed to overlap!");
// Clear result.
result.clear();
path.toVector(result);
- native(result);
+ native(result, style);
}
-void native(SmallVectorImpl<char> &Path) {
-#ifdef LLVM_ON_WIN32
- std::replace(Path.begin(), Path.end(), '/', '\\');
-#else
- for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) {
- if (*PI == '\\') {
- auto PN = PI + 1;
- if (PN < PE && *PN == '\\')
- ++PI; // increment once, the for loop will move over the escaped slash
- else
- *PI = '/';
+void native(SmallVectorImpl<char> &Path, Style style) {
+ if (Path.empty())
+ return;
+ if (real_style(style) == Style::windows) {
+ std::replace(Path.begin(), Path.end(), '/', '\\');
+ if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1], style))) {
+ SmallString<128> PathHome;
+ home_directory(PathHome);
+ PathHome.append(Path.begin() + 1, Path.end());
+ Path = PathHome;
+ }
+ } else {
+ for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) {
+ if (*PI == '\\') {
+ auto PN = PI + 1;
+ if (PN < PE && *PN == '\\')
+ ++PI; // increment once, the for loop will move over the escaped slash
+ else
+ *PI = '/';
+ }
}
}
-#endif
}
-std::string convert_to_slash(StringRef path) {
-#ifdef LLVM_ON_WIN32
+std::string convert_to_slash(StringRef path, Style style) {
+ if (real_style(style) != Style::windows)
+ return path;
+
std::string s = path.str();
std::replace(s.begin(), s.end(), '\\', '/');
return s;
-#else
- return path;
-#endif
}
-StringRef filename(StringRef path) {
- return *rbegin(path);
-}
+StringRef filename(StringRef path, Style style) { return *rbegin(path, style); }
-StringRef stem(StringRef path) {
- StringRef fname = filename(path);
+StringRef stem(StringRef path, Style style) {
+ StringRef fname = filename(path, style);
size_t pos = fname.find_last_of('.');
if (pos == StringRef::npos)
return fname;
@@ -598,8 +589,8 @@ StringRef stem(StringRef path) {
return fname.substr(0, pos);
}
-StringRef extension(StringRef path) {
- StringRef fname = filename(path);
+StringRef extension(StringRef path, Style style) {
+ StringRef fname = filename(path, style);
size_t pos = fname.find_last_of('.');
if (pos == StringRef::npos)
return StringRef();
@@ -611,110 +602,109 @@ StringRef extension(StringRef path) {
return fname.substr(pos);
}
-bool is_separator(char value) {
- switch(value) {
-#ifdef LLVM_ON_WIN32
- case '\\': // fall through
-#endif
- case '/': return true;
- default: return false;
- }
+bool is_separator(char value, Style style) {
+ if (value == '/')
+ return true;
+ if (real_style(style) == Style::windows)
+ return value == '\\';
+ return false;
}
-static const char preferred_separator_string[] = { preferred_separator, '\0' };
-
-StringRef get_separator() {
- return preferred_separator_string;
+StringRef get_separator(Style style) {
+ if (real_style(style) == Style::windows)
+ return "\\";
+ return "/";
}
-bool has_root_name(const Twine &path) {
+bool has_root_name(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !root_name(p).empty();
+ return !root_name(p, style).empty();
}
-bool has_root_directory(const Twine &path) {
+bool has_root_directory(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !root_directory(p).empty();
+ return !root_directory(p, style).empty();
}
-bool has_root_path(const Twine &path) {
+bool has_root_path(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !root_path(p).empty();
+ return !root_path(p, style).empty();
}
-bool has_relative_path(const Twine &path) {
+bool has_relative_path(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !relative_path(p).empty();
+ return !relative_path(p, style).empty();
}
-bool has_filename(const Twine &path) {
+bool has_filename(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !filename(p).empty();
+ return !filename(p, style).empty();
}
-bool has_parent_path(const Twine &path) {
+bool has_parent_path(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !parent_path(p).empty();
+ return !parent_path(p, style).empty();
}
-bool has_stem(const Twine &path) {
+bool has_stem(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !stem(p).empty();
+ return !stem(p, style).empty();
}
-bool has_extension(const Twine &path) {
+bool has_extension(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !extension(p).empty();
+ return !extension(p, style).empty();
}
-bool is_absolute(const Twine &path) {
+bool is_absolute(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- bool rootDir = has_root_directory(p),
-#ifdef LLVM_ON_WIN32
- rootName = has_root_name(p);
-#else
- rootName = true;
-#endif
+ bool rootDir = has_root_directory(p, style);
+ bool rootName =
+ (real_style(style) != Style::windows) || has_root_name(p, style);
return rootDir && rootName;
}
-bool is_relative(const Twine &path) { return !is_absolute(path); }
+bool is_relative(const Twine &path, Style style) {
+ return !is_absolute(path, style);
+}
-StringRef remove_leading_dotslash(StringRef Path) {
+StringRef remove_leading_dotslash(StringRef Path, Style style) {
// Remove leading "./" (or ".//" or "././" etc.)
- while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1])) {
+ while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1], style)) {
Path = Path.substr(2);
- while (Path.size() > 0 && is_separator(Path[0]))
+ while (Path.size() > 0 && is_separator(Path[0], style))
Path = Path.substr(1);
}
return Path;
}
-static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot) {
+static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot,
+ Style style) {
SmallVector<StringRef, 16> components;
// Skip the root path, then look for traversal in the components.
- StringRef rel = path::relative_path(path);
- for (StringRef C : llvm::make_range(path::begin(rel), path::end(rel))) {
+ StringRef rel = path::relative_path(path, style);
+ for (StringRef C :
+ llvm::make_range(path::begin(rel, style), path::end(rel))) {
if (C == ".")
continue;
// Leading ".." will remain in the path unless it's at the root.
@@ -723,22 +713,23 @@ static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot) {
components.pop_back();
continue;
}
- if (path::is_absolute(path))
+ if (path::is_absolute(path, style))
continue;
}
components.push_back(C);
}
- SmallString<256> buffer = path::root_path(path);
+ SmallString<256> buffer = path::root_path(path, style);
for (StringRef C : components)
- path::append(buffer, C);
+ path::append(buffer, style, C);
return buffer;
}
-bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot) {
+bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot,
+ Style style) {
StringRef p(path.data(), path.size());
- SmallString<256> result = remove_dots(p, remove_dot_dot);
+ SmallString<256> result = remove_dots(p, remove_dot_dot, style);
if (result == path)
return false;
@@ -776,7 +767,7 @@ createTemporaryFile(const Twine &Model, int &ResultFD,
llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) {
SmallString<128> Storage;
StringRef P = Model.toNullTerminatedStringRef(Storage);
- assert(P.find_first_of(separators) == StringRef::npos &&
+ 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,
@@ -818,12 +809,9 @@ static std::error_code make_absolute(const Twine &current_directory,
bool use_current_directory) {
StringRef p(path.data(), path.size());
- bool rootDirectory = path::has_root_directory(p),
-#ifdef LLVM_ON_WIN32
- rootName = path::has_root_name(p);
-#else
- rootName = true;
-#endif
+ bool rootDirectory = path::has_root_directory(p);
+ bool rootName =
+ (real_style(Style::native) != Style::windows) || path::has_root_name(p);
// Already absolute.
if (rootName && rootDirectory)
@@ -937,6 +925,36 @@ std::error_code copy_file(const Twine &From, const Twine &To) {
return std::error_code();
}
+ErrorOr<MD5::MD5Result> md5_contents(int FD) {
+ MD5 Hash;
+
+ constexpr size_t BufSize = 4096;
+ std::vector<uint8_t> Buf(BufSize);
+ int BytesRead = 0;
+ for (;;) {
+ BytesRead = read(FD, Buf.data(), BufSize);
+ if (BytesRead <= 0)
+ break;
+ Hash.update(makeArrayRef(Buf.data(), BytesRead));
+ }
+
+ if (BytesRead < 0)
+ return std::error_code(errno, std::generic_category());
+ MD5::MD5Result Result;
+ Hash.final(Result);
+ return Result;
+}
+
+ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path) {
+ int FD;
+ if (auto EC = openFileForRead(Path, FD))
+ return EC;
+
+ auto Result = md5_contents(FD);
+ close(FD);
+ return Result;
+}
+
bool exists(file_status status) {
return status_known(status) && status.type() != file_type::file_not_found;
}
@@ -945,6 +963,13 @@ bool status_known(file_status s) {
return s.type() != file_type::status_error;
}
+file_type get_file_type(const Twine &Path, bool Follow) {
+ file_status st;
+ if (status(Path, st, Follow))
+ return file_type::status_error;
+ return st.type();
+}
+
bool is_directory(file_status status) {
return status.type() == file_type::directory_file;
}
@@ -969,6 +994,18 @@ std::error_code is_regular_file(const Twine &path, bool &result) {
return std::error_code();
}
+bool is_symlink_file(file_status status) {
+ return status.type() == file_type::symlink_file;
+}
+
+std::error_code is_symlink_file(const Twine &path, bool &result) {
+ file_status st;
+ if (std::error_code ec = status(path, st, false))
+ return ec;
+ result = is_symlink_file(st);
+ return std::error_code();
+}
+
bool is_other(file_status status) {
return exists(status) &&
!is_regular_file(status) &&
@@ -1162,7 +1199,15 @@ std::error_code identify_magic(const Twine &Path, file_magic &Result) {
}
std::error_code directory_entry::status(file_status &result) const {
- return fs::status(Path, result);
+ return fs::status(Path, result, FollowSymlinks);
+}
+
+ErrorOr<perms> getPermissions(const Twine &Path) {
+ file_status Status;
+ if (std::error_code EC = status(Path, Status))
+ return EC;
+
+ return Status.permissions();
}
} // end namespace fs
diff --git a/lib/Support/RWMutex.cpp b/lib/Support/RWMutex.cpp
index 3b6309cef21a..6c9781c4e2d6 100644
--- a/lib/Support/RWMutex.cpp
+++ b/lib/Support/RWMutex.cpp
@@ -13,7 +13,6 @@
#include "llvm/Config/config.h"
#include "llvm/Support/RWMutex.h"
-#include <cstring>
//===----------------------------------------------------------------------===//
//=== WARNING: Implementation here must contain only TRULY operating system
@@ -22,29 +21,31 @@
#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0
// Define all methods as no-ops if threading is explicitly disabled
-namespace llvm {
+
+using namespace llvm;
using namespace sys;
-RWMutexImpl::RWMutexImpl() { }
-RWMutexImpl::~RWMutexImpl() { }
+
+RWMutexImpl::RWMutexImpl() = default;
+RWMutexImpl::~RWMutexImpl() = default;
+
bool RWMutexImpl::reader_acquire() { return true; }
bool RWMutexImpl::reader_release() { return true; }
bool RWMutexImpl::writer_acquire() { return true; }
bool RWMutexImpl::writer_release() { return true; }
-}
+
#else
#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_RWLOCK_INIT)
#include <cassert>
+#include <cstdlib>
#include <pthread.h>
-#include <stdlib.h>
-namespace llvm {
+using namespace llvm;
using namespace sys;
// Construct a RWMutex using pthread calls
RWMutexImpl::RWMutexImpl()
- : data_(nullptr)
{
// Declare the pthread_rwlock data structures
pthread_rwlock_t* rwlock =
@@ -113,8 +114,6 @@ RWMutexImpl::writer_release()
return errorcode == 0;
}
-}
-
#elif defined(LLVM_ON_UNIX)
#include "Unix/RWMutex.inc"
#elif defined( LLVM_ON_WIN32)
diff --git a/lib/Support/Signals.cpp b/lib/Support/Signals.cpp
index e5e38f59c040..57f36bf175b3 100644
--- a/lib/Support/Signals.cpp
+++ b/lib/Support/Signals.cpp
@@ -29,7 +29,6 @@
#include <vector>
namespace llvm {
-using namespace sys;
//===----------------------------------------------------------------------===//
//=== WARNING: Implementation here must contain only TRULY operating system
diff --git a/lib/Support/SourceMgr.cpp b/lib/Support/SourceMgr.cpp
index 4cb9b2ff2cda..ca2391c10ff1 100644
--- a/lib/Support/SourceMgr.cpp
+++ b/lib/Support/SourceMgr.cpp
@@ -13,30 +13,43 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/SourceMgr.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/Locale.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/SourceMgr.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <utility>
+
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 the line # cache if allocated.
if (LineNoCacheTy *Cache = getCache(LineNoCache))
@@ -132,12 +145,10 @@ void SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const {
<< ":" << FindLineNumber(IncludeLoc, CurBuf) << ":\n";
}
-
SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
const Twine &Msg,
ArrayRef<SMRange> Ranges,
ArrayRef<SMFixIt> FixIts) const {
-
// First thing to do: find the current buffer containing the specified
// location to pull out the source line.
SmallVector<std::pair<unsigned, unsigned>, 4> ColRanges;
@@ -223,7 +234,7 @@ void SourceMgr::PrintMessage(raw_ostream &OS, SMLoc Loc,
void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
const Twine &Msg, ArrayRef<SMRange> Ranges,
ArrayRef<SMFixIt> FixIts, bool ShowColors) const {
- PrintMessage(llvm::errs(), Loc, Kind, Msg, Ranges, FixIts, ShowColors);
+ PrintMessage(errs(), Loc, Kind, Msg, Ranges, FixIts, ShowColors);
}
//===----------------------------------------------------------------------===//
@@ -233,7 +244,7 @@ void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN,
int Line, int Col, SourceMgr::DiagKind Kind,
StringRef Msg, StringRef LineStr,
- ArrayRef<std::pair<unsigned,unsigned> > Ranges,
+ ArrayRef<std::pair<unsigned,unsigned>> Ranges,
ArrayRef<SMFixIt> Hints)
: SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Kind(Kind),
Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()),
@@ -286,7 +297,7 @@ static void buildFixItLine(std::string &CaretLine, std::string &FixItLine,
// FIXME: This assertion is intended to catch unintended use of multibyte
// characters in fixits. If we decide to do this, we'll have to track
// separate byte widths for the source and fixit lines.
- assert((size_t)llvm::sys::locale::columnWidth(I->getText()) ==
+ assert((size_t)sys::locale::columnWidth(I->getText()) ==
I->getText().size());
// This relies on one byte per column in our fixit hints.
diff --git a/lib/Support/StringRef.cpp b/lib/Support/StringRef.cpp
index d81250e48dde..9b7cc1c1d182 100644
--- a/lib/Support/StringRef.cpp
+++ b/lib/Support/StringRef.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/edit_distance.h"
@@ -595,6 +596,18 @@ bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const {
return false;
}
+bool StringRef::getAsDouble(double &Result, bool AllowInexact) const {
+ APFloat F(0.0);
+ APFloat::opStatus Status =
+ F.convertFromString(*this, APFloat::rmNearestTiesToEven);
+ if (Status != APFloat::opOK) {
+ if (!AllowInexact || Status != APFloat::opInexact)
+ return true;
+ }
+
+ Result = F.convertToDouble();
+ return false;
+}
// Implementation of StringRef hashing.
hash_code llvm::hash_value(StringRef S) {
diff --git a/lib/Support/TargetParser.cpp b/lib/Support/TargetParser.cpp
index 42fab671a251..639d2ece263a 100644
--- a/lib/Support/TargetParser.cpp
+++ b/lib/Support/TargetParser.cpp
@@ -448,6 +448,8 @@ bool llvm::AArch64::getExtensionFeatures(unsigned Extensions,
Features.push_back("+spe");
if (Extensions & AArch64::AEK_RAS)
Features.push_back("+ras");
+ if (Extensions & AArch64::AEK_LSE)
+ Features.push_back("+lse");
return true;
}
@@ -725,6 +727,7 @@ unsigned llvm::ARM::parseArchProfile(StringRef Arch) {
case ARM::AK_ARMV8R:
return ARM::PK_R;
case ARM::AK_ARMV7A:
+ case ARM::AK_ARMV7VE:
case ARM::AK_ARMV7K:
case ARM::AK_ARMV8A:
case ARM::AK_ARMV8_1A:
@@ -761,6 +764,7 @@ unsigned llvm::ARM::parseArchVersion(StringRef Arch) {
case ARM::AK_ARMV6M:
return 6;
case ARM::AK_ARMV7A:
+ case ARM::AK_ARMV7VE:
case ARM::AK_ARMV7R:
case ARM::AK_ARMV7M:
case ARM::AK_ARMV7S:
diff --git a/lib/Support/Threading.cpp b/lib/Support/Threading.cpp
index 760f9e2c388b..6a10b988d464 100644
--- a/lib/Support/Threading.cpp
+++ b/lib/Support/Threading.cpp
@@ -14,14 +14,20 @@
#include "llvm/Support/Threading.h"
#include "llvm/Config/config.h"
-#include "llvm/Support/Atomic.h"
#include "llvm/Support/Host.h"
-#include "llvm/Support/Mutex.h"
-#include "llvm/Support/thread.h"
+
#include <cassert>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
using namespace llvm;
+//===----------------------------------------------------------------------===//
+//=== WARNING: Implementation here must contain only TRULY operating system
+//=== independent code.
+//===----------------------------------------------------------------------===//
+
bool llvm::llvm_is_multithreaded() {
#if LLVM_ENABLE_THREADS != 0
return true;
@@ -30,100 +36,47 @@ bool llvm::llvm_is_multithreaded() {
#endif
}
-#if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H)
-#include <pthread.h>
-
-struct ThreadInfo {
- void (*UserFn)(void *);
- void *UserData;
-};
-static void *ExecuteOnThread_Dispatch(void *Arg) {
- ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(Arg);
- TI->UserFn(TI->UserData);
- return nullptr;
-}
-
-void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData,
+#if LLVM_ENABLE_THREADS == 0 || \
+ (!defined(LLVM_ON_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) {
- ThreadInfo Info = { Fn, UserData };
- pthread_attr_t Attr;
- pthread_t Thread;
-
- // Construct the attributes object.
- if (::pthread_attr_init(&Attr) != 0)
- return;
-
- // Set the requested stack size, if given.
- if (RequestedStackSize != 0) {
- if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0)
- goto error;
- }
-
- // Construct and execute the thread.
- if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0)
- goto error;
-
- // Wait for the thread and clean up.
- ::pthread_join(Thread, nullptr);
-
- error:
- ::pthread_attr_destroy(&Attr);
+ (void)RequestedStackSize;
+ Fn(UserData);
}
-#elif LLVM_ENABLE_THREADS!=0 && defined(LLVM_ON_WIN32)
-#include "Windows/WindowsSupport.h"
-#include <process.h>
-// Windows will at times define MemoryFence.
-#ifdef MemoryFence
-#undef MemoryFence
-#endif
+unsigned llvm::heavyweight_hardware_concurrency() { return 1; }
-struct ThreadInfo {
- void (*func)(void*);
- void *param;
-};
+uint64_t llvm::get_threadid() { return 0; }
-static unsigned __stdcall ThreadCallback(void *param) {
- struct ThreadInfo *info = reinterpret_cast<struct ThreadInfo *>(param);
- info->func(info->param);
+uint32_t llvm::get_max_thread_name_length() { return 0; }
- return 0;
-}
+void llvm::set_thread_name(const Twine &Name) {}
-void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData,
- unsigned RequestedStackSize) {
- struct ThreadInfo param = { Fn, UserData };
-
- HANDLE hThread = (HANDLE)::_beginthreadex(NULL,
- RequestedStackSize, ThreadCallback,
- &param, 0, NULL);
+void llvm::get_thread_name(SmallVectorImpl<char> &Name) { Name.clear(); }
- if (hThread) {
- // We actually don't care whether the wait succeeds or fails, in
- // the same way we don't care whether the pthread_join call succeeds
- // or fails. There's not much we could do if this were to fail. But
- // on success, this call will wait until the thread finishes executing
- // before returning.
- (void)::WaitForSingleObject(hThread, INFINITE);
- ::CloseHandle(hThread);
- }
-}
#else
-// Support for non-Win32, non-pthread implementation.
-void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData,
- unsigned RequestedStackSize) {
- (void) RequestedStackSize;
- Fn(UserData);
-}
-
-#endif
+#include <thread>
unsigned llvm::heavyweight_hardware_concurrency() {
-#if !LLVM_ENABLE_THREADS
- return 1;
-#endif
+ // Since we can't get here unless LLVM_ENABLE_THREADS == 1, it is safe to use
+ // `std::thread` directly instead of `llvm::thread` (and indeed, doing so
+ // allows us to not define `thread` in the llvm namespace, which conflicts
+ // with some platforms such as FreeBSD whose headers also define a struct
+ // called `thread` in the global namespace which can cause ambiguity due to
+ // ADL.
int NumPhysical = sys::getHostNumPhysicalCores();
if (NumPhysical == -1)
- return thread::hardware_concurrency();
+ return std::thread::hardware_concurrency();
return NumPhysical;
}
+
+// Include the platform-specific parts of this class.
+#ifdef LLVM_ON_UNIX
+#include "Unix/Threading.inc"
+#endif
+#ifdef LLVM_ON_WIN32
+#include "Windows/Threading.inc"
+#endif
+
+#endif
diff --git a/lib/Support/Timer.cpp b/lib/Support/Timer.cpp
index fbd73d0b6b3b..8d68c6ae9682 100644
--- a/lib/Support/Timer.cpp
+++ b/lib/Support/Timer.cpp
@@ -72,22 +72,9 @@ std::unique_ptr<raw_fd_ostream> llvm::CreateInfoOutputFile() {
return llvm::make_unique<raw_fd_ostream>(2, false); // stderr.
}
-
-static TimerGroup *DefaultTimerGroup = nullptr;
static TimerGroup *getDefaultTimerGroup() {
- TimerGroup *tmp = DefaultTimerGroup;
- sys::MemoryFence();
- if (tmp) return tmp;
-
- sys::SmartScopedLock<true> Lock(*TimerLock);
- tmp = DefaultTimerGroup;
- if (!tmp) {
- tmp = new TimerGroup("misc", "Miscellaneous Ungrouped Timers");
- sys::MemoryFence();
- DefaultTimerGroup = tmp;
- }
-
- return tmp;
+ static TimerGroup DefaultTimerGroup("misc", "Miscellaneous Ungrouped Timers");
+ return &DefaultTimerGroup;
}
//===----------------------------------------------------------------------===//
@@ -309,7 +296,7 @@ void TimerGroup::PrintQueuedTimers(raw_ostream &OS) {
// If this is not an collection of ungrouped times, print the total time.
// Ungrouped timers don't really make sense to add up. We still print the
// TOTAL line to make the percentages make sense.
- if (this != DefaultTimerGroup)
+ if (this != getDefaultTimerGroup())
OS << format(" Total Execution Time: %5.4f seconds (%5.4f wall clock)\n",
Total.getProcessTime(), Total.getWallTime());
OS << '\n';
diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp
index 6783b40a125d..64d5977e2ebd 100644
--- a/lib/Support/Triple.cpp
+++ b/lib/Support/Triple.cpp
@@ -510,6 +510,7 @@ static Triple::ObjectFormatType parseFormat(StringRef EnvironmentName) {
.EndsWith("coff", Triple::COFF)
.EndsWith("elf", Triple::ELF)
.EndsWith("macho", Triple::MachO)
+ .EndsWith("wasm", Triple::Wasm)
.Default(Triple::UnknownObjectFormat);
}
@@ -550,6 +551,8 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) {
case ARM::AK_ARMV7A:
case ARM::AK_ARMV7R:
return Triple::ARMSubArch_v7;
+ case ARM::AK_ARMV7VE:
+ return Triple::ARMSubArch_v7ve;
case ARM::AK_ARMV7K:
return Triple::ARMSubArch_v7k;
case ARM::AK_ARMV7M:
@@ -581,6 +584,7 @@ static StringRef getObjectFormatTypeName(Triple::ObjectFormatType Kind) {
case Triple::COFF: return "coff";
case Triple::ELF: return "elf";
case Triple::MachO: return "macho";
+ case Triple::Wasm: return "wasm";
}
llvm_unreachable("unknown object format type");
}
@@ -1511,6 +1515,7 @@ StringRef Triple::getARMCPUForArch(StringRef MArch) const {
return "strongarm";
}
case llvm::Triple::NaCl:
+ case llvm::Triple::OpenBSD:
return "cortex-a8";
default:
switch (getEnvironment()) {
diff --git a/lib/Support/Twine.cpp b/lib/Support/Twine.cpp
index 465c6e6b8c4c..d17cd4e66439 100644
--- a/lib/Support/Twine.cpp
+++ b/lib/Support/Twine.cpp
@@ -173,10 +173,12 @@ void Twine::printRepr(raw_ostream &OS) const {
OS << ")";
}
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void Twine::dump() const {
print(dbgs());
}
-void Twine::dumpRepr() const {
+LLVM_DUMP_METHOD void Twine::dumpRepr() const {
printRepr(dbgs());
}
+#endif
diff --git a/lib/Support/Unix/Path.inc b/lib/Support/Unix/Path.inc
index e0b11aaff007..93f8982196b3 100644
--- a/lib/Support/Unix/Path.inc
+++ b/lib/Support/Unix/Path.inc
@@ -48,6 +48,8 @@
# endif
#endif
+#include <pwd.h>
+
#ifdef __APPLE__
#include <mach-o/dyld.h>
#include <sys/attr.h>
@@ -65,23 +67,41 @@
#endif
#include <sys/types.h>
-#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__)
+#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && \
+ !defined(__linux__)
#include <sys/statvfs.h>
#define STATVFS statvfs
+#define FSTATVFS fstatvfs
#define STATVFS_F_FRSIZE(vfs) vfs.f_frsize
#else
-#ifdef __OpenBSD__
+#if defined(__OpenBSD__) || defined(__FreeBSD__)
#include <sys/param.h>
#include <sys/mount.h>
-#elif defined(__ANDROID__)
+#elif defined(__linux__)
+#if defined(HAVE_LINUX_MAGIC_H)
+#include <linux/magic.h>
+#else
+#if defined(HAVE_LINUX_NFS_FS_H)
+#include <linux/nfs_fs.h>
+#endif
+#if defined(HAVE_LINUX_SMB_H)
+#include <linux/smb.h>
+#endif
+#endif
#include <sys/vfs.h>
#else
#include <sys/mount.h>
#endif
#define STATVFS statfs
+#define FSTATVFS fstatfs
#define STATVFS_F_FRSIZE(vfs) static_cast<uint64_t>(vfs.f_bsize)
#endif
+#if defined(__NetBSD__)
+#define STATVFS_F_FLAG(vfs) (vfs).f_flag
+#else
+#define STATVFS_F_FLAG(vfs) (vfs).f_flags
+#endif
using namespace llvm;
@@ -180,7 +200,7 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
if (getprogpath(exe_path, argv0))
return exe_path;
}
-#elif defined(HAVE_DLFCN_H)
+#elif defined(HAVE_DLFCN_H) && defined(HAVE_DLADDR)
// Use dladdr to get executable path if available.
Dl_info DLInfo;
int err = dladdr(MainAddr, &DLInfo);
@@ -210,6 +230,10 @@ UniqueID file_status::getUniqueID() const {
return UniqueID(fs_st_dev, fs_st_ino);
}
+uint32_t file_status::getLinkCount() const {
+ return fs_st_nlinks;
+}
+
ErrorOr<space_info> disk_space(const Twine &Path) {
struct STATVFS Vfs;
if (::STATVFS(Path.str().c_str(), &Vfs))
@@ -257,6 +281,16 @@ std::error_code current_path(SmallVectorImpl<char> &result) {
return std::error_code();
}
+std::error_code set_current_path(const Twine &path) {
+ SmallString<128> path_storage;
+ StringRef p = path.toNullTerminatedStringRef(path_storage);
+
+ if (::chdir(p.begin()) == -1)
+ return std::error_code(errno, std::generic_category());
+
+ return std::error_code();
+}
+
std::error_code create_directory(const Twine &path, bool IgnoreExisting,
perms Perms) {
SmallString<128> path_storage;
@@ -325,6 +359,51 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) {
return std::error_code();
}
+static bool is_local_impl(struct STATVFS &Vfs) {
+#if defined(__linux__)
+#ifndef NFS_SUPER_MAGIC
+#define NFS_SUPER_MAGIC 0x6969
+#endif
+#ifndef SMB_SUPER_MAGIC
+#define SMB_SUPER_MAGIC 0x517B
+#endif
+#ifndef CIFS_MAGIC_NUMBER
+#define CIFS_MAGIC_NUMBER 0xFF534D42
+#endif
+ switch ((uint32_t)Vfs.f_type) {
+ case NFS_SUPER_MAGIC:
+ case SMB_SUPER_MAGIC:
+ case CIFS_MAGIC_NUMBER:
+ return false;
+ default:
+ return true;
+ }
+#elif defined(__CYGWIN__)
+ // Cygwin doesn't expose this information; would need to use Win32 API.
+ return false;
+#else
+ return !!(STATVFS_F_FLAG(Vfs) & MNT_LOCAL);
+#endif
+}
+
+std::error_code is_local(const Twine &Path, bool &Result) {
+ struct STATVFS Vfs;
+ if (::STATVFS(Path.str().c_str(), &Vfs))
+ return std::error_code(errno, std::generic_category());
+
+ Result = is_local_impl(Vfs);
+ return std::error_code();
+}
+
+std::error_code is_local(int FD, bool &Result) {
+ struct STATVFS Vfs;
+ if (::FSTATVFS(FD, &Vfs))
+ return std::error_code(errno, std::generic_category());
+
+ Result = is_local_impl(Vfs);
+ return std::error_code();
+}
+
std::error_code rename(const Twine &from, const Twine &to) {
// Get arguments.
SmallString<128> from_storage;
@@ -405,6 +484,46 @@ std::error_code equivalent(const Twine &A, const Twine &B, bool &result) {
return std::error_code();
}
+static void expandTildeExpr(SmallVectorImpl<char> &Path) {
+ StringRef PathStr(Path.begin(), Path.size());
+ if (PathStr.empty() || !PathStr.startswith("~"))
+ return;
+
+ PathStr = PathStr.drop_front();
+ StringRef Expr =
+ PathStr.take_until([](char c) { return path::is_separator(c); });
+ StringRef Remainder = PathStr.substr(Expr.size() + 1);
+ SmallString<128> Storage;
+ if (Expr.empty()) {
+ // This is just ~/..., resolve it to the current user's home dir.
+ if (!path::home_directory(Storage)) {
+ // For some reason we couldn't get the home directory. Just exit.
+ return;
+ }
+
+ // Overwrite the first character and insert the rest.
+ Path[0] = Storage[0];
+ Path.insert(Path.begin() + 1, Storage.begin() + 1, Storage.end());
+ return;
+ }
+
+ // This is a string of the form ~username/, look up this user's entry in the
+ // password database.
+ struct passwd *Entry = nullptr;
+ std::string User = Expr.str();
+ Entry = ::getpwnam(User.c_str());
+
+ if (!Entry) {
+ // Unable to look up the entry, just return back the original path.
+ return;
+ }
+
+ Storage = Remainder;
+ Path.clear();
+ Path.append(Entry->pw_dir, Entry->pw_dir + strlen(Entry->pw_dir));
+ llvm::sys::path::append(Path, Storage);
+}
+
static std::error_code fillStatus(int StatRet, const struct stat &Status,
file_status &Result) {
if (StatRet != 0) {
@@ -430,22 +549,23 @@ static std::error_code fillStatus(int StatRet, const struct stat &Status,
Type = file_type::fifo_file;
else if (S_ISSOCK(Status.st_mode))
Type = file_type::socket_file;
+ else if (S_ISLNK(Status.st_mode))
+ Type = file_type::symlink_file;
- perms Perms = static_cast<perms>(Status.st_mode);
- Result =
- file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_atime,
- Status.st_mtime, Status.st_uid, Status.st_gid,
- Status.st_size);
+ perms Perms = static_cast<perms>(Status.st_mode) & all_perms;
+ Result = file_status(Type, Perms, Status.st_dev, Status.st_nlink,
+ Status.st_ino, Status.st_atime, Status.st_mtime,
+ Status.st_uid, Status.st_gid, Status.st_size);
return std::error_code();
}
-std::error_code status(const Twine &Path, file_status &Result) {
+std::error_code status(const Twine &Path, file_status &Result, bool Follow) {
SmallString<128> PathStorage;
StringRef P = Path.toNullTerminatedStringRef(PathStorage);
struct stat Status;
- int StatRet = ::stat(P.begin(), &Status);
+ int StatRet = (Follow ? ::stat : ::lstat)(P.begin(), &Status);
return fillStatus(StatRet, Status, Result);
}
@@ -455,6 +575,15 @@ std::error_code status(int FD, file_status &Result) {
return fillStatus(StatRet, Status, Result);
}
+std::error_code setPermissions(const Twine &Path, perms Permissions) {
+ SmallString<128> PathStorage;
+ StringRef P = Path.toNullTerminatedStringRef(PathStorage);
+
+ if (::chmod(P.begin(), Permissions))
+ return std::error_code(errno, std::generic_category());
+ return std::error_code();
+}
+
std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {
#if defined(HAVE_FUTIMENS)
timespec Times[2];
@@ -481,6 +610,26 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset,
int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE;
int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE);
+#if defined(__APPLE__)
+ //----------------------------------------------------------------------
+ // Newer versions of MacOSX have a flag that will allow us to read from
+ // binaries whose code signature is invalid without crashing by using
+ // the MAP_RESILIENT_CODESIGN flag. Also if a file from removable media
+ // is mapped we can avoid crashing and return zeroes to any pages we try
+ // to read if the media becomes unavailable by using the
+ // MAP_RESILIENT_MEDIA flag. These flags are only usable when mapping
+ // with PROT_READ, so take care not to specify them otherwise.
+ //----------------------------------------------------------------------
+ if (Mode == readonly) {
+#if defined(MAP_RESILIENT_CODESIGN)
+ flags |= MAP_RESILIENT_CODESIGN;
+#endif
+#if defined(MAP_RESILIENT_MEDIA)
+ flags |= MAP_RESILIENT_MEDIA;
+#endif
+ }
+#endif // #if defined (__APPLE__)
+
Mapping = ::mmap(nullptr, Size, prot, flags, FD, Offset);
if (Mapping == MAP_FAILED)
return std::error_code(errno, std::generic_category());
@@ -526,7 +675,8 @@ int mapped_file_region::alignment() {
}
std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
- StringRef path){
+ StringRef path,
+ bool follow_symlinks) {
SmallString<128> path_null(path);
DIR *directory = ::opendir(path_null.c_str());
if (!directory)
@@ -535,7 +685,7 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
it.IterationHandle = reinterpret_cast<intptr_t>(directory);
// Add something for replace_filename to replace.
path::append(path_null, ".");
- it.CurrentEntry = directory_entry(path_null.str());
+ it.CurrentEntry = directory_entry(path_null.str(), follow_symlinks);
return directory_iterator_increment(it);
}
@@ -577,10 +727,19 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
SmallVectorImpl<char> *RealPath) {
SmallString<128> Storage;
StringRef P = Name.toNullTerminatedStringRef(Storage);
- while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) {
+ int OpenFlags = O_RDONLY;
+#ifdef O_CLOEXEC
+ OpenFlags |= O_CLOEXEC;
+#endif
+ while ((ResultFD = open(P.begin(), OpenFlags)) < 0) {
if (errno != EINTR)
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
// Attempt to get the real name of the file, if the user asked
if(!RealPath)
return std::error_code();
@@ -616,6 +775,10 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
int OpenFlags = O_CREAT;
+#ifdef O_CLOEXEC
+ OpenFlags |= O_CLOEXEC;
+#endif
+
if (Flags & F_RW)
OpenFlags |= O_RDWR;
else
@@ -635,6 +798,11 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
if (errno != EINTR)
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();
}
@@ -685,18 +853,85 @@ std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath) {
return std::error_code();
}
+template <typename T>
+static std::error_code remove_directories_impl(const T &Entry,
+ bool IgnoreErrors) {
+ std::error_code EC;
+ directory_iterator Begin(Entry, EC, false);
+ directory_iterator End;
+ while (Begin != End) {
+ auto &Item = *Begin;
+ file_status st;
+ EC = Item.status(st);
+ if (EC && !IgnoreErrors)
+ return EC;
+
+ if (is_directory(st)) {
+ EC = remove_directories_impl(Item, IgnoreErrors);
+ if (EC && !IgnoreErrors)
+ return EC;
+ }
+
+ EC = fs::remove(Item.path(), true);
+ if (EC && !IgnoreErrors)
+ return EC;
+
+ Begin.increment(EC);
+ if (EC && !IgnoreErrors)
+ return EC;
+ }
+ return std::error_code();
+}
+
+std::error_code remove_directories(const Twine &path, bool IgnoreErrors) {
+ auto EC = remove_directories_impl(path, IgnoreErrors);
+ if (EC && !IgnoreErrors)
+ return EC;
+ EC = fs::remove(path, true);
+ if (EC && !IgnoreErrors)
+ return EC;
+ return std::error_code();
+}
+
+std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest,
+ bool expand_tilde) {
+ dest.clear();
+ if (path.isTriviallyEmpty())
+ return std::error_code();
+
+ if (expand_tilde) {
+ SmallString<128> Storage;
+ path.toVector(Storage);
+ expandTildeExpr(Storage);
+ return real_path(Storage, dest, false);
+ }
+
+ int fd;
+ std::error_code EC = openFileForRead(path, fd, &dest);
+
+ if (EC)
+ return EC;
+ ::close(fd);
+ return std::error_code();
+}
+
} // end namespace fs
namespace path {
bool home_directory(SmallVectorImpl<char> &result) {
- if (char *RequestedDir = getenv("HOME")) {
- result.clear();
- result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
- return true;
+ char *RequestedDir = getenv("HOME");
+ if (!RequestedDir) {
+ struct passwd *pw = getpwuid(getuid());
+ if (pw && pw->pw_dir)
+ RequestedDir = pw->pw_dir;
}
+ if (!RequestedDir)
+ return false;
- return false;
+ result.clear();
+ result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
+ return true;
}
static bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) {
diff --git a/lib/Support/Unix/Signals.inc b/lib/Support/Unix/Signals.inc
index 9752b70644c6..88ad21e9806e 100644
--- a/lib/Support/Unix/Signals.inc
+++ b/lib/Support/Unix/Signals.inc
@@ -25,8 +25,8 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <string>
-#if HAVE_EXECINFO_H
-# include <execinfo.h> // For backtrace().
+#ifdef HAVE_BACKTRACE
+# include BACKTRACE_HEADER // For backtrace().
#endif
#if HAVE_SIGNAL_H
#include <signal.h>
@@ -59,7 +59,7 @@ using namespace llvm;
static RETSIGTYPE SignalHandler(int Sig); // defined below.
-static ManagedStatic<SmartMutex<true> > SignalsMutex;
+static ManagedStatic<sys::SmartMutex<true> > SignalsMutex;
/// InterruptFunction - The function to call if ctrl-c is pressed.
static void (*InterruptFunction)() = nullptr;
@@ -149,11 +149,7 @@ static void CreateSigAltStack() {}
#endif
static void RegisterHandlers() {
- // We need to dereference the signals mutex during handler registration so
- // that we force its construction. This is to prevent the first use being
- // during handling an actual signal because you can't safely call new in a
- // signal handler.
- *SignalsMutex;
+ sys::SmartScopedLock<true> Guard(*SignalsMutex);
// If the handlers are already registered, we're done.
if (NumRegisteredSignals != 0) return;
@@ -223,7 +219,7 @@ static RETSIGTYPE SignalHandler(int Sig) {
sigprocmask(SIG_UNBLOCK, &SigMask, nullptr);
{
- unique_lock<SmartMutex<true>> Guard(*SignalsMutex);
+ unique_lock<sys::SmartMutex<true>> Guard(*SignalsMutex);
RemoveFilesToRemove();
if (std::find(std::begin(IntSigs), std::end(IntSigs), Sig)
@@ -412,7 +408,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) {
if (printSymbolizedStackTrace(Argv0, StackTrace, depth, OS))
return;
-#if HAVE_DLFCN_H && __GNUG__ && !defined(__CYGWIN__)
+#if HAVE_DLFCN_H && HAVE_DLADDR
int width = 0;
for (int i = 0; i < depth; ++i) {
Dl_info dlinfo;
@@ -462,7 +458,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) {
}
static void PrintStackTraceSignalHandler(void *) {
- PrintStackTrace(llvm::errs());
+ sys::PrintStackTrace(llvm::errs());
}
void llvm::sys::DisableSystemDialogsOnCrash() {}
diff --git a/lib/Support/Unix/Threading.inc b/lib/Support/Unix/Threading.inc
new file mode 100644
index 000000000000..407b194e1b6a
--- /dev/null
+++ b/lib/Support/Unix/Threading.inc
@@ -0,0 +1,215 @@
+//===- Unix/Threading.inc - Unix Threading Implementation ----- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides the Unix specific implementation of Threading functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+
+#if defined(__APPLE__)
+#include <mach/mach_init.h>
+#include <mach/mach_port.h>
+#endif
+
+#include <pthread.h>
+
+#if defined(__FreeBSD__)
+#include <pthread_np.h> // For pthread_getthreadid_np()
+#endif
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <errno.h>
+#include <unistd.h>
+#endif
+
+#if defined(__NetBSD__)
+#include <lwp.h> // For _lwp_self()
+#endif
+
+#if defined(__linux__)
+#include <unistd.h> // For syscall()
+#include <sys/syscall.h> // For syscall codes
+#endif
+
+namespace {
+ struct ThreadInfo {
+ void(*UserFn)(void *);
+ void *UserData;
+ };
+}
+
+static void *ExecuteOnThread_Dispatch(void *Arg) {
+ ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(Arg);
+ TI->UserFn(TI->UserData);
+ return nullptr;
+}
+
+void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData,
+ unsigned RequestedStackSize) {
+ ThreadInfo Info = { Fn, UserData };
+ pthread_attr_t Attr;
+ pthread_t Thread;
+
+ // Construct the attributes object.
+ if (::pthread_attr_init(&Attr) != 0)
+ return;
+
+ // Set the requested stack size, if given.
+ if (RequestedStackSize != 0) {
+ if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0)
+ goto error;
+ }
+
+ // Construct and execute the thread.
+ if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0)
+ goto error;
+
+ // Wait for the thread and clean up.
+ ::pthread_join(Thread, nullptr);
+
+error:
+ ::pthread_attr_destroy(&Attr);
+}
+
+
+uint64_t llvm::get_threadid() {
+#if defined(__APPLE__)
+ // Calling "mach_thread_self()" bumps the reference count on the thread
+ // port, so we need to deallocate it. mach_task_self() doesn't bump the ref
+ // count.
+ thread_port_t Self = mach_thread_self();
+ mach_port_deallocate(mach_task_self(), Self);
+ return Self;
+#elif defined(__FreeBSD__)
+ return uint64_t(pthread_getthreadid_np());
+#elif defined(__NetBSD__)
+ return uint64_t(_lwp_self());
+#elif defined(__ANDROID__)
+ 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
+}
+
+
+static constexpr uint32_t get_max_thread_name_length_impl() {
+#if defined(__NetBSD__)
+ return PTHREAD_MAX_NAMELEN_NP;
+#elif defined(__APPLE__)
+ return 64;
+#elif defined(__linux__)
+#if HAVE_PTHREAD_SETNAME_NP
+ return 16;
+#else
+ return 0;
+#endif
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ return 16;
+#else
+ return 0;
+#endif
+}
+
+uint32_t llvm::get_max_thread_name_length() {
+ return get_max_thread_name_length_impl();
+}
+
+void llvm::set_thread_name(const Twine &Name) {
+ // Make sure the input is null terminated.
+ SmallString<64> Storage;
+ StringRef NameStr = Name.toNullTerminatedStringRef(Storage);
+
+ // Truncate from the beginning, not the end, if the specified name is too
+ // long. For one, this ensures that the resulting string is still null
+ // 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.
+ if (get_max_thread_name_length() > 0)
+ NameStr = NameStr.take_back(get_max_thread_name_length());
+ (void)NameStr;
+#if defined(__linux__)
+#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__)
+#if HAVE_PTHREAD_SETNAME_NP
+ ::pthread_setname_np(::pthread_self(), NameStr.data());
+#endif
+#endif
+#elif defined(__FreeBSD__)
+ ::pthread_set_name_np(::pthread_self(), NameStr.data());
+#elif defined(__NetBSD__)
+ ::pthread_setname_np(::pthread_self(), "%s",
+ const_cast<char *>(NameStr.data()));
+#elif defined(__APPLE__)
+ ::pthread_setname_np(NameStr.data());
+#endif
+}
+
+void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
+ Name.clear();
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ int pid = ::getpid();
+ uint64_t tid = get_threadid();
+
+ struct kinfo_proc *kp = nullptr, *nkp;
+ size_t len = 0;
+ int error;
+ int ctl[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD,
+ (int)pid };
+
+ while (1) {
+ error = sysctl(ctl, 4, kp, &len, nullptr, 0);
+ 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);
+ if (nkp == nullptr) {
+ free(kp);
+ return;
+ }
+ kp = nkp;
+ continue;
+ }
+ if (error != 0)
+ len = 0;
+ break;
+ }
+
+ for (size_t i = 0; i < len / sizeof(*kp); i++) {
+ if (kp[i].ki_tid == (lwpid_t)tid) {
+ Name.append(kp[i].ki_tdname, kp[i].ki_tdname + strlen(kp[i].ki_tdname));
+ break;
+ }
+ }
+ free(kp);
+ return;
+#elif defined(__NetBSD__)
+ constexpr uint32_t len = get_max_thread_name_length_impl();
+ char buf[len];
+ ::pthread_getname_np(::pthread_self(), buf, len);
+
+ 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];
+ if (0 == ::pthread_getname_np(::pthread_self(), Buffer, len))
+ Name.append(Buffer, Buffer + strlen(Buffer));
+#endif
+#endif
+#endif
+}
diff --git a/lib/Support/Windows/DynamicLibrary.inc b/lib/Support/Windows/DynamicLibrary.inc
index 050689483deb..709499deeafa 100644
--- a/lib/Support/Windows/DynamicLibrary.inc
+++ b/lib/Support/Windows/DynamicLibrary.inc
@@ -24,7 +24,6 @@
#endif
namespace llvm {
-using namespace sys;
//===----------------------------------------------------------------------===//
//=== WARNING: Implementation here must contain only Win32 specific code
@@ -33,7 +32,7 @@ using namespace sys;
typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID);
static fpEnumerateLoadedModules fEnumerateLoadedModules;
-static DenseSet<HMODULE> *OpenedHandles;
+static llvm::ManagedStatic<DenseSet<HMODULE> > OpenedHandles;
static bool loadDebugHelp(void) {
HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll");
@@ -51,15 +50,13 @@ ELM_Callback(PCSTR ModuleName, DWORD64 ModuleBase,
return TRUE;
}
-DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
- std::string *errMsg) {
+sys::DynamicLibrary
+sys::DynamicLibrary::getPermanentLibrary(const char *filename,
+ std::string *errMsg) {
SmartScopedLock<true> lock(*SymbolsMutex);
if (!filename) {
// When no file is specified, enumerate all DLLs and EXEs in the process.
- if (OpenedHandles == 0)
- OpenedHandles = new DenseSet<HMODULE>();
-
if (!fEnumerateLoadedModules) {
if (!loadDebugHelp()) {
assert(false && "These APIs should always be available");
@@ -79,7 +76,7 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
MakeErrMsg(errMsg, std::string(filename) + ": Can't convert to UTF-16");
return DynamicLibrary();
}
-
+
HMODULE a_handle = LoadLibraryW(filenameUnicode.data());
if (a_handle == 0) {
@@ -87,9 +84,6 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
return DynamicLibrary();
}
- if (OpenedHandles == 0)
- OpenedHandles = new DenseSet<HMODULE>();
-
// If we've already loaded this library, FreeLibrary() the handle in order to
// keep the internal refcount at +1.
if (!OpenedHandles->insert(a_handle).second)
@@ -98,6 +92,18 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
return DynamicLibrary(a_handle);
}
+sys::DynamicLibrary
+sys::DynamicLibrary::addPermanentLibrary(void *handle, std::string *errMsg) {
+ SmartScopedLock<true> lock(*SymbolsMutex);
+ // If we've already loaded this library, tell the caller.
+ if (!OpenedHandles->insert((HMODULE)handle).second) {
+ MakeErrMsg(errMsg, "Library already loaded");
+ return DynamicLibrary();
+ }
+
+ return DynamicLibrary(handle);
+}
+
// Stack probing routines are in the support library (e.g. libgcc), but we don't
// have dynamic linking on windows. Provide a hook.
#define EXPLICIT_SYMBOL(SYM) \
@@ -123,7 +129,7 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
#undef INLINE_DEF_SYMBOL1
#undef INLINE_DEF_SYMBOL2
-void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) {
+void *sys::DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
SmartScopedLock<true> Lock(*SymbolsMutex);
// First check symbols added via AddSymbol().
@@ -135,7 +141,7 @@ void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) {
}
// Now search the libraries.
- if (OpenedHandles) {
+ if (OpenedHandles.isConstructed()) {
for (DenseSet<HMODULE>::iterator I = OpenedHandles->begin(),
E = OpenedHandles->end(); I != E; ++I) {
FARPROC ptr = GetProcAddress((HMODULE)*I, symbolName);
@@ -171,7 +177,7 @@ void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) {
return 0;
}
-void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
+void *sys::DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
if (!isValid())
return NULL;
if (Data == &OpenedHandles)
diff --git a/lib/Support/Windows/Mutex.inc b/lib/Support/Windows/Mutex.inc
index ab79d079122f..0af145ec9a4e 100644
--- a/lib/Support/Windows/Mutex.inc
+++ b/lib/Support/Windows/Mutex.inc
@@ -20,15 +20,14 @@
#include "llvm/Support/Mutex.h"
namespace llvm {
-using namespace sys;
-MutexImpl::MutexImpl(bool /*recursive*/)
+sys::MutexImpl::MutexImpl(bool /*recursive*/)
{
data_ = new CRITICAL_SECTION;
InitializeCriticalSection((LPCRITICAL_SECTION)data_);
}
-MutexImpl::~MutexImpl()
+sys::MutexImpl::~MutexImpl()
{
DeleteCriticalSection((LPCRITICAL_SECTION)data_);
delete (LPCRITICAL_SECTION)data_;
@@ -36,21 +35,21 @@ MutexImpl::~MutexImpl()
}
bool
-MutexImpl::acquire()
+sys::MutexImpl::acquire()
{
EnterCriticalSection((LPCRITICAL_SECTION)data_);
return true;
}
bool
-MutexImpl::release()
+sys::MutexImpl::release()
{
LeaveCriticalSection((LPCRITICAL_SECTION)data_);
return true;
}
bool
-MutexImpl::tryacquire()
+sys::MutexImpl::tryacquire()
{
return TryEnterCriticalSection((LPCRITICAL_SECTION)data_);
}
diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc
index 27b250b428a5..b00d3905f658 100644
--- a/lib/Support/Windows/Path.inc
+++ b/lib/Support/Windows/Path.inc
@@ -26,6 +26,7 @@
// These two headers must be included last, and make sure shlobj is required
// after Windows.h to make sure it picks up our definition of _WIN32_WINNT
#include "WindowsSupport.h"
+#include <shellapi.h>
#include <shlobj.h>
#undef max
@@ -178,6 +179,10 @@ TimePoint<> file_status::getLastModificationTime() const {
return toTimePoint(Time);
}
+uint32_t file_status::getLinkCount() const {
+ return NumLinks;
+}
+
std::error_code current_path(SmallVectorImpl<char> &result) {
SmallVector<wchar_t, MAX_PATH> cur_path;
DWORD len = MAX_PATH;
@@ -200,6 +205,18 @@ std::error_code current_path(SmallVectorImpl<char> &result) {
return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result);
}
+std::error_code set_current_path(const Twine &path) {
+ // Convert to utf-16.
+ SmallVector<wchar_t, 128> wide_path;
+ if (std::error_code ec = widenPath(path, wide_path))
+ return ec;
+
+ if (!::SetCurrentDirectoryW(wide_path.begin()))
+ return mapWindowsError(::GetLastError());
+
+ return std::error_code();
+}
+
std::error_code create_directory(const Twine &path, bool IgnoreExisting,
perms Perms) {
SmallVector<wchar_t, 128> path_utf16;
@@ -265,6 +282,80 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) {
return std::error_code();
}
+static std::error_code is_local_internal(SmallVectorImpl<wchar_t> &Path,
+ bool &Result) {
+ SmallVector<wchar_t, 128> VolumePath;
+ size_t Len = 128;
+ while (true) {
+ VolumePath.resize(Len);
+ BOOL Success =
+ ::GetVolumePathNameW(Path.data(), VolumePath.data(), VolumePath.size());
+
+ if (Success)
+ break;
+
+ DWORD Err = ::GetLastError();
+ if (Err != ERROR_INSUFFICIENT_BUFFER)
+ return mapWindowsError(Err);
+
+ Len *= 2;
+ }
+ // If the output buffer has exactly enough space for the path name, but not
+ // the null terminator, it will leave the output unterminated. Push a null
+ // terminator onto the end to ensure that this never happens.
+ VolumePath.push_back(L'\0');
+ VolumePath.set_size(wcslen(VolumePath.data()));
+ const wchar_t *P = VolumePath.data();
+
+ UINT Type = ::GetDriveTypeW(P);
+ switch (Type) {
+ case DRIVE_FIXED:
+ Result = true;
+ return std::error_code();
+ case DRIVE_REMOTE:
+ case DRIVE_CDROM:
+ case DRIVE_RAMDISK:
+ case DRIVE_REMOVABLE:
+ Result = false;
+ return std::error_code();
+ default:
+ return make_error_code(errc::no_such_file_or_directory);
+ }
+ llvm_unreachable("Unreachable!");
+}
+
+std::error_code is_local(const Twine &path, bool &result) {
+ if (!llvm::sys::fs::exists(path) || !llvm::sys::path::has_root_path(path))
+ return make_error_code(errc::no_such_file_or_directory);
+
+ SmallString<128> Storage;
+ StringRef P = path.toStringRef(Storage);
+
+ // Convert to utf-16.
+ SmallVector<wchar_t, 128> WidePath;
+ if (std::error_code ec = widenPath(P, WidePath))
+ return ec;
+ return is_local_internal(WidePath, result);
+}
+
+std::error_code is_local(int FD, bool &Result) {
+ SmallVector<wchar_t, 128> FinalPath;
+ HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+
+ size_t Len = 128;
+ do {
+ FinalPath.reserve(Len);
+ Len = ::GetFinalPathNameByHandleW(Handle, FinalPath.data(),
+ FinalPath.capacity() - 1, VOLUME_NAME_NT);
+ if (Len == 0)
+ return mapWindowsError(::GetLastError());
+ } while (Len > FinalPath.capacity());
+
+ FinalPath.set_size(Len);
+
+ return is_local_internal(FinalPath, Result);
+}
+
std::error_code rename(const Twine &from, const Twine &to) {
// Convert to utf-16.
SmallVector<wchar_t, 128> wide_from;
@@ -443,13 +534,16 @@ static std::error_code getStatus(HANDLE FileHandle, file_status &Result) {
file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
? file_type::directory_file
: file_type::regular_file;
- Result =
- file_status(Type, Info.ftLastAccessTime.dwHighDateTime,
- Info.ftLastAccessTime.dwLowDateTime,
- Info.ftLastWriteTime.dwHighDateTime,
- Info.ftLastWriteTime.dwLowDateTime,
- Info.dwVolumeSerialNumber, Info.nFileSizeHigh,
- Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow);
+ perms Permissions = (Info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
+ ? (all_read | all_exe)
+ : all_all;
+ Result = file_status(
+ Type, Permissions, Info.nNumberOfLinks,
+ Info.ftLastAccessTime.dwHighDateTime,
+ Info.ftLastAccessTime.dwLowDateTime,
+ Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime,
+ Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow,
+ Info.nFileIndexHigh, Info.nFileIndexLow);
return std::error_code();
}
@@ -465,7 +559,7 @@ handle_status_error:
return mapWindowsError(LastError);
}
-std::error_code status(const Twine &path, file_status &result) {
+std::error_code status(const Twine &path, file_status &result, bool Follow) {
SmallString<128> path_storage;
SmallVector<wchar_t, 128> path_utf16;
@@ -482,28 +576,19 @@ std::error_code status(const Twine &path, file_status &result) {
if (attr == INVALID_FILE_ATTRIBUTES)
return getStatus(INVALID_HANDLE_VALUE, result);
+ DWORD Flags = FILE_FLAG_BACKUP_SEMANTICS;
// Handle reparse points.
- if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
- ScopedFileHandle h(
- ::CreateFileW(path_utf16.begin(),
- 0, // Attributes only.
- FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS,
- 0));
- if (!h)
- return getStatus(INVALID_HANDLE_VALUE, result);
- }
+ if (!Follow && (attr & FILE_ATTRIBUTE_REPARSE_POINT))
+ Flags |= FILE_FLAG_OPEN_REPARSE_POINT;
ScopedFileHandle h(
::CreateFileW(path_utf16.begin(), 0, // Attributes only.
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
- if (!h)
- return getStatus(INVALID_HANDLE_VALUE, result);
+ NULL, OPEN_EXISTING, Flags, 0));
+ if (!h)
+ return getStatus(INVALID_HANDLE_VALUE, result);
- return getStatus(h, result);
+ return getStatus(h, result);
}
std::error_code status(int FD, file_status &Result) {
@@ -511,6 +596,37 @@ std::error_code status(int FD, file_status &Result) {
return getStatus(FileHandle, Result);
}
+std::error_code setPermissions(const Twine &Path, perms Permissions) {
+ SmallVector<wchar_t, 128> PathUTF16;
+ if (std::error_code EC = widenPath(Path, PathUTF16))
+ return EC;
+
+ DWORD Attributes = ::GetFileAttributesW(PathUTF16.begin());
+ if (Attributes == INVALID_FILE_ATTRIBUTES)
+ return mapWindowsError(GetLastError());
+
+ // There are many Windows file attributes that are not to do with the file
+ // permissions (e.g. FILE_ATTRIBUTE_HIDDEN). We need to be careful to preserve
+ // them.
+ if (Permissions & all_write) {
+ Attributes &= ~FILE_ATTRIBUTE_READONLY;
+ if (Attributes == 0)
+ // FILE_ATTRIBUTE_NORMAL indicates no other attributes are set.
+ Attributes |= FILE_ATTRIBUTE_NORMAL;
+ }
+ else {
+ Attributes |= FILE_ATTRIBUTE_READONLY;
+ // FILE_ATTRIBUTE_NORMAL is not compatible with any other attributes, so
+ // remove it, if it is present.
+ Attributes &= ~FILE_ATTRIBUTE_NORMAL;
+ }
+
+ if (!::SetFileAttributesW(PathUTF16.begin(), Attributes))
+ return mapWindowsError(GetLastError());
+
+ return std::error_code();
+}
+
std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {
FILETIME FT = toFILETIME(Time);
HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
@@ -616,7 +732,8 @@ int mapped_file_region::alignment() {
}
std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
- StringRef path){
+ StringRef path,
+ bool follow_symlinks) {
SmallVector<wchar_t, 128> path_utf16;
if (std::error_code ec = widenPath(path, path_utf16))
@@ -661,7 +778,7 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
it.IterationHandle = intptr_t(FindHandle.take());
SmallString<128> directory_entry_path(path);
path::append(directory_entry_path, directory_entry_name_utf8);
- it.CurrentEntry = directory_entry(directory_entry_path);
+ it.CurrentEntry = directory_entry(directory_entry_path, follow_symlinks);
return std::error_code();
}
@@ -701,6 +818,52 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
return std::error_code();
}
+static std::error_code realPathFromHandle(HANDLE H,
+ SmallVectorImpl<char> &RealPath) {
+ RealPath.clear();
+ llvm::SmallVector<wchar_t, MAX_PATH> Buffer;
+ DWORD CountChars = ::GetFinalPathNameByHandleW(
+ H, Buffer.begin(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED);
+ if (CountChars > Buffer.capacity()) {
+ // The buffer wasn't big enough, try again. In this case the return value
+ // *does* indicate the size of the null terminator.
+ Buffer.reserve(CountChars);
+ CountChars = ::GetFinalPathNameByHandleW(
+ H, Buffer.data(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED);
+ }
+ if (CountChars == 0)
+ return mapWindowsError(GetLastError());
+
+ const wchar_t *Data = Buffer.data();
+ if (CountChars >= 4) {
+ if (0 == ::memcmp(Data, L"\\\\?\\", 8)) {
+ CountChars -= 4;
+ Data += 4;
+ }
+ }
+
+ // Convert the result from UTF-16 to UTF-8.
+ return UTF16ToUTF8(Data, CountChars, RealPath);
+}
+
+static std::error_code directoryRealPath(const Twine &Name,
+ SmallVectorImpl<char> &RealPath) {
+ SmallVector<wchar_t, 128> PathUTF16;
+
+ if (std::error_code EC = widenPath(Name, PathUTF16))
+ return EC;
+
+ 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;
+}
+
std::error_code openFileForRead(const Twine &Name, int &ResultFD,
SmallVectorImpl<char> *RealPath) {
SmallVector<wchar_t, 128> PathUTF16;
@@ -732,20 +895,8 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
}
// Fetch the real name of the file, if the user asked
- if (RealPath) {
- RealPath->clear();
- wchar_t RealPathUTF16[MAX_PATH];
- DWORD CountChars =
- ::GetFinalPathNameByHandleW(H, RealPathUTF16, MAX_PATH,
- FILE_NAME_NORMALIZED);
- if (CountChars > 0 && CountChars < MAX_PATH) {
- // Convert the result from UTF-16 to UTF-8.
- SmallString<MAX_PATH> RealPathUTF8;
- if (!UTF16ToUTF8(RealPathUTF16, CountChars, RealPathUTF8))
- RealPath->append(RealPathUTF8.data(),
- RealPathUTF8.data() + strlen(RealPathUTF8.data()));
- }
- }
+ if (RealPath)
+ realPathFromHandle(H, *RealPath);
ResultFD = FD;
return std::error_code();
@@ -843,6 +994,81 @@ std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath) {
return windows::UTF16ToUTF8(TempPath.data(), CharCount, ResultPath);
}
+
+std::error_code remove_directories(const Twine &path, bool IgnoreErrors) {
+ // Convert to utf-16.
+ SmallVector<wchar_t, 128> Path16;
+ std::error_code EC = widenPath(path, Path16);
+ if (EC && !IgnoreErrors)
+ return EC;
+
+ // SHFileOperation() accepts a list of paths, and so must be double null-
+ // terminated to indicate the end of the list. The buffer is already null
+ // terminated, but since that null character is not considered part of the
+ // vector's size, pushing another one will just consume that byte. So we
+ // need to push 2 null terminators.
+ Path16.push_back(0);
+ Path16.push_back(0);
+
+ SHFILEOPSTRUCTW shfos = {};
+ shfos.wFunc = FO_DELETE;
+ shfos.pFrom = Path16.data();
+ shfos.fFlags = FOF_NO_UI;
+
+ int result = ::SHFileOperationW(&shfos);
+ if (result != 0 && !IgnoreErrors)
+ return mapWindowsError(result);
+ return std::error_code();
+}
+
+static void expandTildeExpr(SmallVectorImpl<char> &Path) {
+ // Path does not begin with a tilde expression.
+ if (Path.empty() || Path[0] != '~')
+ return;
+
+ StringRef PathStr(Path.begin(), Path.size());
+ PathStr = PathStr.drop_front();
+ StringRef Expr = PathStr.take_until([](char c) { return path::is_separator(c); });
+
+ if (!Expr.empty()) {
+ // This is probably a ~username/ expression. Don't support this on Windows.
+ return;
+ }
+
+ SmallString<128> HomeDir;
+ if (!path::home_directory(HomeDir)) {
+ // For some reason we couldn't get the home directory. Just exit.
+ return;
+ }
+
+ // Overwrite the first character and insert the rest.
+ Path[0] = HomeDir[0];
+ Path.insert(Path.begin() + 1, HomeDir.begin() + 1, HomeDir.end());
+}
+
+std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest,
+ bool expand_tilde) {
+ dest.clear();
+ if (path.isTriviallyEmpty())
+ return std::error_code();
+
+ if (expand_tilde) {
+ SmallString<128> Storage;
+ path.toVector(Storage);
+ expandTildeExpr(Storage);
+ return real_path(Storage, dest, false);
+ }
+
+ if (is_directory(path))
+ return directoryRealPath(path, dest);
+
+ int fd;
+ if (std::error_code EC = llvm::sys::fs::openFileForRead(path, fd, &dest))
+ return EC;
+ ::close(fd);
+ return std::error_code();
+}
+
} // end namespace fs
namespace path {
diff --git a/lib/Support/Windows/Process.inc b/lib/Support/Windows/Process.inc
index 8d646b3217a0..18aef610d54a 100644
--- a/lib/Support/Windows/Process.inc
+++ b/lib/Support/Windows/Process.inc
@@ -47,7 +47,6 @@
#endif
using namespace llvm;
-using namespace sys;
// This function retrieves the page size using GetNativeSystemInfo() and is
// present solely so it can be called once to initialize the self_process member
diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc
index 78fc538bd9bf..721167da5b15 100644
--- a/lib/Support/Windows/Program.inc
+++ b/lib/Support/Windows/Program.inc
@@ -29,7 +29,6 @@
//===----------------------------------------------------------------------===//
namespace llvm {
-using namespace sys;
ProcessInfo::ProcessInfo() : ProcessHandle(0), Pid(0), ReturnCode(0) {}
diff --git a/lib/Support/Windows/RWMutex.inc b/lib/Support/Windows/RWMutex.inc
index 2d1d25f67b8a..ac60c2fc05be 100644
--- a/lib/Support/Windows/RWMutex.inc
+++ b/lib/Support/Windows/RWMutex.inc
@@ -19,7 +19,6 @@
#include "WindowsSupport.h"
namespace llvm {
-using namespace sys;
// Windows has slim read-writer lock support on Vista and higher, so we
// will attempt to load the APIs. If they exist, we will use them, and
@@ -73,7 +72,7 @@ static bool loadSRW() {
return sHasSRW;
}
-RWMutexImpl::RWMutexImpl() {
+sys::RWMutexImpl::RWMutexImpl() {
if (loadSRW()) {
data_ = calloc(1, sizeof(SRWLOCK));
fpInitializeSRWLock(static_cast<PSRWLOCK>(data_));
@@ -83,14 +82,14 @@ RWMutexImpl::RWMutexImpl() {
}
}
-RWMutexImpl::~RWMutexImpl() {
+sys::RWMutexImpl::~RWMutexImpl() {
if (!sHasSRW)
DeleteCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
// Nothing to do in the case of slim reader/writers except free the memory.
free(data_);
}
-bool RWMutexImpl::reader_acquire() {
+bool sys::RWMutexImpl::reader_acquire() {
if (sHasSRW) {
fpAcquireSRWLockShared(static_cast<PSRWLOCK>(data_));
} else {
@@ -99,7 +98,7 @@ bool RWMutexImpl::reader_acquire() {
return true;
}
-bool RWMutexImpl::reader_release() {
+bool sys::RWMutexImpl::reader_release() {
if (sHasSRW) {
fpReleaseSRWLockShared(static_cast<PSRWLOCK>(data_));
} else {
@@ -108,7 +107,7 @@ bool RWMutexImpl::reader_release() {
return true;
}
-bool RWMutexImpl::writer_acquire() {
+bool sys::RWMutexImpl::writer_acquire() {
if (sHasSRW) {
fpAcquireSRWLockExclusive(static_cast<PSRWLOCK>(data_));
} else {
@@ -117,7 +116,7 @@ bool RWMutexImpl::writer_acquire() {
return true;
}
-bool RWMutexImpl::writer_release() {
+bool sys::RWMutexImpl::writer_release() {
if (sHasSRW) {
fpReleaseSRWLockExclusive(static_cast<PSRWLOCK>(data_));
} else {
diff --git a/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc
index f739421eece4..1ef51888baf3 100644
--- a/lib/Support/Windows/Signals.inc
+++ b/lib/Support/Windows/Signals.inc
@@ -776,7 +776,7 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
// the nasty sorts of crashes that aren't 100% reproducible from a set of
// inputs (or in the event that the user is unable or unwilling to provide a
// reproducible case).
- if (!llvm::Process::AreCoreFilesPrevented()) {
+ if (!llvm::sys::Process::AreCoreFilesPrevented()) {
MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo;
ExceptionInfo.ThreadId = ::GetCurrentThreadId();
ExceptionInfo.ExceptionPointers = ep;
diff --git a/lib/Support/Windows/ThreadLocal.inc b/lib/Support/Windows/ThreadLocal.inc
index b9cb8ff9836e..8be1c3ecfbb9 100644
--- a/lib/Support/Windows/ThreadLocal.inc
+++ b/lib/Support/Windows/ThreadLocal.inc
@@ -20,33 +20,32 @@
#include "llvm/Support/ThreadLocal.h"
namespace llvm {
-using namespace sys;
-ThreadLocalImpl::ThreadLocalImpl() : data() {
+sys::ThreadLocalImpl::ThreadLocalImpl() : data() {
static_assert(sizeof(DWORD) <= sizeof(data), "size too big");
DWORD* tls = reinterpret_cast<DWORD*>(&data);
*tls = TlsAlloc();
assert(*tls != TLS_OUT_OF_INDEXES);
}
-ThreadLocalImpl::~ThreadLocalImpl() {
+sys::ThreadLocalImpl::~ThreadLocalImpl() {
DWORD* tls = reinterpret_cast<DWORD*>(&data);
TlsFree(*tls);
}
-void *ThreadLocalImpl::getInstance() {
+void *sys::ThreadLocalImpl::getInstance() {
DWORD* tls = reinterpret_cast<DWORD*>(&data);
return TlsGetValue(*tls);
}
-void ThreadLocalImpl::setInstance(const void* d){
+void sys::ThreadLocalImpl::setInstance(const void* d){
DWORD* tls = reinterpret_cast<DWORD*>(&data);
int errorcode = TlsSetValue(*tls, const_cast<void*>(d));
assert(errorcode != 0);
(void)errorcode;
}
-void ThreadLocalImpl::removeInstance() {
+void sys::ThreadLocalImpl::removeInstance() {
setInstance(0);
}
diff --git a/lib/Support/Windows/Threading.inc b/lib/Support/Windows/Threading.inc
new file mode 100644
index 000000000000..decb48887af2
--- /dev/null
+++ b/lib/Support/Windows/Threading.inc
@@ -0,0 +1,109 @@
+//===- Windows/Threading.inc - Win32 Threading Implementation - -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides the Win32 specific implementation of Threading functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+
+#include "Windows/WindowsSupport.h"
+#include <process.h>
+
+// Windows will at times define MemoryFence.
+#ifdef MemoryFence
+#undef MemoryFence
+#endif
+
+namespace {
+ struct ThreadInfo {
+ void(*func)(void*);
+ void *param;
+ };
+}
+
+static unsigned __stdcall ThreadCallback(void *param) {
+ struct ThreadInfo *info = reinterpret_cast<struct ThreadInfo *>(param);
+ info->func(info->param);
+
+ return 0;
+}
+
+void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData,
+ unsigned RequestedStackSize) {
+ struct ThreadInfo param = { Fn, UserData };
+
+ HANDLE hThread = (HANDLE)::_beginthreadex(NULL,
+ RequestedStackSize, ThreadCallback,
+ &param, 0, NULL);
+
+ if (hThread) {
+ // We actually don't care whether the wait succeeds or fails, in
+ // the same way we don't care whether the pthread_join call succeeds
+ // or fails. There's not much we could do if this were to fail. But
+ // on success, this call will wait until the thread finishes executing
+ // before returning.
+ (void)::WaitForSingleObject(hThread, INFINITE);
+ ::CloseHandle(hThread);
+ }
+}
+
+uint64_t llvm::get_threadid() {
+ return uint64_t(::GetCurrentThreadId());
+}
+
+uint32_t llvm::get_max_thread_name_length() { return 0; }
+
+#if defined(_MSC_VER)
+static void SetThreadName(DWORD Id, LPCSTR Name) {
+ constexpr DWORD MS_VC_EXCEPTION = 0x406D1388;
+
+#pragma pack(push, 8)
+ struct THREADNAME_INFO {
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to thread name
+ DWORD dwThreadId; // Thread ID (-1 == current thread)
+ DWORD dwFlags; // Reserved. Do not use.
+ };
+#pragma pack(pop)
+
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = Name;
+ info.dwThreadId = Id;
+ info.dwFlags = 0;
+
+ __try {
+ ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR),
+ (ULONG_PTR *)&info);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER) {
+ }
+}
+#endif
+
+void llvm::set_thread_name(const Twine &Name) {
+#if defined(_MSC_VER)
+ // Make sure the input is null terminated.
+ SmallString<64> Storage;
+ StringRef NameStr = Name.toNullTerminatedStringRef(Storage);
+ SetThreadName(::GetCurrentThreadId(), NameStr.data());
+#endif
+}
+
+void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
+ // "Name" is not an inherent property of a thread on Windows. In fact, when
+ // you "set" the name, you are only firing a one-time message to a debugger
+ // which it interprets as a program setting its threads' name. We may be
+ // able to get fancy by creating a TLS entry when someone calls
+ // set_thread_name so that subsequent calls to get_thread_name return this
+ // value.
+ Name.clear();
+}
diff --git a/lib/Support/YAMLTraits.cpp b/lib/Support/YAMLTraits.cpp
index 9849b3aa1ce9..c410b1d56086 100644
--- a/lib/Support/YAMLTraits.cpp
+++ b/lib/Support/YAMLTraits.cpp
@@ -398,17 +398,10 @@ bool Input::canElideEmptySequence() {
//===----------------------------------------------------------------------===//
Output::Output(raw_ostream &yout, void *context, int WrapColumn)
- : IO(context),
- Out(yout),
- WrapColumn(WrapColumn),
- Column(0),
- ColumnAtFlowStart(0),
- ColumnAtMapFlowStart(0),
- NeedBitValueComma(false),
- NeedFlowSequenceComma(false),
- EnumerationMatchFound(false),
- NeedsNewLine(false) {
-}
+ : IO(context), Out(yout), WrapColumn(WrapColumn), Column(0),
+ ColumnAtFlowStart(0), ColumnAtMapFlowStart(0), NeedBitValueComma(false),
+ NeedFlowSequenceComma(false), EnumerationMatchFound(false),
+ NeedsNewLine(false), WriteDefaultValues(false) {}
Output::~Output() {
}
@@ -462,7 +455,7 @@ std::vector<StringRef> Output::keys() {
bool Output::preflightKey(const char *Key, bool Required, bool SameAsDefault,
bool &UseDefault, void *&) {
UseDefault = false;
- if (Required || !SameAsDefault) {
+ if (Required || !SameAsDefault || WriteDefaultValues) {
auto State = StateStack.back();
if (State == inFlowMapFirstKey || State == inFlowMapOtherKey) {
flowKey(Key);
diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp
index d073802db932..1abc8ed8683d 100644
--- a/lib/Support/raw_ostream.cpp
+++ b/lib/Support/raw_ostream.cpp
@@ -465,8 +465,7 @@ void format_object_base::home() {
static int getFD(StringRef Filename, std::error_code &EC,
sys::fs::OpenFlags Flags) {
// Handle "-" as stdout. Note that when we do this, we consider ourself
- // the owner of stdout. This means that we can do things like close the
- // file descriptor when we're done and set the "binary" flag globally.
+ // 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
@@ -497,6 +496,13 @@ raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered)
ShouldClose = false;
return;
}
+ // We do not want to close STDOUT as there may have been several uses of it
+ // such as the case: llc %s -o=- -pass-remarks-output=- -filetype=asm
+ // which cause multiple closes of STDOUT_FILENO and/or use-after-close of it.
+ // Using dup() in getFD doesn't work as we end up with original STDOUT_FILENO
+ // open anyhow.
+ if (FD <= STDERR_FILENO)
+ ShouldClose = false;
// Get the starting position.
off_t loc = ::lseek(FD, 0, SEEK_CUR);