summaryrefslogtreecommitdiff
path: root/llvm/lib/Support
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Support')
-rw-r--r--llvm/lib/Support/AArch64TargetParser.cpp10
-rw-r--r--llvm/lib/Support/APFixedPoint.cpp4
-rw-r--r--llvm/lib/Support/APFloat.cpp38
-rw-r--r--llvm/lib/Support/APInt.cpp455
-rw-r--r--llvm/lib/Support/ARMTargetParser.cpp14
-rw-r--r--llvm/lib/Support/BinaryStreamReader.cpp16
-rw-r--r--llvm/lib/Support/BinaryStreamRef.cpp31
-rw-r--r--llvm/lib/Support/BinaryStreamWriter.cpp6
-rw-r--r--llvm/lib/Support/Caching.cpp161
-rw-r--r--llvm/lib/Support/CommandLine.cpp13
-rw-r--r--llvm/lib/Support/CrashRecoveryContext.cpp3
-rw-r--r--llvm/lib/Support/DebugOptions.h2
-rw-r--r--llvm/lib/Support/DivisionByConstantInfo.cpp107
-rw-r--r--llvm/lib/Support/Error.cpp11
-rw-r--r--llvm/lib/Support/ErrorHandling.cpp17
-rw-r--r--llvm/lib/Support/ExtensibleRTTI.cpp7
-rw-r--r--llvm/lib/Support/FileUtilities.cpp6
-rw-r--r--llvm/lib/Support/GraphWriter.cpp10
-rw-r--r--llvm/lib/Support/Host.cpp32
-rw-r--r--llvm/lib/Support/JSON.cpp5
-rw-r--r--llvm/lib/Support/KnownBits.cpp15
-rw-r--r--llvm/lib/Support/LockFileManager.cpp2
-rw-r--r--llvm/lib/Support/MD5.cpp85
-rw-r--r--llvm/lib/Support/MSP430AttributeParser.cpp53
-rw-r--r--llvm/lib/Support/MSP430Attributes.cpp22
-rw-r--r--llvm/lib/Support/Parallel.cpp7
-rw-r--r--llvm/lib/Support/Path.cpp103
-rw-r--r--llvm/lib/Support/Process.cpp3
-rw-r--r--llvm/lib/Support/RISCVISAInfo.cpp718
-rw-r--r--llvm/lib/Support/Signposts.cpp32
-rw-r--r--llvm/lib/Support/SmallVector.cpp19
-rw-r--r--llvm/lib/Support/SpecialCaseList.cpp6
-rw-r--r--llvm/lib/Support/TargetRegistry.cpp134
-rw-r--r--llvm/lib/Support/TimeProfiler.cpp8
-rw-r--r--llvm/lib/Support/Timer.cpp5
-rw-r--r--llvm/lib/Support/Triple.cpp92
-rw-r--r--llvm/lib/Support/Unix/Memory.inc8
-rw-r--r--llvm/lib/Support/Unix/Path.inc61
-rw-r--r--llvm/lib/Support/Unix/Process.inc3
-rw-r--r--llvm/lib/Support/Unix/Program.inc3
-rw-r--r--llvm/lib/Support/Unix/Unix.h5
-rw-r--r--llvm/lib/Support/VirtualFileSystem.cpp175
-rw-r--r--llvm/lib/Support/Windows/Path.inc38
-rw-r--r--llvm/lib/Support/Windows/Process.inc4
-rw-r--r--llvm/lib/Support/Windows/Program.inc1
-rw-r--r--llvm/lib/Support/X86TargetParser.cpp82
-rw-r--r--llvm/lib/Support/raw_ostream.cpp5
47 files changed, 1943 insertions, 694 deletions
diff --git a/llvm/lib/Support/AArch64TargetParser.cpp b/llvm/lib/Support/AArch64TargetParser.cpp
index 2993892097e7..b3136a91e7f5 100644
--- a/llvm/lib/Support/AArch64TargetParser.cpp
+++ b/llvm/lib/Support/AArch64TargetParser.cpp
@@ -98,6 +98,8 @@ bool AArch64::getExtensionFeatures(uint64_t Extensions,
Features.push_back("+sve2-sha3");
if (Extensions & AEK_SVE2BITPERM)
Features.push_back("+sve2-bitperm");
+ if (Extensions & AArch64::AEK_TME)
+ Features.push_back("+tme");
if (Extensions & AEK_RCPC)
Features.push_back("+rcpc");
if (Extensions & AEK_BRBE)
@@ -118,6 +120,8 @@ bool AArch64::getExtensionFeatures(uint64_t Extensions,
bool AArch64::getArchFeatures(AArch64::ArchKind AK,
std::vector<StringRef> &Features) {
+ if (AK == ArchKind::ARMV8A)
+ Features.push_back("+v8a");
if (AK == ArchKind::ARMV8_1A)
Features.push_back("+v8.1a");
if (AK == ArchKind::ARMV8_2A)
@@ -132,6 +136,12 @@ bool AArch64::getArchFeatures(AArch64::ArchKind AK,
Features.push_back("+v8.6a");
if (AK == AArch64::ArchKind::ARMV8_7A)
Features.push_back("+v8.7a");
+ if (AK == AArch64::ArchKind::ARMV9A)
+ Features.push_back("+v9a");
+ if (AK == AArch64::ArchKind::ARMV9_1A)
+ Features.push_back("+v9.1a");
+ if (AK == AArch64::ArchKind::ARMV9_2A)
+ Features.push_back("+v9.2a");
if(AK == AArch64::ArchKind::ARMV8R)
Features.push_back("+v8r");
diff --git a/llvm/lib/Support/APFixedPoint.cpp b/llvm/lib/Support/APFixedPoint.cpp
index 9764dd51f572..61b30b5c5c60 100644
--- a/llvm/lib/Support/APFixedPoint.cpp
+++ b/llvm/lib/Support/APFixedPoint.cpp
@@ -306,7 +306,7 @@ APFixedPoint APFixedPoint::div(const APFixedPoint &Other,
APInt::sdivrem(ThisVal, OtherVal, Result, Rem);
// If the quotient is negative and the remainder is nonzero, round
// towards negative infinity by subtracting epsilon from the result.
- if (ThisVal.isNegative() != OtherVal.isNegative() && !Rem.isNullValue())
+ if (ThisVal.isNegative() != OtherVal.isNegative() && !Rem.isZero())
Result = Result - 1;
} else
Result = ThisVal.udiv(OtherVal);
@@ -381,7 +381,7 @@ void APFixedPoint::toString(SmallVectorImpl<char> &Str) const {
// Add 4 digits to hold the value after multiplying 10 (the radix)
unsigned Width = Val.getBitWidth() + 4;
APInt FractPart = Val.zextOrTrunc(Scale).zext(Width);
- APInt FractPartMask = APInt::getAllOnesValue(Scale).zext(Width);
+ APInt FractPartMask = APInt::getAllOnes(Scale).zext(Width);
APInt RadixInt = APInt(Width, 10);
IntPart.toString(Str, /*Radix=*/10);
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp
index 7abca8391f70..4b75c9db8526 100644
--- a/llvm/lib/Support/APFloat.cpp
+++ b/llvm/lib/Support/APFloat.cpp
@@ -92,7 +92,7 @@ namespace llvm {
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};
+ static const fltSemantics semPPCDoubleDouble = {-1, 0, 0, 128};
/* These are legacy semantics for the fallback, inaccrurate implementation of
IBM double-double, if the accurate semPPCDoubleDouble doesn't handle the
@@ -1288,6 +1288,23 @@ IEEEFloat::compareAbsoluteValue(const IEEEFloat &rhs) const {
return cmpEqual;
}
+/* Set the least significant BITS bits of a bignum, clear the
+ rest. */
+static void tcSetLeastSignificantBits(APInt::WordType *dst, unsigned parts,
+ unsigned bits) {
+ unsigned i = 0;
+ while (bits > APInt::APINT_BITS_PER_WORD) {
+ dst[i++] = ~(APInt::WordType)0;
+ bits -= APInt::APINT_BITS_PER_WORD;
+ }
+
+ if (bits)
+ dst[i++] = ~(APInt::WordType)0 >> (APInt::APINT_BITS_PER_WORD - bits);
+
+ while (i < parts)
+ dst[i++] = 0;
+}
+
/* Handle overflow. Sign is preserved. We either become infinity or
the largest finite number. */
IEEEFloat::opStatus IEEEFloat::handleOverflow(roundingMode rounding_mode) {
@@ -1303,8 +1320,8 @@ IEEEFloat::opStatus IEEEFloat::handleOverflow(roundingMode rounding_mode) {
/* Otherwise we become the largest finite number. */
category = fcNormal;
exponent = semantics->maxExponent;
- APInt::tcSetLeastSignificantBits(significandParts(), partCount(),
- semantics->precision);
+ tcSetLeastSignificantBits(significandParts(), partCount(),
+ semantics->precision);
return opInexact;
}
@@ -2412,7 +2429,7 @@ IEEEFloat::convertToInteger(MutableArrayRef<integerPart> parts,
else
bits = width - isSigned;
- APInt::tcSetLeastSignificantBits(parts.data(), dstPartsCount, bits);
+ tcSetLeastSignificantBits(parts.data(), dstPartsCount, bits);
if (sign && isSigned)
APInt::tcShiftLeft(parts.data(), dstPartsCount, width - 1);
}
@@ -3379,7 +3396,6 @@ double IEEEFloat::convertToDouble() const {
/// exponent = 0, integer bit 1 ("pseudodenormal")
/// At the moment, the first three are treated as NaNs, the last one as Normal.
void IEEEFloat::initFromF80LongDoubleAPInt(const APInt &api) {
- assert(api.getBitWidth()==80);
uint64_t i1 = api.getRawData()[0];
uint64_t i2 = api.getRawData()[1];
uint64_t myexponent = (i2 & 0x7fff);
@@ -3411,7 +3427,6 @@ void IEEEFloat::initFromF80LongDoubleAPInt(const APInt &api) {
}
void IEEEFloat::initFromPPCDoubleDoubleAPInt(const APInt &api) {
- assert(api.getBitWidth()==128);
uint64_t i1 = api.getRawData()[0];
uint64_t i2 = api.getRawData()[1];
opStatus fs;
@@ -3435,7 +3450,6 @@ void IEEEFloat::initFromPPCDoubleDoubleAPInt(const APInt &api) {
}
void IEEEFloat::initFromQuadrupleAPInt(const APInt &api) {
- assert(api.getBitWidth()==128);
uint64_t i1 = api.getRawData()[0];
uint64_t i2 = api.getRawData()[1];
uint64_t myexponent = (i2 >> 48) & 0x7fff;
@@ -3471,7 +3485,6 @@ void IEEEFloat::initFromQuadrupleAPInt(const APInt &api) {
}
void IEEEFloat::initFromDoubleAPInt(const APInt &api) {
- assert(api.getBitWidth()==64);
uint64_t i = *api.getRawData();
uint64_t myexponent = (i >> 52) & 0x7ff;
uint64_t mysignificand = i & 0xfffffffffffffLL;
@@ -3500,7 +3513,6 @@ void IEEEFloat::initFromDoubleAPInt(const APInt &api) {
}
void IEEEFloat::initFromFloatAPInt(const APInt &api) {
- assert(api.getBitWidth()==32);
uint32_t i = (uint32_t)*api.getRawData();
uint32_t myexponent = (i >> 23) & 0xff;
uint32_t mysignificand = i & 0x7fffff;
@@ -3529,7 +3541,6 @@ void IEEEFloat::initFromFloatAPInt(const APInt &api) {
}
void IEEEFloat::initFromBFloatAPInt(const APInt &api) {
- assert(api.getBitWidth() == 16);
uint32_t i = (uint32_t)*api.getRawData();
uint32_t myexponent = (i >> 7) & 0xff;
uint32_t mysignificand = i & 0x7f;
@@ -3558,7 +3569,6 @@ void IEEEFloat::initFromBFloatAPInt(const APInt &api) {
}
void IEEEFloat::initFromHalfAPInt(const APInt &api) {
- assert(api.getBitWidth()==16);
uint32_t i = (uint32_t)*api.getRawData();
uint32_t myexponent = (i >> 10) & 0x1f;
uint32_t mysignificand = i & 0x3ff;
@@ -3591,6 +3601,7 @@ void IEEEFloat::initFromHalfAPInt(const APInt &api) {
/// isIEEE argument distinguishes between PPC128 and IEEE128 (not meaningful
/// when the size is anything else).
void IEEEFloat::initFromAPInt(const fltSemantics *Sem, const APInt &api) {
+ assert(api.getBitWidth() == Sem->sizeInBits);
if (Sem == &semIEEEhalf)
return initFromHalfAPInt(api);
if (Sem == &semBFloat)
@@ -4847,9 +4858,8 @@ APFloat::opStatus APFloat::convert(const fltSemantics &ToSemantics,
llvm_unreachable("Unexpected semantics");
}
-APFloat APFloat::getAllOnesValue(const fltSemantics &Semantics,
- unsigned BitWidth) {
- return APFloat(Semantics, APInt::getAllOnesValue(BitWidth));
+APFloat APFloat::getAllOnesValue(const fltSemantics &Semantics) {
+ return APFloat(Semantics, APInt::getAllOnes(Semantics.sizeInBits));
}
void APFloat::print(raw_ostream &OS) const {
diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp
index a8a950f09747..4940b61602d1 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -89,7 +89,6 @@ void APInt::initSlowCase(const APInt& that) {
}
void APInt::initFromArray(ArrayRef<uint64_t> bigVal) {
- assert(BitWidth && "Bitwidth too small");
assert(bigVal.data() && "Null pointer detected!");
if (isSingleWord())
U.VAL = bigVal[0];
@@ -105,19 +104,17 @@ void APInt::initFromArray(ArrayRef<uint64_t> bigVal) {
clearUnusedBits();
}
-APInt::APInt(unsigned numBits, ArrayRef<uint64_t> bigVal)
- : BitWidth(numBits) {
+APInt::APInt(unsigned numBits, ArrayRef<uint64_t> bigVal) : BitWidth(numBits) {
initFromArray(bigVal);
}
APInt::APInt(unsigned numBits, unsigned numWords, const uint64_t bigVal[])
- : BitWidth(numBits) {
+ : BitWidth(numBits) {
initFromArray(makeArrayRef(bigVal, numWords));
}
APInt::APInt(unsigned numbits, StringRef Str, uint8_t radix)
- : BitWidth(numbits) {
- assert(BitWidth && "Bitwidth too small");
+ : BitWidth(numbits) {
fromString(numbits, Str, radix);
}
@@ -140,7 +137,7 @@ void APInt::reallocate(unsigned NewBitWidth) {
U.pVal = getMemory(getNumWords());
}
-void APInt::AssignSlowCase(const APInt& RHS) {
+void APInt::assignSlowCase(const APInt &RHS) {
// Don't do anything for X = X
if (this == &RHS)
return;
@@ -233,27 +230,30 @@ APInt APInt::operator*(const APInt& RHS) const {
return APInt(BitWidth, U.VAL * RHS.U.VAL);
APInt Result(getMemory(getNumWords()), getBitWidth());
-
tcMultiply(Result.U.pVal, U.pVal, RHS.U.pVal, getNumWords());
-
Result.clearUnusedBits();
return Result;
}
-void APInt::AndAssignSlowCase(const APInt& RHS) {
- tcAnd(U.pVal, RHS.U.pVal, getNumWords());
+void APInt::andAssignSlowCase(const APInt &RHS) {
+ WordType *dst = U.pVal, *rhs = RHS.U.pVal;
+ for (size_t i = 0, e = getNumWords(); i != e; ++i)
+ dst[i] &= rhs[i];
}
-void APInt::OrAssignSlowCase(const APInt& RHS) {
- tcOr(U.pVal, RHS.U.pVal, getNumWords());
+void APInt::orAssignSlowCase(const APInt &RHS) {
+ WordType *dst = U.pVal, *rhs = RHS.U.pVal;
+ for (size_t i = 0, e = getNumWords(); i != e; ++i)
+ dst[i] |= rhs[i];
}
-void APInt::XorAssignSlowCase(const APInt& RHS) {
- tcXor(U.pVal, RHS.U.pVal, getNumWords());
+void APInt::xorAssignSlowCase(const APInt &RHS) {
+ WordType *dst = U.pVal, *rhs = RHS.U.pVal;
+ for (size_t i = 0, e = getNumWords(); i != e; ++i)
+ dst[i] ^= rhs[i];
}
-APInt& APInt::operator*=(const APInt& RHS) {
- assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
+APInt &APInt::operator*=(const APInt &RHS) {
*this = *this * RHS;
return *this;
}
@@ -268,7 +268,7 @@ APInt& APInt::operator*=(uint64_t RHS) {
return clearUnusedBits();
}
-bool APInt::EqualSlowCase(const APInt& RHS) const {
+bool APInt::equalSlowCase(const APInt &RHS) const {
return std::equal(U.pVal, U.pVal + getNumWords(), RHS.U.pVal);
}
@@ -327,12 +327,29 @@ void APInt::setBitsSlowCase(unsigned loBit, unsigned hiBit) {
U.pVal[word] = WORDTYPE_MAX;
}
+// Complement a bignum in-place.
+static void tcComplement(APInt::WordType *dst, unsigned parts) {
+ for (unsigned i = 0; i < parts; i++)
+ dst[i] = ~dst[i];
+}
+
/// Toggle every bit to its opposite value.
void APInt::flipAllBitsSlowCase() {
tcComplement(U.pVal, getNumWords());
clearUnusedBits();
}
+/// Concatenate the bits from "NewLSB" onto the bottom of *this. This is
+/// equivalent to:
+/// (this->zext(NewWidth) << NewLSB.getBitWidth()) | NewLSB.zext(NewWidth)
+/// In the slow case, we know the result is large.
+APInt APInt::concatSlowCase(const APInt &NewLSB) const {
+ unsigned NewWidth = getBitWidth() + NewLSB.getBitWidth();
+ APInt Result = NewLSB.zextOrSelf(NewWidth);
+ Result.insertBits(*this, NewLSB.getBitWidth());
+ return Result;
+}
+
/// Toggle a given bit to its opposite value whose position is given
/// as "bitPosition".
/// Toggles a given bit to its opposite value.
@@ -343,8 +360,11 @@ void APInt::flipBit(unsigned bitPosition) {
void APInt::insertBits(const APInt &subBits, unsigned bitPosition) {
unsigned subBitWidth = subBits.getBitWidth();
- assert(0 < subBitWidth && (subBitWidth + bitPosition) <= BitWidth &&
- "Illegal bit insertion");
+ assert((subBitWidth + bitPosition) <= BitWidth && "Illegal bit insertion");
+
+ // inserting no bits is a noop.
+ if (subBitWidth == 0)
+ return;
// Insertion is a direct copy.
if (subBitWidth == BitWidth) {
@@ -424,7 +444,6 @@ void APInt::insertBits(uint64_t subBits, unsigned bitPosition, unsigned numBits)
}
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");
@@ -550,7 +569,7 @@ hash_code llvm::hash_value(const APInt &Arg) {
hash_combine_range(Arg.U.pVal, Arg.U.pVal + Arg.getNumWords()));
}
-unsigned DenseMapInfo<APInt>::getHashValue(const APInt &Key) {
+unsigned DenseMapInfo<APInt, void>::getHashValue(const APInt &Key) {
return static_cast<unsigned>(hash_value(Key));
}
@@ -702,6 +721,8 @@ APInt APInt::reverseBits() const {
return APInt(BitWidth, llvm::reverseBits<uint16_t>(U.VAL));
case 8:
return APInt(BitWidth, llvm::reverseBits<uint8_t>(U.VAL));
+ case 0:
+ return *this;
default:
break;
}
@@ -861,7 +882,6 @@ double APInt::roundToDouble(bool isSigned) const {
// Truncate to new width.
APInt APInt::trunc(unsigned width) const {
assert(width < BitWidth && "Invalid APInt Truncate request");
- assert(width && "Can't truncate to 0 bits");
if (width <= APINT_BITS_PER_WORD)
return APInt(width, getRawData()[0]);
@@ -884,7 +904,6 @@ APInt APInt::trunc(unsigned width) const {
// Truncate to new width with unsigned saturation.
APInt APInt::truncUSat(unsigned width) const {
assert(width < BitWidth && "Invalid APInt Truncate request");
- assert(width && "Can't truncate to 0 bits");
// Can we just losslessly truncate it?
if (isIntN(width))
@@ -896,7 +915,6 @@ APInt APInt::truncUSat(unsigned width) const {
// Truncate to new width with signed saturation.
APInt APInt::truncSSat(unsigned width) const {
assert(width < BitWidth && "Invalid APInt Truncate request");
- assert(width && "Can't truncate to 0 bits");
// Can we just losslessly truncate it?
if (isSignedIntN(width))
@@ -1059,6 +1077,8 @@ void APInt::shlSlowCase(unsigned ShiftAmt) {
// Calculate the rotate amount modulo the bit width.
static unsigned rotateModulo(unsigned BitWidth, const APInt &rotateAmt) {
+ if (LLVM_UNLIKELY(BitWidth == 0))
+ return 0;
unsigned rotBitWidth = rotateAmt.getBitWidth();
APInt rot = rotateAmt;
if (rotBitWidth < BitWidth) {
@@ -1075,6 +1095,8 @@ APInt APInt::rotl(const APInt &rotateAmt) const {
}
APInt APInt::rotl(unsigned rotateAmt) const {
+ if (LLVM_UNLIKELY(BitWidth == 0))
+ return *this;
rotateAmt %= BitWidth;
if (rotateAmt == 0)
return *this;
@@ -1086,12 +1108,43 @@ APInt APInt::rotr(const APInt &rotateAmt) const {
}
APInt APInt::rotr(unsigned rotateAmt) const {
+ if (BitWidth == 0)
+ return *this;
rotateAmt %= BitWidth;
if (rotateAmt == 0)
return *this;
return lshr(rotateAmt) | shl(BitWidth - rotateAmt);
}
+/// \returns the nearest log base 2 of this APInt. Ties round up.
+///
+/// NOTE: When we have a BitWidth of 1, we define:
+///
+/// log2(0) = UINT32_MAX
+/// log2(1) = 0
+///
+/// to get around any mathematical concerns resulting from
+/// referencing 2 in a space where 2 does no exist.
+unsigned APInt::nearestLogBase2() const {
+ // Special case when we have a bitwidth of 1. If VAL is 1, then we
+ // get 0. If VAL is 0, we get WORDTYPE_MAX which gets truncated to
+ // UINT32_MAX.
+ if (BitWidth == 1)
+ return U.VAL - 1;
+
+ // Handle the zero case.
+ if (isZero())
+ return UINT32_MAX;
+
+ // The non-zero case is handled by computing:
+ //
+ // nearestLogBase2(x) = logBase2(x) + x[logBase2(x)-1].
+ //
+ // where x[i] is referring to the value of the ith bit of x.
+ unsigned lg = logBase2();
+ return lg + unsigned((*this)[lg - 1]);
+}
+
// Square Root - this method computes and returns the square root of "this".
// Three mechanisms are used for computation. For small values (<= 5 bits),
// a table lookup is done. This gets some performance for common cases. For
@@ -1222,98 +1275,6 @@ APInt APInt::multiplicativeInverse(const APInt& modulo) const {
return std::move(t[i]);
}
-/// Calculate the magic numbers required to implement a signed integer division
-/// by a constant as a sequence of multiplies, adds and shifts. Requires that
-/// the divisor not be 0, 1, or -1. Taken from "Hacker's Delight", Henry S.
-/// Warren, Jr., chapter 10.
-APInt::ms APInt::magic() const {
- const APInt& d = *this;
- unsigned p;
- APInt ad, anc, delta, q1, r1, q2, r2, t;
- APInt signedMin = APInt::getSignedMinValue(d.getBitWidth());
- struct ms mag;
-
- ad = d.abs();
- t = signedMin + (d.lshr(d.getBitWidth() - 1));
- anc = t - 1 - t.urem(ad); // absolute value of nc
- p = d.getBitWidth() - 1; // initialize p
- q1 = signedMin.udiv(anc); // initialize q1 = 2p/abs(nc)
- r1 = signedMin - q1*anc; // initialize r1 = rem(2p,abs(nc))
- q2 = signedMin.udiv(ad); // initialize q2 = 2p/abs(d)
- r2 = signedMin - q2*ad; // initialize r2 = rem(2p,abs(d))
- do {
- p = p + 1;
- q1 = q1<<1; // update q1 = 2p/abs(nc)
- r1 = r1<<1; // update r1 = rem(2p/abs(nc))
- if (r1.uge(anc)) { // must be unsigned comparison
- q1 = q1 + 1;
- r1 = r1 - anc;
- }
- q2 = q2<<1; // update q2 = 2p/abs(d)
- r2 = r2<<1; // update r2 = rem(2p/abs(d))
- if (r2.uge(ad)) { // must be unsigned comparison
- q2 = q2 + 1;
- r2 = r2 - ad;
- }
- delta = ad - r2;
- } while (q1.ult(delta) || (q1 == delta && r1 == 0));
-
- mag.m = q2 + 1;
- if (d.isNegative()) mag.m = -mag.m; // resulting magic number
- mag.s = p - d.getBitWidth(); // resulting shift
- return mag;
-}
-
-/// Calculate the magic numbers required to implement an unsigned integer
-/// division by a constant as a sequence of multiplies, adds and shifts.
-/// Requires that the divisor not be 0. Taken from "Hacker's Delight", Henry
-/// S. Warren, Jr., chapter 10.
-/// LeadingZeros can be used to simplify the calculation if the upper bits
-/// of the divided value are known zero.
-APInt::mu APInt::magicu(unsigned LeadingZeros) const {
- const APInt& d = *this;
- unsigned p;
- APInt nc, delta, q1, r1, q2, r2;
- struct mu magu;
- magu.a = 0; // initialize "add" indicator
- APInt allOnes = APInt::getAllOnesValue(d.getBitWidth()).lshr(LeadingZeros);
- APInt signedMin = APInt::getSignedMinValue(d.getBitWidth());
- APInt signedMax = APInt::getSignedMaxValue(d.getBitWidth());
-
- nc = allOnes - (allOnes - d).urem(d);
- p = d.getBitWidth() - 1; // initialize p
- q1 = signedMin.udiv(nc); // initialize q1 = 2p/nc
- r1 = signedMin - q1*nc; // initialize r1 = rem(2p,nc)
- q2 = signedMax.udiv(d); // initialize q2 = (2p-1)/d
- r2 = signedMax - q2*d; // initialize r2 = rem((2p-1),d)
- do {
- p = p + 1;
- if (r1.uge(nc - r1)) {
- q1 = q1 + q1 + 1; // update q1
- r1 = r1 + r1 - nc; // update r1
- }
- else {
- q1 = q1+q1; // update q1
- r1 = r1+r1; // update r1
- }
- if ((r2 + 1).uge(d - r2)) {
- if (q2.uge(signedMax)) magu.a = 1;
- q2 = q2+q2 + 1; // update q2
- r2 = r2+r2 + 1 - d; // update r2
- }
- else {
- if (q2.uge(signedMin)) magu.a = 1;
- q2 = q2+q2; // update q2
- r2 = r2+r2 + 1; // update r2
- }
- delta = d - 1 - r2;
- } while (p < d.getBitWidth()*2 &&
- (q1.ult(delta) || (q1 == delta && r1 == 0)));
- magu.m = q2 + 1; // resulting magic number
- magu.s = p - d.getBitWidth(); // resulting shift
- return magu;
-}
-
/// Implementation of Knuth's Algorithm D (Division of nonnegative integers)
/// from "Art of Computer Programming, Volume 2", section 4.3.1, p. 272. The
/// variables here have the same names as in the algorithm. Comments explain
@@ -1984,15 +1945,16 @@ APInt APInt::usub_ov(const APInt &RHS, bool &Overflow) const {
APInt APInt::sdiv_ov(const APInt &RHS, bool &Overflow) const {
// MININT/-1 --> overflow.
- Overflow = isMinSignedValue() && RHS.isAllOnesValue();
+ Overflow = isMinSignedValue() && RHS.isAllOnes();
return sdiv(RHS);
}
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;
+ if (RHS != 0)
+ Overflow = Res.sdiv(RHS) != *this ||
+ (isMinSignedValue() && RHS.isAllOnes());
else
Overflow = false;
return Res;
@@ -2196,7 +2158,7 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix,
}
// First, check for a zero value and just short circuit the logic below.
- if (*this == 0) {
+ if (isZero()) {
while (*Prefix) {
Str.push_back(*Prefix);
++Prefix;
@@ -2305,55 +2267,51 @@ void APInt::print(raw_ostream &OS, bool isSigned) const {
static_assert(APInt::APINT_BITS_PER_WORD % 2 == 0,
"Part width must be divisible by 2!");
-/* Some handy functions local to this file. */
-
-/* Returns the integer part with the least significant BITS set.
- BITS cannot be zero. */
+// 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 ~(APInt::WordType) 0 >> (APInt::APINT_BITS_PER_WORD - bits);
}
-/* Returns the value of the lower half of PART. */
+/// 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. */
+/// 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. */
+/// 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. */
+/// 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. */
+/// Sets the least significant part of a bignum to the input value, and zeroes
+/// out higher parts.
void APInt::tcSet(WordType *dst, WordType part, unsigned parts) {
assert(parts > 0);
-
dst[0] = part;
for (unsigned i = 1; i < parts; i++)
dst[i] = 0;
}
-/* Assign one bignum to another. */
+/// Assign one bignum to another.
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. */
+/// Returns true if a bignum is zero, false otherwise.
bool APInt::tcIsZero(const WordType *src, unsigned parts) {
for (unsigned i = 0; i < parts; i++)
if (src[i])
@@ -2362,28 +2320,27 @@ bool APInt::tcIsZero(const WordType *src, unsigned parts) {
return true;
}
-/* Extract the given bit of a bignum; returns 0 or 1. */
+/// Extract the given bit of a bignum; returns 0 or 1.
int APInt::tcExtractBit(const WordType *parts, unsigned bit) {
return (parts[whichWord(bit)] & maskBit(bit)) != 0;
}
-/* Set the given bit of a bignum. */
+/// Set the given bit of a bignum.
void APInt::tcSetBit(WordType *parts, unsigned bit) {
parts[whichWord(bit)] |= maskBit(bit);
}
-/* Clears the given bit of a bignum. */
+/// Clears the given bit of a bignum.
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. */
+/// 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 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 * APINT_BITS_PER_WORD;
}
}
@@ -2391,8 +2348,8 @@ unsigned APInt::tcLSB(const WordType *parts, unsigned n) {
return -1U;
}
-/* Returns the bit number of the most significant set bit of a number.
- If the input number has no bits set -1U is returned. */
+/// 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 APInt::tcMSB(const WordType *parts, unsigned n) {
do {
--n;
@@ -2407,10 +2364,10 @@ unsigned APInt::tcMSB(const WordType *parts, unsigned n) {
return -1U;
}
-/* Copy the bit vector of width srcBITS from SRC, starting at bit
- srcLSB, to DST, of dstCOUNT parts, such that the bit srcLSB becomes
- the least significant bit of DST. All high bits above srcBITS in
- DST are zero-filled. */
+/// Copy the bit vector of width srcBITS from SRC, starting at bit srcLSB, to
+/// DST, of dstCOUNT parts, such that the bit srcLSB becomes the least
+/// significant bit of DST. All high bits above srcBITS in DST are zero-filled.
+/// */
void
APInt::tcExtract(WordType *dst, unsigned dstCount, const WordType *src,
unsigned srcBits, unsigned srcLSB) {
@@ -2418,14 +2375,14 @@ APInt::tcExtract(WordType *dst, unsigned dstCount, const WordType *src,
assert(dstParts <= dstCount);
unsigned firstSrcPart = srcLSB / APINT_BITS_PER_WORD;
- tcAssign (dst, src + firstSrcPart, dstParts);
+ tcAssign(dst, src + firstSrcPart, dstParts);
unsigned shift = srcLSB % APINT_BITS_PER_WORD;
- tcShiftRight (dst, dstParts, shift);
+ tcShiftRight(dst, dstParts, shift);
- /* 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. */
+ // 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.
unsigned n = dstParts * APINT_BITS_PER_WORD - shift;
if (n < srcBits) {
WordType mask = lowBitMask (srcBits - n);
@@ -2436,12 +2393,12 @@ APInt::tcExtract(WordType *dst, unsigned dstCount, const WordType *src,
dst[dstParts - 1] &= lowBitMask (srcBits % APINT_BITS_PER_WORD);
}
- /* Clear high parts. */
+ // Clear high parts.
while (dstParts < dstCount)
dst[dstParts++] = 0;
}
-/* DST += RHS + C where C is zero or one. Returns the carry flag. */
+//// DST += RHS + C where C is zero or one. Returns the carry flag.
APInt::WordType APInt::tcAdd(WordType *dst, const WordType *rhs,
WordType c, unsigned parts) {
assert(c <= 1);
@@ -2476,7 +2433,7 @@ APInt::WordType APInt::tcAddPart(WordType *dst, WordType src,
return 1;
}
-/* DST -= RHS + C where C is zero or one. Returns the carry flag. */
+/// 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);
@@ -2515,47 +2472,39 @@ APInt::WordType APInt::tcSubtractPart(WordType *dst, WordType src,
return 1;
}
-/* Negate a bignum in-place. */
+/// Negate a bignum in-place.
void APInt::tcNegate(WordType *dst, unsigned parts) {
tcComplement(dst, parts);
tcIncrement(dst, parts);
}
-/* DST += SRC * MULTIPLIER + CARRY if add is true
- DST = SRC * MULTIPLIER + CARRY if add is false
-
- Requires 0 <= DSTPARTS <= SRCPARTS + 1. If DST overlaps SRC
- they must start at the same point, i.e. DST == SRC.
-
- If DSTPARTS == SRCPARTS + 1 no overflow occurs and zero is
- returned. Otherwise DST is filled with the least significant
- DSTPARTS parts of the result, and if all of the omitted higher
- parts were zero return zero, otherwise overflow occurred and
- return one. */
+/// DST += SRC * MULTIPLIER + CARRY if add is true
+/// DST = SRC * MULTIPLIER + CARRY if add is false
+/// Requires 0 <= DSTPARTS <= SRCPARTS + 1. If DST overlaps SRC
+/// they must start at the same point, i.e. DST == SRC.
+/// If DSTPARTS == SRCPARTS + 1 no overflow occurs and zero is
+/// returned. Otherwise DST is filled with the least significant
+/// 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(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. */
+ // 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 loops; minimum of dstParts and srcParts.
unsigned n = std::min(dstParts, srcParts);
for (unsigned i = 0; i < n; i++) {
- WordType low, mid, high, srcPart;
-
- /* [ LOW, HIGH ] = MULTIPLIER * SRC[i] + DST[i] + CARRY.
-
- This cannot overflow, because
-
- (n - 1) * (n - 1) + 2 (n - 1) = (n - 1) * (n + 1)
-
- which is less than n^2. */
-
- srcPart = src[i];
-
+ // [LOW, HIGH] = MULTIPLIER * SRC[i] + DST[i] + CARRY.
+ // This cannot overflow, because:
+ // (n - 1) * (n - 1) + 2 (n - 1) = (n - 1) * (n + 1)
+ // which is less than n^2.
+ WordType srcPart = src[i];
+ WordType low, mid, high;
if (multiplier == 0 || srcPart == 0) {
low = carry;
high = 0;
@@ -2577,14 +2526,14 @@ int APInt::tcMultiplyPart(WordType *dst, const WordType *src,
high++;
low += mid;
- /* Now add carry. */
+ // Now add carry.
if (low + carry < low)
high++;
low += carry;
}
if (add) {
- /* And now DST[i], and store the new low part there. */
+ // And now DST[i], and store the new low part there.
if (low + dst[i] < low)
high++;
dst[i] += low;
@@ -2595,32 +2544,32 @@ int APInt::tcMultiplyPart(WordType *dst, const WordType *src,
}
if (srcParts < dstParts) {
- /* Full multiplication, there is no overflow. */
+ // Full multiplication, there is no overflow.
assert(srcParts + 1 == dstParts);
dst[srcParts] = carry;
return 0;
}
- /* We overflowed if there is carry. */
+ // We overflowed if there is carry.
if (carry)
return 1;
- /* We would overflow if any significant unwritten parts would be
- non-zero. This is true if any remaining src parts are non-zero
- and the multiplier is non-zero. */
+ // We would overflow if any significant unwritten parts would be
+ // non-zero. This is true if any remaining src parts are non-zero
+ // and the multiplier is non-zero.
if (multiplier)
for (unsigned i = dstParts; i < srcParts; i++)
if (src[i])
return 1;
- /* We fitted in the narrow destination. */
+ // We fitted in the narrow destination.
return 0;
}
-/* DST = LHS * RHS, where DST has the same width as the operands and
- is filled with the least significant parts of the result. Returns
- one if overflow occurred, otherwise zero. DST must be disjoint
- from both operands. */
+/// DST = LHS * RHS, where DST has the same width as the operands and
+/// 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(WordType *dst, const WordType *lhs,
const WordType *rhs, unsigned parts) {
assert(dst != lhs && dst != rhs);
@@ -2640,7 +2589,7 @@ int APInt::tcMultiply(WordType *dst, const WordType *lhs,
void 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. */
+ // Put the narrower number on the LHS for less loops below.
if (lhsParts > rhsParts)
return tcFullMultiply (dst, rhs, lhs, rhsParts, lhsParts);
@@ -2652,16 +2601,15 @@ void APInt::tcFullMultiply(WordType *dst, const WordType *lhs,
tcMultiplyPart(&dst[i], rhs, lhs[i], 0, rhsParts, rhsParts + 1, true);
}
-/* If RHS is zero LHS and REMAINDER are left unchanged, return one.
- Otherwise set LHS to LHS / RHS with the fractional part discarded,
- set REMAINDER to the remainder, return zero. i.e.
-
- OLD_LHS = RHS * LHS + REMAINDER
-
- SCRATCH is a bignum of the same size as the operands and result for
- use by the routine; its contents need not be initialized and are
- destroyed. LHS, REMAINDER and SCRATCH must be distinct.
-*/
+// If RHS is zero LHS and REMAINDER are left unchanged, return one.
+// Otherwise set LHS to LHS / RHS with the fractional part discarded,
+// set REMAINDER to the remainder, return zero. i.e.
+//
+// OLD_LHS = RHS * LHS + REMAINDER
+//
+// SCRATCH is a bignum of the same size as the operands and result for
+// use by the routine; its contents need not be initialized and are
+// destroyed. LHS, REMAINDER and SCRATCH must be distinct.
int APInt::tcDivide(WordType *lhs, const WordType *rhs,
WordType *remainder, WordType *srhs,
unsigned parts) {
@@ -2680,8 +2628,8 @@ int APInt::tcDivide(WordType *lhs, const WordType *rhs,
tcAssign(remainder, lhs, parts);
tcSet(lhs, 0, parts);
- /* Loop, subtracting SRHS if REMAINDER is greater and adding that to
- the total. */
+ // Loop, subtracting SRHS if REMAINDER is greater and adding that to the
+ // total.
for (;;) {
int compare = tcCompare(remainder, srhs, parts);
if (compare >= 0) {
@@ -2756,31 +2704,7 @@ void APInt::tcShiftRight(WordType *Dst, unsigned Words, unsigned Count) {
std::memset(Dst + WordsToMove, 0, WordShift * APINT_WORD_SIZE);
}
-/* Bitwise and of two bignums. */
-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(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(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(WordType *dst, unsigned parts) {
- for (unsigned i = 0; i < parts; i++)
- dst[i] = ~dst[i];
-}
-
-/* Comparison (unsigned) of two bignums. */
+// Comparison (unsigned) of two bignums.
int APInt::tcCompare(const WordType *lhs, const WordType *rhs,
unsigned parts) {
while (parts) {
@@ -2792,23 +2716,6 @@ int APInt::tcCompare(const WordType *lhs, const WordType *rhs,
return 0;
}
-/* Set the least significant BITS bits of a bignum, clear the
- rest. */
-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++] = ~(WordType) 0 >> (APINT_BITS_PER_WORD - bits);
-
- while (i < parts)
- dst[i++] = 0;
-}
-
APInt llvm::APIntOps::RoundingUDiv(const APInt &A, const APInt &B,
APInt::Rounding RM) {
// Currently udivrem always rounds down.
@@ -2819,7 +2726,7 @@ APInt llvm::APIntOps::RoundingUDiv(const APInt &A, const APInt &B,
case APInt::Rounding::UP: {
APInt Quo, Rem;
APInt::udivrem(A, B, Quo, Rem);
- if (Rem == 0)
+ if (Rem.isZero())
return Quo;
return Quo + 1;
}
@@ -2834,7 +2741,7 @@ APInt llvm::APIntOps::RoundingSDiv(const APInt &A, const APInt &B,
case APInt::Rounding::UP: {
APInt Quo, Rem;
APInt::sdivrem(A, B, Quo, Rem);
- if (Rem == 0)
+ if (Rem.isZero())
return Quo;
// This algorithm deals with arbitrary rounding mode used by sdivrem.
// We want to check whether the non-integer part of the mathematical value
@@ -2870,7 +2777,7 @@ llvm::APIntOps::SolveQuadraticEquationWrap(APInt A, APInt B, APInt C,
<< "x + " << C << ", rw:" << RangeWidth << '\n');
// Identify 0 as a (non)solution immediately.
- if (C.sextOrTrunc(RangeWidth).isNullValue() ) {
+ if (C.sextOrTrunc(RangeWidth).isZero()) {
LLVM_DEBUG(dbgs() << __func__ << ": zero solution\n");
return APInt(CoeffWidth, 0);
}
@@ -2932,7 +2839,7 @@ llvm::APIntOps::SolveQuadraticEquationWrap(APInt A, APInt B, APInt C,
auto RoundUp = [] (const APInt &V, const APInt &A) -> APInt {
assert(A.isStrictlyPositive());
APInt T = V.abs().urem(A);
- if (T.isNullValue())
+ if (T.isZero())
return V;
return V.isNegative() ? V+T : V+(A-T);
};
@@ -3016,7 +2923,7 @@ llvm::APIntOps::SolveQuadraticEquationWrap(APInt A, APInt B, APInt C,
// can be 0, but cannot be negative.
assert(X.isNonNegative() && "Solution should be non-negative");
- if (!InexactSQ && Rem.isNullValue()) {
+ if (!InexactSQ && Rem.isZero()) {
LLVM_DEBUG(dbgs() << __func__ << ": solution (root): " << X << '\n');
return X;
}
@@ -3032,8 +2939,8 @@ llvm::APIntOps::SolveQuadraticEquationWrap(APInt A, APInt B, APInt C,
APInt VX = (A*X + B)*X + C;
APInt VY = VX + TwoA*X + A + B;
- bool SignChange = VX.isNegative() != VY.isNegative() ||
- VX.isNullValue() != VY.isNullValue();
+ bool SignChange =
+ VX.isNegative() != VY.isNegative() || VX.isZero() != VY.isZero();
// If the sign did not change between X and X+1, X is not a valid solution.
// This could happen when the actual (exact) roots don't have an integer
// between them, so they would both be contained between X and X+1.
@@ -3055,6 +2962,40 @@ llvm::APIntOps::GetMostSignificantDifferentBit(const APInt &A, const APInt &B) {
return A.getBitWidth() - ((A ^ B).countLeadingZeros() + 1);
}
+APInt llvm::APIntOps::ScaleBitMask(const APInt &A, unsigned NewBitWidth) {
+ unsigned OldBitWidth = A.getBitWidth();
+ assert((((OldBitWidth % NewBitWidth) == 0) ||
+ ((NewBitWidth % OldBitWidth) == 0)) &&
+ "One size should be a multiple of the other one. "
+ "Can't do fractional scaling.");
+
+ // Check for matching bitwidths.
+ if (OldBitWidth == NewBitWidth)
+ return A;
+
+ APInt NewA = APInt::getZero(NewBitWidth);
+
+ // Check for null input.
+ if (A.isZero())
+ return NewA;
+
+ if (NewBitWidth > OldBitWidth) {
+ // Repeat bits.
+ unsigned Scale = NewBitWidth / OldBitWidth;
+ for (unsigned i = 0; i != OldBitWidth; ++i)
+ if (A[i])
+ NewA.setBits(i * Scale, (i + 1) * Scale);
+ } else {
+ // Merge bits - if any old bit is set, then set scale equivalent new bit.
+ unsigned Scale = OldBitWidth / NewBitWidth;
+ for (unsigned i = 0; i != NewBitWidth; ++i)
+ if (!A.extractBits(Scale, i * Scale).isZero())
+ NewA.setBit(i);
+ }
+
+ return NewA;
+}
+
/// StoreIntToMemory - Fills the StoreBytes bytes of memory starting from Dst
/// with the integer held in IntVal.
void llvm::StoreIntToMemory(const APInt &IntVal, uint8_t *Dst,
diff --git a/llvm/lib/Support/ARMTargetParser.cpp b/llvm/lib/Support/ARMTargetParser.cpp
index 94b48df27993..4405ed176fe2 100644
--- a/llvm/lib/Support/ARMTargetParser.cpp
+++ b/llvm/lib/Support/ARMTargetParser.cpp
@@ -82,6 +82,10 @@ unsigned ARM::parseArchVersion(StringRef Arch) {
case ArchKind::ARMV8MMainline:
case ArchKind::ARMV8_1MMainline:
return 8;
+ case ArchKind::ARMV9A:
+ case ArchKind::ARMV9_1A:
+ case ArchKind::ARMV9_2A:
+ return 9;
case ArchKind::INVALID:
return 0;
}
@@ -113,6 +117,9 @@ ARM::ProfileKind ARM::parseArchProfile(StringRef Arch) {
case ArchKind::ARMV8_5A:
case ArchKind::ARMV8_6A:
case ArchKind::ARMV8_7A:
+ case ArchKind::ARMV9A:
+ case ArchKind::ARMV9_1A:
+ case ArchKind::ARMV9_2A:
return ProfileKind::A;
case ArchKind::ARMV2:
case ArchKind::ARMV2A:
@@ -158,6 +165,9 @@ StringRef ARM::getArchSynonym(StringRef Arch) {
.Case("v8.6a", "v8.6-a")
.Case("v8.7a", "v8.7-a")
.Case("v8r", "v8-r")
+ .Cases("v9", "v9a", "v9-a")
+ .Case("v9.1a", "v9.1-a")
+ .Case("v9.2a", "v9.2-a")
.Case("v8m.base", "v8-m.base")
.Case("v8m.main", "v8-m.main")
.Case("v8.1m.main", "v8.1-m.main")
@@ -297,7 +307,7 @@ StringRef ARM::getCanonicalArchName(StringRef Arch) {
else if (A.startswith("aarch64")) {
offset = 7;
// AArch64 uses "_be", not "eb" suffix.
- if (A.find("eb") != StringRef::npos)
+ if (A.contains("eb"))
return Error;
if (A.substr(offset, 3) == "_be")
offset += 3;
@@ -323,7 +333,7 @@ StringRef ARM::getCanonicalArchName(StringRef Arch) {
if (A.size() >= 2 && (A[0] != 'v' || !std::isdigit(A[1])))
return Error;
// Can't have an extra 'eb'.
- if (A.find("eb") != StringRef::npos)
+ if (A.contains("eb"))
return Error;
}
diff --git a/llvm/lib/Support/BinaryStreamReader.cpp b/llvm/lib/Support/BinaryStreamReader.cpp
index a0434bdc6115..2fe450db11dd 100644
--- a/llvm/lib/Support/BinaryStreamReader.cpp
+++ b/llvm/lib/Support/BinaryStreamReader.cpp
@@ -72,10 +72,10 @@ Error BinaryStreamReader::readSLEB128(int64_t &Dest) {
}
Error BinaryStreamReader::readCString(StringRef &Dest) {
- uint32_t OriginalOffset = getOffset();
- uint32_t FoundOffset = 0;
+ uint64_t OriginalOffset = getOffset();
+ uint64_t FoundOffset = 0;
while (true) {
- uint32_t ThisOffset = getOffset();
+ uint64_t ThisOffset = getOffset();
ArrayRef<uint8_t> Buffer;
if (auto EC = readLongestContiguousChunk(Buffer))
return EC;
@@ -100,8 +100,8 @@ Error BinaryStreamReader::readCString(StringRef &Dest) {
}
Error BinaryStreamReader::readWideString(ArrayRef<UTF16> &Dest) {
- uint32_t Length = 0;
- uint32_t OriginalOffset = getOffset();
+ uint64_t Length = 0;
+ uint64_t OriginalOffset = getOffset();
const UTF16 *C;
while (true) {
if (auto EC = readObject(C))
@@ -110,7 +110,7 @@ Error BinaryStreamReader::readWideString(ArrayRef<UTF16> &Dest) {
break;
++Length;
}
- uint32_t NewOffset = getOffset();
+ uint64_t NewOffset = getOffset();
setOffset(OriginalOffset);
if (auto EC = readArray(Dest, Length))
@@ -145,7 +145,7 @@ Error BinaryStreamReader::readSubstream(BinarySubstreamRef &Ref,
return readStreamRef(Ref.StreamData, Length);
}
-Error BinaryStreamReader::skip(uint32_t Amount) {
+Error BinaryStreamReader::skip(uint64_t Amount) {
if (Amount > bytesRemaining())
return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
Offset += Amount;
@@ -166,7 +166,7 @@ uint8_t BinaryStreamReader::peek() const {
}
std::pair<BinaryStreamReader, BinaryStreamReader>
-BinaryStreamReader::split(uint32_t Off) const {
+BinaryStreamReader::split(uint64_t Off) const {
assert(getLength() >= Off);
BinaryStreamRef First = Stream.drop_front(Offset);
diff --git a/llvm/lib/Support/BinaryStreamRef.cpp b/llvm/lib/Support/BinaryStreamRef.cpp
index 53e71baad57a..6d79d95e1bf0 100644
--- a/llvm/lib/Support/BinaryStreamRef.cpp
+++ b/llvm/lib/Support/BinaryStreamRef.cpp
@@ -21,15 +21,15 @@ public:
llvm::support::endianness getEndian() const override {
return BBS.getEndian();
}
- Error readBytes(uint32_t Offset, uint32_t Size,
+ Error readBytes(uint64_t Offset, uint64_t Size,
ArrayRef<uint8_t> &Buffer) override {
return BBS.readBytes(Offset, Size, Buffer);
}
- Error readLongestContiguousChunk(uint32_t Offset,
+ Error readLongestContiguousChunk(uint64_t Offset,
ArrayRef<uint8_t> &Buffer) override {
return BBS.readLongestContiguousChunk(Offset, Buffer);
}
- uint32_t getLength() override { return BBS.getLength(); }
+ uint64_t getLength() override { return BBS.getLength(); }
private:
BinaryByteStream BBS;
@@ -44,17 +44,17 @@ public:
llvm::support::endianness getEndian() const override {
return BBS.getEndian();
}
- Error readBytes(uint32_t Offset, uint32_t Size,
+ Error readBytes(uint64_t Offset, uint64_t Size,
ArrayRef<uint8_t> &Buffer) override {
return BBS.readBytes(Offset, Size, Buffer);
}
- Error readLongestContiguousChunk(uint32_t Offset,
+ Error readLongestContiguousChunk(uint64_t Offset,
ArrayRef<uint8_t> &Buffer) override {
return BBS.readLongestContiguousChunk(Offset, Buffer);
}
- uint32_t getLength() override { return BBS.getLength(); }
+ uint64_t getLength() override { return BBS.getLength(); }
- Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) override {
+ Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Data) override {
return BBS.writeBytes(Offset, Data);
}
Error commit() override { return BBS.commit(); }
@@ -66,8 +66,8 @@ private:
BinaryStreamRef::BinaryStreamRef(BinaryStream &Stream)
: BinaryStreamRefBase(Stream) {}
-BinaryStreamRef::BinaryStreamRef(BinaryStream &Stream, uint32_t Offset,
- Optional<uint32_t> Length)
+BinaryStreamRef::BinaryStreamRef(BinaryStream &Stream, uint64_t Offset,
+ Optional<uint64_t> Length)
: BinaryStreamRefBase(Stream, Offset, Length) {}
BinaryStreamRef::BinaryStreamRef(ArrayRef<uint8_t> Data, endianness Endian)
: BinaryStreamRefBase(std::make_shared<ArrayRefImpl>(Data, Endian), 0,
@@ -76,7 +76,7 @@ BinaryStreamRef::BinaryStreamRef(StringRef Data, endianness Endian)
: BinaryStreamRef(makeArrayRef(Data.bytes_begin(), Data.bytes_end()),
Endian) {}
-Error BinaryStreamRef::readBytes(uint32_t Offset, uint32_t Size,
+Error BinaryStreamRef::readBytes(uint64_t Offset, uint64_t Size,
ArrayRef<uint8_t> &Buffer) const {
if (auto EC = checkOffsetForRead(Offset, Size))
return EC;
@@ -84,7 +84,7 @@ Error BinaryStreamRef::readBytes(uint32_t Offset, uint32_t Size,
}
Error BinaryStreamRef::readLongestContiguousChunk(
- uint32_t Offset, ArrayRef<uint8_t> &Buffer) const {
+ uint64_t Offset, ArrayRef<uint8_t> &Buffer) const {
if (auto EC = checkOffsetForRead(Offset, 1))
return EC;
@@ -94,7 +94,7 @@ Error BinaryStreamRef::readLongestContiguousChunk(
// This StreamRef might refer to a smaller window over a larger stream. In
// that case we will have read out more bytes than we should return, because
// we should not read past the end of the current view.
- uint32_t MaxLength = getLength() - Offset;
+ uint64_t MaxLength = getLength() - Offset;
if (Buffer.size() > MaxLength)
Buffer = Buffer.slice(0, MaxLength);
return Error::success();
@@ -104,8 +104,8 @@ WritableBinaryStreamRef::WritableBinaryStreamRef(WritableBinaryStream &Stream)
: BinaryStreamRefBase(Stream) {}
WritableBinaryStreamRef::WritableBinaryStreamRef(WritableBinaryStream &Stream,
- uint32_t Offset,
- Optional<uint32_t> Length)
+ uint64_t Offset,
+ Optional<uint64_t> Length)
: BinaryStreamRefBase(Stream, Offset, Length) {}
WritableBinaryStreamRef::WritableBinaryStreamRef(MutableArrayRef<uint8_t> Data,
@@ -113,8 +113,7 @@ WritableBinaryStreamRef::WritableBinaryStreamRef(MutableArrayRef<uint8_t> Data,
: BinaryStreamRefBase(std::make_shared<MutableArrayRefImpl>(Data, Endian),
0, Data.size()) {}
-
-Error WritableBinaryStreamRef::writeBytes(uint32_t Offset,
+Error WritableBinaryStreamRef::writeBytes(uint64_t Offset,
ArrayRef<uint8_t> Data) const {
if (auto EC = checkOffsetForWrite(Offset, Data.size()))
return EC;
diff --git a/llvm/lib/Support/BinaryStreamWriter.cpp b/llvm/lib/Support/BinaryStreamWriter.cpp
index 986e18da281d..8c9efa0ed9a9 100644
--- a/llvm/lib/Support/BinaryStreamWriter.cpp
+++ b/llvm/lib/Support/BinaryStreamWriter.cpp
@@ -62,7 +62,7 @@ Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) {
return writeStreamRef(Ref, Ref.getLength());
}
-Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_t Length) {
+Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint64_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
@@ -80,7 +80,7 @@ Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_t Length) {
}
std::pair<BinaryStreamWriter, BinaryStreamWriter>
-BinaryStreamWriter::split(uint32_t Off) const {
+BinaryStreamWriter::split(uint64_t Off) const {
assert(getLength() >= Off);
WritableBinaryStreamRef First = Stream.drop_front(Offset);
@@ -93,7 +93,7 @@ BinaryStreamWriter::split(uint32_t Off) const {
}
Error BinaryStreamWriter::padToAlignment(uint32_t Align) {
- uint32_t NewOffset = alignTo(Offset, Align);
+ uint64_t NewOffset = alignTo(Offset, Align);
if (NewOffset > getLength())
return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
while (Offset < NewOffset)
diff --git a/llvm/lib/Support/Caching.cpp b/llvm/lib/Support/Caching.cpp
new file mode 100644
index 000000000000..a2fe37a26617
--- /dev/null
+++ b/llvm/lib/Support/Caching.cpp
@@ -0,0 +1,161 @@
+//===-Caching.cpp - LLVM Local File Cache ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the localCache function, which simplifies creating,
+// adding to, and querying a local file system cache. localCache takes care of
+// periodically pruning older files from the cache using a CachePruningPolicy.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Caching.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+using namespace llvm;
+
+Expected<FileCache> llvm::localCache(Twine CacheNameRef,
+ Twine TempFilePrefixRef,
+ Twine CacheDirectoryPathRef,
+ AddBufferFn AddBuffer) {
+ if (std::error_code EC = sys::fs::create_directories(CacheDirectoryPathRef))
+ return errorCodeToError(EC);
+
+ // Create local copies which are safely captured-by-copy in lambdas
+ SmallString<64> CacheName, TempFilePrefix, CacheDirectoryPath;
+ CacheNameRef.toVector(CacheName);
+ TempFilePrefixRef.toVector(TempFilePrefix);
+ CacheDirectoryPathRef.toVector(CacheDirectoryPath);
+
+ return [=](unsigned Task, StringRef Key) -> Expected<AddStreamFn> {
+ // This choice of file name allows the cache to be pruned (see pruneCache()
+ // in include/llvm/Support/CachePruning.h).
+ SmallString<64> EntryPath;
+ sys::path::append(EntryPath, CacheDirectoryPath, "llvmcache-" + Key);
+ // First, see if we have a cache hit.
+ SmallString<64> ResultPath;
+ Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForRead(
+ Twine(EntryPath), sys::fs::OF_UpdateAtime, &ResultPath);
+ std::error_code EC;
+ if (FDOrErr) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
+ MemoryBuffer::getOpenFile(*FDOrErr, EntryPath,
+ /*FileSize=*/-1,
+ /*RequiresNullTerminator=*/false);
+ sys::fs::closeFile(*FDOrErr);
+ if (MBOrErr) {
+ AddBuffer(Task, std::move(*MBOrErr));
+ return AddStreamFn();
+ }
+ EC = MBOrErr.getError();
+ } else {
+ EC = errorToErrorCode(FDOrErr.takeError());
+ }
+
+ // On Windows we can fail to open a cache file with a permission denied
+ // error. This generally means that another process has requested to delete
+ // the file while it is still open, but it could also mean that another
+ // process has opened the file without the sharing permissions we need.
+ // Since the file is probably being deleted we handle it in the same way as
+ // if the file did not exist at all.
+ if (EC != errc::no_such_file_or_directory && EC != errc::permission_denied)
+ return createStringError(EC, Twine("Failed to open cache file ") +
+ EntryPath + ": " + EC.message() + "\n");
+
+ // This file stream is responsible for commiting the resulting file to the
+ // cache and calling AddBuffer to add it to the link.
+ struct CacheStream : CachedFileStream {
+ AddBufferFn AddBuffer;
+ sys::fs::TempFile TempFile;
+ std::string EntryPath;
+ unsigned Task;
+
+ CacheStream(std::unique_ptr<raw_pwrite_stream> OS, AddBufferFn AddBuffer,
+ sys::fs::TempFile TempFile, std::string EntryPath,
+ unsigned Task)
+ : CachedFileStream(std::move(OS)), AddBuffer(std::move(AddBuffer)),
+ TempFile(std::move(TempFile)), EntryPath(std::move(EntryPath)),
+ Task(Task) {}
+
+ ~CacheStream() {
+ // TODO: Manually commit rather than using non-trivial destructor,
+ // allowing to replace report_fatal_errors with a return Error.
+
+ // Make sure the stream is closed before committing it.
+ OS.reset();
+
+ // Open the file first to avoid racing with a cache pruner.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
+ MemoryBuffer::getOpenFile(
+ sys::fs::convertFDToNativeFile(TempFile.FD), TempFile.TmpName,
+ /*FileSize=*/-1, /*RequiresNullTerminator=*/false);
+ if (!MBOrErr)
+ report_fatal_error(Twine("Failed to open new cache file ") +
+ TempFile.TmpName + ": " +
+ MBOrErr.getError().message() + "\n");
+
+ // On POSIX systems, this will atomically replace the destination if
+ // it already exists. We try to emulate this on Windows, but this may
+ // fail with a permission denied error (for example, if the destination
+ // is currently opened by another process that does not give us the
+ // sharing permissions we need). Since the existing file should be
+ // semantically equivalent to the one we are trying to write, we give
+ // AddBuffer a copy of the bytes we wrote in that case. We do this
+ // instead of just using the existing file, because the pruner might
+ // delete the file before we get a chance to use it.
+ Error E = TempFile.keep(EntryPath);
+ E = handleErrors(std::move(E), [&](const ECError &E) -> Error {
+ std::error_code EC = E.convertToErrorCode();
+ if (EC != errc::permission_denied)
+ return errorCodeToError(EC);
+
+ auto MBCopy = MemoryBuffer::getMemBufferCopy((*MBOrErr)->getBuffer(),
+ EntryPath);
+ MBOrErr = std::move(MBCopy);
+
+ // FIXME: should we consume the discard error?
+ consumeError(TempFile.discard());
+
+ return Error::success();
+ });
+
+ if (E)
+ report_fatal_error(Twine("Failed to rename temporary file ") +
+ TempFile.TmpName + " to " + EntryPath + ": " +
+ toString(std::move(E)) + "\n");
+
+ AddBuffer(Task, std::move(*MBOrErr));
+ }
+ };
+
+ return [=](size_t Task) -> Expected<std::unique_ptr<CachedFileStream>> {
+ // Write to a temporary to avoid race condition
+ SmallString<64> TempFilenameModel;
+ sys::path::append(TempFilenameModel, CacheDirectoryPath,
+ TempFilePrefix + "-%%%%%%.tmp.o");
+ Expected<sys::fs::TempFile> Temp = sys::fs::TempFile::create(
+ TempFilenameModel, sys::fs::owner_read | sys::fs::owner_write);
+ if (!Temp)
+ return createStringError(errc::io_error,
+ toString(Temp.takeError()) + ": " + CacheName +
+ ": Can't get a temporary file");
+
+ // This CacheStream will move the temporary file into the cache when done.
+ return std::make_unique<CacheStream>(
+ std::make_unique<raw_fd_ostream>(Temp->FD, /* ShouldClose */ false),
+ AddBuffer, std::move(*Temp), std::string(EntryPath.str()), Task);
+ };
+ };
+}
diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp
index 4ae3ad4c2453..e64934aa90cc 100644
--- a/llvm/lib/Support/CommandLine.cpp
+++ b/llvm/lib/Support/CommandLine.cpp
@@ -1321,12 +1321,20 @@ bool cl::ParseCommandLineOptions(int argc, const char *const *argv,
Errs, LongOptionsUseDoubleDash);
}
+/// Reset all options at least once, so that we can parse different options.
void CommandLineParser::ResetAllOptionOccurrences() {
- // So that we can parse different command lines multiple times in succession
- // we reset all option values to look like they have never been seen before.
+ // Reset all option values to look like they have never been seen before.
+ // Options might be reset twice (they can be reference in both OptionsMap
+ // and one of the other members), but that does not harm.
for (auto *SC : RegisteredSubCommands) {
for (auto &O : SC->OptionsMap)
O.second->reset();
+ for (Option *O : SC->PositionalOpts)
+ O->reset();
+ for (Option *O : SC->SinkOpts)
+ O->reset();
+ if (SC->ConsumeAfterOpt)
+ SC->ConsumeAfterOpt->reset();
}
}
@@ -2633,6 +2641,7 @@ void cl::AddExtraVersionPrinter(VersionPrinterTy func) {
}
StringMap<Option *> &cl::getRegisteredOptions(SubCommand &Sub) {
+ initCommonOptions();
auto &Subs = GlobalParser->RegisteredSubCommands;
(void)Subs;
assert(is_contained(Subs, &Sub));
diff --git a/llvm/lib/Support/CrashRecoveryContext.cpp b/llvm/lib/Support/CrashRecoveryContext.cpp
index 433d99df5932..b6aaf373a522 100644
--- a/llvm/lib/Support/CrashRecoveryContext.cpp
+++ b/llvm/lib/Support/CrashRecoveryContext.cpp
@@ -428,8 +428,7 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
#endif // !_MSC_VER
-LLVM_ATTRIBUTE_NORETURN
-void CrashRecoveryContext::HandleExit(int RetCode) {
+[[noreturn]] void CrashRecoveryContext::HandleExit(int RetCode) {
#if defined(_WIN32)
// SEH and VEH
::RaiseException(0xE0000000 | RetCode, 0, 0, NULL);
diff --git a/llvm/lib/Support/DebugOptions.h b/llvm/lib/Support/DebugOptions.h
index 4d5250649f6a..75e557d7d8d7 100644
--- a/llvm/lib/Support/DebugOptions.h
+++ b/llvm/lib/Support/DebugOptions.h
@@ -26,4 +26,4 @@ void initWithColorOptions();
void initDebugOptions();
void initRandomSeedOptions();
-} // namespace llvm \ No newline at end of file
+} // namespace llvm
diff --git a/llvm/lib/Support/DivisionByConstantInfo.cpp b/llvm/lib/Support/DivisionByConstantInfo.cpp
new file mode 100644
index 000000000000..077629670e40
--- /dev/null
+++ b/llvm/lib/Support/DivisionByConstantInfo.cpp
@@ -0,0 +1,107 @@
+//===----- DivisonByConstantInfo.cpp - division by constant -*- C++ -*-----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file implements support for optimizing divisions by a constant
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/DivisionByConstantInfo.h"
+
+using namespace llvm;
+
+/// Calculate the magic numbers required to implement a signed integer division
+/// by a constant as a sequence of multiplies, adds and shifts. Requires that
+/// the divisor not be 0, 1, or -1. Taken from "Hacker's Delight", Henry S.
+/// Warren, Jr., Chapter 10.
+SignedDivisionByConstantInfo SignedDivisionByConstantInfo::get(const APInt &D) {
+ unsigned P;
+ APInt AD, ANC, Delta, Q1, R1, Q2, R2, T;
+ APInt SignedMin = APInt::getSignedMinValue(D.getBitWidth());
+ struct SignedDivisionByConstantInfo Retval;
+
+ AD = D.abs();
+ T = SignedMin + (D.lshr(D.getBitWidth() - 1));
+ ANC = T - 1 - T.urem(AD); // absolute value of NC
+ P = D.getBitWidth() - 1; // initialize P
+ Q1 = SignedMin.udiv(ANC); // initialize Q1 = 2P/abs(NC)
+ R1 = SignedMin - Q1 * ANC; // initialize R1 = rem(2P,abs(NC))
+ Q2 = SignedMin.udiv(AD); // initialize Q2 = 2P/abs(D)
+ R2 = SignedMin - Q2 * AD; // initialize R2 = rem(2P,abs(D))
+ do {
+ P = P + 1;
+ Q1 = Q1 << 1; // update Q1 = 2P/abs(NC)
+ R1 = R1 << 1; // update R1 = rem(2P/abs(NC))
+ if (R1.uge(ANC)) { // must be unsigned comparison
+ Q1 = Q1 + 1;
+ R1 = R1 - ANC;
+ }
+ Q2 = Q2 << 1; // update Q2 = 2P/abs(D)
+ R2 = R2 << 1; // update R2 = rem(2P/abs(D))
+ if (R2.uge(AD)) { // must be unsigned comparison
+ Q2 = Q2 + 1;
+ R2 = R2 - AD;
+ }
+ Delta = AD - R2;
+ } while (Q1.ult(Delta) || (Q1 == Delta && R1 == 0));
+
+ Retval.Magic = Q2 + 1;
+ if (D.isNegative())
+ Retval.Magic = -Retval.Magic; // resulting magic number
+ Retval.ShiftAmount = P - D.getBitWidth(); // resulting shift
+ return Retval;
+}
+
+/// Calculate the magic numbers required to implement an unsigned integer
+/// division by a constant as a sequence of multiplies, adds and shifts.
+/// Requires that the divisor not be 0. Taken from "Hacker's Delight", Henry
+/// S. Warren, Jr., chapter 10.
+/// LeadingZeros can be used to simplify the calculation if the upper bits
+/// of the divided value are known zero.
+UnsignedDivisonByConstantInfo
+UnsignedDivisonByConstantInfo::get(const APInt &D, unsigned LeadingZeros) {
+ unsigned P;
+ APInt NC, Delta, Q1, R1, Q2, R2;
+ struct UnsignedDivisonByConstantInfo Retval;
+ Retval.IsAdd = 0; // initialize "add" indicator
+ APInt AllOnes = APInt::getAllOnes(D.getBitWidth()).lshr(LeadingZeros);
+ APInt SignedMin = APInt::getSignedMinValue(D.getBitWidth());
+ APInt SignedMax = APInt::getSignedMaxValue(D.getBitWidth());
+
+ NC = AllOnes - (AllOnes - D).urem(D);
+ P = D.getBitWidth() - 1; // initialize P
+ Q1 = SignedMin.udiv(NC); // initialize Q1 = 2P/NC
+ R1 = SignedMin - Q1 * NC; // initialize R1 = rem(2P,NC)
+ Q2 = SignedMax.udiv(D); // initialize Q2 = (2P-1)/D
+ R2 = SignedMax - Q2 * D; // initialize R2 = rem((2P-1),D)
+ do {
+ P = P + 1;
+ if (R1.uge(NC - R1)) {
+ Q1 = Q1 + Q1 + 1; // update Q1
+ R1 = R1 + R1 - NC; // update R1
+ } else {
+ Q1 = Q1 + Q1; // update Q1
+ R1 = R1 + R1; // update R1
+ }
+ if ((R2 + 1).uge(D - R2)) {
+ if (Q2.uge(SignedMax))
+ Retval.IsAdd = 1;
+ Q2 = Q2 + Q2 + 1; // update Q2
+ R2 = R2 + R2 + 1 - D; // update R2
+ } else {
+ if (Q2.uge(SignedMin))
+ Retval.IsAdd = 1;
+ Q2 = Q2 + Q2; // update Q2
+ R2 = R2 + R2 + 1; // update R2
+ }
+ Delta = D - 1 - R2;
+ } while (P < D.getBitWidth() * 2 &&
+ (Q1.ult(Delta) || (Q1 == Delta && R1 == 0)));
+ Retval.Magic = Q2 + 1; // resulting magic number
+ Retval.ShiftAmount = P - D.getBitWidth(); // resulting shift
+ return Retval;
+}
diff --git a/llvm/lib/Support/Error.cpp b/llvm/lib/Support/Error.cpp
index e7ab4387dfd1..8bfc8ee7a8cc 100644
--- a/llvm/lib/Support/Error.cpp
+++ b/llvm/lib/Support/Error.cpp
@@ -80,8 +80,11 @@ std::error_code inconvertibleErrorCode() {
}
std::error_code FileError::convertToErrorCode() const {
- return std::error_code(static_cast<int>(ErrorErrorCode::FileError),
- *ErrorErrorCat);
+ std::error_code NestedEC = Err->convertToErrorCode();
+ if (NestedEC == inconvertibleErrorCode())
+ return std::error_code(static_cast<int>(ErrorErrorCode::FileError),
+ *ErrorErrorCat);
+ return NestedEC;
}
Error errorCodeToError(std::error_code EC) {
@@ -96,7 +99,7 @@ std::error_code errorToErrorCode(Error Err) {
EC = EI.convertToErrorCode();
});
if (EC == inconvertibleErrorCode())
- report_fatal_error(EC.message());
+ report_fatal_error(Twine(EC.message()));
return EC;
}
@@ -144,7 +147,7 @@ void report_fatal_error(Error Err, bool GenCrashDiag) {
raw_string_ostream ErrStream(ErrMsg);
logAllUnhandledErrors(std::move(Err), ErrStream);
}
- report_fatal_error(ErrMsg);
+ report_fatal_error(Twine(ErrMsg));
}
} // end namespace llvm
diff --git a/llvm/lib/Support/ErrorHandling.cpp b/llvm/lib/Support/ErrorHandling.cpp
index ce6344284f06..80c0e00439a5 100644
--- a/llvm/lib/Support/ErrorHandling.cpp
+++ b/llvm/lib/Support/ErrorHandling.cpp
@@ -83,10 +83,6 @@ void llvm::report_fatal_error(const char *Reason, bool GenCrashDiag) {
report_fatal_error(Twine(Reason), GenCrashDiag);
}
-void llvm::report_fatal_error(const std::string &Reason, bool GenCrashDiag) {
- report_fatal_error(Twine(Reason), GenCrashDiag);
-}
-
void llvm::report_fatal_error(StringRef Reason, bool GenCrashDiag) {
report_fatal_error(Twine(Reason), GenCrashDiag);
}
@@ -105,7 +101,7 @@ void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
}
if (handler) {
- handler(handlerData, Reason.str(), GenCrashDiag);
+ handler(handlerData, Reason.str().c_str(), GenCrashDiag);
} else {
// Blast the result out to stderr. We don't try hard to make sure this
// succeeds (e.g. handling EINTR) and we can't use errs() here because
@@ -218,11 +214,11 @@ void llvm::llvm_unreachable_internal(const char *msg, const char *file,
#endif
}
-static void bindingsErrorHandler(void *user_data, const std::string& reason,
+static void bindingsErrorHandler(void *user_data, const char *reason,
bool gen_crash_diag) {
LLVMFatalErrorHandler handler =
LLVM_EXTENSION reinterpret_cast<LLVMFatalErrorHandler>(user_data);
- handler(reason.c_str());
+ handler(reason);
}
void LLVMInstallFatalErrorHandler(LLVMFatalErrorHandler Handler) {
@@ -247,7 +243,10 @@ std::error_code llvm::mapWindowsError(unsigned EV) {
switch (EV) {
MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied);
MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists);
+ MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory);
+ MAP_ERR_TO_COND(ERROR_BAD_PATHNAME, no_such_file_or_directory);
MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device);
+ MAP_ERR_TO_COND(ERROR_BROKEN_PIPE, broken_pipe);
MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long);
MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy);
MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy);
@@ -269,18 +268,20 @@ std::error_code llvm::mapWindowsError(unsigned EV) {
MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported);
MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument);
MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument);
+ MAP_ERR_TO_COND(ERROR_INVALID_PARAMETER, invalid_argument);
MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available);
MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available);
MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument);
MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied);
MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory);
MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again);
+ MAP_ERR_TO_COND(ERROR_NOT_SUPPORTED, not_supported);
MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error);
MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy);
MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory);
MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory);
- MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory);
MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error);
+ MAP_ERR_TO_COND(ERROR_REPARSE_TAG_INVALID, invalid_argument);
MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again);
MAP_ERR_TO_COND(ERROR_SEEK, io_error);
MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied);
diff --git a/llvm/lib/Support/ExtensibleRTTI.cpp b/llvm/lib/Support/ExtensibleRTTI.cpp
index 1c98d1bb8feb..a6a5c196fb35 100644
--- a/llvm/lib/Support/ExtensibleRTTI.cpp
+++ b/llvm/lib/Support/ExtensibleRTTI.cpp
@@ -1,9 +1,8 @@
//===----- lib/Support/ExtensibleRTTI.cpp - ExtensibleRTTI utilities ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Support/FileUtilities.cpp b/llvm/lib/Support/FileUtilities.cpp
index e4a86bb69de4..dbe28e56b2c3 100644
--- a/llvm/lib/Support/FileUtilities.cpp
+++ b/llvm/lib/Support/FileUtilities.cpp
@@ -300,8 +300,7 @@ llvm::Error llvm::writeFileAtomically(
std::function<llvm::Error(llvm::raw_ostream &)> Writer) {
SmallString<128> GeneratedUniqPath;
int TempFD;
- if (sys::fs::createUniqueFile(TempPathModel.str(), TempFD,
- GeneratedUniqPath)) {
+ if (sys::fs::createUniqueFile(TempPathModel, TempFD, GeneratedUniqPath)) {
return llvm::make_error<AtomicFileWriteError>(
atomic_write_error::failed_to_create_uniq_file);
}
@@ -319,8 +318,7 @@ llvm::Error llvm::writeFileAtomically(
atomic_write_error::output_stream_error);
}
- if (sys::fs::rename(/*from=*/GeneratedUniqPath.c_str(),
- /*to=*/FinalPath.str().c_str())) {
+ if (sys::fs::rename(/*from=*/GeneratedUniqPath, /*to=*/FinalPath)) {
return llvm::make_error<AtomicFileWriteError>(
atomic_write_error::failed_to_rename_temp_file);
}
diff --git a/llvm/lib/Support/GraphWriter.cpp b/llvm/lib/Support/GraphWriter.cpp
index b41869aba95f..696e6b7a99d8 100644
--- a/llvm/lib/Support/GraphWriter.cpp
+++ b/llvm/lib/Support/GraphWriter.cpp
@@ -23,11 +23,12 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
-#include <system_error>
#include <string>
+#include <system_error>
#include <vector>
using namespace llvm;
@@ -94,11 +95,8 @@ StringRef llvm::DOT::getColorString(unsigned ColorNumber) {
static std::string replaceIllegalFilenameChars(std::string Filename,
const char ReplacementChar) {
-#ifdef _WIN32
- std::string IllegalChars = "\\/:?\"<>|";
-#else
- std::string IllegalChars = "/";
-#endif
+ std::string IllegalChars =
+ is_style_windows(sys::path::Style::native) ? "\\/:?\"<>|" : "/";
for (char IllegalChar : IllegalChars) {
std::replace(Filename.begin(), Filename.end(), IllegalChar,
diff --git a/llvm/lib/Support/Host.cpp b/llvm/lib/Support/Host.cpp
index f873ff06f1f7..7b14616f6fea 100644
--- a/llvm/lib/Support/Host.cpp
+++ b/llvm/lib/Support/Host.cpp
@@ -772,6 +772,22 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
*Subtype = X86::INTEL_COREI7_ICELAKE_CLIENT;
break;
+ // Tigerlake:
+ case 0x8c:
+ case 0x8d:
+ CPU = "tigerlake";
+ *Type = X86::INTEL_COREI7;
+ *Subtype = X86::INTEL_COREI7_TIGERLAKE;
+ break;
+
+ // Alderlake:
+ case 0x97:
+ case 0x9a:
+ CPU = "alderlake";
+ *Type = X86::INTEL_COREI7;
+ *Subtype = X86::INTEL_COREI7_ALDERLAKE;
+ break;
+
// Icelake Xeon:
case 0x6a:
case 0x6c:
@@ -1055,8 +1071,10 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
setFeature(X86::FEATURE_FMA);
if ((ECX >> 19) & 1)
setFeature(X86::FEATURE_SSE4_1);
- if ((ECX >> 20) & 1)
+ if ((ECX >> 20) & 1) {
setFeature(X86::FEATURE_SSE4_2);
+ setFeature(X86::FEATURE_CRC32);
+ }
if ((ECX >> 23) & 1)
setFeature(X86::FEATURE_POPCNT);
if ((ECX >> 25) & 1)
@@ -1338,6 +1356,16 @@ StringRef sys::getHostCPUName() {
return "generic";
}
}
+#elif defined(__riscv)
+StringRef sys::getHostCPUName() {
+#if __riscv_xlen == 64
+ return "generic-rv64";
+#elif __riscv_xlen == 32
+ return "generic-rv32";
+#else
+#error "Unhandled value of __riscv_xlen"
+#endif
+}
#else
StringRef sys::getHostCPUName() { return "generic"; }
namespace llvm {
@@ -1502,6 +1530,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
Features["cx16"] = (ECX >> 13) & 1;
Features["sse4.1"] = (ECX >> 19) & 1;
Features["sse4.2"] = (ECX >> 20) & 1;
+ Features["crc32"] = Features["sse4.2"];
Features["movbe"] = (ECX >> 22) & 1;
Features["popcnt"] = (ECX >> 23) & 1;
Features["aes"] = (ECX >> 25) & 1;
@@ -1617,6 +1646,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
// For more info, see X86 ISA docs.
Features["pconfig"] = HasLeaf7 && ((EDX >> 18) & 1);
Features["amx-bf16"] = HasLeaf7 && ((EDX >> 22) & 1) && HasAMXSave;
+ Features["avx512fp16"] = HasLeaf7 && ((EDX >> 23) & 1) && HasAVX512Save;
Features["amx-tile"] = HasLeaf7 && ((EDX >> 24) & 1) && HasAMXSave;
Features["amx-int8"] = HasLeaf7 && ((EDX >> 25) & 1) && HasAMXSave;
bool HasLeaf7Subleaf1 =
diff --git a/llvm/lib/Support/JSON.cpp b/llvm/lib/Support/JSON.cpp
index dbfd673553f4..17b36ed51850 100644
--- a/llvm/lib/Support/JSON.cpp
+++ b/llvm/lib/Support/JSON.cpp
@@ -109,6 +109,7 @@ void Value::copyFrom(const Value &M) {
case T_Boolean:
case T_Double:
case T_Integer:
+ case T_UINT64:
memcpy(&Union, &M.Union, sizeof(Union));
break;
case T_StringRef:
@@ -133,6 +134,7 @@ void Value::moveFrom(const Value &&M) {
case T_Boolean:
case T_Double:
case T_Integer:
+ case T_UINT64:
memcpy(&Union, &M.Union, sizeof(Union));
break;
case T_StringRef:
@@ -159,6 +161,7 @@ void Value::destroy() {
case T_Boolean:
case T_Double:
case T_Integer:
+ case T_UINT64:
break;
case T_StringRef:
as<StringRef>().~StringRef();
@@ -750,6 +753,8 @@ void llvm::json::OStream::value(const Value &V) {
valueBegin();
if (V.Type == Value::T_Integer)
OS << *V.getAsInteger();
+ else if (V.Type == Value::T_UINT64)
+ OS << *V.getAsUINT64();
else
OS << format("%.*g", std::numeric_limits<double>::max_digits10,
*V.getAsNumber());
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index d997bd85f1e0..90483817c302 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -404,7 +404,7 @@ KnownBits KnownBits::abs(bool IntMinIsPoison) const {
// We only know that the absolute values's MSB will be zero if INT_MIN is
// poison, or there is a set bit that isn't the sign bit (otherwise it could
// be INT_MIN).
- if (IntMinIsPoison || (!One.isNullValue() && !One.isMinSignedValue()))
+ if (IntMinIsPoison || (!One.isZero() && !One.isMinSignedValue()))
KnownAbs.Zero.setSignBit();
// FIXME: Handle known negative input?
@@ -412,10 +412,13 @@ KnownBits KnownBits::abs(bool IntMinIsPoison) const {
return KnownAbs;
}
-KnownBits KnownBits::mul(const KnownBits &LHS, const KnownBits &RHS) {
+KnownBits KnownBits::mul(const KnownBits &LHS, const KnownBits &RHS,
+ bool SelfMultiply) {
unsigned BitWidth = LHS.getBitWidth();
assert(BitWidth == RHS.getBitWidth() && !LHS.hasConflict() &&
!RHS.hasConflict() && "Operand mismatch");
+ assert((!SelfMultiply || (LHS.One == RHS.One && LHS.Zero == RHS.Zero)) &&
+ "Self multiplication knownbits mismatch");
// Compute a conservative estimate for high known-0 bits.
unsigned LeadZ =
@@ -489,6 +492,14 @@ KnownBits KnownBits::mul(const KnownBits &LHS, const KnownBits &RHS) {
Res.Zero.setHighBits(LeadZ);
Res.Zero |= (~BottomKnown).getLoBits(ResultBitsKnown);
Res.One = BottomKnown.getLoBits(ResultBitsKnown);
+
+ // If we're self-multiplying then bit[1] is guaranteed to be zero.
+ if (SelfMultiply && BitWidth > 1) {
+ assert(Res.One[1] == 0 &&
+ "Self-multiplication failed Quadratic Reciprocity!");
+ Res.Zero.setBit(1);
+ }
+
return Res;
}
diff --git a/llvm/lib/Support/LockFileManager.cpp b/llvm/lib/Support/LockFileManager.cpp
index a2b56ab295c4..5fd52999adb5 100644
--- a/llvm/lib/Support/LockFileManager.cpp
+++ b/llvm/lib/Support/LockFileManager.cpp
@@ -35,7 +35,7 @@
#include <unistd.h>
#endif
-#if defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (__MAC_OS_X_VERSION_MIN_REQUIRED > 1050)
+#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1050)
#define USE_OSX_GETHOSTUUID 1
#else
#define USE_OSX_GETHOSTUUID 0
diff --git a/llvm/lib/Support/MD5.cpp b/llvm/lib/Support/MD5.cpp
index 5e0b076f176e..9dceb4d418cd 100644
--- a/llvm/lib/Support/MD5.cpp
+++ b/llvm/lib/Support/MD5.cpp
@@ -67,11 +67,11 @@
// SET reads 4 input bytes in little-endian byte order and stores them
// in a properly aligned word in host byte order.
#define SET(n) \
- (block[(n)] = \
- (MD5_u32plus) ptr[(n) * 4] | ((MD5_u32plus) ptr[(n) * 4 + 1] << 8) | \
- ((MD5_u32plus) ptr[(n) * 4 + 2] << 16) | \
- ((MD5_u32plus) ptr[(n) * 4 + 3] << 24))
-#define GET(n) (block[(n)])
+ (InternalState.block[(n)] = (MD5_u32plus)ptr[(n)*4] | \
+ ((MD5_u32plus)ptr[(n)*4 + 1] << 8) | \
+ ((MD5_u32plus)ptr[(n)*4 + 2] << 16) | \
+ ((MD5_u32plus)ptr[(n)*4 + 3] << 24))
+#define GET(n) (InternalState.block[(n)])
using namespace llvm;
@@ -85,10 +85,10 @@ const uint8_t *MD5::body(ArrayRef<uint8_t> Data) {
ptr = Data.data();
- a = this->a;
- b = this->b;
- c = this->c;
- d = this->d;
+ a = InternalState.a;
+ b = InternalState.b;
+ c = InternalState.c;
+ d = InternalState.d;
do {
saved_a = a;
@@ -176,10 +176,10 @@ const uint8_t *MD5::body(ArrayRef<uint8_t> Data) {
ptr += 64;
} while (Size -= 64);
- this->a = a;
- this->b = b;
- this->c = c;
- this->d = d;
+ InternalState.a = a;
+ InternalState.b = b;
+ InternalState.c = c;
+ InternalState.d = d;
return ptr;
}
@@ -193,10 +193,10 @@ void MD5::update(ArrayRef<uint8_t> Data) {
const uint8_t *Ptr = Data.data();
unsigned long Size = Data.size();
- saved_lo = lo;
- if ((lo = (saved_lo + Size) & 0x1fffffff) < saved_lo)
- hi++;
- hi += Size >> 29;
+ saved_lo = InternalState.lo;
+ if ((InternalState.lo = (saved_lo + Size) & 0x1fffffff) < saved_lo)
+ InternalState.hi++;
+ InternalState.hi += Size >> 29;
used = saved_lo & 0x3f;
@@ -204,14 +204,14 @@ void MD5::update(ArrayRef<uint8_t> Data) {
free = 64 - used;
if (Size < free) {
- memcpy(&buffer[used], Ptr, Size);
+ memcpy(&InternalState.buffer[used], Ptr, Size);
return;
}
- memcpy(&buffer[used], Ptr, free);
+ memcpy(&InternalState.buffer[used], Ptr, free);
Ptr = Ptr + free;
Size -= free;
- body(makeArrayRef(buffer, 64));
+ body(makeArrayRef(InternalState.buffer, 64));
}
if (Size >= 64) {
@@ -219,7 +219,7 @@ void MD5::update(ArrayRef<uint8_t> Data) {
Size &= 0x3f;
}
- memcpy(buffer, Ptr, Size);
+ memcpy(InternalState.buffer, Ptr, Size);
}
/// Add the bytes in the StringRef \p Str to the hash.
@@ -235,31 +235,48 @@ void MD5::update(StringRef Str) {
void MD5::final(MD5Result &Result) {
unsigned long used, free;
- used = lo & 0x3f;
+ used = InternalState.lo & 0x3f;
- buffer[used++] = 0x80;
+ InternalState.buffer[used++] = 0x80;
free = 64 - used;
if (free < 8) {
- memset(&buffer[used], 0, free);
- body(makeArrayRef(buffer, 64));
+ memset(&InternalState.buffer[used], 0, free);
+ body(makeArrayRef(InternalState.buffer, 64));
used = 0;
free = 64;
}
- memset(&buffer[used], 0, free - 8);
+ memset(&InternalState.buffer[used], 0, free - 8);
- lo <<= 3;
- support::endian::write32le(&buffer[56], lo);
- support::endian::write32le(&buffer[60], hi);
+ InternalState.lo <<= 3;
+ support::endian::write32le(&InternalState.buffer[56], InternalState.lo);
+ support::endian::write32le(&InternalState.buffer[60], InternalState.hi);
- body(makeArrayRef(buffer, 64));
+ body(makeArrayRef(InternalState.buffer, 64));
- support::endian::write32le(&Result[0], a);
- support::endian::write32le(&Result[4], b);
- support::endian::write32le(&Result[8], c);
- support::endian::write32le(&Result[12], d);
+ support::endian::write32le(&Result[0], InternalState.a);
+ support::endian::write32le(&Result[4], InternalState.b);
+ support::endian::write32le(&Result[8], InternalState.c);
+ support::endian::write32le(&Result[12], InternalState.d);
+}
+
+StringRef MD5::final() {
+ final(Result);
+ return StringRef(reinterpret_cast<char *>(Result.Bytes.data()),
+ Result.Bytes.size());
+}
+
+StringRef MD5::result() {
+ auto StateToRestore = InternalState;
+
+ auto Hash = final();
+
+ // Restore the state
+ InternalState = StateToRestore;
+
+ return Hash;
}
SmallString<32> MD5::MD5Result::digest() const {
diff --git a/llvm/lib/Support/MSP430AttributeParser.cpp b/llvm/lib/Support/MSP430AttributeParser.cpp
new file mode 100644
index 000000000000..a9948a158fc0
--- /dev/null
+++ b/llvm/lib/Support/MSP430AttributeParser.cpp
@@ -0,0 +1,53 @@
+//===-- MSP430AttributeParser.cpp - MSP430 Attribute Parser ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/MSP430AttributeParser.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace llvm;
+using namespace llvm::MSP430Attrs;
+
+constexpr std::array<MSP430AttributeParser::DisplayHandler, 4>
+ MSP430AttributeParser::DisplayRoutines{
+ {{MSP430Attrs::TagISA, &MSP430AttributeParser::parseISA},
+ {MSP430Attrs::TagCodeModel, &MSP430AttributeParser::parseCodeModel},
+ {MSP430Attrs::TagDataModel, &MSP430AttributeParser::parseDataModel},
+ {MSP430Attrs::TagEnumSize, &MSP430AttributeParser::parseEnumSize}}};
+
+Error MSP430AttributeParser::parseISA(AttrType Tag) {
+ static const char *StringVals[] = {"None", "MSP430", "MSP430X"};
+ return parseStringAttribute("ISA", Tag, makeArrayRef(StringVals));
+}
+
+Error MSP430AttributeParser::parseCodeModel(AttrType Tag) {
+ static const char *StringVals[] = {"None", "Small", "Large"};
+ return parseStringAttribute("Code Model", Tag, makeArrayRef(StringVals));
+}
+
+Error MSP430AttributeParser::parseDataModel(AttrType Tag) {
+ static const char *StringVals[] = {"None", "Small", "Large", "Restricted"};
+ return parseStringAttribute("Data Model", Tag, makeArrayRef(StringVals));
+}
+
+Error MSP430AttributeParser::parseEnumSize(AttrType Tag) {
+ static const char *StringVals[] = {"None", "Small", "Integer", "Don't Care"};
+ return parseStringAttribute("Enum Size", Tag, makeArrayRef(StringVals));
+}
+
+Error MSP430AttributeParser::handler(uint64_t Tag, bool &Handled) {
+ Handled = false;
+ for (const DisplayHandler &Disp : DisplayRoutines) {
+ if (uint64_t(Disp.Attribute) != Tag)
+ continue;
+ if (Error E = (this->*Disp.Routine)(static_cast<AttrType>(Tag)))
+ return E;
+ Handled = true;
+ break;
+ }
+ return Error::success();
+}
diff --git a/llvm/lib/Support/MSP430Attributes.cpp b/llvm/lib/Support/MSP430Attributes.cpp
new file mode 100644
index 000000000000..4483a6872559
--- /dev/null
+++ b/llvm/lib/Support/MSP430Attributes.cpp
@@ -0,0 +1,22 @@
+//===-- MSP430Attributes.cpp - MSP430 Attributes --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/MSP430Attributes.h"
+
+using namespace llvm;
+using namespace llvm::MSP430Attrs;
+
+static constexpr TagNameItem TagData[] = {{TagISA, "Tag_ISA"},
+ {TagCodeModel, "Tag_Code_Model"},
+ {TagDataModel, "Tag_Data_Model"},
+ {TagEnumSize, "Tag_Enum_Size"}};
+
+constexpr TagNameMap MSP430AttributeTags{TagData};
+const TagNameMap &llvm::MSP430Attrs::getMSP430AttributeTags() {
+ return MSP430AttributeTags;
+}
diff --git a/llvm/lib/Support/Parallel.cpp b/llvm/lib/Support/Parallel.cpp
index 9a2e1003da5a..71e3a1362f7e 100644
--- a/llvm/lib/Support/Parallel.cpp
+++ b/llvm/lib/Support/Parallel.cpp
@@ -151,7 +151,12 @@ static std::atomic<int> TaskGroupInstances;
// lock, only allow the first TaskGroup to run tasks parallelly. In the scenario
// of nested parallel_for_each(), only the outermost one runs parallelly.
TaskGroup::TaskGroup() : Parallel(TaskGroupInstances++ == 0) {}
-TaskGroup::~TaskGroup() { --TaskGroupInstances; }
+TaskGroup::~TaskGroup() {
+ // We must ensure that all the workloads have finished before decrementing the
+ // instances count.
+ L.sync();
+ --TaskGroupInstances;
+}
void TaskGroup::spawn(std::function<void()> F) {
if (Parallel) {
diff --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp
index a724ba2faf93..3957547dfaaa 100644
--- a/llvm/lib/Support/Path.cpp
+++ b/llvm/lib/Support/Path.cpp
@@ -12,6 +12,7 @@
#include "llvm/Support/Path.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Config/config.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Errc.h"
@@ -37,15 +38,16 @@ namespace {
using llvm::sys::path::Style;
inline Style real_style(Style style) {
-#ifdef _WIN32
- return (style == Style::posix) ? Style::posix : Style::windows;
-#else
- return (style == Style::windows) ? Style::windows : Style::posix;
-#endif
+ if (style != Style::native)
+ return style;
+ if (is_style_posix(style))
+ return Style::posix;
+ return LLVM_WINDOWS_PREFER_FORWARD_SLASH ? Style::windows_slash
+ : Style::windows_backslash;
}
inline const char *separators(Style style) {
- if (real_style(style) == Style::windows)
+ if (is_style_windows(style))
return "\\/";
return "/";
}
@@ -66,7 +68,7 @@ namespace {
if (path.empty())
return path;
- if (real_style(style) == Style::windows) {
+ if (is_style_windows(style)) {
// C:
if (path.size() >= 2 &&
std::isalpha(static_cast<unsigned char>(path[0])) && path[1] == ':')
@@ -98,7 +100,7 @@ namespace {
size_t pos = str.find_last_of(separators(style), str.size() - 1);
- if (real_style(style) == Style::windows) {
+ if (is_style_windows(style)) {
if (pos == StringRef::npos)
pos = str.find_last_of(':', str.size() - 2);
}
@@ -113,7 +115,7 @@ namespace {
// directory in str, it returns StringRef::npos.
size_t root_dir_start(StringRef str, Style style) {
// case "c:/"
- if (real_style(style) == Style::windows) {
+ if (is_style_windows(style)) {
if (str.size() > 2 && str[1] == ':' && is_separator(str[2], style))
return 2;
}
@@ -259,7 +261,7 @@ const_iterator &const_iterator::operator++() {
// Root dir.
if (was_net ||
// c:/
- (real_style(S) == Style::windows && Component.endswith(":"))) {
+ (is_style_windows(S) && Component.endswith(":"))) {
Component = Path.substr(Position, 1);
return *this;
}
@@ -348,7 +350,7 @@ StringRef root_path(StringRef path, Style style) {
if (b != e) {
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(":");
+ bool has_drive = is_style_windows(style) && b->endswith(":");
if (has_net || has_drive) {
if ((++pos != e) && is_separator((*pos)[0], style)) {
@@ -373,7 +375,7 @@ StringRef root_name(StringRef path, Style style) {
if (b != e) {
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(":");
+ bool has_drive = is_style_windows(style) && b->endswith(":");
if (has_net || has_drive) {
// just {C:,//net}, return the first component.
@@ -390,7 +392,7 @@ StringRef root_directory(StringRef path, Style style) {
if (b != e) {
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(":");
+ bool has_drive = is_style_windows(style) && b->endswith(":");
if ((has_net || has_drive) &&
// {C:,//net}, skip to the next component.
@@ -497,7 +499,7 @@ void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
static bool starts_with(StringRef Path, StringRef Prefix,
Style style = Style::native) {
// Windows prefix matching : case and separator insensitive
- if (real_style(style) == Style::windows) {
+ if (is_style_windows(style)) {
if (Path.size() < Prefix.size())
return false;
for (size_t I = 0, E = Prefix.size(); I != E; ++I) {
@@ -548,8 +550,10 @@ void native(const Twine &path, SmallVectorImpl<char> &result, Style style) {
void native(SmallVectorImpl<char> &Path, Style style) {
if (Path.empty())
return;
- if (real_style(style) == Style::windows) {
- std::replace(Path.begin(), Path.end(), '/', '\\');
+ if (is_style_windows(style)) {
+ for (char &Ch : Path)
+ if (is_separator(Ch, style))
+ Ch = preferred_separator(style);
if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1], style))) {
SmallString<128> PathHome;
home_directory(PathHome);
@@ -557,14 +561,12 @@ void native(SmallVectorImpl<char> &Path, Style style) {
Path = PathHome;
}
} else {
- for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI)
- if (*PI == '\\')
- *PI = '/';
+ std::replace(Path.begin(), Path.end(), '\\', '/');
}
}
std::string convert_to_slash(StringRef path, Style style) {
- if (real_style(style) != Style::windows)
+ if (is_style_posix(style))
return std::string(path);
std::string s = path.str();
@@ -599,7 +601,7 @@ StringRef extension(StringRef path, Style style) {
bool is_separator(char value, Style style) {
if (value == '/')
return true;
- if (real_style(style) == Style::windows)
+ if (is_style_windows(style))
return value == '\\';
return false;
}
@@ -671,8 +673,7 @@ bool is_absolute(const Twine &path, Style style) {
StringRef p = path.toStringRef(path_storage);
bool rootDir = has_root_directory(p, style);
- bool rootName =
- (real_style(style) != Style::windows) || has_root_name(p, style);
+ bool rootName = is_style_posix(style) || has_root_name(p, style);
return rootDir && rootName;
}
@@ -686,7 +687,7 @@ bool is_absolute_gnu(const Twine &path, Style style) {
if (!p.empty() && is_separator(p.front(), style))
return true;
- if (real_style(style) == Style::windows) {
+ if (is_style_windows(style)) {
// Handle drive letter pattern (a character followed by ':') on Windows.
if (p.size() >= 2 && (p[0] && p[1] == ':'))
return true;
@@ -906,8 +907,7 @@ void make_absolute(const Twine &current_directory,
bool rootName = path::has_root_name(p);
// Already absolute.
- if ((rootName || real_style(Style::native) != Style::windows) &&
- rootDirectory)
+ if ((rootName || is_style_posix(Style::native)) && rootDirectory)
return;
// All of the following conditions will need the current directory.
@@ -1190,6 +1190,10 @@ TempFile &TempFile::operator=(TempFile &&Other) {
FD = Other.FD;
Other.Done = true;
Other.FD = -1;
+#ifdef _WIN32
+ RemoveOnClose = Other.RemoveOnClose;
+ Other.RemoveOnClose = false;
+#endif
return *this;
}
@@ -1204,20 +1208,23 @@ Error TempFile::discard() {
FD = -1;
#ifdef _WIN32
- // On windows closing will remove the file.
- TmpName = "";
- return Error::success();
+ // On Windows, closing will remove the file, if we set the delete
+ // disposition. If not, remove it manually.
+ bool Remove = RemoveOnClose;
#else
- // Always try to close and remove.
+ // Always try to remove the file.
+ bool Remove = true;
+#endif
std::error_code RemoveEC;
- if (!TmpName.empty()) {
+ if (Remove && !TmpName.empty()) {
RemoveEC = fs::remove(TmpName);
sys::DontRemoveFileOnSignal(TmpName);
if (!RemoveEC)
TmpName = "";
+ } else {
+ TmpName = "";
}
return errorCodeToError(RemoveEC);
-#endif
}
Error TempFile::keep(const Twine &Name) {
@@ -1228,19 +1235,26 @@ Error TempFile::keep(const Twine &Name) {
// If we can't cancel the delete don't rename.
auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
std::error_code RenameEC = setDeleteDisposition(H, false);
+ bool ShouldDelete = false;
if (!RenameEC) {
RenameEC = rename_handle(H, Name);
// If rename failed because it's cross-device, copy instead
if (RenameEC ==
std::error_code(ERROR_NOT_SAME_DEVICE, std::system_category())) {
RenameEC = copy_file(TmpName, Name);
- setDeleteDisposition(H, true);
+ ShouldDelete = true;
}
}
- // If we can't rename, discard the temporary file.
+ // If we can't rename or copy, discard the temporary file.
if (RenameEC)
- setDeleteDisposition(H, true);
+ ShouldDelete = true;
+ if (ShouldDelete) {
+ if (!RemoveOnClose)
+ setDeleteDisposition(H, true);
+ else
+ remove(TmpName);
+ }
#else
std::error_code RenameEC = fs::rename(TmpName, Name);
if (RenameEC) {
@@ -1250,8 +1264,8 @@ Error TempFile::keep(const Twine &Name) {
if (RenameEC)
remove(TmpName);
}
- sys::DontRemoveFileOnSignal(TmpName);
#endif
+ sys::DontRemoveFileOnSignal(TmpName);
if (!RenameEC)
TmpName = "";
@@ -1273,9 +1287,8 @@ Error TempFile::keep() {
auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
if (std::error_code EC = setDeleteDisposition(H, false))
return errorCodeToError(EC);
-#else
- sys::DontRemoveFileOnSignal(TmpName);
#endif
+ sys::DontRemoveFileOnSignal(TmpName);
TmpName = "";
@@ -1297,14 +1310,22 @@ Expected<TempFile> TempFile::create(const Twine &Model, unsigned Mode,
return errorCodeToError(EC);
TempFile Ret(ResultPath, FD);
-#ifndef _WIN32
- if (sys::RemoveFileOnSignal(ResultPath)) {
+#ifdef _WIN32
+ auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+ bool SetSignalHandler = false;
+ if (std::error_code EC = setDeleteDisposition(H, true)) {
+ Ret.RemoveOnClose = true;
+ SetSignalHandler = true;
+ }
+#else
+ bool SetSignalHandler = true;
+#endif
+ if (SetSignalHandler && sys::RemoveFileOnSignal(ResultPath)) {
// Make sure we delete the file when RemoveFileOnSignal fails.
consumeError(Ret.discard());
std::error_code EC(errc::operation_not_permitted);
return errorCodeToError(EC);
}
-#endif
return std::move(Ret);
}
} // namespace fs
diff --git a/llvm/lib/Support/Process.cpp b/llvm/lib/Support/Process.cpp
index e7e9a8b56f74..547b3b73eec2 100644
--- a/llvm/lib/Support/Process.cpp
+++ b/llvm/lib/Support/Process.cpp
@@ -92,8 +92,7 @@ static bool coreFilesPrevented = !LLVM_ENABLE_CRASH_DUMPS;
bool Process::AreCoreFilesPrevented() { return coreFilesPrevented; }
-LLVM_ATTRIBUTE_NORETURN
-void Process::Exit(int RetCode, bool NoCleanup) {
+[[noreturn]] void Process::Exit(int RetCode, bool NoCleanup) {
if (CrashRecoveryContext *CRC = CrashRecoveryContext::GetCurrent())
CRC->HandleExit(RetCode);
diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp
new file mode 100644
index 000000000000..8e984002f90d
--- /dev/null
+++ b/llvm/lib/Support/RISCVISAInfo.cpp
@@ -0,0 +1,718 @@
+//===-- RISCVISAInfo.cpp - RISCV Arch String Parser --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/RISCVISAInfo.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <array>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace {
+/// Represents the major and version number components of a RISC-V extension
+struct RISCVExtensionVersion {
+ unsigned Major;
+ unsigned Minor;
+};
+
+struct RISCVSupportedExtension {
+ const char *Name;
+ /// Supported version.
+ RISCVExtensionVersion Version;
+};
+
+} // end anonymous namespace
+
+static constexpr StringLiteral AllStdExts = "mafdqlcbjtpvn";
+
+static const RISCVSupportedExtension SupportedExtensions[] = {
+ {"i", RISCVExtensionVersion{2, 0}},
+ {"e", RISCVExtensionVersion{1, 9}},
+ {"m", RISCVExtensionVersion{2, 0}},
+ {"a", RISCVExtensionVersion{2, 0}},
+ {"f", RISCVExtensionVersion{2, 0}},
+ {"d", RISCVExtensionVersion{2, 0}},
+ {"c", RISCVExtensionVersion{2, 0}},
+};
+
+static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
+ {"v", RISCVExtensionVersion{0, 10}},
+ {"zba", RISCVExtensionVersion{1, 0}},
+ {"zbb", RISCVExtensionVersion{1, 0}},
+ {"zbc", RISCVExtensionVersion{1, 0}},
+ {"zbe", RISCVExtensionVersion{0, 93}},
+ {"zbf", RISCVExtensionVersion{0, 93}},
+ {"zbm", RISCVExtensionVersion{0, 93}},
+ {"zbp", RISCVExtensionVersion{0, 93}},
+ {"zbr", RISCVExtensionVersion{0, 93}},
+ {"zbs", RISCVExtensionVersion{1, 0}},
+ {"zbt", RISCVExtensionVersion{0, 93}},
+
+ {"zvamo", RISCVExtensionVersion{0, 10}},
+ {"zvlsseg", RISCVExtensionVersion{0, 10}},
+
+ {"zfhmin", RISCVExtensionVersion{0, 1}},
+ {"zfh", RISCVExtensionVersion{0, 1}},
+};
+
+static bool stripExperimentalPrefix(StringRef &Ext) {
+ return Ext.consume_front("experimental-");
+}
+
+struct FindByName {
+ FindByName(StringRef Ext) : Ext(Ext){};
+ StringRef Ext;
+ bool operator()(const RISCVSupportedExtension &ExtInfo) {
+ return ExtInfo.Name == Ext;
+ }
+};
+
+static Optional<RISCVExtensionVersion> findDefaultVersion(StringRef ExtName) {
+ // Find default version of an extension.
+ // TODO: We might set default version based on profile or ISA spec.
+ for (auto &ExtInfo : {makeArrayRef(SupportedExtensions),
+ makeArrayRef(SupportedExperimentalExtensions)}) {
+ auto ExtensionInfoIterator = llvm::find_if(ExtInfo, FindByName(ExtName));
+
+ if (ExtensionInfoIterator == ExtInfo.end()) {
+ continue;
+ }
+ return ExtensionInfoIterator->Version;
+ }
+ return None;
+}
+
+void RISCVISAInfo::addExtension(StringRef ExtName, unsigned MajorVersion,
+ unsigned MinorVersion) {
+ RISCVExtensionInfo Ext;
+ Ext.ExtName = ExtName.str();
+ Ext.MajorVersion = MajorVersion;
+ Ext.MinorVersion = MinorVersion;
+ Exts[ExtName.str()] = Ext;
+}
+
+static StringRef getExtensionTypeDesc(StringRef Ext) {
+ if (Ext.startswith("sx"))
+ return "non-standard supervisor-level extension";
+ if (Ext.startswith("s"))
+ return "standard supervisor-level extension";
+ if (Ext.startswith("x"))
+ return "non-standard user-level extension";
+ if (Ext.startswith("z"))
+ return "standard user-level extension";
+ return StringRef();
+}
+
+static StringRef getExtensionType(StringRef Ext) {
+ if (Ext.startswith("sx"))
+ return "sx";
+ if (Ext.startswith("s"))
+ return "s";
+ if (Ext.startswith("x"))
+ return "x";
+ if (Ext.startswith("z"))
+ return "z";
+ return StringRef();
+}
+
+static Optional<RISCVExtensionVersion> isExperimentalExtension(StringRef Ext) {
+ auto ExtIterator =
+ llvm::find_if(SupportedExperimentalExtensions, FindByName(Ext));
+ if (ExtIterator == std::end(SupportedExperimentalExtensions))
+ return None;
+
+ return ExtIterator->Version;
+}
+
+bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) {
+ bool IsExperimental = stripExperimentalPrefix(Ext);
+
+ if (IsExperimental)
+ return llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext));
+ else
+ return llvm::any_of(SupportedExtensions, FindByName(Ext));
+}
+
+bool RISCVISAInfo::isSupportedExtension(StringRef Ext) {
+ return llvm::any_of(SupportedExtensions, FindByName(Ext)) ||
+ llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext));
+}
+
+bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,
+ unsigned MinorVersion) {
+ auto FindByNameAndVersion = [=](const RISCVSupportedExtension &ExtInfo) {
+ return ExtInfo.Name == Ext && (MajorVersion == ExtInfo.Version.Major) &&
+ (MinorVersion == ExtInfo.Version.Minor);
+ };
+ return llvm::any_of(SupportedExtensions, FindByNameAndVersion) ||
+ llvm::any_of(SupportedExperimentalExtensions, FindByNameAndVersion);
+}
+
+bool RISCVISAInfo::hasExtension(StringRef Ext) const {
+ stripExperimentalPrefix(Ext);
+
+ if (!isSupportedExtension(Ext))
+ return false;
+
+ return Exts.count(Ext.str()) != 0;
+}
+
+// Get the rank for single-letter extension, lower value meaning higher
+// priority.
+static int singleLetterExtensionRank(char Ext) {
+ switch (Ext) {
+ case 'i':
+ return -2;
+ case 'e':
+ return -1;
+ default:
+ break;
+ }
+
+ size_t Pos = AllStdExts.find(Ext);
+ int Rank;
+ if (Pos == StringRef::npos)
+ // If we got an unknown extension letter, then give it an alphabetical
+ // order, but after all known standard extensions.
+ Rank = AllStdExts.size() + (Ext - 'a');
+ else
+ Rank = Pos;
+
+ return Rank;
+}
+
+// Get the rank for multi-letter extension, lower value meaning higher
+// priority/order in canonical order.
+static int multiLetterExtensionRank(const std::string &ExtName) {
+ assert(ExtName.length() >= 2);
+ int HighOrder;
+ int LowOrder = 0;
+ // The order between multi-char extensions: s -> h -> z -> x.
+ char ExtClass = ExtName[0];
+ switch (ExtClass) {
+ case 's':
+ HighOrder = 0;
+ break;
+ case 'h':
+ HighOrder = 1;
+ break;
+ case 'z':
+ HighOrder = 2;
+ // `z` extension must be sorted by canonical order of second letter.
+ // e.g. zmx has higher rank than zax.
+ LowOrder = singleLetterExtensionRank(ExtName[1]);
+ break;
+ case 'x':
+ HighOrder = 3;
+ break;
+ default:
+ llvm_unreachable("Unknown prefix for multi-char extension");
+ return -1;
+ }
+
+ return (HighOrder << 8) + LowOrder;
+}
+
+// Compare function for extension.
+// Only compare the extension name, ignore version comparison.
+bool RISCVISAInfo::compareExtension(const std::string &LHS,
+ const std::string &RHS) {
+ size_t LHSLen = LHS.length();
+ size_t RHSLen = RHS.length();
+ if (LHSLen == 1 && RHSLen != 1)
+ return true;
+
+ if (LHSLen != 1 && RHSLen == 1)
+ return false;
+
+ if (LHSLen == 1 && RHSLen == 1)
+ return singleLetterExtensionRank(LHS[0]) <
+ singleLetterExtensionRank(RHS[0]);
+
+ // Both are multi-char ext here.
+ int LHSRank = multiLetterExtensionRank(LHS);
+ int RHSRank = multiLetterExtensionRank(RHS);
+ if (LHSRank != RHSRank)
+ return LHSRank < RHSRank;
+
+ // If the rank is same, it must be sorted by lexicographic order.
+ return LHS < RHS;
+}
+
+void RISCVISAInfo::toFeatures(
+ std::vector<StringRef> &Features,
+ std::function<StringRef(const Twine &)> StrAlloc) const {
+ for (auto &Ext : Exts) {
+ StringRef ExtName = Ext.first;
+
+ if (ExtName == "i")
+ continue;
+
+ if (ExtName == "zvlsseg") {
+ Features.push_back("+experimental-v");
+ Features.push_back("+experimental-zvlsseg");
+ } else if (ExtName == "zvamo") {
+ Features.push_back("+experimental-v");
+ Features.push_back("+experimental-zvlsseg");
+ Features.push_back("+experimental-zvamo");
+ } else if (isExperimentalExtension(ExtName)) {
+ Features.push_back(StrAlloc("+experimental-" + ExtName));
+ } else {
+ Features.push_back(StrAlloc("+" + ExtName));
+ }
+ }
+}
+
+// Extensions may have a version number, and may be separated by
+// an underscore '_' e.g.: rv32i2_m2.
+// Version number is divided into major and minor version numbers,
+// separated by a 'p'. If the minor version is 0 then 'p0' can be
+// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
+static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,
+ unsigned &Minor, unsigned &ConsumeLength,
+ bool EnableExperimentalExtension,
+ bool ExperimentalExtensionVersionCheck) {
+ StringRef MajorStr, MinorStr;
+ Major = 0;
+ Minor = 0;
+ ConsumeLength = 0;
+ MajorStr = In.take_while(isDigit);
+ In = In.substr(MajorStr.size());
+
+ if (!MajorStr.empty() && In.consume_front("p")) {
+ MinorStr = In.take_while(isDigit);
+ In = In.substr(MajorStr.size() + 1);
+
+ // Expected 'p' to be followed by minor version number.
+ if (MinorStr.empty()) {
+ return createStringError(
+ errc::invalid_argument,
+ "minor version number missing after 'p' for extension '" + Ext + "'");
+ }
+ }
+
+ if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))
+ return createStringError(
+ errc::invalid_argument,
+ "Failed to parse major version number for extension '" + Ext + "'");
+
+ if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))
+ return createStringError(
+ errc::invalid_argument,
+ "Failed to parse minor version number for extension '" + Ext + "'");
+
+ ConsumeLength = MajorStr.size();
+
+ if (!MinorStr.empty())
+ ConsumeLength += MinorStr.size() + 1 /*'p'*/;
+
+ // Expected multi-character extension with version number to have no
+ // subsequent characters (i.e. must either end string or be followed by
+ // an underscore).
+ if (Ext.size() > 1 && In.size()) {
+ std::string Error =
+ "multi-character extensions must be separated by underscores";
+ return createStringError(errc::invalid_argument, Error);
+ }
+
+ // If experimental extension, require use of current version number number
+ if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
+ if (!EnableExperimentalExtension) {
+ std::string Error = "requires '-menable-experimental-extensions' for "
+ "experimental extension '" +
+ Ext.str() + "'";
+ return createStringError(errc::invalid_argument, Error);
+ }
+
+ if (ExperimentalExtensionVersionCheck &&
+ (MajorStr.empty() && MinorStr.empty())) {
+ std::string Error =
+ "experimental extension requires explicit version number `" +
+ Ext.str() + "`";
+ return createStringError(errc::invalid_argument, Error);
+ }
+
+ auto SupportedVers = *ExperimentalExtension;
+ if (ExperimentalExtensionVersionCheck &&
+ (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) {
+ std::string Error = "unsupported version number " + MajorStr.str();
+ if (!MinorStr.empty())
+ Error += "." + MinorStr.str();
+ Error += " for experimental extension '" + Ext.str() +
+ "'(this compiler supports " + utostr(SupportedVers.Major) + "." +
+ utostr(SupportedVers.Minor) + ")";
+ return createStringError(errc::invalid_argument, Error);
+ }
+ return Error::success();
+ }
+
+ // Exception rule for `g`, we don't have clear version scheme for that on
+ // ISA spec.
+ if (Ext == "g")
+ return Error::success();
+
+ if (MajorStr.empty() && MinorStr.empty()) {
+ if (auto DefaultVersion = findDefaultVersion(Ext)) {
+ Major = DefaultVersion->Major;
+ Minor = DefaultVersion->Minor;
+ }
+ // No matter found or not, return success, assume other place will
+ // verify.
+ return Error::success();
+ }
+
+ if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor))
+ return Error::success();
+
+ std::string Error = "unsupported version number " + std::string(MajorStr);
+ if (!MinorStr.empty())
+ Error += "." + MinorStr.str();
+ Error += " for extension '" + Ext.str() + "'";
+ return createStringError(errc::invalid_argument, Error);
+}
+
+llvm::Expected<std::unique_ptr<RISCVISAInfo>>
+RISCVISAInfo::parseFeatures(unsigned XLen,
+ const std::vector<std::string> &Features) {
+ assert(XLen == 32 || XLen == 64);
+ std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
+
+ bool HasE = false;
+ for (auto &Feature : Features) {
+ StringRef ExtName = Feature;
+ bool Experimental = false;
+ assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
+ bool Add = ExtName[0] == '+';
+ ExtName = ExtName.drop_front(1); // Drop '+' or '-'
+ Experimental = stripExperimentalPrefix(ExtName);
+ auto ExtensionInfos = Experimental
+ ? makeArrayRef(SupportedExperimentalExtensions)
+ : makeArrayRef(SupportedExtensions);
+ auto ExtensionInfoIterator =
+ llvm::find_if(ExtensionInfos, FindByName(ExtName));
+
+ // Not all features is related to ISA extension, like `relax` or
+ // `save-restore`, skip those feature.
+ if (ExtensionInfoIterator == ExtensionInfos.end())
+ continue;
+
+ if (Add) {
+ if (ExtName == "e") {
+ if (XLen != 32)
+ return createStringError(
+ errc::invalid_argument,
+ "standard user-level extension 'e' requires 'rv32'");
+ HasE = true;
+ }
+
+ ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version.Major,
+ ExtensionInfoIterator->Version.Minor);
+ } else
+ ISAInfo->Exts.erase(ExtName.str());
+ }
+ if (!HasE) {
+ if (auto Version = findDefaultVersion("i"))
+ ISAInfo->addExtension("i", Version->Major, Version->Minor);
+ else
+ llvm_unreachable("Default extension version for 'i' not found?");
+ }
+
+ ISAInfo->updateFLen();
+
+ return std::move(ISAInfo);
+}
+
+llvm::Expected<std::unique_ptr<RISCVISAInfo>>
+RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
+ bool ExperimentalExtensionVersionCheck) {
+ // RISC-V ISA strings must be lowercase.
+ if (llvm::any_of(Arch, isupper)) {
+ return createStringError(errc::invalid_argument,
+ "string must be lowercase");
+ }
+
+ bool HasRV64 = Arch.startswith("rv64");
+ // ISA string must begin with rv32 or rv64.
+ if (!(Arch.startswith("rv32") || HasRV64) || (Arch.size() < 5)) {
+ return createStringError(errc::invalid_argument,
+ "string must begin with rv32{i,e,g} or rv64{i,g}");
+ }
+
+ unsigned XLen = HasRV64 ? 64 : 32;
+ std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
+
+ // The canonical order specified in ISA manual.
+ // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
+ StringRef StdExts = AllStdExts;
+ bool HasF = false, HasD = false;
+ char Baseline = Arch[4];
+
+ // First letter should be 'e', 'i' or 'g'.
+ switch (Baseline) {
+ default:
+ return createStringError(errc::invalid_argument,
+ "first letter should be 'e', 'i' or 'g'");
+ case 'e': {
+ // Extension 'e' is not allowed in rv64.
+ if (HasRV64)
+ return createStringError(
+ errc::invalid_argument,
+ "standard user-level extension 'e' requires 'rv32'");
+ break;
+ }
+ case 'i':
+ break;
+ case 'g':
+ // g = imafd
+ StdExts = StdExts.drop_front(4);
+ HasF = true;
+ HasD = true;
+ break;
+ }
+
+ // Skip rvxxx
+ StringRef Exts = Arch.substr(5);
+
+ // Remove multi-letter standard extensions, non-standard extensions and
+ // supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes.
+ // Parse them at the end.
+ // Find the very first occurrence of 's', 'x' or 'z'.
+ StringRef OtherExts;
+ size_t Pos = Exts.find_first_of("zsx");
+ if (Pos != StringRef::npos) {
+ OtherExts = Exts.substr(Pos);
+ Exts = Exts.substr(0, Pos);
+ }
+
+ unsigned Major, Minor, ConsumeLength;
+ if (auto E = getExtensionVersion(std::string(1, Baseline), Exts, Major, Minor,
+ ConsumeLength, EnableExperimentalExtension,
+ ExperimentalExtensionVersionCheck))
+ return std::move(E);
+
+ if (Baseline == 'g') {
+ // No matter which version is given to `g`, we always set imafd to default
+ // version since the we don't have clear version scheme for that on
+ // ISA spec.
+ for (auto Ext : {"i", "m", "a", "f", "d"})
+ if (auto Version = findDefaultVersion(Ext))
+ ISAInfo->addExtension(Ext, Version->Major, Version->Minor);
+ else
+ llvm_unreachable("Default extension version not found?");
+ } else
+ // Baseline is `i` or `e`
+ ISAInfo->addExtension(std::string(1, Baseline), Major, Minor);
+
+ // Consume the base ISA version number and any '_' between rvxxx and the
+ // first extension
+ Exts = Exts.drop_front(ConsumeLength);
+ Exts.consume_front("_");
+
+ // TODO: Use version number when setting target features
+
+ auto StdExtsItr = StdExts.begin();
+ auto StdExtsEnd = StdExts.end();
+ for (auto I = Exts.begin(), E = Exts.end(); I != E;) {
+ char C = *I;
+
+ // Check ISA extensions are specified in the canonical order.
+ while (StdExtsItr != StdExtsEnd && *StdExtsItr != C)
+ ++StdExtsItr;
+
+ if (StdExtsItr == StdExtsEnd) {
+ // Either c contains a valid extension but it was not given in
+ // canonical order or it is an invalid extension.
+ if (StdExts.contains(C)) {
+ return createStringError(
+ errc::invalid_argument,
+ "standard user-level extension not given in canonical order '%c'",
+ C);
+ }
+
+ return createStringError(errc::invalid_argument,
+ "invalid standard user-level extension '%c'", C);
+ }
+
+ // Move to next char to prevent repeated letter.
+ ++StdExtsItr;
+
+ std::string Next;
+ unsigned Major, Minor, ConsumeLength;
+ if (std::next(I) != E)
+ Next = std::string(std::next(I), E);
+ if (auto E = getExtensionVersion(std::string(1, C), Next, Major, Minor,
+ ConsumeLength, EnableExperimentalExtension,
+ ExperimentalExtensionVersionCheck))
+ return std::move(E);
+
+ // The order is OK, then push it into features.
+ // TODO: Use version number when setting target features
+ switch (C) {
+ default:
+ // Currently LLVM supports only "mafdcbv".
+ return createStringError(errc::invalid_argument,
+ "unsupported standard user-level extension '%c'",
+ C);
+ case 'm':
+ ISAInfo->addExtension("m", Major, Minor);
+ break;
+ case 'a':
+ ISAInfo->addExtension("a", Major, Minor);
+ break;
+ case 'f':
+ ISAInfo->addExtension("f", Major, Minor);
+ HasF = true;
+ break;
+ case 'd':
+ ISAInfo->addExtension("d", Major, Minor);
+ HasD = true;
+ break;
+ case 'c':
+ ISAInfo->addExtension("c", Major, Minor);
+ break;
+ case 'v':
+ ISAInfo->addExtension("v", Major, Minor);
+ ISAInfo->addExtension("zvlsseg", Major, Minor);
+ break;
+ }
+ // Consume full extension name and version, including any optional '_'
+ // between this extension and the next
+ ++I;
+ I += ConsumeLength;
+ if (*I == '_')
+ ++I;
+ }
+ // Dependency check.
+ // It's illegal to specify the 'd' (double-precision floating point)
+ // extension without also specifying the 'f' (single precision
+ // floating-point) extension.
+ // TODO: This has been removed in later specs, which specify that D implies F
+ if (HasD && !HasF)
+ return createStringError(errc::invalid_argument,
+ "d requires f extension to also be specified");
+
+ // Additional dependency checks.
+ // TODO: The 'q' extension requires rv64.
+ // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
+
+ if (OtherExts.empty())
+ return std::move(ISAInfo);
+
+ // Handle other types of extensions other than the standard
+ // general purpose and standard user-level extensions.
+ // Parse the ISA string containing non-standard user-level
+ // extensions, standard supervisor-level extensions and
+ // non-standard supervisor-level extensions.
+ // These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a
+ // canonical order, might have a version number (major, minor)
+ // and are separated by a single underscore '_'.
+ // Set the hardware features for the extensions that are supported.
+
+ // Multi-letter extensions are seperated by a single underscore
+ // as described in RISC-V User-Level ISA V2.2.
+ SmallVector<StringRef, 8> Split;
+ OtherExts.split(Split, '_');
+
+ SmallVector<StringRef, 8> AllExts;
+ std::array<StringRef, 4> Prefix{"z", "x", "s", "sx"};
+ auto I = Prefix.begin();
+ auto E = Prefix.end();
+
+ for (StringRef Ext : Split) {
+ if (Ext.empty())
+ return createStringError(errc::invalid_argument,
+ "extension name missing after separator '_'");
+
+ StringRef Type = getExtensionType(Ext);
+ StringRef Desc = getExtensionTypeDesc(Ext);
+ auto Pos = Ext.find_if(isDigit);
+ StringRef Name(Ext.substr(0, Pos));
+ StringRef Vers(Ext.substr(Pos));
+
+ if (Type.empty())
+ return createStringError(errc::invalid_argument,
+ "invalid extension prefix '" + Ext + "'");
+
+ // Check ISA extensions are specified in the canonical order.
+ while (I != E && *I != Type)
+ ++I;
+
+ if (I == E)
+ return createStringError(errc::invalid_argument,
+ "%s not given in canonical order '%s'",
+ Desc.str().c_str(), Ext.str().c_str());
+
+ if (Name.size() == Type.size()) {
+ return createStringError(errc::invalid_argument,
+ "%s name missing after '%s'", Desc.str().c_str(),
+ Type.str().c_str());
+ }
+
+ unsigned Major, Minor, ConsumeLength;
+ if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
+ EnableExperimentalExtension,
+ ExperimentalExtensionVersionCheck))
+ return std::move(E);
+
+ // Check if duplicated extension.
+ if (llvm::is_contained(AllExts, Name))
+ return createStringError(errc::invalid_argument, "duplicated %s '%s'",
+ Desc.str().c_str(), Name.str().c_str());
+
+ ISAInfo->addExtension(Name, Major, Minor);
+ // Extension format is correct, keep parsing the extensions.
+ // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
+ AllExts.push_back(Name);
+ }
+
+ for (auto Ext : AllExts) {
+ if (!isSupportedExtension(Ext)) {
+ StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
+ return createStringError(errc::invalid_argument, "unsupported %s '%s'",
+ Desc.str().c_str(), Ext.str().c_str());
+ }
+ }
+
+ ISAInfo->updateFLen();
+
+ return std::move(ISAInfo);
+}
+
+void RISCVISAInfo::updateFLen() {
+ FLen = 0;
+ // TODO: Handle q extension.
+ if (Exts.count("d"))
+ FLen = 64;
+ else if (Exts.count("f"))
+ FLen = 32;
+}
+
+std::string RISCVISAInfo::toString() const {
+ std::string Buffer;
+ raw_string_ostream Arch(Buffer);
+
+ Arch << "rv" << XLen;
+
+ ListSeparator LS("_");
+ for (auto &Ext : Exts) {
+ StringRef ExtName = Ext.first;
+ auto ExtInfo = Ext.second;
+ Arch << LS << ExtName;
+ Arch << ExtInfo.MajorVersion << "p" << ExtInfo.MinorVersion;
+ }
+
+ return Arch.str();
+}
diff --git a/llvm/lib/Support/Signposts.cpp b/llvm/lib/Support/Signposts.cpp
index 49a0b16baa02..58fafb26cdf3 100644
--- a/llvm/lib/Support/Signposts.cpp
+++ b/llvm/lib/Support/Signposts.cpp
@@ -1,23 +1,27 @@
//===-- Signposts.cpp - Interval debug annotations ------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/Signposts.h"
#include "llvm/Support/Timer.h"
+#include "llvm/Config/config.h"
#if LLVM_SUPPORT_XCODE_SIGNPOSTS
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Mutex.h"
-#endif
+#include <Availability.h>
+#include <os/signpost.h>
+#endif // if LLVM_SUPPORT_XCODE_SIGNPOSTS
using namespace llvm;
#if LLVM_SUPPORT_XCODE_SIGNPOSTS
+#define SIGNPOSTS_AVAILABLE() \
+ __builtin_available(macos 10.14, iOS 12, tvOS 12, watchOS 5, *)
namespace {
os_log_t *LogCreator() {
os_log_t *X = new os_log_t;
@@ -35,13 +39,13 @@ struct LogDeleter {
namespace llvm {
class SignpostEmitterImpl {
using LogPtrTy = std::unique_ptr<os_log_t, LogDeleter>;
+ using LogTy = LogPtrTy::element_type;
LogPtrTy SignpostLog;
DenseMap<const void *, os_signpost_id_t> Signposts;
sys::SmartMutex<true> Mutex;
-public:
- os_log_t &getLogger() const { return *SignpostLog; }
+ LogTy &getLogger() const { return *SignpostLog; }
os_signpost_id_t getSignpostForObject(const void *O) {
sys::SmartScopedLock<true> Lock(Mutex);
const auto &I = Signposts.find(O);
@@ -55,6 +59,7 @@ public:
return Inserted.first->second;
}
+public:
SignpostEmitterImpl() : SignpostLog(LogCreator()) {}
bool isEnabled() const {
@@ -73,7 +78,7 @@ public:
}
}
- void endInterval(const void *O) {
+ void endInterval(const void *O, llvm::StringRef Name) {
if (isEnabled()) {
if (SIGNPOSTS_AVAILABLE()) {
// Both strings used here are required to be constant literal strings.
@@ -119,17 +124,10 @@ void SignpostEmitter::startInterval(const void *O, StringRef Name) {
#endif // if !HAVE_ANY_SIGNPOST_IMPL
}
-#if HAVE_ANY_SIGNPOST_IMPL
-os_log_t &SignpostEmitter::getLogger() const { return Impl->getLogger(); }
-os_signpost_id_t SignpostEmitter::getSignpostForObject(const void *O) {
- return Impl->getSignpostForObject(O);
-}
-#endif
-
-void SignpostEmitter::endInterval(const void *O) {
+void SignpostEmitter::endInterval(const void *O, StringRef Name) {
#if HAVE_ANY_SIGNPOST_IMPL
if (Impl == nullptr)
return;
- Impl->endInterval(O);
+ Impl->endInterval(O, Name);
#endif // if !HAVE_ANY_SIGNPOST_IMPL
}
diff --git a/llvm/lib/Support/SmallVector.cpp b/llvm/lib/Support/SmallVector.cpp
index 0005f7840912..2d7721e4e1fb 100644
--- a/llvm/lib/Support/SmallVector.cpp
+++ b/llvm/lib/Support/SmallVector.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Twine.h"
#include <cstdint>
#ifdef LLVM_ENABLE_EXCEPTIONS
#include <stdexcept>
@@ -19,12 +20,21 @@ using namespace llvm;
// Check that no bytes are wasted and everything is well-aligned.
namespace {
+// These structures may cause binary compat warnings on AIX. Suppress the
+// warning since we are only using these types for the static assertions below.
+#if defined(_AIX)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Waix-compat"
+#endif
struct Struct16B {
alignas(16) void *X;
};
struct Struct32B {
alignas(32) void *X;
};
+#if defined(_AIX)
+#pragma GCC diagnostic pop
+#endif
}
static_assert(sizeof(SmallVector<void *, 0>) ==
sizeof(unsigned) * 2 + sizeof(void *),
@@ -47,8 +57,7 @@ static_assert(sizeof(SmallVector<char, 0>) ==
/// Report that MinSize doesn't fit into this vector's size type. Throws
/// std::length_error or calls report_fatal_error.
-LLVM_ATTRIBUTE_NORETURN
-static void report_size_overflow(size_t MinSize, size_t MaxSize);
+[[noreturn]] static void report_size_overflow(size_t MinSize, size_t MaxSize);
static void report_size_overflow(size_t MinSize, size_t MaxSize) {
std::string Reason = "SmallVector unable to grow. Requested capacity (" +
std::to_string(MinSize) +
@@ -57,13 +66,13 @@ static void report_size_overflow(size_t MinSize, size_t MaxSize) {
#ifdef LLVM_ENABLE_EXCEPTIONS
throw std::length_error(Reason);
#else
- report_fatal_error(Reason);
+ report_fatal_error(Twine(Reason));
#endif
}
/// Report that this vector is already at maximum capacity. Throws
/// std::length_error or calls report_fatal_error.
-LLVM_ATTRIBUTE_NORETURN static void report_at_maximum_capacity(size_t MaxSize);
+[[noreturn]] static void report_at_maximum_capacity(size_t MaxSize);
static void report_at_maximum_capacity(size_t MaxSize) {
std::string Reason =
"SmallVector capacity unable to grow. Already at maximum size " +
@@ -71,7 +80,7 @@ static void report_at_maximum_capacity(size_t MaxSize) {
#ifdef LLVM_ENABLE_EXCEPTIONS
throw std::length_error(Reason);
#else
- report_fatal_error(Reason);
+ report_fatal_error(Twine(Reason));
#endif
}
diff --git a/llvm/lib/Support/SpecialCaseList.cpp b/llvm/lib/Support/SpecialCaseList.cpp
index 73f852624a69..1939ed9e9547 100644
--- a/llvm/lib/Support/SpecialCaseList.cpp
+++ b/llvm/lib/Support/SpecialCaseList.cpp
@@ -64,7 +64,7 @@ unsigned SpecialCaseList::Matcher::match(StringRef Query) const {
return It->second;
if (Trigrams.isDefinitelyOut(Query))
return false;
- for (auto& RegExKV : RegExes)
+ for (const auto &RegExKV : RegExes)
if (RegExKV.first->match(Query))
return RegExKV.second;
return 0;
@@ -93,7 +93,7 @@ SpecialCaseList::createOrDie(const std::vector<std::string> &Paths,
std::string Error;
if (auto SCL = create(Paths, FS, Error))
return SCL;
- report_fatal_error(Error);
+ report_fatal_error(Twine(Error));
}
bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths,
@@ -209,7 +209,7 @@ bool SpecialCaseList::inSection(StringRef Section, StringRef Prefix,
unsigned SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix,
StringRef Query,
StringRef Category) const {
- for (auto &SectionIter : Sections)
+ for (const auto &SectionIter : Sections)
if (SectionIter.SectionMatcher->match(Section)) {
unsigned Blame =
inSectionBlame(SectionIter.Entries, Prefix, Query, Category);
diff --git a/llvm/lib/Support/TargetRegistry.cpp b/llvm/lib/Support/TargetRegistry.cpp
deleted file mode 100644
index 1f9c3bbf8229..000000000000
--- a/llvm/lib/Support/TargetRegistry.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-//===--- TargetRegistry.cpp - Target registration -------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cassert>
-#include <vector>
-using namespace llvm;
-
-// Clients are responsible for avoid race conditions in registration.
-static Target *FirstTarget = nullptr;
-
-iterator_range<TargetRegistry::iterator> TargetRegistry::targets() {
- return make_range(iterator(FirstTarget), iterator());
-}
-
-const Target *TargetRegistry::lookupTarget(const std::string &ArchName,
- Triple &TheTriple,
- std::string &Error) {
- // Allocate target machine. First, check whether the user has explicitly
- // specified an architecture to compile for. If so we have to look it up by
- // name, because it might be a backend that has no mapping to a target triple.
- const Target *TheTarget = nullptr;
- if (!ArchName.empty()) {
- auto I = find_if(targets(),
- [&](const Target &T) { return ArchName == T.getName(); });
-
- if (I == targets().end()) {
- Error = "error: invalid target '" + ArchName + "'.\n";
- return nullptr;
- }
-
- TheTarget = &*I;
-
- // Adjust the triple to match (if known), otherwise stick with the
- // given triple.
- Triple::ArchType Type = Triple::getArchTypeForLLVMName(ArchName);
- if (Type != Triple::UnknownArch)
- TheTriple.setArch(Type);
- } else {
- // Get the target specific parser.
- std::string TempError;
- TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), TempError);
- if (!TheTarget) {
- Error = ": error: unable to get target for '"
- + TheTriple.getTriple()
- + "', see --version and --triple.\n";
- return nullptr;
- }
- }
-
- return TheTarget;
-}
-
-const Target *TargetRegistry::lookupTarget(const std::string &TT,
- std::string &Error) {
- // Provide special warning when no targets are initialized.
- if (targets().begin() == targets().end()) {
- Error = "Unable to find target for this triple (no targets are registered)";
- return nullptr;
- }
- Triple::ArchType Arch = Triple(TT).getArch();
- auto ArchMatch = [&](const Target &T) { return T.ArchMatchFn(Arch); };
- auto I = find_if(targets(), ArchMatch);
-
- if (I == targets().end()) {
- Error = "No available targets are compatible with triple \"" + TT + "\"";
- return nullptr;
- }
-
- auto J = std::find_if(std::next(I), targets().end(), ArchMatch);
- if (J != targets().end()) {
- Error = std::string("Cannot choose between targets \"") + I->Name +
- "\" and \"" + J->Name + "\"";
- return nullptr;
- }
-
- return &*I;
-}
-
-void TargetRegistry::RegisterTarget(Target &T, const char *Name,
- const char *ShortDesc,
- const char *BackendName,
- Target::ArchMatchFnTy ArchMatchFn,
- bool HasJIT) {
- assert(Name && ShortDesc && ArchMatchFn &&
- "Missing required target information!");
-
- // Check if this target has already been initialized, we allow this as a
- // convenience to some clients.
- if (T.Name)
- return;
-
- // Add to the list of targets.
- T.Next = FirstTarget;
- FirstTarget = &T;
-
- T.Name = Name;
- T.ShortDesc = ShortDesc;
- T.BackendName = BackendName;
- T.ArchMatchFn = ArchMatchFn;
- T.HasJIT = HasJIT;
-}
-
-static int TargetArraySortFn(const std::pair<StringRef, const Target *> *LHS,
- const std::pair<StringRef, const Target *> *RHS) {
- return LHS->first.compare(RHS->first);
-}
-
-void TargetRegistry::printRegisteredTargetsForVersion(raw_ostream &OS) {
- std::vector<std::pair<StringRef, const Target*> > Targets;
- size_t Width = 0;
- for (const auto &T : TargetRegistry::targets()) {
- Targets.push_back(std::make_pair(T.getName(), &T));
- Width = std::max(Width, Targets.back().first.size());
- }
- array_pod_sort(Targets.begin(), Targets.end(), TargetArraySortFn);
-
- OS << " Registered Targets:\n";
- for (unsigned i = 0, e = Targets.size(); i != e; ++i) {
- OS << " " << Targets[i].first;
- OS.indent(Width - Targets[i].first.size()) << " - "
- << Targets[i].second->getShortDescription() << '\n';
- }
- if (Targets.empty())
- OS << " (none)\n";
-}
diff --git a/llvm/lib/Support/TimeProfiler.cpp b/llvm/lib/Support/TimeProfiler.cpp
index 8f2544e9e26d..2b094a4983a0 100644
--- a/llvm/lib/Support/TimeProfiler.cpp
+++ b/llvm/lib/Support/TimeProfiler.cpp
@@ -110,9 +110,8 @@ struct llvm::TimeTraceProfiler {
// templates from within, we only want to add the topmost one. "topmost"
// happens to be the ones that don't have any currently open entries above
// itself.
- if (std::find_if(++Stack.rbegin(), Stack.rend(), [&](const Entry &Val) {
- return Val.Name == E.Name;
- }) == Stack.rend()) {
+ if (llvm::none_of(llvm::drop_begin(llvm::reverse(Stack)),
+ [&](const Entry &Val) { return Val.Name == E.Name; })) {
auto &CountAndTotal = CountAndTotalPerName[E.Name];
CountAndTotal.first++;
CountAndTotal.second += Duration;
@@ -272,8 +271,9 @@ void llvm::timeTraceProfilerInitialize(unsigned TimeTraceGranularity,
// Called from main thread.
void llvm::timeTraceProfilerCleanup() {
delete TimeTraceProfilerInstance;
+ TimeTraceProfilerInstance = nullptr;
std::lock_guard<std::mutex> Lock(Mu);
- for (auto TTP : *ThreadTimeTraceProfilerInstances)
+ for (auto *TTP : *ThreadTimeTraceProfilerInstances)
delete TTP;
ThreadTimeTraceProfilerInstances->clear();
}
diff --git a/llvm/lib/Support/Timer.cpp b/llvm/lib/Support/Timer.cpp
index f025ecd3d45c..08e1a8a0e0aa 100644
--- a/llvm/lib/Support/Timer.cpp
+++ b/llvm/lib/Support/Timer.cpp
@@ -199,7 +199,7 @@ void Timer::stopTimer() {
Running = false;
Time += TimeRecord::getCurrentTime(false);
Time -= StartTime;
- Signposts->endInterval(this);
+ Signposts->endInterval(this, getName());
}
void Timer::clear() {
@@ -393,8 +393,7 @@ void TimerGroup::PrintQueuedTimers(raw_ostream &OS) {
OS << " --- Name ---\n";
// Loop through all of the timing data, printing it out.
- for (const PrintRecord &Record : make_range(TimersToPrint.rbegin(),
- TimersToPrint.rend())) {
+ for (const PrintRecord &Record : llvm::reverse(TimersToPrint)) {
Record.Time.print(Total, OS);
OS << Record.Description << '\n';
}
diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp
index 88311546354b..b9a92e280576 100644
--- a/llvm/lib/Support/Triple.cpp
+++ b/llvm/lib/Support/Triple.cpp
@@ -67,6 +67,8 @@ StringRef Triple::getArchTypeName(ArchType Kind) {
case sparcv9: return "sparcv9";
case spir64: return "spir64";
case spir: return "spir";
+ case spirv32: return "spirv32";
+ case spirv64: return "spirv64";
case systemz: return "s390x";
case tce: return "tce";
case tcele: return "tcele";
@@ -147,6 +149,10 @@ StringRef Triple::getArchTypePrefix(ArchType Kind) {
case spir:
case spir64: return "spir";
+
+ case spirv32:
+ case spirv64: return "spirv";
+
case kalimba: return "kalimba";
case lanai: return "lanai";
case shave: return "shave";
@@ -323,6 +329,8 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) {
.Case("hsail64", hsail64)
.Case("spir", spir)
.Case("spir64", spir64)
+ .Case("spirv32", spirv32)
+ .Case("spirv64", spirv64)
.Case("kalimba", kalimba)
.Case("lanai", lanai)
.Case("shave", shave)
@@ -456,6 +464,8 @@ static Triple::ArchType parseArch(StringRef ArchName) {
.Case("hsail64", Triple::hsail64)
.Case("spir", Triple::spir)
.Case("spir64", Triple::spir64)
+ .Case("spirv32", Triple::spirv32)
+ .Case("spirv64", Triple::spirv64)
.StartsWith("kalimba", Triple::kalimba)
.Case("lanai", Triple::lanai)
.Case("renderscript32", Triple::renderscript32)
@@ -653,6 +663,12 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) {
return Triple::ARMSubArch_v8_6a;
case ARM::ArchKind::ARMV8_7A:
return Triple::ARMSubArch_v8_7a;
+ case ARM::ArchKind::ARMV9A:
+ return Triple::ARMSubArch_v9;
+ case ARM::ArchKind::ARMV9_1A:
+ return Triple::ARMSubArch_v9_1a;
+ case ARM::ArchKind::ARMV9_2A:
+ return Triple::ARMSubArch_v9_2a;
case ARM::ArchKind::ARMV8R:
return Triple::ARMSubArch_v8r;
case ARM::ArchKind::ARMV8MBaseline:
@@ -753,6 +769,11 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) {
case Triple::wasm32:
case Triple::wasm64:
return Triple::Wasm;
+
+ case Triple::spirv32:
+ case Triple::spirv64:
+ // TODO: In future this will be Triple::SPIRV.
+ return Triple::UnknownObjectFormat;
}
llvm_unreachable("unknown architecture");
}
@@ -1024,6 +1045,30 @@ StringRef Triple::getArchName() const {
return StringRef(Data).split('-').first; // Isolate first component
}
+StringRef Triple::getArchName(ArchType Kind, SubArchType SubArch) const {
+ switch (Kind) {
+ case Triple::mips:
+ if (SubArch == MipsSubArch_r6)
+ return "mipsisa32r6";
+ break;
+ case Triple::mipsel:
+ if (SubArch == MipsSubArch_r6)
+ return "mipsisa32r6el";
+ break;
+ case Triple::mips64:
+ if (SubArch == MipsSubArch_r6)
+ return "mipsisa64r6";
+ break;
+ case Triple::mips64el:
+ if (SubArch == MipsSubArch_r6)
+ return "mipsisa64r6el";
+ break;
+ default:
+ break;
+ }
+ return getArchTypeName(Kind);
+}
+
StringRef Triple::getVendorName() const {
StringRef Tmp = StringRef(Data).split('-').second; // Strip first component
return Tmp.split('-').first; // Isolate second component
@@ -1205,8 +1250,8 @@ void Triple::setTriple(const Twine &Str) {
*this = Triple(Str);
}
-void Triple::setArch(ArchType Kind) {
- setArchName(getArchTypeName(Kind));
+void Triple::setArch(ArchType Kind, SubArchType SubArch) {
+ setArchName(getArchName(Kind, SubArch));
}
void Triple::setVendor(VendorType Kind) {
@@ -1298,6 +1343,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) {
case llvm::Triple::sparc:
case llvm::Triple::sparcel:
case llvm::Triple::spir:
+ case llvm::Triple::spirv32:
case llvm::Triple::tce:
case llvm::Triple::tcele:
case llvm::Triple::thumb:
@@ -1324,6 +1370,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) {
case llvm::Triple::riscv64:
case llvm::Triple::sparcv9:
case llvm::Triple::spir64:
+ case llvm::Triple::spirv64:
case llvm::Triple::systemz:
case llvm::Triple::ve:
case llvm::Triple::wasm64:
@@ -1383,6 +1430,7 @@ Triple Triple::get32BitArchVariant() const {
case Triple::sparc:
case Triple::sparcel:
case Triple::spir:
+ case Triple::spirv32:
case Triple::tce:
case Triple::tcele:
case Triple::thumb:
@@ -1398,8 +1446,12 @@ Triple Triple::get32BitArchVariant() const {
case Triple::amdil64: T.setArch(Triple::amdil); break;
case Triple::hsail64: T.setArch(Triple::hsail); break;
case Triple::le64: T.setArch(Triple::le32); break;
- case Triple::mips64: T.setArch(Triple::mips); break;
- case Triple::mips64el: T.setArch(Triple::mipsel); break;
+ case Triple::mips64:
+ T.setArch(Triple::mips, getSubArch());
+ break;
+ case Triple::mips64el:
+ T.setArch(Triple::mipsel, getSubArch());
+ break;
case Triple::nvptx64: T.setArch(Triple::nvptx); break;
case Triple::ppc64: T.setArch(Triple::ppc); break;
case Triple::ppc64le: T.setArch(Triple::ppcle); break;
@@ -1407,6 +1459,7 @@ Triple Triple::get32BitArchVariant() const {
case Triple::riscv64: T.setArch(Triple::riscv32); break;
case Triple::sparcv9: T.setArch(Triple::sparc); break;
case Triple::spir64: T.setArch(Triple::spir); break;
+ case Triple::spirv64: T.setArch(Triple::spirv32); break;
case Triple::wasm64: T.setArch(Triple::wasm32); break;
case Triple::x86_64: T.setArch(Triple::x86); break;
}
@@ -1451,6 +1504,7 @@ Triple Triple::get64BitArchVariant() const {
case Triple::riscv64:
case Triple::sparcv9:
case Triple::spir64:
+ case Triple::spirv64:
case Triple::systemz:
case Triple::ve:
case Triple::wasm64:
@@ -1464,8 +1518,12 @@ Triple Triple::get64BitArchVariant() const {
case Triple::armeb: T.setArch(Triple::aarch64_be); break;
case Triple::hsail: T.setArch(Triple::hsail64); break;
case Triple::le32: T.setArch(Triple::le64); break;
- case Triple::mips: T.setArch(Triple::mips64); break;
- case Triple::mipsel: T.setArch(Triple::mips64el); break;
+ case Triple::mips:
+ T.setArch(Triple::mips64, getSubArch());
+ break;
+ case Triple::mipsel:
+ T.setArch(Triple::mips64el, getSubArch());
+ break;
case Triple::nvptx: T.setArch(Triple::nvptx64); break;
case Triple::ppc: T.setArch(Triple::ppc64); break;
case Triple::ppcle: T.setArch(Triple::ppc64le); break;
@@ -1473,6 +1531,7 @@ Triple Triple::get64BitArchVariant() const {
case Triple::riscv32: T.setArch(Triple::riscv64); break;
case Triple::sparc: T.setArch(Triple::sparcv9); break;
case Triple::spir: T.setArch(Triple::spir64); break;
+ case Triple::spirv32: T.setArch(Triple::spirv64); break;
case Triple::thumb: T.setArch(Triple::aarch64); break;
case Triple::thumbeb: T.setArch(Triple::aarch64_be); break;
case Triple::wasm32: T.setArch(Triple::wasm64); break;
@@ -1509,6 +1568,8 @@ Triple Triple::getBigEndianArchVariant() const {
case Triple::shave:
case Triple::spir64:
case Triple::spir:
+ case Triple::spirv32:
+ case Triple::spirv64:
case Triple::wasm32:
case Triple::wasm64:
case Triple::x86:
@@ -1526,8 +1587,12 @@ Triple Triple::getBigEndianArchVariant() const {
case Triple::aarch64: T.setArch(Triple::aarch64_be); break;
case Triple::bpfel: T.setArch(Triple::bpfeb); break;
- case Triple::mips64el:T.setArch(Triple::mips64); break;
- case Triple::mipsel: T.setArch(Triple::mips); break;
+ case Triple::mips64el:
+ T.setArch(Triple::mips64, getSubArch());
+ break;
+ case Triple::mipsel:
+ T.setArch(Triple::mips, getSubArch());
+ break;
case Triple::ppcle: T.setArch(Triple::ppc); break;
case Triple::ppc64le: T.setArch(Triple::ppc64); break;
case Triple::sparcel: T.setArch(Triple::sparc); break;
@@ -1559,8 +1624,12 @@ Triple Triple::getLittleEndianArchVariant() const {
case Triple::aarch64_be: T.setArch(Triple::aarch64); break;
case Triple::bpfeb: T.setArch(Triple::bpfel); break;
- case Triple::mips64: T.setArch(Triple::mips64el); break;
- case Triple::mips: T.setArch(Triple::mipsel); break;
+ case Triple::mips64:
+ T.setArch(Triple::mips64el, getSubArch());
+ break;
+ case Triple::mips:
+ T.setArch(Triple::mipsel, getSubArch());
+ break;
case Triple::ppc: T.setArch(Triple::ppcle); break;
case Triple::ppc64: T.setArch(Triple::ppc64le); break;
case Triple::sparc: T.setArch(Triple::sparcel); break;
@@ -1604,6 +1673,8 @@ bool Triple::isLittleEndian() const {
case Triple::sparcel:
case Triple::spir64:
case Triple::spir:
+ case Triple::spirv32:
+ case Triple::spirv64:
case Triple::tcele:
case Triple::thumb:
case Triple::ve:
@@ -1709,6 +1780,7 @@ StringRef Triple::getARMCPUForArch(StringRef MArch) const {
switch (getOS()) {
case llvm::Triple::FreeBSD:
case llvm::Triple::NetBSD:
+ case llvm::Triple::OpenBSD:
if (!MArch.empty() && MArch == "v6")
return "arm1176jzf-s";
if (!MArch.empty() && MArch == "v7")
diff --git a/llvm/lib/Support/Unix/Memory.inc b/llvm/lib/Support/Unix/Memory.inc
index be88e7db1400..b83477e0e4cc 100644
--- a/llvm/lib/Support/Unix/Memory.inc
+++ b/llvm/lib/Support/Unix/Memory.inc
@@ -29,14 +29,6 @@
#include <zircon/syscalls.h>
#endif
-#if defined(__mips__)
-# if defined(__OpenBSD__)
-# include <mips64/sysarch.h>
-# elif !defined(__FreeBSD__)
-# include <sys/cachectl.h>
-# endif
-#endif
-
#if defined(__APPLE__)
extern "C" void sys_icache_invalidate(const void *Addr, size_t len);
#else
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index c37b3a54644a..19d89db55627 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -39,6 +39,9 @@
#include <mach-o/dyld.h>
#include <sys/attr.h>
#include <copyfile.h>
+#if __has_include(<sys/clonefile.h>)
+#include <sys/clonefile.h>
+#endif
#elif defined(__FreeBSD__)
#include <osreldate.h>
#if __FreeBSD_version >= 1300057
@@ -125,7 +128,8 @@ const file_t kInvalidFile = -1;
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
defined(__minix) || defined(__FreeBSD_kernel__) || defined(__linux__) || \
- defined(__CYGWIN__) || defined(__DragonFly__) || defined(_AIX) || defined(__GNU__)
+ defined(__CYGWIN__) || defined(__DragonFly__) || defined(_AIX) || defined(__GNU__) || \
+ (defined(__sun__) && defined(__svr4__))
static int
test_dir(char ret[PATH_MAX], const char *dir, const char *bin)
{
@@ -283,6 +287,20 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
// Fall back to the classical detection.
if (getprogpath(exe_path, argv0))
return exe_path;
+#elif defined(__sun__) && defined(__svr4__)
+ char exe_path[PATH_MAX];
+ const char *aPath = "/proc/self/execname";
+ if (sys::fs::exists(aPath)) {
+ int fd = open(aPath, O_RDONLY);
+ if (fd == -1)
+ return "";
+ if (read(fd, exe_path, sizeof(exe_path)) < 0)
+ return "";
+ return exe_path;
+ }
+ // Fall back to the classical detection.
+ if (getprogpath(exe_path, argv0) != NULL)
+ return exe_path;
#elif defined(__MVS__)
int token = 0;
W_PSPROC buf;
@@ -1442,22 +1460,37 @@ namespace fs {
/// file descriptor variant of this function still uses the default
/// implementation.
std::error_code copy_file(const Twine &From, const Twine &To) {
- uint32_t Flag = COPYFILE_DATA;
-#if __has_builtin(__builtin_available) && defined(COPYFILE_CLONE)
+ std::string FromS = From.str();
+ std::string ToS = To.str();
+#if __has_builtin(__builtin_available)
if (__builtin_available(macos 10.12, *)) {
- bool IsSymlink;
- if (std::error_code Error = is_symlink_file(From, IsSymlink))
- return Error;
- // COPYFILE_CLONE clones the symlink instead of following it
- // and returns EEXISTS if the target file already exists.
- if (!IsSymlink && !exists(To))
- Flag = COPYFILE_CLONE;
+ // Optimistically try to use clonefile() and handle errors, rather than
+ // calling stat() to see if it'll work.
+ //
+ // Note: It's okay if From is a symlink. In contrast to the behaviour of
+ // copyfile() with COPYFILE_CLONE, clonefile() clones targets (not the
+ // symlink itself) unless the flag CLONE_NOFOLLOW is passed.
+ if (!clonefile(FromS.c_str(), ToS.c_str(), 0))
+ return std::error_code();
+
+ auto Errno = errno;
+ switch (Errno) {
+ case EEXIST: // To already exists.
+ case ENOTSUP: // Device does not support cloning.
+ case EXDEV: // From and To are on different devices.
+ break;
+ default:
+ // Anything else will also break copyfile().
+ return std::error_code(Errno, std::generic_category());
+ }
+
+ // TODO: For EEXIST, profile calling fs::generateUniqueName() and
+ // clonefile() in a retry loop (then rename() on success) before falling
+ // back to copyfile(). Depending on the size of the file this could be
+ // cheaper.
}
#endif
- int Status =
- copyfile(From.str().c_str(), To.str().c_str(), /* State */ NULL, Flag);
-
- if (Status == 0)
+ if (!copyfile(FromS.c_str(), ToS.c_str(), /*State=*/NULL, COPYFILE_DATA))
return std::error_code();
return std::error_code(errno, std::generic_category());
}
diff --git a/llvm/lib/Support/Unix/Process.inc b/llvm/lib/Support/Unix/Process.inc
index 30b957e6a1c4..d3d9fb7d7187 100644
--- a/llvm/lib/Support/Unix/Process.inc
+++ b/llvm/lib/Support/Unix/Process.inc
@@ -461,5 +461,4 @@ unsigned llvm::sys::Process::GetRandomNumber() {
#endif
}
-LLVM_ATTRIBUTE_NORETURN
-void Process::ExitNoCleanup(int RetCode) { _Exit(RetCode); }
+[[noreturn]] void Process::ExitNoCleanup(int RetCode) { _Exit(RetCode); }
diff --git a/llvm/lib/Support/Unix/Program.inc b/llvm/lib/Support/Unix/Program.inc
index be59bb0232de..089342030b97 100644
--- a/llvm/lib/Support/Unix/Program.inc
+++ b/llvm/lib/Support/Unix/Program.inc
@@ -71,7 +71,8 @@ ErrorOr<std::string> sys::findProgramByName(StringRef Name,
assert(!Name.empty() && "Must have a name!");
// Use the given path verbatim if it contains any slashes; this matches
// the behavior of sh(1) and friends.
- if (Name.find('/') != StringRef::npos) return std::string(Name);
+ if (Name.contains('/'))
+ return std::string(Name);
SmallVector<StringRef, 16> EnvironmentPaths;
if (Paths.empty())
diff --git a/llvm/lib/Support/Unix/Unix.h b/llvm/lib/Support/Unix/Unix.h
index 60929139598b..1599241a344a 100644
--- a/llvm/lib/Support/Unix/Unix.h
+++ b/llvm/lib/Support/Unix/Unix.h
@@ -67,11 +67,10 @@ static inline bool MakeErrMsg(
}
// Include StrError(errnum) in a fatal error message.
-LLVM_ATTRIBUTE_NORETURN static inline void ReportErrnumFatal(const char *Msg,
- int errnum) {
+[[noreturn]] static inline void ReportErrnumFatal(const char *Msg, int errnum) {
std::string ErrMsg;
MakeErrMsg(&ErrMsg, Msg, errnum);
- llvm::report_fatal_error(ErrMsg);
+ llvm::report_fatal_error(llvm::Twine(ErrMsg));
}
namespace llvm {
diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp
index 15bb54e61817..9bf0384b5f1b 100644
--- a/llvm/lib/Support/VirtualFileSystem.cpp
+++ b/llvm/lib/Support/VirtualFileSystem.cpp
@@ -32,6 +32,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileSystem/UniqueID.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
@@ -193,6 +194,7 @@ public:
bool RequiresNullTerminator,
bool IsVolatile) override;
std::error_code close() override;
+ void setPath(const Twine &Path) override;
};
} // namespace
@@ -228,6 +230,12 @@ std::error_code RealFile::close() {
return EC;
}
+void RealFile::setPath(const Twine &Path) {
+ RealName = Path.str();
+ if (auto Status = status())
+ S = Status.get().copyWithNewName(Status.get(), Path);
+}
+
namespace {
/// A file system according to your operating system.
@@ -442,7 +450,7 @@ std::error_code OverlayFileSystem::isLocal(const Twine &Path, bool &Result) {
std::error_code
OverlayFileSystem::getRealPath(const Twine &Path,
SmallVectorImpl<char> &Output) const {
- for (auto &FS : FSList)
+ for (const auto &FS : FSList)
if (FS->exists(Path))
return FS->getRealPath(Path, Output);
return errc::no_such_file_or_directory;
@@ -638,6 +646,8 @@ public:
}
std::error_code close() override { return {}; }
+
+ void setPath(const Twine &Path) override { RequestedName = Path.str(); }
};
} // namespace
@@ -655,6 +665,9 @@ public:
Status getStatus(const Twine &RequestedName) const {
return Status::copyWithNewName(Stat, RequestedName);
}
+
+ UniqueID getUniqueID() const { return Stat.getUniqueID(); }
+
InMemoryNode *getChild(StringRef Name) {
auto I = Entries.find(Name);
if (I != Entries.end())
@@ -698,10 +711,28 @@ Status getNodeStatus(const InMemoryNode *Node, const Twine &RequestedName) {
} // namespace
} // namespace detail
+// The UniqueID of in-memory files is derived from path and content.
+// This avoids difficulties in creating exactly equivalent in-memory FSes,
+// as often needed in multithreaded programs.
+static sys::fs::UniqueID getUniqueID(hash_code Hash) {
+ return sys::fs::UniqueID(std::numeric_limits<uint64_t>::max(),
+ uint64_t(size_t(Hash)));
+}
+static sys::fs::UniqueID getFileID(sys::fs::UniqueID Parent,
+ llvm::StringRef Name,
+ llvm::StringRef Contents) {
+ return getUniqueID(llvm::hash_combine(Parent.getFile(), Name, Contents));
+}
+static sys::fs::UniqueID getDirectoryID(sys::fs::UniqueID Parent,
+ llvm::StringRef Name) {
+ return getUniqueID(llvm::hash_combine(Parent.getFile(), Name));
+}
+
InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths)
: Root(new detail::InMemoryDirectory(
- Status("", getNextVirtualUniqueID(), llvm::sys::TimePoint<>(), 0, 0,
- 0, llvm::sys::fs::file_type::directory_file,
+ Status("", getDirectoryID(llvm::sys::fs::UniqueID(), ""),
+ llvm::sys::TimePoint<>(), 0, 0, 0,
+ llvm::sys::fs::file_type::directory_file,
llvm::sys::fs::perms::all_all))),
UseNormalizedPaths(UseNormalizedPaths) {}
@@ -754,10 +785,14 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
Child.reset(new detail::InMemoryHardLink(P.str(), *HardLinkTarget));
else {
// Create a new file or directory.
- Status Stat(P.str(), getNextVirtualUniqueID(),
- llvm::sys::toTimePoint(ModificationTime), ResolvedUser,
- ResolvedGroup, Buffer->getBufferSize(), ResolvedType,
- ResolvedPerms);
+ Status Stat(
+ P.str(),
+ (ResolvedType == sys::fs::file_type::directory_file)
+ ? getDirectoryID(Dir->getUniqueID(), Name)
+ : getFileID(Dir->getUniqueID(), Name, Buffer->getBuffer()),
+ llvm::sys::toTimePoint(ModificationTime), ResolvedUser,
+ ResolvedGroup, Buffer->getBufferSize(), ResolvedType,
+ ResolvedPerms);
if (ResolvedType == sys::fs::file_type::directory_file) {
Child.reset(new detail::InMemoryDirectory(std::move(Stat)));
} else {
@@ -772,9 +807,9 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
// Create a new directory. Use the path up to here.
Status Stat(
StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
- getNextVirtualUniqueID(), llvm::sys::toTimePoint(ModificationTime),
- ResolvedUser, ResolvedGroup, 0, sys::fs::file_type::directory_file,
- NewDirectoryPerms);
+ getDirectoryID(Dir->getUniqueID(), Name),
+ llvm::sys::toTimePoint(ModificationTime), ResolvedUser, ResolvedGroup,
+ 0, sys::fs::file_type::directory_file, NewDirectoryPerms);
Dir = cast<detail::InMemoryDirectory>(Dir->addChild(
Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
continue;
@@ -1015,9 +1050,10 @@ static llvm::sys::path::Style getExistingStyle(llvm::StringRef Path) {
// Detect the path style in use by checking the first separator.
llvm::sys::path::Style style = llvm::sys::path::Style::native;
const size_t n = Path.find_first_of("/\\");
+ // Can't distinguish between posix and windows_slash here.
if (n != static_cast<size_t>(-1))
style = (Path[n] == '/') ? llvm::sys::path::Style::posix
- : llvm::sys::path::Style::windows;
+ : llvm::sys::path::Style::windows_backslash;
return style;
}
@@ -1091,6 +1127,7 @@ public:
}
};
+namespace {
/// Directory iterator implementation for \c RedirectingFileSystem's
/// directory remap entries that maps the paths reported by the external
/// file system's directory iterator back to the virtual directory's path.
@@ -1129,6 +1166,7 @@ public:
return EC;
}
};
+} // namespace
llvm::ErrorOr<std::string>
RedirectingFileSystem::getCurrentWorkingDirectory() const {
@@ -1161,8 +1199,10 @@ std::error_code RedirectingFileSystem::isLocal(const Twine &Path_,
}
std::error_code RedirectingFileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
+ // is_absolute(..., Style::windows_*) accepts paths with both slash types.
if (llvm::sys::path::is_absolute(Path, llvm::sys::path::Style::posix) ||
- llvm::sys::path::is_absolute(Path, llvm::sys::path::Style::windows))
+ llvm::sys::path::is_absolute(Path,
+ llvm::sys::path::Style::windows_backslash))
return {};
auto WorkingDir = getCurrentWorkingDirectory();
@@ -1173,9 +1213,15 @@ std::error_code RedirectingFileSystem::makeAbsolute(SmallVectorImpl<char> &Path)
// is native and there is no way to override that. Since we know WorkingDir
// is absolute, we can use it to determine which style we actually have and
// append Path ourselves.
- sys::path::Style style = sys::path::Style::windows;
+ sys::path::Style style = sys::path::Style::windows_backslash;
if (sys::path::is_absolute(WorkingDir.get(), sys::path::Style::posix)) {
style = sys::path::Style::posix;
+ } else {
+ // Distinguish between windows_backslash and windows_slash; getExistingStyle
+ // returns posix for a path with windows_slash.
+ if (getExistingStyle(WorkingDir.get()) !=
+ sys::path::Style::windows_backslash)
+ style = sys::path::Style::windows_slash;
}
std::string Result = WorkingDir.get();
@@ -1207,7 +1253,7 @@ directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
}
// Use status to make sure the path exists and refers to a directory.
- ErrorOr<Status> S = status(Path, *Result);
+ ErrorOr<Status> S = status(Path, Dir, *Result);
if (!S) {
if (shouldFallBackToExternalFS(S.getError(), Result->E))
return ExternalFS->dir_begin(Dir, EC);
@@ -1593,8 +1639,9 @@ private:
// which style we have, and use it consistently.
if (sys::path::is_absolute(Name, sys::path::Style::posix)) {
path_style = sys::path::Style::posix;
- } else if (sys::path::is_absolute(Name, sys::path::Style::windows)) {
- path_style = sys::path::Style::windows;
+ } else if (sys::path::is_absolute(Name,
+ sys::path::Style::windows_backslash)) {
+ path_style = sys::path::Style::windows_backslash;
} else {
assert(NameValueNode && "Name presence should be checked earlier");
error(NameValueNode,
@@ -1933,47 +1980,68 @@ RedirectingFileSystem::lookupPathImpl(
return make_error_code(llvm::errc::no_such_file_or_directory);
}
-static Status getRedirectedFileStatus(const Twine &Path, bool UseExternalNames,
+static Status getRedirectedFileStatus(const Twine &OriginalPath,
+ bool UseExternalNames,
Status ExternalStatus) {
Status S = ExternalStatus;
if (!UseExternalNames)
- S = Status::copyWithNewName(S, Path);
+ S = Status::copyWithNewName(S, OriginalPath);
S.IsVFSMapped = true;
return S;
}
ErrorOr<Status> RedirectingFileSystem::status(
- const Twine &Path, const RedirectingFileSystem::LookupResult &Result) {
+ const Twine &CanonicalPath, const Twine &OriginalPath,
+ const RedirectingFileSystem::LookupResult &Result) {
if (Optional<StringRef> ExtRedirect = Result.getExternalRedirect()) {
- ErrorOr<Status> S = ExternalFS->status(*ExtRedirect);
+ SmallString<256> CanonicalRemappedPath((*ExtRedirect).str());
+ if (std::error_code EC = makeCanonical(CanonicalRemappedPath))
+ return EC;
+
+ ErrorOr<Status> S = ExternalFS->status(CanonicalRemappedPath);
if (!S)
return S;
+ S = Status::copyWithNewName(*S, *ExtRedirect);
auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result.E);
- return getRedirectedFileStatus(Path, RE->useExternalName(UseExternalNames),
- *S);
+ return getRedirectedFileStatus(OriginalPath,
+ RE->useExternalName(UseExternalNames), *S);
}
auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(Result.E);
- return Status::copyWithNewName(DE->getStatus(), Path);
+ return Status::copyWithNewName(DE->getStatus(), CanonicalPath);
}
-ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path_) {
- SmallString<256> Path;
- Path_.toVector(Path);
+ErrorOr<Status>
+RedirectingFileSystem::getExternalStatus(const Twine &CanonicalPath,
+ const Twine &OriginalPath) const {
+ if (auto Result = ExternalFS->status(CanonicalPath)) {
+ return Result.get().copyWithNewName(Result.get(), OriginalPath);
+ } else {
+ return Result.getError();
+ }
+}
- if (std::error_code EC = makeCanonical(Path))
+ErrorOr<Status> RedirectingFileSystem::status(const Twine &OriginalPath) {
+ SmallString<256> CanonicalPath;
+ OriginalPath.toVector(CanonicalPath);
+
+ if (std::error_code EC = makeCanonical(CanonicalPath))
return EC;
- ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
+ ErrorOr<RedirectingFileSystem::LookupResult> Result =
+ lookupPath(CanonicalPath);
if (!Result) {
- if (shouldFallBackToExternalFS(Result.getError()))
- return ExternalFS->status(Path);
+ if (shouldFallBackToExternalFS(Result.getError())) {
+ return getExternalStatus(CanonicalPath, OriginalPath);
+ }
return Result.getError();
}
- ErrorOr<Status> S = status(Path, *Result);
- if (!S && shouldFallBackToExternalFS(S.getError(), Result->E))
- S = ExternalFS->status(Path);
+ ErrorOr<Status> S = status(CanonicalPath, OriginalPath, *Result);
+ if (!S && shouldFallBackToExternalFS(S.getError(), Result->E)) {
+ return getExternalStatus(CanonicalPath, OriginalPath);
+ }
+
return S;
}
@@ -1998,22 +2066,39 @@ public:
}
std::error_code close() override { return InnerFile->close(); }
+
+ void setPath(const Twine &Path) override { S = S.copyWithNewName(S, Path); }
};
} // namespace
ErrorOr<std::unique_ptr<File>>
-RedirectingFileSystem::openFileForRead(const Twine &Path_) {
- SmallString<256> Path;
- Path_.toVector(Path);
+File::getWithPath(ErrorOr<std::unique_ptr<File>> Result, const Twine &P) {
+ if (!Result)
+ return Result;
- if (std::error_code EC = makeCanonical(Path))
+ ErrorOr<std::unique_ptr<File>> F = std::move(*Result);
+ auto Name = F->get()->getName();
+ if (Name && Name.get() != P.str())
+ F->get()->setPath(P);
+ return F;
+}
+
+ErrorOr<std::unique_ptr<File>>
+RedirectingFileSystem::openFileForRead(const Twine &OriginalPath) {
+ SmallString<256> CanonicalPath;
+ OriginalPath.toVector(CanonicalPath);
+
+ if (std::error_code EC = makeCanonical(CanonicalPath))
return EC;
- ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
+ ErrorOr<RedirectingFileSystem::LookupResult> Result =
+ lookupPath(CanonicalPath);
if (!Result) {
if (shouldFallBackToExternalFS(Result.getError()))
- return ExternalFS->openFileForRead(Path);
+ return File::getWithPath(ExternalFS->openFileForRead(CanonicalPath),
+ OriginalPath);
+
return Result.getError();
}
@@ -2021,12 +2106,18 @@ RedirectingFileSystem::openFileForRead(const Twine &Path_) {
return make_error_code(llvm::errc::invalid_argument);
StringRef ExtRedirect = *Result->getExternalRedirect();
+ SmallString<256> CanonicalRemappedPath(ExtRedirect.str());
+ if (std::error_code EC = makeCanonical(CanonicalRemappedPath))
+ return EC;
+
auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
- auto ExternalFile = ExternalFS->openFileForRead(ExtRedirect);
+ auto ExternalFile = File::getWithPath(
+ ExternalFS->openFileForRead(CanonicalRemappedPath), ExtRedirect);
if (!ExternalFile) {
if (shouldFallBackToExternalFS(ExternalFile.getError(), Result->E))
- return ExternalFS->openFileForRead(Path);
+ return File::getWithPath(ExternalFS->openFileForRead(CanonicalPath),
+ OriginalPath);
return ExternalFile;
}
@@ -2036,7 +2127,7 @@ RedirectingFileSystem::openFileForRead(const Twine &Path_) {
// FIXME: Update the status with the name and VFSMapped.
Status S = getRedirectedFileStatus(
- Path, RE->useExternalName(UseExternalNames), *ExternalStatus);
+ OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
return std::unique_ptr<File>(
std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
}
diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc
index c1d291731a88..b15e71a9ce2a 100644
--- a/llvm/lib/Support/Windows/Path.inc
+++ b/llvm/lib/Support/Windows/Path.inc
@@ -74,6 +74,11 @@ std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16,
SmallString<MAX_PATH> Path8Str;
Path8.toVector(Path8Str);
+ // If the path is a long path, mangled into forward slashes, normalize
+ // back to backslashes here.
+ if (Path8Str.startswith("//?/"))
+ llvm::sys::path::native(Path8Str, path::Style::windows_backslash);
+
if (std::error_code EC = UTF8ToUTF16(Path8Str, Path16))
return EC;
@@ -100,8 +105,10 @@ std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16,
}
// Remove '.' and '..' because long paths treat these as real path components.
+ // Explicitly use the backslash form here, as we're prepending the \\?\
+ // prefix.
llvm::sys::path::native(Path8Str, path::Style::windows);
- llvm::sys::path::remove_dots(Path8Str, true);
+ llvm::sys::path::remove_dots(Path8Str, true, path::Style::windows);
const StringRef RootName = llvm::sys::path::root_name(Path8Str);
assert(!RootName.empty() &&
@@ -145,6 +152,7 @@ std::string getMainExecutable(const char *argv0, void *MainExecAddr) {
if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8))
return "";
+ llvm::sys::path::make_preferred(PathNameUTF8);
return std::string(PathNameUTF8.data());
}
@@ -207,7 +215,13 @@ std::error_code current_path(SmallVectorImpl<char> &result) {
// On success, GetCurrentDirectoryW returns the number of characters not
// including the null-terminator.
cur_path.set_size(len);
- return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result);
+
+ if (std::error_code EC =
+ UTF16ToUTF8(cur_path.begin(), cur_path.size(), result))
+ return EC;
+
+ llvm::sys::path::make_preferred(result);
+ return std::error_code();
}
std::error_code set_current_path(const Twine &path) {
@@ -388,7 +402,11 @@ static std::error_code realPathFromHandle(HANDLE H,
}
// Convert the result from UTF-16 to UTF-8.
- return UTF16ToUTF8(Data, CountChars, RealPath);
+ if (std::error_code EC = UTF16ToUTF8(Data, CountChars, RealPath))
+ return EC;
+
+ llvm::sys::path::make_preferred(RealPath);
+ return std::error_code();
}
std::error_code is_local(int FD, bool &Result) {
@@ -416,8 +434,7 @@ static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) {
// Check if the file is on a network (non-local) drive. If so, don't
// continue when DeleteFile is true, since it prevents opening the file for
- // writes. Note -- this will leak temporary files on disk, but only when the
- // target file is on a network drive.
+ // writes.
SmallVector<wchar_t, 128> FinalPath;
if (std::error_code EC = realPathFromHandle(Handle, FinalPath))
return EC;
@@ -427,7 +444,7 @@ static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) {
return EC;
if (!IsLocal)
- return std::error_code();
+ return errc::not_supported;
// The file is on a local drive, we can safely set FILE_DISPOSITION_INFO's
// flag.
@@ -1183,12 +1200,6 @@ Expected<file_t> openNativeFile(const Twine &Name, CreationDisposition Disp,
}
}
- if (Flags & OF_Delete) {
- if ((EC = setDeleteDisposition(Result, true))) {
- ::CloseHandle(Result);
- return errorCodeToError(EC);
- }
- }
return Result;
}
@@ -1414,6 +1425,8 @@ static bool getKnownFolderPath(KNOWNFOLDERID folderId,
bool ok = !UTF16ToUTF8(path, ::wcslen(path), result);
::CoTaskMemFree(path);
+ if (ok)
+ llvm::sys::path::make_preferred(result);
return ok;
}
@@ -1474,6 +1487,7 @@ void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) {
// Fall back to a system default.
const char *DefaultResult = "C:\\Temp";
Result.append(DefaultResult, DefaultResult + strlen(DefaultResult));
+ llvm::sys::path::make_preferred(Result);
}
} // end namespace path
diff --git a/llvm/lib/Support/Windows/Process.inc b/llvm/lib/Support/Windows/Process.inc
index 6f58c52e0746..6732063b562e 100644
--- a/llvm/lib/Support/Windows/Process.inc
+++ b/llvm/lib/Support/Windows/Process.inc
@@ -261,6 +261,7 @@ windows::GetCommandLineArguments(SmallVectorImpl<const char *> &Args,
EC = GetExecutableName(Filename);
if (EC)
return EC;
+ sys::path::make_preferred(Arg0);
sys::path::append(Arg0, Filename);
Args[0] = Saver.save(Arg0).data();
return std::error_code();
@@ -504,8 +505,7 @@ bool llvm::RunningWindows8OrGreater() {
return GetWindowsOSVersion() >= llvm::VersionTuple(6, 2, 0, 0);
}
-LLVM_ATTRIBUTE_NORETURN
-void Process::ExitNoCleanup(int RetCode) {
+[[noreturn]] void Process::ExitNoCleanup(int RetCode) {
TerminateProcess(GetCurrentProcess(), RetCode);
llvm_unreachable("TerminateProcess doesn't return");
}
diff --git a/llvm/lib/Support/Windows/Program.inc b/llvm/lib/Support/Windows/Program.inc
index 824834c1cbbe..a9cf2db7ec72 100644
--- a/llvm/lib/Support/Windows/Program.inc
+++ b/llvm/lib/Support/Windows/Program.inc
@@ -103,6 +103,7 @@ ErrorOr<std::string> sys::findProgramByName(StringRef Name,
if (U8Result.empty())
return mapWindowsError(::GetLastError());
+ llvm::sys::path::make_preferred(U8Result);
return std::string(U8Result.begin(), U8Result.end());
}
diff --git a/llvm/lib/Support/X86TargetParser.cpp b/llvm/lib/Support/X86TargetParser.cpp
index c9530659caad..ab49ac548f89 100644
--- a/llvm/lib/Support/X86TargetParser.cpp
+++ b/llvm/lib/Support/X86TargetParser.cpp
@@ -11,7 +11,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/X86TargetParser.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
+#include <numeric>
using namespace llvm;
using namespace llvm::X86;
@@ -137,8 +139,8 @@ constexpr FeatureBitset FeaturesNocona =
// Basic 64-bit capable CPU.
constexpr FeatureBitset FeaturesX86_64 = FeaturesPentium4 | Feature64BIT;
constexpr FeatureBitset FeaturesX86_64_V2 = FeaturesX86_64 | FeatureSAHF |
- FeaturePOPCNT | FeatureSSE4_2 |
- FeatureCMPXCHG16B;
+ FeaturePOPCNT | FeatureCRC32 |
+ FeatureSSE4_2 | FeatureCMPXCHG16B;
constexpr FeatureBitset FeaturesX86_64_V3 =
FeaturesX86_64_V2 | FeatureAVX2 | FeatureBMI | FeatureBMI2 | FeatureF16C |
FeatureFMA | FeatureLZCNT | FeatureMOVBE | FeatureXSAVE;
@@ -151,7 +153,7 @@ constexpr FeatureBitset FeaturesCore2 =
FeaturesNocona | FeatureSAHF | FeatureSSSE3;
constexpr FeatureBitset FeaturesPenryn = FeaturesCore2 | FeatureSSE4_1;
constexpr FeatureBitset FeaturesNehalem =
- FeaturesPenryn | FeaturePOPCNT | FeatureSSE4_2;
+ FeaturesPenryn | FeaturePOPCNT | FeatureCRC32 | FeatureSSE4_2;
constexpr FeatureBitset FeaturesWestmere = FeaturesNehalem | FeaturePCLMUL;
constexpr FeatureBitset FeaturesSandyBridge =
FeaturesWestmere | FeatureAVX | FeatureXSAVE | FeatureXSAVEOPT;
@@ -201,11 +203,11 @@ constexpr FeatureBitset FeaturesTigerlake =
FeaturesICLClient | FeatureAVX512VP2INTERSECT | FeatureMOVDIR64B |
FeatureCLWB | FeatureMOVDIRI | FeatureSHSTK | FeatureKL | FeatureWIDEKL;
constexpr FeatureBitset FeaturesSapphireRapids =
- FeaturesICLServer | FeatureAMX_TILE | FeatureAMX_INT8 | FeatureAMX_BF16 |
- FeatureAVX512BF16 | FeatureAVX512VP2INTERSECT | FeatureCLDEMOTE |
- FeatureENQCMD | FeatureMOVDIR64B | FeatureMOVDIRI | FeaturePTWRITE |
- FeatureSERIALIZE | FeatureSHSTK | FeatureTSXLDTRK | FeatureUINTR |
- FeatureWAITPKG | FeatureAVXVNNI;
+ FeaturesICLServer | FeatureAMX_BF16 | FeatureAMX_INT8 | FeatureAMX_TILE |
+ FeatureAVX512BF16 | FeatureAVX512FP16 | FeatureAVX512VP2INTERSECT |
+ FeatureAVXVNNI | FeatureCLDEMOTE | FeatureENQCMD | FeatureMOVDIR64B |
+ FeatureMOVDIRI | FeaturePTWRITE | FeatureSERIALIZE | FeatureSHSTK |
+ FeatureTSXLDTRK | FeatureUINTR | FeatureWAITPKG;
// Intel Atom processors.
// Bonnell has feature parity with Core2 and adds MOVBE.
@@ -254,16 +256,17 @@ constexpr FeatureBitset FeaturesBTVER1 =
FeatureSSE | FeatureSSE2 | FeatureSSE3 | FeatureSSSE3 | FeatureSSE4_A |
FeatureSAHF;
constexpr FeatureBitset FeaturesBTVER2 =
- FeaturesBTVER1 | FeatureAES | FeatureAVX | FeatureBMI | FeatureF16C |
- FeatureMOVBE | FeaturePCLMUL | FeatureXSAVE | FeatureXSAVEOPT;
+ FeaturesBTVER1 | FeatureAES | FeatureAVX | FeatureBMI | FeatureCRC32 |
+ FeatureF16C | FeatureMOVBE | FeaturePCLMUL | FeatureXSAVE | FeatureXSAVEOPT;
// AMD Bulldozer architecture processors.
constexpr FeatureBitset FeaturesBDVER1 =
FeatureX87 | FeatureAES | FeatureAVX | FeatureCMPXCHG8B |
- FeatureCMPXCHG16B | Feature64BIT | FeatureFMA4 | FeatureFXSR | FeatureLWP |
- FeatureLZCNT | FeatureMMX | FeaturePCLMUL | FeaturePOPCNT | FeaturePRFCHW |
- FeatureSAHF | FeatureSSE | FeatureSSE2 | FeatureSSE3 | FeatureSSSE3 |
- FeatureSSE4_1 | FeatureSSE4_2 | FeatureSSE4_A | FeatureXOP | FeatureXSAVE;
+ FeatureCMPXCHG16B | FeatureCRC32 | Feature64BIT | FeatureFMA4 |
+ FeatureFXSR | FeatureLWP | FeatureLZCNT | FeatureMMX | FeaturePCLMUL |
+ FeaturePOPCNT | FeaturePRFCHW | FeatureSAHF | FeatureSSE | FeatureSSE2 |
+ FeatureSSE3 | FeatureSSSE3 | FeatureSSE4_1 | FeatureSSE4_2 | FeatureSSE4_A |
+ FeatureXOP | FeatureXSAVE;
constexpr FeatureBitset FeaturesBDVER2 =
FeaturesBDVER1 | FeatureBMI | FeatureFMA | FeatureF16C | FeatureTBM;
constexpr FeatureBitset FeaturesBDVER3 =
@@ -276,9 +279,9 @@ constexpr FeatureBitset FeaturesBDVER4 = FeaturesBDVER3 | FeatureAVX2 |
constexpr FeatureBitset FeaturesZNVER1 =
FeatureX87 | FeatureADX | FeatureAES | FeatureAVX | FeatureAVX2 |
FeatureBMI | FeatureBMI2 | FeatureCLFLUSHOPT | FeatureCLZERO |
- FeatureCMPXCHG8B | FeatureCMPXCHG16B | Feature64BIT | FeatureF16C |
- FeatureFMA | FeatureFSGSBASE | FeatureFXSR | FeatureLZCNT | FeatureMMX |
- FeatureMOVBE | FeatureMWAITX | FeaturePCLMUL | FeaturePOPCNT |
+ FeatureCMPXCHG8B | FeatureCMPXCHG16B | FeatureCRC32 | Feature64BIT |
+ FeatureF16C | FeatureFMA | FeatureFSGSBASE | FeatureFXSR | FeatureLZCNT |
+ FeatureMMX | FeatureMOVBE | FeatureMWAITX | FeaturePCLMUL | FeaturePOPCNT |
FeaturePRFCHW | FeatureRDRND | FeatureRDSEED | FeatureSAHF | FeatureSHA |
FeatureSSE | FeatureSSE2 | FeatureSSE3 | FeatureSSSE3 | FeatureSSE4_1 |
FeatureSSE4_2 | FeatureSSE4_A | FeatureXSAVE | FeatureXSAVEC |
@@ -470,6 +473,7 @@ constexpr FeatureBitset ImpliedFeaturesCLZERO = {};
constexpr FeatureBitset ImpliedFeaturesCMOV = {};
constexpr FeatureBitset ImpliedFeaturesCMPXCHG16B = {};
constexpr FeatureBitset ImpliedFeaturesCMPXCHG8B = {};
+constexpr FeatureBitset ImpliedFeaturesCRC32 = {};
constexpr FeatureBitset ImpliedFeaturesENQCMD = {};
constexpr FeatureBitset ImpliedFeaturesFSGSBASE = {};
constexpr FeatureBitset ImpliedFeaturesFXSR = {};
@@ -576,6 +580,8 @@ constexpr FeatureBitset ImpliedFeaturesAMX_BF16 = FeatureAMX_TILE;
constexpr FeatureBitset ImpliedFeaturesAMX_INT8 = FeatureAMX_TILE;
constexpr FeatureBitset ImpliedFeaturesHRESET = {};
+static constexpr FeatureBitset ImpliedFeaturesAVX512FP16 =
+ FeatureAVX512BW | FeatureAVX512DQ | FeatureAVX512VL;
// Key Locker Features
constexpr FeatureBitset ImpliedFeaturesKL = FeatureSSE2;
constexpr FeatureBitset ImpliedFeaturesWIDEKL = FeatureKL;
@@ -660,3 +666,45 @@ void llvm::X86::updateImpliedFeatures(
if (ImpliedBits[i] && !FeatureInfos[i].Name.empty())
Features[FeatureInfos[i].Name] = Enabled;
}
+
+uint64_t llvm::X86::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) {
+ // Processor features and mapping to processor feature value.
+ uint64_t FeaturesMask = 0;
+ for (const StringRef &FeatureStr : FeatureStrs) {
+ unsigned Feature = StringSwitch<unsigned>(FeatureStr)
+#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) \
+ .Case(STR, llvm::X86::FEATURE_##ENUM)
+#include "llvm/Support/X86TargetParser.def"
+ ;
+ FeaturesMask |= (1ULL << Feature);
+ }
+ return FeaturesMask;
+}
+
+unsigned llvm::X86::getFeaturePriority(ProcessorFeatures Feat) {
+#ifndef NDEBUG
+ // Check that priorities are set properly in the .def file. We expect that
+ // "compat" features are assigned non-duplicate consecutive priorities
+ // starting from zero (0, 1, ..., num_features - 1).
+#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) PRIORITY,
+ unsigned Priorities[] = {
+#include "llvm/Support/X86TargetParser.def"
+ std::numeric_limits<unsigned>::max() // Need to consume last comma.
+ };
+ std::array<unsigned, array_lengthof(Priorities) - 1> HelperList;
+ std::iota(HelperList.begin(), HelperList.end(), 0);
+ assert(std::is_permutation(HelperList.begin(), HelperList.end(),
+ std::begin(Priorities),
+ std::prev(std::end(Priorities))) &&
+ "Priorities don't form consecutive range!");
+#endif
+
+ switch (Feat) {
+#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) \
+ case X86::FEATURE_##ENUM: \
+ return PRIORITY;
+#include "llvm/Support/X86TargetParser.def"
+ default:
+ llvm_unreachable("No Feature Priority for non-CPUSupports Features");
+ }
+}
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index d4e1c884d125..4590a3d19b0d 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -185,7 +185,7 @@ raw_ostream &raw_ostream::write_escaped(StringRef Str,
// Write out the escaped representation.
if (UseHexEscapes) {
*this << '\\' << 'x';
- *this << hexdigit((c >> 4 & 0xF));
+ *this << hexdigit((c >> 4) & 0xF);
*this << hexdigit((c >> 0) & 0xF);
} else {
// Always use a full 3-character octal escape.
@@ -679,7 +679,8 @@ raw_fd_ostream::~raw_fd_ostream() {
// has_error() and clear the error flag with clear_error() before
// destructing raw_ostream objects which may have errors.
if (has_error())
- report_fatal_error("IO failure on output stream: " + error().message(),
+ report_fatal_error(Twine("IO failure on output stream: ") +
+ error().message(),
/*gen_crash_diag=*/false);
}