diff options
Diffstat (limited to 'llvm/lib/Support')
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 ¤t_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); } |
