diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Support')
58 files changed, 2753 insertions, 4200 deletions
diff --git a/contrib/llvm-project/llvm/lib/Support/AArch64TargetParser.cpp b/contrib/llvm-project/llvm/lib/Support/AArch64TargetParser.cpp index a6de44605675..503a7bd49d15 100644 --- a/contrib/llvm-project/llvm/lib/Support/AArch64TargetParser.cpp +++ b/contrib/llvm-project/llvm/lib/Support/AArch64TargetParser.cpp @@ -35,11 +35,11 @@ unsigned AArch64::getDefaultFPU(StringRef CPU, AArch64::ArchKind AK) { .Default(ARM::FK_INVALID); } -unsigned AArch64::getDefaultExtensions(StringRef CPU, AArch64::ArchKind AK) { +uint64_t AArch64::getDefaultExtensions(StringRef CPU, AArch64::ArchKind AK) { if (CPU == "generic") return AArch64ARCHNames[static_cast<unsigned>(AK)].ArchBaseExtensions; - return StringSwitch<unsigned>(CPU) + return StringSwitch<uint64_t>(CPU) #define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ .Case(NAME, AArch64ARCHNames[static_cast<unsigned>(ArchKind::ID)] \ .ArchBaseExtensions | \ @@ -59,7 +59,7 @@ AArch64::ArchKind AArch64::getCPUArchKind(StringRef CPU) { .Default(ArchKind::INVALID); } -bool AArch64::getExtensionFeatures(unsigned Extensions, +bool AArch64::getExtensionFeatures(uint64_t Extensions, std::vector<StringRef> &Features) { if (Extensions == AArch64::AEK_INVALID) return false; @@ -100,6 +100,12 @@ bool AArch64::getExtensionFeatures(unsigned Extensions, Features.push_back("+sve2-bitperm"); if (Extensions & AEK_RCPC) Features.push_back("+rcpc"); + if (Extensions & AEK_BRBE) + Features.push_back("+brbe"); + if (Extensions & AEK_PAUTH) + Features.push_back("+pauth"); + if (Extensions & AEK_FLAGM) + Features.push_back("+flagm"); return true; } @@ -118,6 +124,10 @@ bool AArch64::getArchFeatures(AArch64::ArchKind AK, Features.push_back("+v8.5a"); if (AK == AArch64::ArchKind::ARMV8_6A) Features.push_back("+v8.6a"); + if (AK == AArch64::ArchKind::ARMV8_7A) + Features.push_back("+v8.7a"); + if(AK == AArch64::ArchKind::ARMV8R) + Features.push_back("+v8r"); return AK != ArchKind::INVALID; } diff --git a/contrib/llvm-project/llvm/lib/Support/AMDGPUMetadata.cpp b/contrib/llvm-project/llvm/lib/Support/AMDGPUMetadata.cpp index bfa1fe86cd3e..3d6325134d75 100644 --- a/contrib/llvm-project/llvm/lib/Support/AMDGPUMetadata.cpp +++ b/contrib/llvm-project/llvm/lib/Support/AMDGPUMetadata.cpp @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/Twine.h" #include "llvm/Support/AMDGPUMetadata.h" #include "llvm/Support/YAMLTraits.h" @@ -211,7 +210,7 @@ struct MappingTraits<HSAMD::Metadata> { namespace AMDGPU { namespace HSAMD { -std::error_code fromString(std::string String, Metadata &HSAMetadata) { +std::error_code fromString(StringRef String, Metadata &HSAMetadata) { yaml::Input YamlInput(String); YamlInput >> HSAMetadata; return YamlInput.error(); diff --git a/contrib/llvm-project/llvm/lib/Support/APFixedPoint.cpp b/contrib/llvm-project/llvm/lib/Support/APFixedPoint.cpp new file mode 100644 index 000000000000..9764dd51f572 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Support/APFixedPoint.cpp @@ -0,0 +1,574 @@ +//===- APFixedPoint.cpp - Fixed point constant handling ---------*- 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 +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the implementation for the fixed point number interface. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/APFixedPoint.h" +#include "llvm/ADT/APFloat.h" + +namespace llvm { + +APFixedPoint APFixedPoint::convert(const FixedPointSemantics &DstSema, + bool *Overflow) const { + APSInt NewVal = Val; + unsigned DstWidth = DstSema.getWidth(); + unsigned DstScale = DstSema.getScale(); + bool Upscaling = DstScale > getScale(); + if (Overflow) + *Overflow = false; + + if (Upscaling) { + NewVal = NewVal.extend(NewVal.getBitWidth() + DstScale - getScale()); + NewVal <<= (DstScale - getScale()); + } else { + NewVal >>= (getScale() - DstScale); + } + + auto Mask = APInt::getBitsSetFrom( + NewVal.getBitWidth(), + std::min(DstScale + DstSema.getIntegralBits(), NewVal.getBitWidth())); + APInt Masked(NewVal & Mask); + + // Change in the bits above the sign + if (!(Masked == Mask || Masked == 0)) { + // Found overflow in the bits above the sign + if (DstSema.isSaturated()) + NewVal = NewVal.isNegative() ? Mask : ~Mask; + else if (Overflow) + *Overflow = true; + } + + // If the dst semantics are unsigned, but our value is signed and negative, we + // clamp to zero. + if (!DstSema.isSigned() && NewVal.isSigned() && NewVal.isNegative()) { + // Found negative overflow for unsigned result + if (DstSema.isSaturated()) + NewVal = 0; + else if (Overflow) + *Overflow = true; + } + + NewVal = NewVal.extOrTrunc(DstWidth); + NewVal.setIsSigned(DstSema.isSigned()); + return APFixedPoint(NewVal, DstSema); +} + +int APFixedPoint::compare(const APFixedPoint &Other) const { + APSInt ThisVal = getValue(); + APSInt OtherVal = Other.getValue(); + bool ThisSigned = Val.isSigned(); + bool OtherSigned = OtherVal.isSigned(); + unsigned OtherScale = Other.getScale(); + unsigned OtherWidth = OtherVal.getBitWidth(); + + unsigned CommonWidth = std::max(Val.getBitWidth(), OtherWidth); + + // Prevent overflow in the event the widths are the same but the scales differ + CommonWidth += getScale() >= OtherScale ? getScale() - OtherScale + : OtherScale - getScale(); + + ThisVal = ThisVal.extOrTrunc(CommonWidth); + OtherVal = OtherVal.extOrTrunc(CommonWidth); + + unsigned CommonScale = std::max(getScale(), OtherScale); + ThisVal = ThisVal.shl(CommonScale - getScale()); + OtherVal = OtherVal.shl(CommonScale - OtherScale); + + if (ThisSigned && OtherSigned) { + if (ThisVal.sgt(OtherVal)) + return 1; + else if (ThisVal.slt(OtherVal)) + return -1; + } else if (!ThisSigned && !OtherSigned) { + if (ThisVal.ugt(OtherVal)) + return 1; + else if (ThisVal.ult(OtherVal)) + return -1; + } else if (ThisSigned && !OtherSigned) { + if (ThisVal.isSignBitSet()) + return -1; + else if (ThisVal.ugt(OtherVal)) + return 1; + else if (ThisVal.ult(OtherVal)) + return -1; + } else { + // !ThisSigned && OtherSigned + if (OtherVal.isSignBitSet()) + return 1; + else if (ThisVal.ugt(OtherVal)) + return 1; + else if (ThisVal.ult(OtherVal)) + return -1; + } + + return 0; +} + +APFixedPoint APFixedPoint::getMax(const FixedPointSemantics &Sema) { + bool IsUnsigned = !Sema.isSigned(); + auto Val = APSInt::getMaxValue(Sema.getWidth(), IsUnsigned); + if (IsUnsigned && Sema.hasUnsignedPadding()) + Val = Val.lshr(1); + return APFixedPoint(Val, Sema); +} + +APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) { + auto Val = APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned()); + return APFixedPoint(Val, Sema); +} + +bool FixedPointSemantics::fitsInFloatSemantics( + const fltSemantics &FloatSema) const { + // A fixed point semantic fits in a floating point semantic if the maximum + // and minimum values as integers of the fixed point semantic can fit in the + // floating point semantic. + + // If these values do not fit, then a floating point rescaling of the true + // maximum/minimum value will not fit either, so the floating point semantic + // cannot be used to perform such a rescaling. + + APSInt MaxInt = APFixedPoint::getMax(*this).getValue(); + APFloat F(FloatSema); + APFloat::opStatus Status = F.convertFromAPInt(MaxInt, MaxInt.isSigned(), + APFloat::rmNearestTiesToAway); + if ((Status & APFloat::opOverflow) || !isSigned()) + return !(Status & APFloat::opOverflow); + + APSInt MinInt = APFixedPoint::getMin(*this).getValue(); + Status = F.convertFromAPInt(MinInt, MinInt.isSigned(), + APFloat::rmNearestTiesToAway); + return !(Status & APFloat::opOverflow); +} + +FixedPointSemantics FixedPointSemantics::getCommonSemantics( + const FixedPointSemantics &Other) const { + unsigned CommonScale = std::max(getScale(), Other.getScale()); + unsigned CommonWidth = + std::max(getIntegralBits(), Other.getIntegralBits()) + CommonScale; + + bool ResultIsSigned = isSigned() || Other.isSigned(); + bool ResultIsSaturated = isSaturated() || Other.isSaturated(); + bool ResultHasUnsignedPadding = false; + if (!ResultIsSigned) { + // Both are unsigned. + ResultHasUnsignedPadding = hasUnsignedPadding() && + Other.hasUnsignedPadding() && !ResultIsSaturated; + } + + // If the result is signed, add an extra bit for the sign. Otherwise, if it is + // unsigned and has unsigned padding, we only need to add the extra padding + // bit back if we are not saturating. + if (ResultIsSigned || ResultHasUnsignedPadding) + CommonWidth++; + + return FixedPointSemantics(CommonWidth, CommonScale, ResultIsSigned, + ResultIsSaturated, ResultHasUnsignedPadding); +} + +APFixedPoint APFixedPoint::add(const APFixedPoint &Other, + bool *Overflow) const { + auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics()); + APFixedPoint ConvertedThis = convert(CommonFXSema); + APFixedPoint ConvertedOther = Other.convert(CommonFXSema); + APSInt ThisVal = ConvertedThis.getValue(); + APSInt OtherVal = ConvertedOther.getValue(); + bool Overflowed = false; + + APSInt Result; + if (CommonFXSema.isSaturated()) { + Result = CommonFXSema.isSigned() ? ThisVal.sadd_sat(OtherVal) + : ThisVal.uadd_sat(OtherVal); + } else { + Result = ThisVal.isSigned() ? ThisVal.sadd_ov(OtherVal, Overflowed) + : ThisVal.uadd_ov(OtherVal, Overflowed); + } + + if (Overflow) + *Overflow = Overflowed; + + return APFixedPoint(Result, CommonFXSema); +} + +APFixedPoint APFixedPoint::sub(const APFixedPoint &Other, + bool *Overflow) const { + auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics()); + APFixedPoint ConvertedThis = convert(CommonFXSema); + APFixedPoint ConvertedOther = Other.convert(CommonFXSema); + APSInt ThisVal = ConvertedThis.getValue(); + APSInt OtherVal = ConvertedOther.getValue(); + bool Overflowed = false; + + APSInt Result; + if (CommonFXSema.isSaturated()) { + Result = CommonFXSema.isSigned() ? ThisVal.ssub_sat(OtherVal) + : ThisVal.usub_sat(OtherVal); + } else { + Result = ThisVal.isSigned() ? ThisVal.ssub_ov(OtherVal, Overflowed) + : ThisVal.usub_ov(OtherVal, Overflowed); + } + + if (Overflow) + *Overflow = Overflowed; + + return APFixedPoint(Result, CommonFXSema); +} + +APFixedPoint APFixedPoint::mul(const APFixedPoint &Other, + bool *Overflow) const { + auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics()); + APFixedPoint ConvertedThis = convert(CommonFXSema); + APFixedPoint ConvertedOther = Other.convert(CommonFXSema); + APSInt ThisVal = ConvertedThis.getValue(); + APSInt OtherVal = ConvertedOther.getValue(); + bool Overflowed = false; + + // Widen the LHS and RHS so we can perform a full multiplication. + unsigned Wide = CommonFXSema.getWidth() * 2; + if (CommonFXSema.isSigned()) { + ThisVal = ThisVal.sextOrSelf(Wide); + OtherVal = OtherVal.sextOrSelf(Wide); + } else { + ThisVal = ThisVal.zextOrSelf(Wide); + OtherVal = OtherVal.zextOrSelf(Wide); + } + + // Perform the full multiplication and downscale to get the same scale. + // + // Note that the right shifts here perform an implicit downwards rounding. + // This rounding could discard bits that would technically place the result + // outside the representable range. We interpret the spec as allowing us to + // perform the rounding step first, avoiding the overflow case that would + // arise. + APSInt Result; + if (CommonFXSema.isSigned()) + Result = ThisVal.smul_ov(OtherVal, Overflowed) + .ashr(CommonFXSema.getScale()); + else + Result = ThisVal.umul_ov(OtherVal, Overflowed) + .lshr(CommonFXSema.getScale()); + assert(!Overflowed && "Full multiplication cannot overflow!"); + Result.setIsSigned(CommonFXSema.isSigned()); + + // If our result lies outside of the representative range of the common + // semantic, we either have overflow or saturation. + APSInt Max = APFixedPoint::getMax(CommonFXSema).getValue() + .extOrTrunc(Wide); + APSInt Min = APFixedPoint::getMin(CommonFXSema).getValue() + .extOrTrunc(Wide); + if (CommonFXSema.isSaturated()) { + if (Result < Min) + Result = Min; + else if (Result > Max) + Result = Max; + } else + Overflowed = Result < Min || Result > Max; + + if (Overflow) + *Overflow = Overflowed; + + return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()), + CommonFXSema); +} + +APFixedPoint APFixedPoint::div(const APFixedPoint &Other, + bool *Overflow) const { + auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics()); + APFixedPoint ConvertedThis = convert(CommonFXSema); + APFixedPoint ConvertedOther = Other.convert(CommonFXSema); + APSInt ThisVal = ConvertedThis.getValue(); + APSInt OtherVal = ConvertedOther.getValue(); + bool Overflowed = false; + + // Widen the LHS and RHS so we can perform a full division. + unsigned Wide = CommonFXSema.getWidth() * 2; + if (CommonFXSema.isSigned()) { + ThisVal = ThisVal.sextOrSelf(Wide); + OtherVal = OtherVal.sextOrSelf(Wide); + } else { + ThisVal = ThisVal.zextOrSelf(Wide); + OtherVal = OtherVal.zextOrSelf(Wide); + } + + // Upscale to compensate for the loss of precision from division, and + // perform the full division. + ThisVal = ThisVal.shl(CommonFXSema.getScale()); + APSInt Result; + if (CommonFXSema.isSigned()) { + APInt Rem; + 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()) + Result = Result - 1; + } else + Result = ThisVal.udiv(OtherVal); + Result.setIsSigned(CommonFXSema.isSigned()); + + // If our result lies outside of the representative range of the common + // semantic, we either have overflow or saturation. + APSInt Max = APFixedPoint::getMax(CommonFXSema).getValue() + .extOrTrunc(Wide); + APSInt Min = APFixedPoint::getMin(CommonFXSema).getValue() + .extOrTrunc(Wide); + if (CommonFXSema.isSaturated()) { + if (Result < Min) + Result = Min; + else if (Result > Max) + Result = Max; + } else + Overflowed = Result < Min || Result > Max; + + if (Overflow) + *Overflow = Overflowed; + + return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()), + CommonFXSema); +} + +APFixedPoint APFixedPoint::shl(unsigned Amt, bool *Overflow) const { + APSInt ThisVal = Val; + bool Overflowed = false; + + // Widen the LHS. + unsigned Wide = Sema.getWidth() * 2; + if (Sema.isSigned()) + ThisVal = ThisVal.sextOrSelf(Wide); + else + ThisVal = ThisVal.zextOrSelf(Wide); + + // Clamp the shift amount at the original width, and perform the shift. + Amt = std::min(Amt, ThisVal.getBitWidth()); + APSInt Result = ThisVal << Amt; + Result.setIsSigned(Sema.isSigned()); + + // If our result lies outside of the representative range of the + // semantic, we either have overflow or saturation. + APSInt Max = APFixedPoint::getMax(Sema).getValue().extOrTrunc(Wide); + APSInt Min = APFixedPoint::getMin(Sema).getValue().extOrTrunc(Wide); + if (Sema.isSaturated()) { + if (Result < Min) + Result = Min; + else if (Result > Max) + Result = Max; + } else + Overflowed = Result < Min || Result > Max; + + if (Overflow) + *Overflow = Overflowed; + + return APFixedPoint(Result.sextOrTrunc(Sema.getWidth()), Sema); +} + +void APFixedPoint::toString(SmallVectorImpl<char> &Str) const { + APSInt Val = getValue(); + unsigned Scale = getScale(); + + if (Val.isSigned() && Val.isNegative() && Val != -Val) { + Val = -Val; + Str.push_back('-'); + } + + APSInt IntPart = Val >> Scale; + + // 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 RadixInt = APInt(Width, 10); + + IntPart.toString(Str, /*Radix=*/10); + Str.push_back('.'); + do { + (FractPart * RadixInt) + .lshr(Scale) + .toString(Str, /*Radix=*/10, Val.isSigned()); + FractPart = (FractPart * RadixInt) & FractPartMask; + } while (FractPart != 0); +} + +APFixedPoint APFixedPoint::negate(bool *Overflow) const { + if (!isSaturated()) { + if (Overflow) + *Overflow = + (!isSigned() && Val != 0) || (isSigned() && Val.isMinSignedValue()); + return APFixedPoint(-Val, Sema); + } + + // We never overflow for saturation + if (Overflow) + *Overflow = false; + + if (isSigned()) + return Val.isMinSignedValue() ? getMax(Sema) : APFixedPoint(-Val, Sema); + else + return APFixedPoint(Sema); +} + +APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign, + bool *Overflow) const { + APSInt Result = getIntPart(); + unsigned SrcWidth = getWidth(); + + APSInt DstMin = APSInt::getMinValue(DstWidth, !DstSign); + APSInt DstMax = APSInt::getMaxValue(DstWidth, !DstSign); + + if (SrcWidth < DstWidth) { + Result = Result.extend(DstWidth); + } else if (SrcWidth > DstWidth) { + DstMin = DstMin.extend(SrcWidth); + DstMax = DstMax.extend(SrcWidth); + } + + if (Overflow) { + if (Result.isSigned() && !DstSign) { + *Overflow = Result.isNegative() || Result.ugt(DstMax); + } else if (Result.isUnsigned() && DstSign) { + *Overflow = Result.ugt(DstMax); + } else { + *Overflow = Result < DstMin || Result > DstMax; + } + } + + Result.setIsSigned(DstSign); + return Result.extOrTrunc(DstWidth); +} + +const fltSemantics *APFixedPoint::promoteFloatSemantics(const fltSemantics *S) { + if (S == &APFloat::BFloat()) + return &APFloat::IEEEdouble(); + else if (S == &APFloat::IEEEhalf()) + return &APFloat::IEEEsingle(); + else if (S == &APFloat::IEEEsingle()) + return &APFloat::IEEEdouble(); + else if (S == &APFloat::IEEEdouble()) + return &APFloat::IEEEquad(); + llvm_unreachable("Could not promote float type!"); +} + +APFloat APFixedPoint::convertToFloat(const fltSemantics &FloatSema) const { + // For some operations, rounding mode has an effect on the result, while + // other operations are lossless and should never result in rounding. + // To signify which these operations are, we define two rounding modes here. + APFloat::roundingMode RM = APFloat::rmNearestTiesToEven; + APFloat::roundingMode LosslessRM = APFloat::rmTowardZero; + + // Make sure that we are operating in a type that works with this fixed-point + // semantic. + const fltSemantics *OpSema = &FloatSema; + while (!Sema.fitsInFloatSemantics(*OpSema)) + OpSema = promoteFloatSemantics(OpSema); + + // Convert the fixed point value bits as an integer. If the floating point + // value does not have the required precision, we will round according to the + // given mode. + APFloat Flt(*OpSema); + APFloat::opStatus S = Flt.convertFromAPInt(Val, Sema.isSigned(), RM); + + // If we cared about checking for precision loss, we could look at this + // status. + (void)S; + + // Scale down the integer value in the float to match the correct scaling + // factor. + APFloat ScaleFactor(std::pow(2, -(int)Sema.getScale())); + bool Ignored; + ScaleFactor.convert(*OpSema, LosslessRM, &Ignored); + Flt.multiply(ScaleFactor, LosslessRM); + + if (OpSema != &FloatSema) + Flt.convert(FloatSema, RM, &Ignored); + + return Flt; +} + +APFixedPoint APFixedPoint::getFromIntValue(const APSInt &Value, + const FixedPointSemantics &DstFXSema, + bool *Overflow) { + FixedPointSemantics IntFXSema = FixedPointSemantics::GetIntegerSemantics( + Value.getBitWidth(), Value.isSigned()); + return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow); +} + +APFixedPoint +APFixedPoint::getFromFloatValue(const APFloat &Value, + const FixedPointSemantics &DstFXSema, + bool *Overflow) { + // For some operations, rounding mode has an effect on the result, while + // other operations are lossless and should never result in rounding. + // To signify which these operations are, we define two rounding modes here, + // even though they are the same mode. + APFloat::roundingMode RM = APFloat::rmTowardZero; + APFloat::roundingMode LosslessRM = APFloat::rmTowardZero; + + const fltSemantics &FloatSema = Value.getSemantics(); + + if (Value.isNaN()) { + // Handle NaN immediately. + if (Overflow) + *Overflow = true; + return APFixedPoint(DstFXSema); + } + + // Make sure that we are operating in a type that works with this fixed-point + // semantic. + const fltSemantics *OpSema = &FloatSema; + while (!DstFXSema.fitsInFloatSemantics(*OpSema)) + OpSema = promoteFloatSemantics(OpSema); + + APFloat Val = Value; + + bool Ignored; + if (&FloatSema != OpSema) + Val.convert(*OpSema, LosslessRM, &Ignored); + + // Scale up the float so that the 'fractional' part of the mantissa ends up in + // the integer range instead. Rounding mode is irrelevant here. + // It is fine if this overflows to infinity even for saturating types, + // since we will use floating point comparisons to check for saturation. + APFloat ScaleFactor(std::pow(2, DstFXSema.getScale())); + ScaleFactor.convert(*OpSema, LosslessRM, &Ignored); + Val.multiply(ScaleFactor, LosslessRM); + + // Convert to the integral representation of the value. This rounding mode + // is significant. + APSInt Res(DstFXSema.getWidth(), !DstFXSema.isSigned()); + Val.convertToInteger(Res, RM, &Ignored); + + // Round the integral value and scale back. This makes the + // overflow calculations below work properly. If we do not round here, + // we risk checking for overflow with a value that is outside the + // representable range of the fixed-point semantic even though no overflow + // would occur had we rounded first. + ScaleFactor = APFloat(std::pow(2, -(int)DstFXSema.getScale())); + ScaleFactor.convert(*OpSema, LosslessRM, &Ignored); + Val.roundToIntegral(RM); + Val.multiply(ScaleFactor, LosslessRM); + + // Check for overflow/saturation by checking if the floating point value + // is outside the range representable by the fixed-point value. + APFloat FloatMax = getMax(DstFXSema).convertToFloat(*OpSema); + APFloat FloatMin = getMin(DstFXSema).convertToFloat(*OpSema); + bool Overflowed = false; + if (DstFXSema.isSaturated()) { + if (Val > FloatMax) + Res = getMax(DstFXSema).getValue(); + else if (Val < FloatMin) + Res = getMin(DstFXSema).getValue(); + } else + Overflowed = Val > FloatMax || Val < FloatMin; + + if (Overflow) + *Overflow = Overflowed; + + return APFixedPoint(Res, DstFXSema); +} + +} // namespace llvm diff --git a/contrib/llvm-project/llvm/lib/Support/APFloat.cpp b/contrib/llvm-project/llvm/lib/Support/APFloat.cpp index 362595d8f8b1..5dea98ee3993 100644 --- a/contrib/llvm-project/llvm/lib/Support/APFloat.cpp +++ b/contrib/llvm-project/llvm/lib/Support/APFloat.cpp @@ -755,6 +755,7 @@ void IEEEFloat::copySignificand(const IEEEFloat &rhs) { void IEEEFloat::makeNaN(bool SNaN, bool Negative, const APInt *fill) { category = fcNaN; sign = Negative; + exponent = exponentNaN(); integerPart *significand = significandParts(); unsigned numParts = partCount(); @@ -841,7 +842,7 @@ bool IEEEFloat::isSignificandAllOnes() const { // Test if the significand excluding the integral bit is all ones. This allows // us to test for binade boundaries. const integerPart *Parts = significandParts(); - const unsigned PartCount = partCount(); + const unsigned PartCount = partCountForBits(semantics->precision); for (unsigned i = 0; i < PartCount - 1; i++) if (~Parts[i]) return false; @@ -849,8 +850,8 @@ bool IEEEFloat::isSignificandAllOnes() const { // Set the unused high bits to all ones when we compare. const unsigned NumHighBits = PartCount*integerPartWidth - semantics->precision + 1; - assert(NumHighBits <= integerPartWidth && "Can not have more high bits to " - "fill than integerPartWidth"); + assert(NumHighBits <= integerPartWidth && NumHighBits > 0 && + "Can not have more high bits to fill than integerPartWidth"); const integerPart HighBitFill = ~integerPart(0) << (integerPartWidth - NumHighBits); if (~(Parts[PartCount - 1] | HighBitFill)) @@ -863,15 +864,16 @@ bool IEEEFloat::isSignificandAllZeros() const { // Test if the significand excluding the integral bit is all zeros. This // allows us to test for binade boundaries. const integerPart *Parts = significandParts(); - const unsigned PartCount = partCount(); + const unsigned PartCount = partCountForBits(semantics->precision); for (unsigned i = 0; i < PartCount - 1; i++) if (Parts[i]) return false; + // Compute how many bits are used in the final word. const unsigned NumHighBits = PartCount*integerPartWidth - semantics->precision + 1; - assert(NumHighBits <= integerPartWidth && "Can not have more high bits to " + assert(NumHighBits < integerPartWidth && "Can not have more high bits to " "clear than integerPartWidth"); const integerPart HighBitMask = ~integerPart(0) >> NumHighBits; @@ -925,8 +927,7 @@ IEEEFloat::IEEEFloat(const fltSemantics &ourSemantics, integerPart value) { IEEEFloat::IEEEFloat(const fltSemantics &ourSemantics) { initialize(&ourSemantics); - category = fcZero; - sign = false; + makeZero(false); } // Delegate to the previous constructor, because later copy constructor may @@ -2242,26 +2243,15 @@ IEEEFloat::opStatus IEEEFloat::convert(const fltSemantics &toSemantics, if (!X86SpecialNan && semantics == &semX87DoubleExtended) APInt::tcSetBit(significandParts(), semantics->precision - 1); - // If we are truncating NaN, it is possible that we shifted out all of the - // set bits in a signalling NaN payload. But NaN must remain NaN, so some - // bit in the significand must be set (otherwise it is Inf). - // This can only happen with sNaN. Set the 1st bit after the quiet bit, - // so that we still have an sNaN. - // FIXME: Set quiet and return opInvalidOp (on convert of any sNaN). - // But this requires fixing LLVM to parse 32-bit hex FP or ignoring - // conversions while parsing IR. - if (APInt::tcIsZero(significandParts(), newPartCount)) { - assert(shift < 0 && "Should not lose NaN payload on extend"); - assert(semantics->precision >= 3 && "Unexpectedly narrow significand"); - assert(*losesInfo && "Missing payload should have set lost info"); - APInt::tcSetBit(significandParts(), semantics->precision - 3); + // Convert of sNaN creates qNaN and raises an exception (invalid op). + // This also guarantees that a sNaN does not become Inf on a truncation + // that loses all payload bits. + if (isSignaling()) { + makeQuiet(); + fs = opInvalidOp; + } else { + fs = opOK; } - - // gcc forces the Quiet bit on, which means (float)(double)(float_sNan) - // does not give you back the same bits. This is dubious, and we - // don't currently do it. You're really supposed to get - // an invalid operation signal at runtime, but nobody does that. - fs = opOK; } else { *losesInfo = false; fs = opOK; @@ -3394,15 +3384,13 @@ void IEEEFloat::initFromF80LongDoubleAPInt(const APInt &api) { sign = static_cast<unsigned int>(i2>>15); if (myexponent == 0 && mysignificand == 0) { - // exponent, significand meaningless - category = fcZero; + makeZero(sign); } else if (myexponent==0x7fff && mysignificand==0x8000000000000000ULL) { - // exponent, significand meaningless - category = fcInfinity; + makeInf(sign); } else if ((myexponent == 0x7fff && mysignificand != 0x8000000000000000ULL) || (myexponent != 0x7fff && myexponent != 0 && myintegerbit == 0)) { - // exponent meaningless category = fcNaN; + exponent = exponentNaN(); significandParts()[0] = mysignificand; significandParts()[1] = 0; } else { @@ -3453,16 +3441,14 @@ void IEEEFloat::initFromQuadrupleAPInt(const APInt &api) { sign = static_cast<unsigned int>(i2>>63); if (myexponent==0 && (mysignificand==0 && mysignificand2==0)) { - // exponent, significand meaningless - category = fcZero; + makeZero(sign); } else if (myexponent==0x7fff && (mysignificand==0 && mysignificand2==0)) { - // exponent, significand meaningless - category = fcInfinity; + makeInf(sign); } else if (myexponent==0x7fff && (mysignificand!=0 || mysignificand2 !=0)) { - // exponent meaningless category = fcNaN; + exponent = exponentNaN(); significandParts()[0] = mysignificand; significandParts()[1] = mysignificand2; } else { @@ -3488,14 +3474,12 @@ void IEEEFloat::initFromDoubleAPInt(const APInt &api) { sign = static_cast<unsigned int>(i>>63); if (myexponent==0 && mysignificand==0) { - // exponent, significand meaningless - category = fcZero; + makeZero(sign); } else if (myexponent==0x7ff && mysignificand==0) { - // exponent, significand meaningless - category = fcInfinity; + makeInf(sign); } else if (myexponent==0x7ff && mysignificand!=0) { - // exponent meaningless category = fcNaN; + exponent = exponentNaN(); *significandParts() = mysignificand; } else { category = fcNormal; @@ -3519,14 +3503,12 @@ void IEEEFloat::initFromFloatAPInt(const APInt &api) { sign = i >> 31; if (myexponent==0 && mysignificand==0) { - // exponent, significand meaningless - category = fcZero; + makeZero(sign); } else if (myexponent==0xff && mysignificand==0) { - // exponent, significand meaningless - category = fcInfinity; + makeInf(sign); } else if (myexponent==0xff && mysignificand!=0) { - // sign, exponent, significand meaningless category = fcNaN; + exponent = exponentNaN(); *significandParts() = mysignificand; } else { category = fcNormal; @@ -3550,14 +3532,12 @@ void IEEEFloat::initFromBFloatAPInt(const APInt &api) { sign = i >> 15; if (myexponent == 0 && mysignificand == 0) { - // exponent, significand meaningless - category = fcZero; + makeZero(sign); } else if (myexponent == 0xff && mysignificand == 0) { - // exponent, significand meaningless - category = fcInfinity; + makeInf(sign); } else if (myexponent == 0xff && mysignificand != 0) { - // sign, exponent, significand meaningless category = fcNaN; + exponent = exponentNaN(); *significandParts() = mysignificand; } else { category = fcNormal; @@ -3581,14 +3561,12 @@ void IEEEFloat::initFromHalfAPInt(const APInt &api) { sign = i >> 15; if (myexponent==0 && mysignificand==0) { - // exponent, significand meaningless - category = fcZero; + makeZero(sign); } else if (myexponent==0x1f && mysignificand==0) { - // exponent, significand meaningless - category = fcInfinity; + makeInf(sign); } else if (myexponent==0x1f && mysignificand!=0) { - // sign, exponent, significand meaningless category = fcNaN; + exponent = exponentNaN(); *significandParts() = mysignificand; } else { category = fcNormal; @@ -4146,17 +4124,29 @@ IEEEFloat::opStatus IEEEFloat::next(bool nextDown) { return result; } +APFloatBase::ExponentType IEEEFloat::exponentNaN() const { + return semantics->maxExponent + 1; +} + +APFloatBase::ExponentType IEEEFloat::exponentInf() const { + return semantics->maxExponent + 1; +} + +APFloatBase::ExponentType IEEEFloat::exponentZero() const { + return semantics->minExponent - 1; +} + void IEEEFloat::makeInf(bool Negative) { category = fcInfinity; sign = Negative; - exponent = semantics->maxExponent + 1; + exponent = exponentInf(); APInt::tcSet(significandParts(), 0, partCount()); } void IEEEFloat::makeZero(bool Negative) { category = fcZero; sign = Negative; - exponent = semantics->minExponent-1; + exponent = exponentZero(); APInt::tcSet(significandParts(), 0, partCount()); } @@ -4884,6 +4874,6 @@ APFloat::opStatus APFloat::convertToInteger(APSInt &result, return status; } -} // End llvm namespace +} // namespace llvm #undef APFLOAT_DISPATCH_ON_SEMANTICS diff --git a/contrib/llvm-project/llvm/lib/Support/APInt.cpp b/contrib/llvm-project/llvm/lib/Support/APInt.cpp index 9a6f93feaa29..12ceb2df112e 100644 --- a/contrib/llvm-project/llvm/lib/Support/APInt.cpp +++ b/contrib/llvm-project/llvm/lib/Support/APInt.cpp @@ -338,8 +338,7 @@ void APInt::flipAllBitsSlowCase() { /// Toggles a given bit to its opposite value. void APInt::flipBit(unsigned bitPosition) { assert(bitPosition < BitWidth && "Out of the bit-width range!"); - if ((*this)[bitPosition]) clearBit(bitPosition); - else setBit(bitPosition); + setBitVal(bitPosition, !(*this)[bitPosition]); } void APInt::insertBits(const APInt &subBits, unsigned bitPosition) { @@ -393,12 +392,8 @@ void APInt::insertBits(const APInt &subBits, unsigned bitPosition) { // General case - set/clear individual bits in dst based on src. // TODO - there is scope for optimization here, but at the moment this code // path is barely used so prefer readability over performance. - for (unsigned i = 0; i != subBitWidth; ++i) { - if (subBits[i]) - setBit(bitPosition + i); - else - clearBit(bitPosition + i); - } + for (unsigned i = 0; i != subBitWidth; ++i) + setBitVal(bitPosition + i, subBits[i]); } void APInt::insertBits(uint64_t subBits, unsigned bitPosition, unsigned numBits) { @@ -966,6 +961,12 @@ APInt APInt::sextOrTrunc(unsigned width) const { return *this; } +APInt APInt::truncOrSelf(unsigned width) const { + if (BitWidth > width) + return trunc(width); + return *this; +} + APInt APInt::zextOrSelf(unsigned width) const { if (BitWidth < width) return zext(width); diff --git a/contrib/llvm-project/llvm/lib/Support/ARMAttributeParser.cpp b/contrib/llvm-project/llvm/lib/Support/ARMAttributeParser.cpp index 17ad38d22614..459691923af8 100644 --- a/contrib/llvm-project/llvm/lib/Support/ARMAttributeParser.cpp +++ b/contrib/llvm-project/llvm/lib/Support/ARMAttributeParser.cpp @@ -113,7 +113,7 @@ Error ARMAttributeParser::ARM_ISA_use(AttrType tag) { } Error ARMAttributeParser::THUMB_ISA_use(AttrType tag) { - static const char *strings[] = {"Not Permitted", "Thumb-1", "Thumb-2"}; + static const char *strings[] = {"Not Permitted", "Thumb-1", "Thumb-2", "Permitted"}; return parseStringAttribute("THUMB_ISA_use", tag, makeArrayRef(strings)); } diff --git a/contrib/llvm-project/llvm/lib/Support/ARMTargetParser.cpp b/contrib/llvm-project/llvm/lib/Support/ARMTargetParser.cpp index 56a91f7dc787..eb425cbb1d25 100644 --- a/contrib/llvm-project/llvm/lib/Support/ARMTargetParser.cpp +++ b/contrib/llvm-project/llvm/lib/Support/ARMTargetParser.cpp @@ -76,6 +76,7 @@ unsigned ARM::parseArchVersion(StringRef Arch) { case ArchKind::ARMV8_4A: case ArchKind::ARMV8_5A: case ArchKind::ARMV8_6A: + case ArchKind::ARMV8_7A: case ArchKind::ARMV8R: case ArchKind::ARMV8MBaseline: case ArchKind::ARMV8MMainline: @@ -111,6 +112,7 @@ ARM::ProfileKind ARM::parseArchProfile(StringRef Arch) { case ArchKind::ARMV8_4A: case ArchKind::ARMV8_5A: case ArchKind::ARMV8_6A: + case ArchKind::ARMV8_7A: return ProfileKind::A; case ArchKind::ARMV2: case ArchKind::ARMV2A: @@ -154,6 +156,7 @@ StringRef ARM::getArchSynonym(StringRef Arch) { .Case("v8.4a", "v8.4-a") .Case("v8.5a", "v8.5-a") .Case("v8.6a", "v8.6-a") + .Case("v8.7a", "v8.7-a") .Case("v8r", "v8-r") .Case("v8m.base", "v8-m.base") .Case("v8m.main", "v8-m.main") @@ -255,7 +258,7 @@ ARM::ISAKind ARM::parseArchISA(StringRef Arch) { unsigned ARM::parseFPU(StringRef FPU) { StringRef Syn = getFPUSynonym(FPU); - for (const auto F : FPUNames) { + for (const auto &F : FPUNames) { if (Syn == F.getName()) return F.ID; } @@ -280,6 +283,8 @@ StringRef ARM::getCanonicalArchName(StringRef Arch) { // Begins with "arm" / "thumb", move past it. if (A.startswith("arm64_32")) offset = 8; + else if (A.startswith("arm64e")) + offset = 6; else if (A.startswith("arm64")) offset = 5; else if (A.startswith("aarch64_32")) @@ -409,7 +414,7 @@ bool ARM::getExtensionFeatures(uint64_t Extensions, if (Extensions == AEK_INVALID) return false; - for (const auto AE : ARCHExtNames) { + for (const auto &AE : ARCHExtNames) { if ((Extensions & AE.ID) == AE.ID && AE.Feature) Features.push_back(AE.Feature); else if (AE.NegFeature) @@ -436,7 +441,7 @@ unsigned ARM::getArchAttr(ARM::ArchKind AK) { } StringRef ARM::getArchExtName(uint64_t ArchExtKind) { - for (const auto AE : ARCHExtNames) { + for (const auto &AE : ARCHExtNames) { if (ArchExtKind == AE.ID) return AE.getName(); } @@ -453,7 +458,7 @@ static bool stripNegationPrefix(StringRef &Name) { StringRef ARM::getArchExtFeature(StringRef ArchExt) { bool Negated = stripNegationPrefix(ArchExt); - for (const auto AE : ARCHExtNames) { + for (const auto &AE : ARCHExtNames) { if (AE.Feature && ArchExt == AE.getName()) return StringRef(Negated ? AE.NegFeature : AE.Feature); } @@ -490,9 +495,10 @@ static unsigned findDoublePrecisionFPU(unsigned InputFPUKind) { return ARM::FK_INVALID; } -bool ARM::appendArchExtFeatures( - StringRef CPU, ARM::ArchKind AK, StringRef ArchExt, - std::vector<StringRef> &Features) { +bool ARM::appendArchExtFeatures(StringRef CPU, ARM::ArchKind AK, + StringRef ArchExt, + std::vector<StringRef> &Features, + unsigned &ArgFPUID) { size_t StartingNumFeatures = Features.size(); const bool Negated = stripNegationPrefix(ArchExt); @@ -501,7 +507,7 @@ bool ARM::appendArchExtFeatures( if (ID == AEK_INVALID) return false; - for (const auto AE : ARCHExtNames) { + for (const auto &AE : ARCHExtNames) { if (Negated) { if ((AE.ID & ID) == ID && AE.NegFeature) Features.push_back(AE.NegFeature); @@ -527,13 +533,14 @@ bool ARM::appendArchExtFeatures( } else { FPUKind = getDefaultFPU(CPU, AK); } + ArgFPUID = FPUKind; return ARM::getFPUFeatures(FPUKind, Features); } return StartingNumFeatures != Features.size(); } StringRef ARM::getHWDivName(uint64_t HWDivKind) { - for (const auto D : HWDivNames) { + for (const auto &D : HWDivNames) { if (HWDivKind == D.ID) return D.getName(); } @@ -546,7 +553,7 @@ StringRef ARM::getDefaultCPU(StringRef Arch) { return StringRef(); // Look for multiple AKs to find the default for pair AK+Name. - for (const auto CPU : CPUNames) { + for (const auto &CPU : CPUNames) { if (CPU.ArchID == AK && CPU.Default) return CPU.getName(); } @@ -557,7 +564,7 @@ StringRef ARM::getDefaultCPU(StringRef Arch) { uint64_t ARM::parseHWDiv(StringRef HWDiv) { StringRef Syn = getHWDivSynonym(HWDiv); - for (const auto D : HWDivNames) { + for (const auto &D : HWDivNames) { if (Syn == D.getName()) return D.ID; } @@ -565,7 +572,7 @@ uint64_t ARM::parseHWDiv(StringRef HWDiv) { } uint64_t ARM::parseArchExt(StringRef ArchExt) { - for (const auto A : ARCHExtNames) { + for (const auto &A : ARCHExtNames) { if (ArchExt == A.getName()) return A.ID; } @@ -573,7 +580,7 @@ uint64_t ARM::parseArchExt(StringRef ArchExt) { } ARM::ArchKind ARM::parseCPUArch(StringRef CPU) { - for (const auto C : CPUNames) { + for (const auto &C : CPUNames) { if (CPU == C.getName()) return C.ArchID; } diff --git a/contrib/llvm-project/llvm/lib/Support/CRC.cpp b/contrib/llvm-project/llvm/lib/Support/CRC.cpp index 7ff09debe3b7..2bc668beed32 100644 --- a/contrib/llvm-project/llvm/lib/Support/CRC.cpp +++ b/contrib/llvm-project/llvm/lib/Support/CRC.cpp @@ -25,7 +25,7 @@ using namespace llvm; -#if LLVM_ENABLE_ZLIB == 0 || !HAVE_ZLIB_H +#if !LLVM_ENABLE_ZLIB static const uint32_t CRCTable[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, diff --git a/contrib/llvm-project/llvm/lib/Support/CachePruning.cpp b/contrib/llvm-project/llvm/lib/Support/CachePruning.cpp index 7663644db558..5c5759ffbaca 100644 --- a/contrib/llvm-project/llvm/lib/Support/CachePruning.cpp +++ b/contrib/llvm-project/llvm/lib/Support/CachePruning.cpp @@ -211,11 +211,12 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { // Walk all of the files within this directory. for (sys::fs::directory_iterator File(CachePathNative, EC), FileEnd; File != FileEnd && !EC; File.increment(EC)) { - // Ignore any files not beginning with the string "llvmcache-". This + // Ignore filenames not beginning with "llvmcache-" or "Thin-". This // includes the timestamp file as well as any files created by the user. // This acts as a safeguard against data loss if the user specifies the // wrong directory as their cache directory. - if (!sys::path::filename(File->path()).startswith("llvmcache-")) + StringRef filename = sys::path::filename(File->path()); + if (!filename.startswith("llvmcache-") && !filename.startswith("Thin-")) continue; // Look at this file. If we can't stat it, there's nothing interesting diff --git a/contrib/llvm-project/llvm/lib/Support/CommandLine.cpp b/contrib/llvm-project/llvm/lib/Support/CommandLine.cpp index 12ef0d511b14..6d89481bf28a 100644 --- a/contrib/llvm-project/llvm/lib/Support/CommandLine.cpp +++ b/contrib/llvm-project/llvm/lib/Support/CommandLine.cpp @@ -464,7 +464,7 @@ void Option::addCategory(OptionCategory &C) { // must be explicitly added if you want multiple categories that include it. if (&C != &GeneralCategory && Categories[0] == &GeneralCategory) Categories[0] = &C; - else if (find(Categories, &C) == Categories.end()) + else if (!is_contained(Categories, &C)) Categories.push_back(&C); } @@ -531,11 +531,7 @@ Option *CommandLineParser::LookupOption(SubCommand &Sub, StringRef &Arg, // If we have an equals sign, remember the value. if (EqualPos == StringRef::npos) { // Look up the option. - auto I = Sub.OptionsMap.find(Arg); - if (I == Sub.OptionsMap.end()) - return nullptr; - - return I != Sub.OptionsMap.end() ? I->second : nullptr; + return Sub.OptionsMap.lookup(Arg); } // If the argument before the = is a valid option name and the option allows @@ -832,7 +828,7 @@ void cl::TokenizeGNUCommandLine(StringRef Src, StringSaver &Saver, // Consume runs of whitespace. if (Token.empty()) { while (I != E && isWhitespace(Src[I])) { - // Mark the end of lines in response files + // Mark the end of lines in response files. if (MarkEOLs && Src[I] == '\n') NewArgv.push_back(nullptr); ++I; @@ -869,6 +865,9 @@ void cl::TokenizeGNUCommandLine(StringRef Src, StringSaver &Saver, if (isWhitespace(C)) { if (!Token.empty()) NewArgv.push_back(Saver.save(StringRef(Token)).data()); + // Mark the end of lines in response files. + if (MarkEOLs && C == '\n') + NewArgv.push_back(nullptr); Token.clear(); continue; } @@ -880,9 +879,6 @@ void cl::TokenizeGNUCommandLine(StringRef Src, StringSaver &Saver, // Append the last token after hitting EOF with no whitespace. if (!Token.empty()) NewArgv.push_back(Saver.save(StringRef(Token)).data()); - // Mark the end of response files - if (MarkEOLs) - NewArgv.push_back(nullptr); } /// Backslashes are interpreted in a rather complicated way in the Windows-style @@ -956,11 +952,11 @@ tokenizeWindowsCommandLineImpl(StringRef Src, StringSaver &Saver, ++I; StringRef NormalChars = Src.slice(Start, I); if (I >= E || isWhitespaceOrNull(Src[I])) { - if (I < E && Src[I] == '\n') - MarkEOL(); // No special characters: slice out the substring and start the next // token. Copy the string if the caller asks us to. AddToken(AlwaysCopy ? Saver.save(NormalChars) : NormalChars); + if (I < E && Src[I] == '\n') + MarkEOL(); } else if (Src[I] == '\"') { Token += NormalChars; State = QUOTED; @@ -1208,7 +1204,7 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, }; // Check for recursive response files. - if (std::any_of(FileStack.begin() + 1, FileStack.end(), IsEquivalent)) { + if (any_of(drop_begin(FileStack), IsEquivalent)) { // This file is recursive, so we leave it in the argument stream and // move on. AllExpanded = false; @@ -1251,6 +1247,22 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, return AllExpanded; } +bool cl::expandResponseFiles(int Argc, const char *const *Argv, + const char *EnvVar, StringSaver &Saver, + SmallVectorImpl<const char *> &NewArgv) { + auto Tokenize = Triple(sys::getProcessTriple()).isOSWindows() + ? cl::TokenizeWindowsCommandLine + : cl::TokenizeGNUCommandLine; + // The environment variable specifies initial options. + if (EnvVar) + if (llvm::Optional<std::string> EnvValue = sys::Process::GetEnv(EnvVar)) + Tokenize(*EnvValue, Saver, NewArgv, /*MarkEOLs=*/false); + + // Command line options can override the environment variable. + NewArgv.append(Argv + 1, Argv + Argc); + return ExpandResponseFiles(Saver, Tokenize, NewArgv); +} + bool cl::readConfigFile(StringRef CfgFile, StringSaver &Saver, SmallVectorImpl<const char *> &Argv) { SmallString<128> AbsPath; @@ -1271,36 +1283,6 @@ bool cl::readConfigFile(StringRef CfgFile, StringSaver &Saver, /*MarkEOLs*/ false, /*RelativeNames*/ true); } -/// ParseEnvironmentOptions - An alternative entry point to the -/// CommandLine library, which allows you to read the program's name -/// from the caller (as PROGNAME) and its command-line arguments from -/// an environment variable (whose name is given in ENVVAR). -/// -void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, - const char *Overview) { - // Check args. - assert(progName && "Program name not specified"); - assert(envVar && "Environment variable name missing"); - - // Get the environment variable they want us to parse options out of. - llvm::Optional<std::string> envValue = sys::Process::GetEnv(StringRef(envVar)); - if (!envValue) - return; - - // Get program's "name", which we wouldn't know without the caller - // telling us. - SmallVector<const char *, 20> newArgv; - BumpPtrAllocator A; - StringSaver Saver(A); - newArgv.push_back(Saver.save(progName).data()); - - // Parse the value of the environment variable into a "command line" - // and hand it off to ParseCommandLineOptions(). - TokenizeGNUCommandLine(*envValue, Saver, newArgv); - int newArgc = static_cast<int>(newArgv.size()); - ParseCommandLineOptions(newArgc, &newArgv[0], StringRef(Overview)); -} - bool cl::ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview, raw_ostream *Errs, const char *EnvVar, @@ -2604,7 +2586,7 @@ void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories, SubCommand &Sub) { for (auto &I : Sub.OptionsMap) { for (auto &Cat : I.second->Categories) { - if (find(Categories, Cat) == Categories.end() && Cat != &GenericCategory) + if (!is_contained(Categories, Cat) && Cat != &GenericCategory) I.second->setHiddenFlag(cl::ReallyHidden); } } diff --git a/contrib/llvm-project/llvm/lib/Support/Compression.cpp b/contrib/llvm-project/llvm/lib/Support/Compression.cpp index 27d92f0e0aec..b8c77cf69b95 100644 --- a/contrib/llvm-project/llvm/lib/Support/Compression.cpp +++ b/contrib/llvm-project/llvm/lib/Support/Compression.cpp @@ -17,13 +17,13 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" -#if LLVM_ENABLE_ZLIB == 1 && HAVE_ZLIB_H +#if LLVM_ENABLE_ZLIB #include <zlib.h> #endif using namespace llvm; -#if LLVM_ENABLE_ZLIB == 1 && HAVE_LIBZ +#if LLVM_ENABLE_ZLIB static Error createError(StringRef Err) { return make_error<StringError>(Err, inconvertibleErrorCode()); } diff --git a/contrib/llvm-project/llvm/lib/Support/ConvertUTFWrapper.cpp b/contrib/llvm-project/llvm/lib/Support/ConvertUTFWrapper.cpp index 6ec567882ea6..d8d46712a593 100644 --- a/contrib/llvm-project/llvm/lib/Support/ConvertUTFWrapper.cpp +++ b/contrib/llvm-project/llvm/lib/Support/ConvertUTFWrapper.cpp @@ -97,6 +97,8 @@ bool convertUTF16ToUTF8String(ArrayRef<char> SrcBytes, std::string &Out) { const UTF16 *Src = reinterpret_cast<const UTF16 *>(SrcBytes.begin()); const UTF16 *SrcEnd = reinterpret_cast<const UTF16 *>(SrcBytes.end()); + assert((uintptr_t)Src % sizeof(UTF16) == 0); + // Byteswap if necessary. std::vector<UTF16> ByteSwapped; if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_SWAPPED) { diff --git a/contrib/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp b/contrib/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp index ec7d7d641dce..3d3ca7f567c7 100644 --- a/contrib/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp +++ b/contrib/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp @@ -9,14 +9,12 @@ #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ExitCodes.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Signals.h" #include "llvm/Support/ThreadLocal.h" #include <mutex> #include <setjmp.h> -#if LLVM_ON_UNIX -#include <sysexits.h> // EX_IOERR -#endif using namespace llvm; @@ -97,6 +95,13 @@ static void uninstallExceptionOrSignalHandlers(); CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {} +CrashRecoveryContext::CrashRecoveryContext() { + // On Windows, if abort() was previously triggered (and caught by a previous + // CrashRecoveryContext) the Windows CRT removes our installed signal handler, + // so we need to install it again. + sys::DisableSystemDialogsOnCrash(); +} + CrashRecoveryContext::~CrashRecoveryContext() { // Reclaim registered resources. CrashRecoveryContextCleanup *i = head; @@ -370,9 +375,10 @@ static void CrashRecoverySignalHandler(int Signal) { sigaddset(&SigMask, Signal); sigprocmask(SIG_UNBLOCK, &SigMask, nullptr); - // As per convention, -2 indicates a crash or timeout as opposed to failure to - // execute (see llvm/include/llvm/Support/Program.h) - int RetCode = -2; + // Return the same error code as if the program crashed, as mentioned in the + // section "Exit Status for Commands": + // https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html + int RetCode = 128 + Signal; // Don't consider a broken pipe as a crash (see clang/lib/Driver/Driver.cpp) if (Signal == SIGPIPE) @@ -436,6 +442,27 @@ void CrashRecoveryContext::HandleExit(int RetCode) { llvm_unreachable("Most likely setjmp wasn't called!"); } +bool CrashRecoveryContext::throwIfCrash(int RetCode) { +#if defined(_WIN32) + // On Windows, the high bits are reserved for kernel return codes. Values + // starting with 0x80000000 are reserved for "warnings"; values of 0xC0000000 + // and up are for "errors". In practice, both are interpreted as a + // non-continuable signal. + unsigned Code = ((unsigned)RetCode & 0xF0000000) >> 28; + if (Code != 0xC && Code != 8) + return false; + ::RaiseException(RetCode, 0, 0, NULL); +#else + // On Unix, signals are represented by return codes of 128 or higher. + // Exit code 128 is a reserved value and should not be raised as a signal. + if (RetCode <= 128) + return false; + llvm::sys::unregisterHandlers(); + raise(RetCode - 128); +#endif + return true; +} + // FIXME: Portability. static void setThreadBackgroundPriority() { #ifdef __APPLE__ diff --git a/contrib/llvm-project/llvm/lib/Support/DebugCounter.cpp b/contrib/llvm-project/llvm/lib/Support/DebugCounter.cpp index 8c579f395282..7bb231c79239 100644 --- a/contrib/llvm-project/llvm/lib/Support/DebugCounter.cpp +++ b/contrib/llvm-project/llvm/lib/Support/DebugCounter.cpp @@ -118,7 +118,7 @@ void DebugCounter::push_back(const std::string &Val) { void DebugCounter::print(raw_ostream &OS) const { SmallVector<StringRef, 16> CounterNames(RegisteredCounters.begin(), RegisteredCounters.end()); - sort(CounterNames.begin(), CounterNames.end()); + sort(CounterNames); auto &Us = instance(); OS << "Counters and values:\n"; diff --git a/contrib/llvm-project/llvm/lib/Support/DynamicLibrary.cpp b/contrib/llvm-project/llvm/lib/Support/DynamicLibrary.cpp index d23716016fb2..bdf74623670b 100644 --- a/contrib/llvm-project/llvm/lib/Support/DynamicLibrary.cpp +++ b/contrib/llvm-project/llvm/lib/Support/DynamicLibrary.cpp @@ -39,9 +39,7 @@ public: HandleSet() : Process(nullptr) {} ~HandleSet(); - HandleList::iterator Find(void *Handle) { - return std::find(Handles.begin(), Handles.end(), Handle); - } + HandleList::iterator Find(void *Handle) { return find(Handles, Handle); } bool Contains(void *Handle) { return Handle == Process || Find(Handle) != Handles.end(); diff --git a/contrib/llvm-project/llvm/lib/Support/ELFAttributeParser.cpp b/contrib/llvm-project/llvm/lib/Support/ELFAttributeParser.cpp index df955cdf5d30..2a30794bc1e9 100644 --- a/contrib/llvm-project/llvm/lib/Support/ELFAttributeParser.cpp +++ b/contrib/llvm-project/llvm/lib/Support/ELFAttributeParser.cpp @@ -200,7 +200,7 @@ Error ELFAttributeParser::parse(ArrayRef<uint8_t> section, // Unrecognized format-version. uint8_t formatVersion = de.getU8(cursor); - if (formatVersion != 'A') + if (formatVersion != ELFAttrs::Format_Version) return createStringError(errc::invalid_argument, "unrecognized format-version: 0x" + utohexstr(formatVersion)); diff --git a/contrib/llvm-project/llvm/lib/Support/Error.cpp b/contrib/llvm-project/llvm/lib/Support/Error.cpp index 315a11e967d1..e7ab4387dfd1 100644 --- a/contrib/llvm-project/llvm/lib/Support/Error.cpp +++ b/contrib/llvm-project/llvm/lib/Support/Error.cpp @@ -168,3 +168,7 @@ void LLVMDisposeErrorMessage(char *ErrMsg) { delete[] ErrMsg; } LLVMErrorTypeId LLVMGetStringErrorTypeId() { return reinterpret_cast<void *>(&StringError::ID); } + +LLVMErrorRef LLVMCreateStringError(const char *ErrMsg) { + return wrap(make_error<StringError>(ErrMsg, inconvertibleErrorCode())); +} diff --git a/contrib/llvm-project/llvm/lib/Support/ErrorHandling.cpp b/contrib/llvm-project/llvm/lib/Support/ErrorHandling.cpp index f70a6921a41a..ce6344284f06 100644 --- a/contrib/llvm-project/llvm/lib/Support/ErrorHandling.cpp +++ b/contrib/llvm-project/llvm/lib/Support/ErrorHandling.cpp @@ -168,9 +168,11 @@ void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) { #else // Don't call the normal error handler. It may allocate memory. Directly write // an OOM to stderr and abort. - char OOMMessage[] = "LLVM ERROR: out of memory\n"; - ssize_t written = ::write(2, OOMMessage, strlen(OOMMessage)); - (void)written; + const char *OOMMessage = "LLVM ERROR: out of memory\n"; + const char *Newline = "\n"; + (void)!::write(2, OOMMessage, strlen(OOMMessage)); + (void)!::write(2, Reason, strlen(Reason)); + (void)!::write(2, Newline, strlen(Newline)); abort(); #endif } @@ -192,7 +194,8 @@ static void out_of_memory_new_handler() { void llvm::install_out_of_memory_new_handler() { std::new_handler old = std::set_new_handler(out_of_memory_new_handler); (void)old; - assert(old == nullptr && "new-handler already installed"); + assert((old == nullptr || old == out_of_memory_new_handler) && + "new-handler already installed"); } #endif diff --git a/contrib/llvm-project/llvm/lib/Support/FileCheck.cpp b/contrib/llvm-project/llvm/lib/Support/FileCheck.cpp deleted file mode 100644 index d0e79c675bcb..000000000000 --- a/contrib/llvm-project/llvm/lib/Support/FileCheck.cpp +++ /dev/null @@ -1,2580 +0,0 @@ -//===- FileCheck.cpp - Check that File's Contents match what is expected --===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// FileCheck does a line-by line check of a file that validates whether it -// contains the expected content. This is useful for regression tests etc. -// -// This file implements most of the API that will be used by the FileCheck utility -// as well as various unittests. -//===----------------------------------------------------------------------===// - -#include "llvm/Support/FileCheck.h" -#include "FileCheckImpl.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/CheckedArithmetic.h" -#include "llvm/Support/FormatVariadic.h" -#include <cstdint> -#include <list> -#include <tuple> -#include <utility> - -using namespace llvm; - -StringRef ExpressionFormat::toString() const { - switch (Value) { - case Kind::NoFormat: - return StringRef("<none>"); - case Kind::Unsigned: - return StringRef("%u"); - case Kind::Signed: - return StringRef("%d"); - case Kind::HexUpper: - return StringRef("%X"); - case Kind::HexLower: - return StringRef("%x"); - } - llvm_unreachable("unknown expression format"); -} - -Expected<StringRef> ExpressionFormat::getWildcardRegex() const { - switch (Value) { - case Kind::Unsigned: - return StringRef("[0-9]+"); - case Kind::Signed: - return StringRef("-?[0-9]+"); - case Kind::HexUpper: - return StringRef("[0-9A-F]+"); - case Kind::HexLower: - return StringRef("[0-9a-f]+"); - default: - return createStringError(std::errc::invalid_argument, - "trying to match value with invalid format"); - } -} - -Expected<std::string> -ExpressionFormat::getMatchingString(ExpressionValue IntegerValue) const { - if (Value == Kind::Signed) { - Expected<int64_t> SignedValue = IntegerValue.getSignedValue(); - if (!SignedValue) - return SignedValue.takeError(); - return itostr(*SignedValue); - } - - Expected<uint64_t> UnsignedValue = IntegerValue.getUnsignedValue(); - if (!UnsignedValue) - return UnsignedValue.takeError(); - switch (Value) { - case Kind::Unsigned: - return utostr(*UnsignedValue); - case Kind::HexUpper: - return utohexstr(*UnsignedValue, /*LowerCase=*/false); - case Kind::HexLower: - return utohexstr(*UnsignedValue, /*LowerCase=*/true); - default: - return createStringError(std::errc::invalid_argument, - "trying to match value with invalid format"); - } -} - -Expected<ExpressionValue> -ExpressionFormat::valueFromStringRepr(StringRef StrVal, - const SourceMgr &SM) const { - bool ValueIsSigned = Value == Kind::Signed; - StringRef OverflowErrorStr = "unable to represent numeric value"; - if (ValueIsSigned) { - int64_t SignedValue; - - if (StrVal.getAsInteger(10, SignedValue)) - return ErrorDiagnostic::get(SM, StrVal, OverflowErrorStr); - - return ExpressionValue(SignedValue); - } - - bool Hex = Value == Kind::HexUpper || Value == Kind::HexLower; - uint64_t UnsignedValue; - if (StrVal.getAsInteger(Hex ? 16 : 10, UnsignedValue)) - return ErrorDiagnostic::get(SM, StrVal, OverflowErrorStr); - - return ExpressionValue(UnsignedValue); -} - -static int64_t getAsSigned(uint64_t UnsignedValue) { - // Use memcpy to reinterpret the bitpattern in Value since casting to - // signed is implementation-defined if the unsigned value is too big to be - // represented in the signed type and using an union violates type aliasing - // rules. - int64_t SignedValue; - memcpy(&SignedValue, &UnsignedValue, sizeof(SignedValue)); - return SignedValue; -} - -Expected<int64_t> ExpressionValue::getSignedValue() const { - if (Negative) - return getAsSigned(Value); - - if (Value > (uint64_t)std::numeric_limits<int64_t>::max()) - return make_error<OverflowError>(); - - // Value is in the representable range of int64_t so we can use cast. - return static_cast<int64_t>(Value); -} - -Expected<uint64_t> ExpressionValue::getUnsignedValue() const { - if (Negative) - return make_error<OverflowError>(); - - return Value; -} - -ExpressionValue ExpressionValue::getAbsolute() const { - if (!Negative) - return *this; - - int64_t SignedValue = getAsSigned(Value); - int64_t MaxInt64 = std::numeric_limits<int64_t>::max(); - // Absolute value can be represented as int64_t. - if (SignedValue >= -MaxInt64) - return ExpressionValue(-getAsSigned(Value)); - - // -X == -(max int64_t + Rem), negate each component independently. - SignedValue += MaxInt64; - uint64_t RemainingValueAbsolute = -SignedValue; - return ExpressionValue(MaxInt64 + RemainingValueAbsolute); -} - -Expected<ExpressionValue> llvm::operator+(const ExpressionValue &LeftOperand, - const ExpressionValue &RightOperand) { - if (LeftOperand.isNegative() && RightOperand.isNegative()) { - int64_t LeftValue = cantFail(LeftOperand.getSignedValue()); - int64_t RightValue = cantFail(RightOperand.getSignedValue()); - Optional<int64_t> Result = checkedAdd<int64_t>(LeftValue, RightValue); - if (!Result) - return make_error<OverflowError>(); - - return ExpressionValue(*Result); - } - - // (-A) + B == B - A. - if (LeftOperand.isNegative()) - return RightOperand - LeftOperand.getAbsolute(); - - // A + (-B) == A - B. - if (RightOperand.isNegative()) - return LeftOperand - RightOperand.getAbsolute(); - - // Both values are positive at this point. - uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); - uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); - Optional<uint64_t> Result = - checkedAddUnsigned<uint64_t>(LeftValue, RightValue); - if (!Result) - return make_error<OverflowError>(); - - return ExpressionValue(*Result); -} - -Expected<ExpressionValue> llvm::operator-(const ExpressionValue &LeftOperand, - const ExpressionValue &RightOperand) { - // Result will be negative and thus might underflow. - if (LeftOperand.isNegative() && !RightOperand.isNegative()) { - int64_t LeftValue = cantFail(LeftOperand.getSignedValue()); - uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); - // Result <= -1 - (max int64_t) which overflows on 1- and 2-complement. - if (RightValue > (uint64_t)std::numeric_limits<int64_t>::max()) - return make_error<OverflowError>(); - Optional<int64_t> Result = - checkedSub(LeftValue, static_cast<int64_t>(RightValue)); - if (!Result) - return make_error<OverflowError>(); - - return ExpressionValue(*Result); - } - - // (-A) - (-B) == B - A. - if (LeftOperand.isNegative()) - return RightOperand.getAbsolute() - LeftOperand.getAbsolute(); - - // A - (-B) == A + B. - if (RightOperand.isNegative()) - return LeftOperand + RightOperand.getAbsolute(); - - // Both values are positive at this point. - uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); - uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); - if (LeftValue >= RightValue) - return ExpressionValue(LeftValue - RightValue); - else { - uint64_t AbsoluteDifference = RightValue - LeftValue; - uint64_t MaxInt64 = std::numeric_limits<int64_t>::max(); - // Value might underflow. - if (AbsoluteDifference > MaxInt64) { - AbsoluteDifference -= MaxInt64; - int64_t Result = -MaxInt64; - int64_t MinInt64 = std::numeric_limits<int64_t>::min(); - // Underflow, tested by: - // abs(Result + (max int64_t)) > abs((min int64_t) + (max int64_t)) - if (AbsoluteDifference > static_cast<uint64_t>(-(MinInt64 - Result))) - return make_error<OverflowError>(); - Result -= static_cast<int64_t>(AbsoluteDifference); - return ExpressionValue(Result); - } - - return ExpressionValue(-static_cast<int64_t>(AbsoluteDifference)); - } -} - -Expected<ExpressionValue> llvm::operator*(const ExpressionValue &LeftOperand, - const ExpressionValue &RightOperand) { - // -A * -B == A * B - if (LeftOperand.isNegative() && RightOperand.isNegative()) - return LeftOperand.getAbsolute() * RightOperand.getAbsolute(); - - // A * -B == -B * A - if (RightOperand.isNegative()) - return RightOperand * LeftOperand; - - assert(!RightOperand.isNegative() && "Unexpected negative operand!"); - - // Result will be negative and can underflow. - if (LeftOperand.isNegative()) { - auto Result = LeftOperand.getAbsolute() * RightOperand.getAbsolute(); - if (!Result) - return Result; - - return ExpressionValue(0) - *Result; - } - - // Result will be positive and can overflow. - uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); - uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); - Optional<uint64_t> Result = - checkedMulUnsigned<uint64_t>(LeftValue, RightValue); - if (!Result) - return make_error<OverflowError>(); - - return ExpressionValue(*Result); -} - -Expected<ExpressionValue> llvm::operator/(const ExpressionValue &LeftOperand, - const ExpressionValue &RightOperand) { - // -A / -B == A / B - if (LeftOperand.isNegative() && RightOperand.isNegative()) - return LeftOperand.getAbsolute() / RightOperand.getAbsolute(); - - // Check for divide by zero. - if (RightOperand == ExpressionValue(0)) - return make_error<OverflowError>(); - - // Result will be negative and can underflow. - if (LeftOperand.isNegative() || RightOperand.isNegative()) - return ExpressionValue(0) - - cantFail(LeftOperand.getAbsolute() / RightOperand.getAbsolute()); - - uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); - uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); - return ExpressionValue(LeftValue / RightValue); -} - -Expected<ExpressionValue> llvm::max(const ExpressionValue &LeftOperand, - const ExpressionValue &RightOperand) { - if (LeftOperand.isNegative() && RightOperand.isNegative()) { - int64_t LeftValue = cantFail(LeftOperand.getSignedValue()); - int64_t RightValue = cantFail(RightOperand.getSignedValue()); - return ExpressionValue(std::max(LeftValue, RightValue)); - } - - if (!LeftOperand.isNegative() && !RightOperand.isNegative()) { - uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); - uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); - return ExpressionValue(std::max(LeftValue, RightValue)); - } - - if (LeftOperand.isNegative()) - return RightOperand; - - return LeftOperand; -} - -Expected<ExpressionValue> llvm::min(const ExpressionValue &LeftOperand, - const ExpressionValue &RightOperand) { - if (cantFail(max(LeftOperand, RightOperand)) == LeftOperand) - return RightOperand; - - return LeftOperand; -} - -Expected<ExpressionValue> NumericVariableUse::eval() const { - Optional<ExpressionValue> Value = Variable->getValue(); - if (Value) - return *Value; - - return make_error<UndefVarError>(getExpressionStr()); -} - -Expected<ExpressionValue> BinaryOperation::eval() const { - Expected<ExpressionValue> LeftOp = LeftOperand->eval(); - Expected<ExpressionValue> RightOp = RightOperand->eval(); - - // Bubble up any error (e.g. undefined variables) in the recursive - // evaluation. - if (!LeftOp || !RightOp) { - Error Err = Error::success(); - if (!LeftOp) - Err = joinErrors(std::move(Err), LeftOp.takeError()); - if (!RightOp) - Err = joinErrors(std::move(Err), RightOp.takeError()); - return std::move(Err); - } - - return EvalBinop(*LeftOp, *RightOp); -} - -Expected<ExpressionFormat> -BinaryOperation::getImplicitFormat(const SourceMgr &SM) const { - Expected<ExpressionFormat> LeftFormat = LeftOperand->getImplicitFormat(SM); - Expected<ExpressionFormat> RightFormat = RightOperand->getImplicitFormat(SM); - if (!LeftFormat || !RightFormat) { - Error Err = Error::success(); - if (!LeftFormat) - Err = joinErrors(std::move(Err), LeftFormat.takeError()); - if (!RightFormat) - Err = joinErrors(std::move(Err), RightFormat.takeError()); - return std::move(Err); - } - - if (*LeftFormat != ExpressionFormat::Kind::NoFormat && - *RightFormat != ExpressionFormat::Kind::NoFormat && - *LeftFormat != *RightFormat) - return ErrorDiagnostic::get( - SM, getExpressionStr(), - "implicit format conflict between '" + LeftOperand->getExpressionStr() + - "' (" + LeftFormat->toString() + ") and '" + - RightOperand->getExpressionStr() + "' (" + RightFormat->toString() + - "), need an explicit format specifier"); - - return *LeftFormat != ExpressionFormat::Kind::NoFormat ? *LeftFormat - : *RightFormat; -} - -Expected<std::string> NumericSubstitution::getResult() const { - assert(ExpressionPointer->getAST() != nullptr && - "Substituting empty expression"); - Expected<ExpressionValue> EvaluatedValue = - ExpressionPointer->getAST()->eval(); - if (!EvaluatedValue) - return EvaluatedValue.takeError(); - ExpressionFormat Format = ExpressionPointer->getFormat(); - return Format.getMatchingString(*EvaluatedValue); -} - -Expected<std::string> StringSubstitution::getResult() const { - // Look up the value and escape it so that we can put it into the regex. - Expected<StringRef> VarVal = Context->getPatternVarValue(FromStr); - if (!VarVal) - return VarVal.takeError(); - return Regex::escape(*VarVal); -} - -bool Pattern::isValidVarNameStart(char C) { return C == '_' || isAlpha(C); } - -Expected<Pattern::VariableProperties> -Pattern::parseVariable(StringRef &Str, const SourceMgr &SM) { - if (Str.empty()) - return ErrorDiagnostic::get(SM, Str, "empty variable name"); - - size_t I = 0; - bool IsPseudo = Str[0] == '@'; - - // Global vars start with '$'. - if (Str[0] == '$' || IsPseudo) - ++I; - - if (!isValidVarNameStart(Str[I++])) - return ErrorDiagnostic::get(SM, Str, "invalid variable name"); - - for (size_t E = Str.size(); I != E; ++I) - // Variable names are composed of alphanumeric characters and underscores. - if (Str[I] != '_' && !isAlnum(Str[I])) - break; - - StringRef Name = Str.take_front(I); - Str = Str.substr(I); - return VariableProperties {Name, IsPseudo}; -} - -// StringRef holding all characters considered as horizontal whitespaces by -// FileCheck input canonicalization. -constexpr StringLiteral SpaceChars = " \t"; - -// Parsing helper function that strips the first character in S and returns it. -static char popFront(StringRef &S) { - char C = S.front(); - S = S.drop_front(); - return C; -} - -char OverflowError::ID = 0; -char UndefVarError::ID = 0; -char ErrorDiagnostic::ID = 0; -char NotFoundError::ID = 0; - -Expected<NumericVariable *> Pattern::parseNumericVariableDefinition( - StringRef &Expr, FileCheckPatternContext *Context, - Optional<size_t> LineNumber, ExpressionFormat ImplicitFormat, - const SourceMgr &SM) { - Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM); - if (!ParseVarResult) - return ParseVarResult.takeError(); - StringRef Name = ParseVarResult->Name; - - if (ParseVarResult->IsPseudo) - return ErrorDiagnostic::get( - SM, Name, "definition of pseudo numeric variable unsupported"); - - // Detect collisions between string and numeric variables when the latter - // is created later than the former. - if (Context->DefinedVariableTable.find(Name) != - Context->DefinedVariableTable.end()) - return ErrorDiagnostic::get( - SM, Name, "string variable with name '" + Name + "' already exists"); - - Expr = Expr.ltrim(SpaceChars); - if (!Expr.empty()) - return ErrorDiagnostic::get( - SM, Expr, "unexpected characters after numeric variable name"); - - NumericVariable *DefinedNumericVariable; - auto VarTableIter = Context->GlobalNumericVariableTable.find(Name); - if (VarTableIter != Context->GlobalNumericVariableTable.end()) { - DefinedNumericVariable = VarTableIter->second; - if (DefinedNumericVariable->getImplicitFormat() != ImplicitFormat) - return ErrorDiagnostic::get( - SM, Expr, "format different from previous variable definition"); - } else - DefinedNumericVariable = - Context->makeNumericVariable(Name, ImplicitFormat, LineNumber); - - return DefinedNumericVariable; -} - -Expected<std::unique_ptr<NumericVariableUse>> Pattern::parseNumericVariableUse( - StringRef Name, bool IsPseudo, Optional<size_t> LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM) { - if (IsPseudo && !Name.equals("@LINE")) - return ErrorDiagnostic::get( - SM, Name, "invalid pseudo numeric variable '" + Name + "'"); - - // Numeric variable definitions and uses are parsed in the order in which - // they appear in the CHECK patterns. For each definition, the pointer to the - // class instance of the corresponding numeric variable definition is stored - // in GlobalNumericVariableTable in parsePattern. Therefore, if the pointer - // we get below is null, it means no such variable was defined before. When - // that happens, we create a dummy variable so that parsing can continue. All - // uses of undefined variables, whether string or numeric, are then diagnosed - // in printSubstitutions() after failing to match. - auto VarTableIter = Context->GlobalNumericVariableTable.find(Name); - NumericVariable *NumericVariable; - if (VarTableIter != Context->GlobalNumericVariableTable.end()) - NumericVariable = VarTableIter->second; - else { - NumericVariable = Context->makeNumericVariable( - Name, ExpressionFormat(ExpressionFormat::Kind::Unsigned)); - Context->GlobalNumericVariableTable[Name] = NumericVariable; - } - - Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber(); - if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber) - return ErrorDiagnostic::get( - SM, Name, - "numeric variable '" + Name + - "' defined earlier in the same CHECK directive"); - - return std::make_unique<NumericVariableUse>(Name, NumericVariable); -} - -Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand( - StringRef &Expr, AllowedOperand AO, bool MaybeInvalidConstraint, - Optional<size_t> LineNumber, FileCheckPatternContext *Context, - const SourceMgr &SM) { - if (Expr.startswith("(")) { - if (AO != AllowedOperand::Any) - return ErrorDiagnostic::get( - SM, Expr, "parenthesized expression not permitted here"); - return parseParenExpr(Expr, LineNumber, Context, SM); - } - - if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) { - // Try to parse as a numeric variable use. - Expected<Pattern::VariableProperties> ParseVarResult = - parseVariable(Expr, SM); - if (ParseVarResult) { - // Try to parse a function call. - if (Expr.ltrim(SpaceChars).startswith("(")) { - if (AO != AllowedOperand::Any) - return ErrorDiagnostic::get(SM, ParseVarResult->Name, - "unexpected function call"); - - return parseCallExpr(Expr, ParseVarResult->Name, LineNumber, Context, - SM); - } - - return parseNumericVariableUse(ParseVarResult->Name, - ParseVarResult->IsPseudo, LineNumber, - Context, SM); - } - - if (AO == AllowedOperand::LineVar) - return ParseVarResult.takeError(); - // Ignore the error and retry parsing as a literal. - consumeError(ParseVarResult.takeError()); - } - - // Otherwise, parse it as a literal. - int64_t SignedLiteralValue; - uint64_t UnsignedLiteralValue; - StringRef SaveExpr = Expr; - // Accept both signed and unsigned literal, default to signed literal. - if (!Expr.consumeInteger((AO == AllowedOperand::LegacyLiteral) ? 10 : 0, - UnsignedLiteralValue)) - return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()), - UnsignedLiteralValue); - Expr = SaveExpr; - if (AO == AllowedOperand::Any && !Expr.consumeInteger(0, SignedLiteralValue)) - return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()), - SignedLiteralValue); - - return ErrorDiagnostic::get( - SM, Expr, - Twine("invalid ") + - (MaybeInvalidConstraint ? "matching constraint or " : "") + - "operand format"); -} - -Expected<std::unique_ptr<ExpressionAST>> -Pattern::parseParenExpr(StringRef &Expr, Optional<size_t> LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM) { - Expr = Expr.ltrim(SpaceChars); - assert(Expr.startswith("(")); - - // Parse right operand. - Expr.consume_front("("); - Expr = Expr.ltrim(SpaceChars); - if (Expr.empty()) - return ErrorDiagnostic::get(SM, Expr, "missing operand in expression"); - - // Note: parseNumericOperand handles nested opening parentheses. - Expected<std::unique_ptr<ExpressionAST>> SubExprResult = parseNumericOperand( - Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber, - Context, SM); - Expr = Expr.ltrim(SpaceChars); - while (SubExprResult && !Expr.empty() && !Expr.startswith(")")) { - StringRef OrigExpr = Expr; - SubExprResult = parseBinop(OrigExpr, Expr, std::move(*SubExprResult), false, - LineNumber, Context, SM); - Expr = Expr.ltrim(SpaceChars); - } - if (!SubExprResult) - return SubExprResult; - - if (!Expr.consume_front(")")) { - return ErrorDiagnostic::get(SM, Expr, - "missing ')' at end of nested expression"); - } - return SubExprResult; -} - -Expected<std::unique_ptr<ExpressionAST>> -Pattern::parseBinop(StringRef Expr, StringRef &RemainingExpr, - std::unique_ptr<ExpressionAST> LeftOp, - bool IsLegacyLineExpr, Optional<size_t> LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM) { - RemainingExpr = RemainingExpr.ltrim(SpaceChars); - if (RemainingExpr.empty()) - return std::move(LeftOp); - - // Check if this is a supported operation and select a function to perform - // it. - SMLoc OpLoc = SMLoc::getFromPointer(RemainingExpr.data()); - char Operator = popFront(RemainingExpr); - binop_eval_t EvalBinop; - switch (Operator) { - case '+': - EvalBinop = operator+; - break; - case '-': - EvalBinop = operator-; - break; - default: - return ErrorDiagnostic::get( - SM, OpLoc, Twine("unsupported operation '") + Twine(Operator) + "'"); - } - - // Parse right operand. - RemainingExpr = RemainingExpr.ltrim(SpaceChars); - if (RemainingExpr.empty()) - return ErrorDiagnostic::get(SM, RemainingExpr, - "missing operand in expression"); - // The second operand in a legacy @LINE expression is always a literal. - AllowedOperand AO = - IsLegacyLineExpr ? AllowedOperand::LegacyLiteral : AllowedOperand::Any; - Expected<std::unique_ptr<ExpressionAST>> RightOpResult = - parseNumericOperand(RemainingExpr, AO, /*MaybeInvalidConstraint=*/false, - LineNumber, Context, SM); - if (!RightOpResult) - return RightOpResult; - - Expr = Expr.drop_back(RemainingExpr.size()); - return std::make_unique<BinaryOperation>(Expr, EvalBinop, std::move(LeftOp), - std::move(*RightOpResult)); -} - -Expected<std::unique_ptr<ExpressionAST>> -Pattern::parseCallExpr(StringRef &Expr, StringRef FuncName, - Optional<size_t> LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM) { - Expr = Expr.ltrim(SpaceChars); - assert(Expr.startswith("(")); - - auto OptFunc = StringSwitch<Optional<binop_eval_t>>(FuncName) - .Case("add", operator+) - .Case("div", operator/) - .Case("max", max) - .Case("min", min) - .Case("mul", operator*) - .Case("sub", operator-) - .Default(None); - - if (!OptFunc) - return ErrorDiagnostic::get( - SM, FuncName, Twine("call to undefined function '") + FuncName + "'"); - - Expr.consume_front("("); - Expr = Expr.ltrim(SpaceChars); - - // Parse call arguments, which are comma separated. - SmallVector<std::unique_ptr<ExpressionAST>, 4> Args; - while (!Expr.empty() && !Expr.startswith(")")) { - if (Expr.startswith(",")) - return ErrorDiagnostic::get(SM, Expr, "missing argument"); - - // Parse the argument, which is an arbitary expression. - StringRef OuterBinOpExpr = Expr; - Expected<std::unique_ptr<ExpressionAST>> Arg = parseNumericOperand( - Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber, - Context, SM); - while (Arg && !Expr.empty()) { - Expr = Expr.ltrim(SpaceChars); - // Have we reached an argument terminator? - if (Expr.startswith(",") || Expr.startswith(")")) - break; - - // Arg = Arg <op> <expr> - Arg = parseBinop(OuterBinOpExpr, Expr, std::move(*Arg), false, LineNumber, - Context, SM); - } - - // Prefer an expression error over a generic invalid argument message. - if (!Arg) - return Arg.takeError(); - Args.push_back(std::move(*Arg)); - - // Have we parsed all available arguments? - Expr = Expr.ltrim(SpaceChars); - if (!Expr.consume_front(",")) - break; - - Expr = Expr.ltrim(SpaceChars); - if (Expr.startswith(")")) - return ErrorDiagnostic::get(SM, Expr, "missing argument"); - } - - if (!Expr.consume_front(")")) - return ErrorDiagnostic::get(SM, Expr, - "missing ')' at end of call expression"); - - const unsigned NumArgs = Args.size(); - if (NumArgs == 2) - return std::make_unique<BinaryOperation>(Expr, *OptFunc, std::move(Args[0]), - std::move(Args[1])); - - // TODO: Support more than binop_eval_t. - return ErrorDiagnostic::get(SM, FuncName, - Twine("function '") + FuncName + - Twine("' takes 2 arguments but ") + - Twine(NumArgs) + " given"); -} - -Expected<std::unique_ptr<Expression>> Pattern::parseNumericSubstitutionBlock( - StringRef Expr, Optional<NumericVariable *> &DefinedNumericVariable, - bool IsLegacyLineExpr, Optional<size_t> LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM) { - std::unique_ptr<ExpressionAST> ExpressionASTPointer = nullptr; - StringRef DefExpr = StringRef(); - DefinedNumericVariable = None; - ExpressionFormat ExplicitFormat = ExpressionFormat(); - - // Parse format specifier (NOTE: ',' is also an argument seperator). - size_t FormatSpecEnd = Expr.find(','); - size_t FunctionStart = Expr.find('('); - if (FormatSpecEnd != StringRef::npos && FormatSpecEnd < FunctionStart) { - Expr = Expr.ltrim(SpaceChars); - if (!Expr.consume_front("%")) - return ErrorDiagnostic::get( - SM, Expr, "invalid matching format specification in expression"); - - // Check for unknown matching format specifier and set matching format in - // class instance representing this expression. - SMLoc fmtloc = SMLoc::getFromPointer(Expr.data()); - switch (popFront(Expr)) { - case 'u': - ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::Unsigned); - break; - case 'd': - ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::Signed); - break; - case 'x': - ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::HexLower); - break; - case 'X': - ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::HexUpper); - break; - default: - return ErrorDiagnostic::get(SM, fmtloc, - "invalid format specifier in expression"); - } - - Expr = Expr.ltrim(SpaceChars); - if (!Expr.consume_front(",")) - return ErrorDiagnostic::get( - SM, Expr, "invalid matching format specification in expression"); - } - - // Save variable definition expression if any. - size_t DefEnd = Expr.find(':'); - if (DefEnd != StringRef::npos) { - DefExpr = Expr.substr(0, DefEnd); - Expr = Expr.substr(DefEnd + 1); - } - - // Parse matching constraint. - Expr = Expr.ltrim(SpaceChars); - bool HasParsedValidConstraint = false; - if (Expr.consume_front("==")) - HasParsedValidConstraint = true; - - // Parse the expression itself. - Expr = Expr.ltrim(SpaceChars); - if (Expr.empty()) { - if (HasParsedValidConstraint) - return ErrorDiagnostic::get( - SM, Expr, "empty numeric expression should not have a constraint"); - } else { - Expr = Expr.rtrim(SpaceChars); - StringRef OuterBinOpExpr = Expr; - // The first operand in a legacy @LINE expression is always the @LINE - // pseudo variable. - AllowedOperand AO = - IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any; - Expected<std::unique_ptr<ExpressionAST>> ParseResult = parseNumericOperand( - Expr, AO, !HasParsedValidConstraint, LineNumber, Context, SM); - while (ParseResult && !Expr.empty()) { - ParseResult = parseBinop(OuterBinOpExpr, Expr, std::move(*ParseResult), - IsLegacyLineExpr, LineNumber, Context, SM); - // Legacy @LINE expressions only allow 2 operands. - if (ParseResult && IsLegacyLineExpr && !Expr.empty()) - return ErrorDiagnostic::get( - SM, Expr, - "unexpected characters at end of expression '" + Expr + "'"); - } - if (!ParseResult) - return ParseResult.takeError(); - ExpressionASTPointer = std::move(*ParseResult); - } - - // Select format of the expression, i.e. (i) its explicit format, if any, - // otherwise (ii) its implicit format, if any, otherwise (iii) the default - // format (unsigned). Error out in case of conflicting implicit format - // without explicit format. - ExpressionFormat Format; - if (ExplicitFormat) - Format = ExplicitFormat; - else if (ExpressionASTPointer) { - Expected<ExpressionFormat> ImplicitFormat = - ExpressionASTPointer->getImplicitFormat(SM); - if (!ImplicitFormat) - return ImplicitFormat.takeError(); - Format = *ImplicitFormat; - } - if (!Format) - Format = ExpressionFormat(ExpressionFormat::Kind::Unsigned); - - std::unique_ptr<Expression> ExpressionPointer = - std::make_unique<Expression>(std::move(ExpressionASTPointer), Format); - - // Parse the numeric variable definition. - if (DefEnd != StringRef::npos) { - DefExpr = DefExpr.ltrim(SpaceChars); - Expected<NumericVariable *> ParseResult = parseNumericVariableDefinition( - DefExpr, Context, LineNumber, ExpressionPointer->getFormat(), SM); - - if (!ParseResult) - return ParseResult.takeError(); - DefinedNumericVariable = *ParseResult; - } - - return std::move(ExpressionPointer); -} - -bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix, - SourceMgr &SM, const FileCheckRequest &Req) { - bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot; - IgnoreCase = Req.IgnoreCase; - - PatternLoc = SMLoc::getFromPointer(PatternStr.data()); - - if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines)) - // Ignore trailing whitespace. - while (!PatternStr.empty() && - (PatternStr.back() == ' ' || PatternStr.back() == '\t')) - PatternStr = PatternStr.substr(0, PatternStr.size() - 1); - - // Check that there is something on the line. - if (PatternStr.empty() && CheckTy != Check::CheckEmpty) { - SM.PrintMessage(PatternLoc, SourceMgr::DK_Error, - "found empty check string with prefix '" + Prefix + ":'"); - return true; - } - - if (!PatternStr.empty() && CheckTy == Check::CheckEmpty) { - SM.PrintMessage( - PatternLoc, SourceMgr::DK_Error, - "found non-empty check string for empty check with prefix '" + Prefix + - ":'"); - return true; - } - - if (CheckTy == Check::CheckEmpty) { - RegExStr = "(\n$)"; - return false; - } - - // Check to see if this is a fixed string, or if it has regex pieces. - if (!MatchFullLinesHere && - (PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos && - PatternStr.find("[[") == StringRef::npos))) { - FixedStr = PatternStr; - return false; - } - - if (MatchFullLinesHere) { - RegExStr += '^'; - if (!Req.NoCanonicalizeWhiteSpace) - RegExStr += " *"; - } - - // Paren value #0 is for the fully matched string. Any new parenthesized - // values add from there. - unsigned CurParen = 1; - - // Otherwise, there is at least one regex piece. Build up the regex pattern - // by escaping scary characters in fixed strings, building up one big regex. - while (!PatternStr.empty()) { - // RegEx matches. - if (PatternStr.startswith("{{")) { - // This is the start of a regex match. Scan for the }}. - size_t End = PatternStr.find("}}"); - if (End == StringRef::npos) { - SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()), - SourceMgr::DK_Error, - "found start of regex string with no end '}}'"); - return true; - } - - // Enclose {{}} patterns in parens just like [[]] even though we're not - // capturing the result for any purpose. This is required in case the - // expression contains an alternation like: CHECK: abc{{x|z}}def. We - // want this to turn into: "abc(x|z)def" not "abcx|zdef". - RegExStr += '('; - ++CurParen; - - if (AddRegExToRegEx(PatternStr.substr(2, End - 2), CurParen, SM)) - return true; - RegExStr += ')'; - - PatternStr = PatternStr.substr(End + 2); - continue; - } - - // String and numeric substitution blocks. Pattern substitution blocks come - // in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some - // other regex) and assigns it to the string variable 'foo'. The latter - // substitutes foo's value. Numeric substitution blocks recognize the same - // form as string ones, but start with a '#' sign after the double - // brackets. They also accept a combined form which sets a numeric variable - // to the evaluation of an expression. Both string and numeric variable - // names must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be - // valid, as this helps catch some common errors. - if (PatternStr.startswith("[[")) { - StringRef UnparsedPatternStr = PatternStr.substr(2); - // Find the closing bracket pair ending the match. End is going to be an - // offset relative to the beginning of the match string. - size_t End = FindRegexVarEnd(UnparsedPatternStr, SM); - StringRef MatchStr = UnparsedPatternStr.substr(0, End); - bool IsNumBlock = MatchStr.consume_front("#"); - - if (End == StringRef::npos) { - SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()), - SourceMgr::DK_Error, - "Invalid substitution block, no ]] found"); - return true; - } - // Strip the substitution block we are parsing. End points to the start - // of the "]]" closing the expression so account for it in computing the - // index of the first unparsed character. - PatternStr = UnparsedPatternStr.substr(End + 2); - - bool IsDefinition = false; - bool SubstNeeded = false; - // Whether the substitution block is a legacy use of @LINE with string - // substitution block syntax. - bool IsLegacyLineExpr = false; - StringRef DefName; - StringRef SubstStr; - StringRef MatchRegexp; - size_t SubstInsertIdx = RegExStr.size(); - - // Parse string variable or legacy @LINE expression. - if (!IsNumBlock) { - size_t VarEndIdx = MatchStr.find(":"); - size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t"); - if (SpacePos != StringRef::npos) { - SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data() + SpacePos), - SourceMgr::DK_Error, "unexpected whitespace"); - return true; - } - - // Get the name (e.g. "foo") and verify it is well formed. - StringRef OrigMatchStr = MatchStr; - Expected<Pattern::VariableProperties> ParseVarResult = - parseVariable(MatchStr, SM); - if (!ParseVarResult) { - logAllUnhandledErrors(ParseVarResult.takeError(), errs()); - return true; - } - StringRef Name = ParseVarResult->Name; - bool IsPseudo = ParseVarResult->IsPseudo; - - IsDefinition = (VarEndIdx != StringRef::npos); - SubstNeeded = !IsDefinition; - if (IsDefinition) { - if ((IsPseudo || !MatchStr.consume_front(":"))) { - SM.PrintMessage(SMLoc::getFromPointer(Name.data()), - SourceMgr::DK_Error, - "invalid name in string variable definition"); - return true; - } - - // Detect collisions between string and numeric variables when the - // former is created later than the latter. - if (Context->GlobalNumericVariableTable.find(Name) != - Context->GlobalNumericVariableTable.end()) { - SM.PrintMessage( - SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error, - "numeric variable with name '" + Name + "' already exists"); - return true; - } - DefName = Name; - MatchRegexp = MatchStr; - } else { - if (IsPseudo) { - MatchStr = OrigMatchStr; - IsLegacyLineExpr = IsNumBlock = true; - } else - SubstStr = Name; - } - } - - // Parse numeric substitution block. - std::unique_ptr<Expression> ExpressionPointer; - Optional<NumericVariable *> DefinedNumericVariable; - if (IsNumBlock) { - Expected<std::unique_ptr<Expression>> ParseResult = - parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable, - IsLegacyLineExpr, LineNumber, Context, - SM); - if (!ParseResult) { - logAllUnhandledErrors(ParseResult.takeError(), errs()); - return true; - } - ExpressionPointer = std::move(*ParseResult); - SubstNeeded = ExpressionPointer->getAST() != nullptr; - if (DefinedNumericVariable) { - IsDefinition = true; - DefName = (*DefinedNumericVariable)->getName(); - } - if (SubstNeeded) - SubstStr = MatchStr; - else { - ExpressionFormat Format = ExpressionPointer->getFormat(); - MatchRegexp = cantFail(Format.getWildcardRegex()); - } - } - - // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]]. - if (IsDefinition) { - RegExStr += '('; - ++SubstInsertIdx; - - if (IsNumBlock) { - NumericVariableMatch NumericVariableDefinition = { - *DefinedNumericVariable, CurParen}; - NumericVariableDefs[DefName] = NumericVariableDefinition; - // This store is done here rather than in match() to allow - // parseNumericVariableUse() to get the pointer to the class instance - // of the right variable definition corresponding to a given numeric - // variable use. - Context->GlobalNumericVariableTable[DefName] = - *DefinedNumericVariable; - } else { - VariableDefs[DefName] = CurParen; - // Mark string variable as defined to detect collisions between - // string and numeric variables in parseNumericVariableUse() and - // defineCmdlineVariables() when the latter is created later than the - // former. We cannot reuse GlobalVariableTable for this by populating - // it with an empty string since we would then lose the ability to - // detect the use of an undefined variable in match(). - Context->DefinedVariableTable[DefName] = true; - } - - ++CurParen; - } - - if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM)) - return true; - - if (IsDefinition) - RegExStr += ')'; - - // Handle substitutions: [[foo]] and [[#<foo expr>]]. - if (SubstNeeded) { - // Handle substitution of string variables that were defined earlier on - // the same line by emitting a backreference. Expressions do not - // support substituting a numeric variable defined on the same line. - if (!IsNumBlock && VariableDefs.find(SubstStr) != VariableDefs.end()) { - unsigned CaptureParenGroup = VariableDefs[SubstStr]; - if (CaptureParenGroup < 1 || CaptureParenGroup > 9) { - SM.PrintMessage(SMLoc::getFromPointer(SubstStr.data()), - SourceMgr::DK_Error, - "Can't back-reference more than 9 variables"); - return true; - } - AddBackrefToRegEx(CaptureParenGroup); - } else { - // Handle substitution of string variables ([[<var>]]) defined in - // previous CHECK patterns, and substitution of expressions. - Substitution *Substitution = - IsNumBlock - ? Context->makeNumericSubstitution( - SubstStr, std::move(ExpressionPointer), SubstInsertIdx) - : Context->makeStringSubstitution(SubstStr, SubstInsertIdx); - Substitutions.push_back(Substitution); - } - } - } - - // Handle fixed string matches. - // Find the end, which is the start of the next regex. - size_t FixedMatchEnd = PatternStr.find("{{"); - FixedMatchEnd = std::min(FixedMatchEnd, PatternStr.find("[[")); - RegExStr += Regex::escape(PatternStr.substr(0, FixedMatchEnd)); - PatternStr = PatternStr.substr(FixedMatchEnd); - } - - if (MatchFullLinesHere) { - if (!Req.NoCanonicalizeWhiteSpace) - RegExStr += " *"; - RegExStr += '$'; - } - - return false; -} - -bool Pattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) { - Regex R(RS); - std::string Error; - if (!R.isValid(Error)) { - SM.PrintMessage(SMLoc::getFromPointer(RS.data()), SourceMgr::DK_Error, - "invalid regex: " + Error); - return true; - } - - RegExStr += RS.str(); - CurParen += R.getNumMatches(); - return false; -} - -void Pattern::AddBackrefToRegEx(unsigned BackrefNum) { - assert(BackrefNum >= 1 && BackrefNum <= 9 && "Invalid backref number"); - std::string Backref = std::string("\\") + std::string(1, '0' + BackrefNum); - RegExStr += Backref; -} - -Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen, - const SourceMgr &SM) const { - // If this is the EOF pattern, match it immediately. - if (CheckTy == Check::CheckEOF) { - MatchLen = 0; - return Buffer.size(); - } - - // If this is a fixed string pattern, just match it now. - if (!FixedStr.empty()) { - MatchLen = FixedStr.size(); - size_t Pos = - IgnoreCase ? Buffer.find_lower(FixedStr) : Buffer.find(FixedStr); - if (Pos == StringRef::npos) - return make_error<NotFoundError>(); - return Pos; - } - - // Regex match. - - // If there are substitutions, we need to create a temporary string with the - // actual value. - StringRef RegExToMatch = RegExStr; - std::string TmpStr; - if (!Substitutions.empty()) { - TmpStr = RegExStr; - if (LineNumber) - Context->LineVariable->setValue(ExpressionValue(*LineNumber)); - - size_t InsertOffset = 0; - // Substitute all string variables and expressions whose values are only - // now known. Use of string variables defined on the same line are handled - // by back-references. - for (const auto &Substitution : Substitutions) { - // Substitute and check for failure (e.g. use of undefined variable). - Expected<std::string> Value = Substitution->getResult(); - if (!Value) { - // Convert to an ErrorDiagnostic to get location information. This is - // done here rather than PrintNoMatch since now we know which - // substitution block caused the overflow. - Error Err = - handleErrors(Value.takeError(), [&](const OverflowError &E) { - return ErrorDiagnostic::get(SM, Substitution->getFromString(), - "unable to substitute variable or " - "numeric expression: overflow error"); - }); - return std::move(Err); - } - - // Plop it into the regex at the adjusted offset. - TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset, - Value->begin(), Value->end()); - InsertOffset += Value->size(); - } - - // Match the newly constructed regex. - RegExToMatch = TmpStr; - } - - SmallVector<StringRef, 4> MatchInfo; - unsigned int Flags = Regex::Newline; - if (IgnoreCase) - Flags |= Regex::IgnoreCase; - if (!Regex(RegExToMatch, Flags).match(Buffer, &MatchInfo)) - return make_error<NotFoundError>(); - - // Successful regex match. - assert(!MatchInfo.empty() && "Didn't get any match"); - StringRef FullMatch = MatchInfo[0]; - - // If this defines any string variables, remember their values. - for (const auto &VariableDef : VariableDefs) { - assert(VariableDef.second < MatchInfo.size() && "Internal paren error"); - Context->GlobalVariableTable[VariableDef.first] = - MatchInfo[VariableDef.second]; - } - - // If this defines any numeric variables, remember their values. - for (const auto &NumericVariableDef : NumericVariableDefs) { - const NumericVariableMatch &NumericVariableMatch = - NumericVariableDef.getValue(); - unsigned CaptureParenGroup = NumericVariableMatch.CaptureParenGroup; - assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error"); - NumericVariable *DefinedNumericVariable = - NumericVariableMatch.DefinedNumericVariable; - - StringRef MatchedValue = MatchInfo[CaptureParenGroup]; - ExpressionFormat Format = DefinedNumericVariable->getImplicitFormat(); - Expected<ExpressionValue> Value = - Format.valueFromStringRepr(MatchedValue, SM); - if (!Value) - return Value.takeError(); - DefinedNumericVariable->setValue(*Value); - } - - // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after - // the required preceding newline, which is consumed by the pattern in the - // case of CHECK-EMPTY but not CHECK-NEXT. - size_t MatchStartSkip = CheckTy == Check::CheckEmpty; - MatchLen = FullMatch.size() - MatchStartSkip; - return FullMatch.data() - Buffer.data() + MatchStartSkip; -} - -unsigned Pattern::computeMatchDistance(StringRef Buffer) const { - // Just compute the number of matching characters. For regular expressions, we - // just compare against the regex itself and hope for the best. - // - // FIXME: One easy improvement here is have the regex lib generate a single - // example regular expression which matches, and use that as the example - // string. - StringRef ExampleString(FixedStr); - if (ExampleString.empty()) - ExampleString = RegExStr; - - // Only compare up to the first line in the buffer, or the string size. - StringRef BufferPrefix = Buffer.substr(0, ExampleString.size()); - BufferPrefix = BufferPrefix.split('\n').first; - return BufferPrefix.edit_distance(ExampleString); -} - -void Pattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer, - SMRange MatchRange) const { - // Print what we know about substitutions. - if (!Substitutions.empty()) { - for (const auto &Substitution : Substitutions) { - SmallString<256> Msg; - raw_svector_ostream OS(Msg); - Expected<std::string> MatchedValue = Substitution->getResult(); - - // Substitution failed or is not known at match time, print the undefined - // variables it uses. - if (!MatchedValue) { - bool UndefSeen = false; - handleAllErrors( - MatchedValue.takeError(), [](const NotFoundError &E) {}, - // Handled in PrintNoMatch(). - [](const ErrorDiagnostic &E) {}, - // Handled in match(). - [](const OverflowError &E) {}, - [&](const UndefVarError &E) { - if (!UndefSeen) { - OS << "uses undefined variable(s):"; - UndefSeen = true; - } - OS << " "; - E.log(OS); - }); - } else { - // Substitution succeeded. Print substituted value. - OS << "with \""; - OS.write_escaped(Substitution->getFromString()) << "\" equal to \""; - OS.write_escaped(*MatchedValue) << "\""; - } - - if (MatchRange.isValid()) - SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, OS.str(), - {MatchRange}); - else - SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), - SourceMgr::DK_Note, OS.str()); - } - } -} - -static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy, - const SourceMgr &SM, SMLoc Loc, - Check::FileCheckType CheckTy, - StringRef Buffer, size_t Pos, size_t Len, - std::vector<FileCheckDiag> *Diags, - bool AdjustPrevDiag = false) { - SMLoc Start = SMLoc::getFromPointer(Buffer.data() + Pos); - SMLoc End = SMLoc::getFromPointer(Buffer.data() + Pos + Len); - SMRange Range(Start, End); - if (Diags) { - if (AdjustPrevDiag) - Diags->rbegin()->MatchTy = MatchTy; - else - Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range); - } - return Range; -} - -void Pattern::printFuzzyMatch(const SourceMgr &SM, StringRef Buffer, - std::vector<FileCheckDiag> *Diags) const { - // Attempt to find the closest/best fuzzy match. Usually an error happens - // because some string in the output didn't exactly match. In these cases, we - // would like to show the user a best guess at what "should have" matched, to - // save them having to actually check the input manually. - size_t NumLinesForward = 0; - size_t Best = StringRef::npos; - double BestQuality = 0; - - // Use an arbitrary 4k limit on how far we will search. - for (size_t i = 0, e = std::min(size_t(4096), Buffer.size()); i != e; ++i) { - if (Buffer[i] == '\n') - ++NumLinesForward; - - // Patterns have leading whitespace stripped, so skip whitespace when - // looking for something which looks like a pattern. - if (Buffer[i] == ' ' || Buffer[i] == '\t') - continue; - - // Compute the "quality" of this match as an arbitrary combination of the - // match distance and the number of lines skipped to get to this match. - unsigned Distance = computeMatchDistance(Buffer.substr(i)); - double Quality = Distance + (NumLinesForward / 100.); - - if (Quality < BestQuality || Best == StringRef::npos) { - Best = i; - BestQuality = Quality; - } - } - - // Print the "possible intended match here" line if we found something - // reasonable and not equal to what we showed in the "scanning from here" - // line. - if (Best && Best != StringRef::npos && BestQuality < 50) { - SMRange MatchRange = - ProcessMatchResult(FileCheckDiag::MatchFuzzy, SM, getLoc(), - getCheckTy(), Buffer, Best, 0, Diags); - SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, - "possible intended match here"); - - // FIXME: If we wanted to be really friendly we would show why the match - // failed, as it can be hard to spot simple one character differences. - } -} - -Expected<StringRef> -FileCheckPatternContext::getPatternVarValue(StringRef VarName) { - auto VarIter = GlobalVariableTable.find(VarName); - if (VarIter == GlobalVariableTable.end()) - return make_error<UndefVarError>(VarName); - - return VarIter->second; -} - -template <class... Types> -NumericVariable *FileCheckPatternContext::makeNumericVariable(Types... args) { - NumericVariables.push_back(std::make_unique<NumericVariable>(args...)); - return NumericVariables.back().get(); -} - -Substitution * -FileCheckPatternContext::makeStringSubstitution(StringRef VarName, - size_t InsertIdx) { - Substitutions.push_back( - std::make_unique<StringSubstitution>(this, VarName, InsertIdx)); - return Substitutions.back().get(); -} - -Substitution *FileCheckPatternContext::makeNumericSubstitution( - StringRef ExpressionStr, std::unique_ptr<Expression> Expression, - size_t InsertIdx) { - Substitutions.push_back(std::make_unique<NumericSubstitution>( - this, ExpressionStr, std::move(Expression), InsertIdx)); - return Substitutions.back().get(); -} - -size_t Pattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) { - // Offset keeps track of the current offset within the input Str - size_t Offset = 0; - // [...] Nesting depth - size_t BracketDepth = 0; - - while (!Str.empty()) { - if (Str.startswith("]]") && BracketDepth == 0) - return Offset; - if (Str[0] == '\\') { - // Backslash escapes the next char within regexes, so skip them both. - Str = Str.substr(2); - Offset += 2; - } else { - switch (Str[0]) { - default: - break; - case '[': - BracketDepth++; - break; - case ']': - if (BracketDepth == 0) { - SM.PrintMessage(SMLoc::getFromPointer(Str.data()), - SourceMgr::DK_Error, - "missing closing \"]\" for regex variable"); - exit(1); - } - BracketDepth--; - break; - } - Str = Str.substr(1); - Offset++; - } - } - - return StringRef::npos; -} - -StringRef FileCheck::CanonicalizeFile(MemoryBuffer &MB, - SmallVectorImpl<char> &OutputBuffer) { - OutputBuffer.reserve(MB.getBufferSize()); - - for (const char *Ptr = MB.getBufferStart(), *End = MB.getBufferEnd(); - Ptr != End; ++Ptr) { - // Eliminate trailing dosish \r. - if (Ptr <= End - 2 && Ptr[0] == '\r' && Ptr[1] == '\n') { - continue; - } - - // If current char is not a horizontal whitespace or if horizontal - // whitespace canonicalization is disabled, dump it to output as is. - if (Req.NoCanonicalizeWhiteSpace || (*Ptr != ' ' && *Ptr != '\t')) { - OutputBuffer.push_back(*Ptr); - continue; - } - - // Otherwise, add one space and advance over neighboring space. - OutputBuffer.push_back(' '); - while (Ptr + 1 != End && (Ptr[1] == ' ' || Ptr[1] == '\t')) - ++Ptr; - } - - // Add a null byte and then return all but that byte. - OutputBuffer.push_back('\0'); - return StringRef(OutputBuffer.data(), OutputBuffer.size() - 1); -} - -FileCheckDiag::FileCheckDiag(const SourceMgr &SM, - const Check::FileCheckType &CheckTy, - SMLoc CheckLoc, MatchType MatchTy, - SMRange InputRange) - : CheckTy(CheckTy), CheckLoc(CheckLoc), MatchTy(MatchTy) { - auto Start = SM.getLineAndColumn(InputRange.Start); - auto End = SM.getLineAndColumn(InputRange.End); - InputStartLine = Start.first; - InputStartCol = Start.second; - InputEndLine = End.first; - InputEndCol = End.second; -} - -static bool IsPartOfWord(char c) { - return (isAlnum(c) || c == '-' || c == '_'); -} - -Check::FileCheckType &Check::FileCheckType::setCount(int C) { - assert(Count > 0 && "zero and negative counts are not supported"); - assert((C == 1 || Kind == CheckPlain) && - "count supported only for plain CHECK directives"); - Count = C; - return *this; -} - -std::string Check::FileCheckType::getDescription(StringRef Prefix) const { - switch (Kind) { - case Check::CheckNone: - return "invalid"; - case Check::CheckPlain: - if (Count > 1) - return Prefix.str() + "-COUNT"; - return std::string(Prefix); - case Check::CheckNext: - return Prefix.str() + "-NEXT"; - case Check::CheckSame: - return Prefix.str() + "-SAME"; - case Check::CheckNot: - return Prefix.str() + "-NOT"; - case Check::CheckDAG: - return Prefix.str() + "-DAG"; - case Check::CheckLabel: - return Prefix.str() + "-LABEL"; - case Check::CheckEmpty: - return Prefix.str() + "-EMPTY"; - case Check::CheckComment: - return std::string(Prefix); - case Check::CheckEOF: - return "implicit EOF"; - case Check::CheckBadNot: - return "bad NOT"; - case Check::CheckBadCount: - return "bad COUNT"; - } - llvm_unreachable("unknown FileCheckType"); -} - -static std::pair<Check::FileCheckType, StringRef> -FindCheckType(const FileCheckRequest &Req, StringRef Buffer, StringRef Prefix) { - if (Buffer.size() <= Prefix.size()) - return {Check::CheckNone, StringRef()}; - - char NextChar = Buffer[Prefix.size()]; - - StringRef Rest = Buffer.drop_front(Prefix.size() + 1); - - // Check for comment. - if (Req.CommentPrefixes.end() != std::find(Req.CommentPrefixes.begin(), - Req.CommentPrefixes.end(), - Prefix)) { - if (NextChar == ':') - return {Check::CheckComment, Rest}; - // Ignore a comment prefix if it has a suffix like "-NOT". - return {Check::CheckNone, StringRef()}; - } - - // Verify that the : is present after the prefix. - if (NextChar == ':') - return {Check::CheckPlain, Rest}; - - if (NextChar != '-') - return {Check::CheckNone, StringRef()}; - - if (Rest.consume_front("COUNT-")) { - int64_t Count; - if (Rest.consumeInteger(10, Count)) - // Error happened in parsing integer. - return {Check::CheckBadCount, Rest}; - if (Count <= 0 || Count > INT32_MAX) - return {Check::CheckBadCount, Rest}; - if (!Rest.consume_front(":")) - return {Check::CheckBadCount, Rest}; - return {Check::FileCheckType(Check::CheckPlain).setCount(Count), Rest}; - } - - if (Rest.consume_front("NEXT:")) - return {Check::CheckNext, Rest}; - - if (Rest.consume_front("SAME:")) - return {Check::CheckSame, Rest}; - - if (Rest.consume_front("NOT:")) - return {Check::CheckNot, Rest}; - - if (Rest.consume_front("DAG:")) - return {Check::CheckDAG, Rest}; - - if (Rest.consume_front("LABEL:")) - return {Check::CheckLabel, Rest}; - - if (Rest.consume_front("EMPTY:")) - return {Check::CheckEmpty, Rest}; - - // You can't combine -NOT with another suffix. - if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") || - Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") || - Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:") || - Rest.startswith("EMPTY-NOT:") || Rest.startswith("NOT-EMPTY:")) - return {Check::CheckBadNot, Rest}; - - return {Check::CheckNone, Rest}; -} - -// From the given position, find the next character after the word. -static size_t SkipWord(StringRef Str, size_t Loc) { - while (Loc < Str.size() && IsPartOfWord(Str[Loc])) - ++Loc; - return Loc; -} - -/// Searches the buffer for the first prefix in the prefix regular expression. -/// -/// This searches the buffer using the provided regular expression, however it -/// enforces constraints beyond that: -/// 1) The found prefix must not be a suffix of something that looks like -/// a valid prefix. -/// 2) The found prefix must be followed by a valid check type suffix using \c -/// FindCheckType above. -/// -/// \returns a pair of StringRefs into the Buffer, which combines: -/// - the first match of the regular expression to satisfy these two is -/// returned, -/// otherwise an empty StringRef is returned to indicate failure. -/// - buffer rewound to the location right after parsed suffix, for parsing -/// to continue from -/// -/// If this routine returns a valid prefix, it will also shrink \p Buffer to -/// start at the beginning of the returned prefix, increment \p LineNumber for -/// each new line consumed from \p Buffer, and set \p CheckTy to the type of -/// check found by examining the suffix. -/// -/// If no valid prefix is found, the state of Buffer, LineNumber, and CheckTy -/// is unspecified. -static std::pair<StringRef, StringRef> -FindFirstMatchingPrefix(const FileCheckRequest &Req, Regex &PrefixRE, - StringRef &Buffer, unsigned &LineNumber, - Check::FileCheckType &CheckTy) { - SmallVector<StringRef, 2> Matches; - - while (!Buffer.empty()) { - // Find the first (longest) match using the RE. - if (!PrefixRE.match(Buffer, &Matches)) - // No match at all, bail. - return {StringRef(), StringRef()}; - - StringRef Prefix = Matches[0]; - Matches.clear(); - - assert(Prefix.data() >= Buffer.data() && - Prefix.data() < Buffer.data() + Buffer.size() && - "Prefix doesn't start inside of buffer!"); - size_t Loc = Prefix.data() - Buffer.data(); - StringRef Skipped = Buffer.substr(0, Loc); - Buffer = Buffer.drop_front(Loc); - LineNumber += Skipped.count('\n'); - - // Check that the matched prefix isn't a suffix of some other check-like - // word. - // FIXME: This is a very ad-hoc check. it would be better handled in some - // other way. Among other things it seems hard to distinguish between - // intentional and unintentional uses of this feature. - if (Skipped.empty() || !IsPartOfWord(Skipped.back())) { - // Now extract the type. - StringRef AfterSuffix; - std::tie(CheckTy, AfterSuffix) = FindCheckType(Req, Buffer, Prefix); - - // If we've found a valid check type for this prefix, we're done. - if (CheckTy != Check::CheckNone) - return {Prefix, AfterSuffix}; - } - - // If we didn't successfully find a prefix, we need to skip this invalid - // prefix and continue scanning. We directly skip the prefix that was - // matched and any additional parts of that check-like word. - Buffer = Buffer.drop_front(SkipWord(Buffer, Prefix.size())); - } - - // We ran out of buffer while skipping partial matches so give up. - return {StringRef(), StringRef()}; -} - -void FileCheckPatternContext::createLineVariable() { - assert(!LineVariable && "@LINE pseudo numeric variable already created"); - StringRef LineName = "@LINE"; - LineVariable = makeNumericVariable( - LineName, ExpressionFormat(ExpressionFormat::Kind::Unsigned)); - GlobalNumericVariableTable[LineName] = LineVariable; -} - -FileCheck::FileCheck(FileCheckRequest Req) - : Req(Req), PatternContext(std::make_unique<FileCheckPatternContext>()), - CheckStrings(std::make_unique<std::vector<FileCheckString>>()) {} - -FileCheck::~FileCheck() = default; - -bool FileCheck::readCheckFile( - SourceMgr &SM, StringRef Buffer, Regex &PrefixRE, - std::pair<unsigned, unsigned> *ImpPatBufferIDRange) { - if (ImpPatBufferIDRange) - ImpPatBufferIDRange->first = ImpPatBufferIDRange->second = 0; - - Error DefineError = - PatternContext->defineCmdlineVariables(Req.GlobalDefines, SM); - if (DefineError) { - logAllUnhandledErrors(std::move(DefineError), errs()); - return true; - } - - PatternContext->createLineVariable(); - - std::vector<Pattern> ImplicitNegativeChecks; - for (StringRef PatternString : Req.ImplicitCheckNot) { - // Create a buffer with fake command line content in order to display the - // command line option responsible for the specific implicit CHECK-NOT. - std::string Prefix = "-implicit-check-not='"; - std::string Suffix = "'"; - std::unique_ptr<MemoryBuffer> CmdLine = MemoryBuffer::getMemBufferCopy( - (Prefix + PatternString + Suffix).str(), "command line"); - - StringRef PatternInBuffer = - CmdLine->getBuffer().substr(Prefix.size(), PatternString.size()); - unsigned BufferID = SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc()); - if (ImpPatBufferIDRange) { - if (ImpPatBufferIDRange->first == ImpPatBufferIDRange->second) { - ImpPatBufferIDRange->first = BufferID; - ImpPatBufferIDRange->second = BufferID + 1; - } else { - assert(BufferID == ImpPatBufferIDRange->second && - "expected consecutive source buffer IDs"); - ++ImpPatBufferIDRange->second; - } - } - - ImplicitNegativeChecks.push_back( - Pattern(Check::CheckNot, PatternContext.get())); - ImplicitNegativeChecks.back().parsePattern(PatternInBuffer, - "IMPLICIT-CHECK", SM, Req); - } - - std::vector<Pattern> DagNotMatches = ImplicitNegativeChecks; - - // LineNumber keeps track of the line on which CheckPrefix instances are - // found. - unsigned LineNumber = 1; - - bool FoundUsedCheckPrefix = false; - while (1) { - Check::FileCheckType CheckTy; - - // See if a prefix occurs in the memory buffer. - StringRef UsedPrefix; - StringRef AfterSuffix; - std::tie(UsedPrefix, AfterSuffix) = - FindFirstMatchingPrefix(Req, PrefixRE, Buffer, LineNumber, CheckTy); - if (UsedPrefix.empty()) - break; - if (CheckTy != Check::CheckComment) - FoundUsedCheckPrefix = true; - - assert(UsedPrefix.data() == Buffer.data() && - "Failed to move Buffer's start forward, or pointed prefix outside " - "of the buffer!"); - assert(AfterSuffix.data() >= Buffer.data() && - AfterSuffix.data() < Buffer.data() + Buffer.size() && - "Parsing after suffix doesn't start inside of buffer!"); - - // Location to use for error messages. - const char *UsedPrefixStart = UsedPrefix.data(); - - // Skip the buffer to the end of parsed suffix (or just prefix, if no good - // suffix was processed). - Buffer = AfterSuffix.empty() ? Buffer.drop_front(UsedPrefix.size()) - : AfterSuffix; - - // Complain about useful-looking but unsupported suffixes. - if (CheckTy == Check::CheckBadNot) { - SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error, - "unsupported -NOT combo on prefix '" + UsedPrefix + "'"); - return true; - } - - // Complain about invalid count specification. - if (CheckTy == Check::CheckBadCount) { - SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error, - "invalid count in -COUNT specification on prefix '" + - UsedPrefix + "'"); - return true; - } - - // Okay, we found the prefix, yay. Remember the rest of the line, but ignore - // leading whitespace. - if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines)) - Buffer = Buffer.substr(Buffer.find_first_not_of(" \t")); - - // Scan ahead to the end of line. - size_t EOL = Buffer.find_first_of("\n\r"); - - // Remember the location of the start of the pattern, for diagnostics. - SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); - - // Extract the pattern from the buffer. - StringRef PatternBuffer = Buffer.substr(0, EOL); - Buffer = Buffer.substr(EOL); - - // If this is a comment, we're done. - if (CheckTy == Check::CheckComment) - continue; - - // Parse the pattern. - Pattern P(CheckTy, PatternContext.get(), LineNumber); - if (P.parsePattern(PatternBuffer, UsedPrefix, SM, Req)) - return true; - - // Verify that CHECK-LABEL lines do not define or use variables - if ((CheckTy == Check::CheckLabel) && P.hasVariable()) { - SM.PrintMessage( - SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, - "found '" + UsedPrefix + "-LABEL:'" - " with variable definition or use"); - return true; - } - - // Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them. - if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame || - CheckTy == Check::CheckEmpty) && - CheckStrings->empty()) { - StringRef Type = CheckTy == Check::CheckNext - ? "NEXT" - : CheckTy == Check::CheckEmpty ? "EMPTY" : "SAME"; - SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), - SourceMgr::DK_Error, - "found '" + UsedPrefix + "-" + Type + - "' without previous '" + UsedPrefix + ": line"); - return true; - } - - // Handle CHECK-DAG/-NOT. - if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) { - DagNotMatches.push_back(P); - continue; - } - - // Okay, add the string we captured to the output vector and move on. - CheckStrings->emplace_back(P, UsedPrefix, PatternLoc); - std::swap(DagNotMatches, CheckStrings->back().DagNotStrings); - DagNotMatches = ImplicitNegativeChecks; - } - - // When there are no used prefixes we report an error except in the case that - // no prefix is specified explicitly but -implicit-check-not is specified. - if (!FoundUsedCheckPrefix && - (ImplicitNegativeChecks.empty() || !Req.IsDefaultCheckPrefix)) { - errs() << "error: no check strings found with prefix" - << (Req.CheckPrefixes.size() > 1 ? "es " : " "); - for (size_t I = 0, E = Req.CheckPrefixes.size(); I != E; ++I) { - if (I != 0) - errs() << ", "; - errs() << "\'" << Req.CheckPrefixes[I] << ":'"; - } - errs() << '\n'; - return true; - } - - // Add an EOF pattern for any trailing --implicit-check-not/CHECK-DAG/-NOTs, - // and use the first prefix as a filler for the error message. - if (!DagNotMatches.empty()) { - CheckStrings->emplace_back( - Pattern(Check::CheckEOF, PatternContext.get(), LineNumber + 1), - *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data())); - std::swap(DagNotMatches, CheckStrings->back().DagNotStrings); - } - - return false; -} - -static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM, - StringRef Prefix, SMLoc Loc, const Pattern &Pat, - int MatchedCount, StringRef Buffer, size_t MatchPos, - size_t MatchLen, const FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) { - bool PrintDiag = true; - if (ExpectedMatch) { - if (!Req.Verbose) - return; - if (!Req.VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF) - return; - // Due to their verbosity, we don't print verbose diagnostics here if we're - // gathering them for a different rendering, but we always print other - // diagnostics. - PrintDiag = !Diags; - } - SMRange MatchRange = ProcessMatchResult( - ExpectedMatch ? FileCheckDiag::MatchFoundAndExpected - : FileCheckDiag::MatchFoundButExcluded, - SM, Loc, Pat.getCheckTy(), Buffer, MatchPos, MatchLen, Diags); - if (!PrintDiag) - return; - - std::string Message = formatv("{0}: {1} string found in input", - Pat.getCheckTy().getDescription(Prefix), - (ExpectedMatch ? "expected" : "excluded")) - .str(); - if (Pat.getCount() > 1) - Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str(); - - SM.PrintMessage( - Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message); - SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here", - {MatchRange}); - Pat.printSubstitutions(SM, Buffer, MatchRange); -} - -static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM, - const FileCheckString &CheckStr, int MatchedCount, - StringRef Buffer, size_t MatchPos, size_t MatchLen, - FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) { - PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat, - MatchedCount, Buffer, MatchPos, MatchLen, Req, Diags); -} - -static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM, - StringRef Prefix, SMLoc Loc, const Pattern &Pat, - int MatchedCount, StringRef Buffer, - bool VerboseVerbose, std::vector<FileCheckDiag> *Diags, - Error MatchErrors) { - assert(MatchErrors && "Called on successful match"); - bool PrintDiag = true; - if (!ExpectedMatch) { - if (!VerboseVerbose) { - consumeError(std::move(MatchErrors)); - return; - } - // Due to their verbosity, we don't print verbose diagnostics here if we're - // gathering them for a different rendering, but we always print other - // diagnostics. - PrintDiag = !Diags; - } - - // If the current position is at the end of a line, advance to the start of - // the next line. - Buffer = Buffer.substr(Buffer.find_first_not_of(" \t\n\r")); - SMRange SearchRange = ProcessMatchResult( - ExpectedMatch ? FileCheckDiag::MatchNoneButExpected - : FileCheckDiag::MatchNoneAndExcluded, - SM, Loc, Pat.getCheckTy(), Buffer, 0, Buffer.size(), Diags); - if (!PrintDiag) { - consumeError(std::move(MatchErrors)); - return; - } - - MatchErrors = handleErrors(std::move(MatchErrors), - [](const ErrorDiagnostic &E) { E.log(errs()); }); - - // No problem matching the string per se. - if (!MatchErrors) - return; - consumeError(std::move(MatchErrors)); - - // Print "not found" diagnostic. - std::string Message = formatv("{0}: {1} string not found in input", - Pat.getCheckTy().getDescription(Prefix), - (ExpectedMatch ? "expected" : "excluded")) - .str(); - if (Pat.getCount() > 1) - Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str(); - SM.PrintMessage( - Loc, ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark, Message); - - // Print the "scanning from here" line. - SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, "scanning from here"); - - // Allow the pattern to print additional information if desired. - Pat.printSubstitutions(SM, Buffer); - - if (ExpectedMatch) - Pat.printFuzzyMatch(SM, Buffer, Diags); -} - -static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM, - const FileCheckString &CheckStr, int MatchedCount, - StringRef Buffer, bool VerboseVerbose, - std::vector<FileCheckDiag> *Diags, Error MatchErrors) { - PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat, - MatchedCount, Buffer, VerboseVerbose, Diags, - std::move(MatchErrors)); -} - -/// Counts the number of newlines in the specified range. -static unsigned CountNumNewlinesBetween(StringRef Range, - const char *&FirstNewLine) { - unsigned NumNewLines = 0; - while (1) { - // Scan for newline. - Range = Range.substr(Range.find_first_of("\n\r")); - if (Range.empty()) - return NumNewLines; - - ++NumNewLines; - - // Handle \n\r and \r\n as a single newline. - if (Range.size() > 1 && (Range[1] == '\n' || Range[1] == '\r') && - (Range[0] != Range[1])) - Range = Range.substr(1); - Range = Range.substr(1); - - if (NumNewLines == 1) - FirstNewLine = Range.begin(); - } -} - -size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer, - bool IsLabelScanMode, size_t &MatchLen, - FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) const { - size_t LastPos = 0; - std::vector<const Pattern *> NotStrings; - - // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL - // bounds; we have not processed variable definitions within the bounded block - // yet so cannot handle any final CHECK-DAG yet; this is handled when going - // over the block again (including the last CHECK-LABEL) in normal mode. - if (!IsLabelScanMode) { - // Match "dag strings" (with mixed "not strings" if any). - LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags); - if (LastPos == StringRef::npos) - return StringRef::npos; - } - - // Match itself from the last position after matching CHECK-DAG. - size_t LastMatchEnd = LastPos; - size_t FirstMatchPos = 0; - // Go match the pattern Count times. Majority of patterns only match with - // count 1 though. - assert(Pat.getCount() != 0 && "pattern count can not be zero"); - for (int i = 1; i <= Pat.getCount(); i++) { - StringRef MatchBuffer = Buffer.substr(LastMatchEnd); - size_t CurrentMatchLen; - // get a match at current start point - Expected<size_t> MatchResult = Pat.match(MatchBuffer, CurrentMatchLen, SM); - - // report - if (!MatchResult) { - PrintNoMatch(true, SM, *this, i, MatchBuffer, Req.VerboseVerbose, Diags, - MatchResult.takeError()); - return StringRef::npos; - } - size_t MatchPos = *MatchResult; - PrintMatch(true, SM, *this, i, MatchBuffer, MatchPos, CurrentMatchLen, Req, - Diags); - if (i == 1) - FirstMatchPos = LastPos + MatchPos; - - // move start point after the match - LastMatchEnd += MatchPos + CurrentMatchLen; - } - // Full match len counts from first match pos. - MatchLen = LastMatchEnd - FirstMatchPos; - - // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT - // or CHECK-NOT - if (!IsLabelScanMode) { - size_t MatchPos = FirstMatchPos - LastPos; - StringRef MatchBuffer = Buffer.substr(LastPos); - StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos); - - // If this check is a "CHECK-NEXT", verify that the previous match was on - // the previous line (i.e. that there is one newline between them). - if (CheckNext(SM, SkippedRegion)) { - ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc, - Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen, - Diags, Req.Verbose); - return StringRef::npos; - } - - // If this check is a "CHECK-SAME", verify that the previous match was on - // the same line (i.e. that there is no newline between them). - if (CheckSame(SM, SkippedRegion)) { - ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc, - Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen, - Diags, Req.Verbose); - return StringRef::npos; - } - - // If this match had "not strings", verify that they don't exist in the - // skipped region. - if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags)) - return StringRef::npos; - } - - return FirstMatchPos; -} - -bool FileCheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { - if (Pat.getCheckTy() != Check::CheckNext && - Pat.getCheckTy() != Check::CheckEmpty) - return false; - - Twine CheckName = - Prefix + - Twine(Pat.getCheckTy() == Check::CheckEmpty ? "-EMPTY" : "-NEXT"); - - // Count the number of newlines between the previous match and this one. - const char *FirstNewLine = nullptr; - unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine); - - if (NumNewLines == 0) { - SM.PrintMessage(Loc, SourceMgr::DK_Error, - CheckName + ": is on the same line as previous match"); - SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, - "'next' match was here"); - SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, - "previous match ended here"); - return true; - } - - if (NumNewLines != 1) { - SM.PrintMessage(Loc, SourceMgr::DK_Error, - CheckName + - ": is not on the line after the previous match"); - SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, - "'next' match was here"); - SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, - "previous match ended here"); - SM.PrintMessage(SMLoc::getFromPointer(FirstNewLine), SourceMgr::DK_Note, - "non-matching line after previous match is here"); - return true; - } - - return false; -} - -bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const { - if (Pat.getCheckTy() != Check::CheckSame) - return false; - - // Count the number of newlines between the previous match and this one. - const char *FirstNewLine = nullptr; - unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine); - - if (NumNewLines != 0) { - SM.PrintMessage(Loc, SourceMgr::DK_Error, - Prefix + - "-SAME: is not on the same line as the previous match"); - SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, - "'next' match was here"); - SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, - "previous match ended here"); - return true; - } - - return false; -} - -bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer, - const std::vector<const Pattern *> &NotStrings, - const FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) const { - for (const Pattern *Pat : NotStrings) { - assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!"); - - size_t MatchLen = 0; - Expected<size_t> MatchResult = Pat->match(Buffer, MatchLen, SM); - - if (!MatchResult) { - PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, - Req.VerboseVerbose, Diags, MatchResult.takeError()); - continue; - } - size_t Pos = *MatchResult; - - PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, Pos, MatchLen, - Req, Diags); - - return true; - } - - return false; -} - -size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, - std::vector<const Pattern *> &NotStrings, - const FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) const { - if (DagNotStrings.empty()) - return 0; - - // The start of the search range. - size_t StartPos = 0; - - struct MatchRange { - size_t Pos; - size_t End; - }; - // A sorted list of ranges for non-overlapping CHECK-DAG matches. Match - // ranges are erased from this list once they are no longer in the search - // range. - std::list<MatchRange> MatchRanges; - - // We need PatItr and PatEnd later for detecting the end of a CHECK-DAG - // group, so we don't use a range-based for loop here. - for (auto PatItr = DagNotStrings.begin(), PatEnd = DagNotStrings.end(); - PatItr != PatEnd; ++PatItr) { - const Pattern &Pat = *PatItr; - assert((Pat.getCheckTy() == Check::CheckDAG || - Pat.getCheckTy() == Check::CheckNot) && - "Invalid CHECK-DAG or CHECK-NOT!"); - - if (Pat.getCheckTy() == Check::CheckNot) { - NotStrings.push_back(&Pat); - continue; - } - - assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!"); - - // CHECK-DAG always matches from the start. - size_t MatchLen = 0, MatchPos = StartPos; - - // Search for a match that doesn't overlap a previous match in this - // CHECK-DAG group. - for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) { - StringRef MatchBuffer = Buffer.substr(MatchPos); - Expected<size_t> MatchResult = Pat.match(MatchBuffer, MatchLen, SM); - // With a group of CHECK-DAGs, a single mismatching means the match on - // that group of CHECK-DAGs fails immediately. - if (!MatchResult) { - PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer, - Req.VerboseVerbose, Diags, MatchResult.takeError()); - return StringRef::npos; - } - size_t MatchPosBuf = *MatchResult; - // Re-calc it as the offset relative to the start of the original string. - MatchPos += MatchPosBuf; - if (Req.VerboseVerbose) - PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos, - MatchLen, Req, Diags); - MatchRange M{MatchPos, MatchPos + MatchLen}; - if (Req.AllowDeprecatedDagOverlap) { - // We don't need to track all matches in this mode, so we just maintain - // one match range that encompasses the current CHECK-DAG group's - // matches. - if (MatchRanges.empty()) - MatchRanges.insert(MatchRanges.end(), M); - else { - auto Block = MatchRanges.begin(); - Block->Pos = std::min(Block->Pos, M.Pos); - Block->End = std::max(Block->End, M.End); - } - break; - } - // Iterate previous matches until overlapping match or insertion point. - bool Overlap = false; - for (; MI != ME; ++MI) { - if (M.Pos < MI->End) { - // !Overlap => New match has no overlap and is before this old match. - // Overlap => New match overlaps this old match. - Overlap = MI->Pos < M.End; - break; - } - } - if (!Overlap) { - // Insert non-overlapping match into list. - MatchRanges.insert(MI, M); - break; - } - if (Req.VerboseVerbose) { - // Due to their verbosity, we don't print verbose diagnostics here if - // we're gathering them for a different rendering, but we always print - // other diagnostics. - if (!Diags) { - SMLoc OldStart = SMLoc::getFromPointer(Buffer.data() + MI->Pos); - SMLoc OldEnd = SMLoc::getFromPointer(Buffer.data() + MI->End); - SMRange OldRange(OldStart, OldEnd); - SM.PrintMessage(OldStart, SourceMgr::DK_Note, - "match discarded, overlaps earlier DAG match here", - {OldRange}); - } else - Diags->rbegin()->MatchTy = FileCheckDiag::MatchFoundButDiscarded; - } - MatchPos = MI->End; - } - if (!Req.VerboseVerbose) - PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos, - MatchLen, Req, Diags); - - // Handle the end of a CHECK-DAG group. - if (std::next(PatItr) == PatEnd || - std::next(PatItr)->getCheckTy() == Check::CheckNot) { - if (!NotStrings.empty()) { - // If there are CHECK-NOTs between two CHECK-DAGs or from CHECK to - // CHECK-DAG, verify that there are no 'not' strings occurred in that - // region. - StringRef SkippedRegion = - Buffer.slice(StartPos, MatchRanges.begin()->Pos); - if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags)) - return StringRef::npos; - // Clear "not strings". - NotStrings.clear(); - } - // All subsequent CHECK-DAGs and CHECK-NOTs should be matched from the - // end of this CHECK-DAG group's match range. - StartPos = MatchRanges.rbegin()->End; - // Don't waste time checking for (impossible) overlaps before that. - MatchRanges.clear(); - } - } - - return StartPos; -} - -static bool ValidatePrefixes(StringRef Kind, StringSet<> &UniquePrefixes, - ArrayRef<StringRef> SuppliedPrefixes) { - for (StringRef Prefix : SuppliedPrefixes) { - if (Prefix.empty()) { - errs() << "error: supplied " << Kind << " prefix must not be the empty " - << "string\n"; - return false; - } - static const Regex Validator("^[a-zA-Z0-9_-]*$"); - if (!Validator.match(Prefix)) { - errs() << "error: supplied " << Kind << " prefix must start with a " - << "letter and contain only alphanumeric characters, hyphens, and " - << "underscores: '" << Prefix << "'\n"; - return false; - } - if (!UniquePrefixes.insert(Prefix).second) { - errs() << "error: supplied " << Kind << " prefix must be unique among " - << "check and comment prefixes: '" << Prefix << "'\n"; - return false; - } - } - return true; -} - -static const char *DefaultCheckPrefixes[] = {"CHECK"}; -static const char *DefaultCommentPrefixes[] = {"COM", "RUN"}; - -bool FileCheck::ValidateCheckPrefixes() { - StringSet<> UniquePrefixes; - // Add default prefixes to catch user-supplied duplicates of them below. - if (Req.CheckPrefixes.empty()) { - for (const char *Prefix : DefaultCheckPrefixes) - UniquePrefixes.insert(Prefix); - } - if (Req.CommentPrefixes.empty()) { - for (const char *Prefix : DefaultCommentPrefixes) - UniquePrefixes.insert(Prefix); - } - // Do not validate the default prefixes, or diagnostics about duplicates might - // incorrectly indicate that they were supplied by the user. - if (!ValidatePrefixes("check", UniquePrefixes, Req.CheckPrefixes)) - return false; - if (!ValidatePrefixes("comment", UniquePrefixes, Req.CommentPrefixes)) - return false; - return true; -} - -Regex FileCheck::buildCheckPrefixRegex() { - if (Req.CheckPrefixes.empty()) { - for (const char *Prefix : DefaultCheckPrefixes) - Req.CheckPrefixes.push_back(Prefix); - Req.IsDefaultCheckPrefix = true; - } - if (Req.CommentPrefixes.empty()) { - for (const char *Prefix : DefaultCommentPrefixes) - Req.CommentPrefixes.push_back(Prefix); - } - - // We already validated the contents of CheckPrefixes and CommentPrefixes so - // just concatenate them as alternatives. - SmallString<32> PrefixRegexStr; - for (size_t I = 0, E = Req.CheckPrefixes.size(); I != E; ++I) { - if (I != 0) - PrefixRegexStr.push_back('|'); - PrefixRegexStr.append(Req.CheckPrefixes[I]); - } - for (StringRef Prefix : Req.CommentPrefixes) { - PrefixRegexStr.push_back('|'); - PrefixRegexStr.append(Prefix); - } - - return Regex(PrefixRegexStr); -} - -Error FileCheckPatternContext::defineCmdlineVariables( - ArrayRef<StringRef> CmdlineDefines, SourceMgr &SM) { - assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() && - "Overriding defined variable with command-line variable definitions"); - - if (CmdlineDefines.empty()) - return Error::success(); - - // Create a string representing the vector of command-line definitions. Each - // definition is on its own line and prefixed with a definition number to - // clarify which definition a given diagnostic corresponds to. - unsigned I = 0; - Error Errs = Error::success(); - std::string CmdlineDefsDiag; - SmallVector<std::pair<size_t, size_t>, 4> CmdlineDefsIndices; - for (StringRef CmdlineDef : CmdlineDefines) { - std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str(); - size_t EqIdx = CmdlineDef.find('='); - if (EqIdx == StringRef::npos) { - CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0)); - continue; - } - // Numeric variable definition. - if (CmdlineDef[0] == '#') { - // Append a copy of the command-line definition adapted to use the same - // format as in the input file to be able to reuse - // parseNumericSubstitutionBlock. - CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str(); - std::string SubstitutionStr = std::string(CmdlineDef); - SubstitutionStr[EqIdx] = ':'; - CmdlineDefsIndices.push_back( - std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size())); - CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str(); - } else { - CmdlineDefsDiag += DefPrefix; - CmdlineDefsIndices.push_back( - std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size())); - CmdlineDefsDiag += (CmdlineDef + "\n").str(); - } - } - - // Create a buffer with fake command line content in order to display - // parsing diagnostic with location information and point to the - // global definition with invalid syntax. - std::unique_ptr<MemoryBuffer> CmdLineDefsDiagBuffer = - MemoryBuffer::getMemBufferCopy(CmdlineDefsDiag, "Global defines"); - StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer(); - SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc()); - - for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) { - StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first, - CmdlineDefIndices.second); - if (CmdlineDef.empty()) { - Errs = joinErrors( - std::move(Errs), - ErrorDiagnostic::get(SM, CmdlineDef, - "missing equal sign in global definition")); - continue; - } - - // Numeric variable definition. - if (CmdlineDef[0] == '#') { - // Now parse the definition both to check that the syntax is correct and - // to create the necessary class instance. - StringRef CmdlineDefExpr = CmdlineDef.substr(1); - Optional<NumericVariable *> DefinedNumericVariable; - Expected<std::unique_ptr<Expression>> ExpressionResult = - Pattern::parseNumericSubstitutionBlock( - CmdlineDefExpr, DefinedNumericVariable, false, None, this, SM); - if (!ExpressionResult) { - Errs = joinErrors(std::move(Errs), ExpressionResult.takeError()); - continue; - } - std::unique_ptr<Expression> Expression = std::move(*ExpressionResult); - // Now evaluate the expression whose value this variable should be set - // to, since the expression of a command-line variable definition should - // only use variables defined earlier on the command-line. If not, this - // is an error and we report it. - Expected<ExpressionValue> Value = Expression->getAST()->eval(); - if (!Value) { - Errs = joinErrors(std::move(Errs), Value.takeError()); - continue; - } - - assert(DefinedNumericVariable && "No variable defined"); - (*DefinedNumericVariable)->setValue(*Value); - - // Record this variable definition. - GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] = - *DefinedNumericVariable; - } else { - // String variable definition. - std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('='); - StringRef CmdlineName = CmdlineNameVal.first; - StringRef OrigCmdlineName = CmdlineName; - Expected<Pattern::VariableProperties> ParseVarResult = - Pattern::parseVariable(CmdlineName, SM); - if (!ParseVarResult) { - Errs = joinErrors(std::move(Errs), ParseVarResult.takeError()); - continue; - } - // Check that CmdlineName does not denote a pseudo variable is only - // composed of the parsed numeric variable. This catches cases like - // "FOO+2" in a "FOO+2=10" definition. - if (ParseVarResult->IsPseudo || !CmdlineName.empty()) { - Errs = joinErrors(std::move(Errs), - ErrorDiagnostic::get( - SM, OrigCmdlineName, - "invalid name in string variable definition '" + - OrigCmdlineName + "'")); - continue; - } - StringRef Name = ParseVarResult->Name; - - // Detect collisions between string and numeric variables when the former - // is created later than the latter. - if (GlobalNumericVariableTable.find(Name) != - GlobalNumericVariableTable.end()) { - Errs = joinErrors(std::move(Errs), - ErrorDiagnostic::get(SM, Name, - "numeric variable with name '" + - Name + "' already exists")); - continue; - } - GlobalVariableTable.insert(CmdlineNameVal); - // Mark the string variable as defined to detect collisions between - // string and numeric variables in defineCmdlineVariables when the latter - // is created later than the former. We cannot reuse GlobalVariableTable - // for this by populating it with an empty string since we would then - // lose the ability to detect the use of an undefined variable in - // match(). - DefinedVariableTable[Name] = true; - } - } - - return Errs; -} - -void FileCheckPatternContext::clearLocalVars() { - SmallVector<StringRef, 16> LocalPatternVars, LocalNumericVars; - for (const StringMapEntry<StringRef> &Var : GlobalVariableTable) - if (Var.first()[0] != '$') - LocalPatternVars.push_back(Var.first()); - - // Numeric substitution reads the value of a variable directly, not via - // GlobalNumericVariableTable. Therefore, we clear local variables by - // clearing their value which will lead to a numeric substitution failure. We - // also mark the variable for removal from GlobalNumericVariableTable since - // this is what defineCmdlineVariables checks to decide that no global - // variable has been defined. - for (const auto &Var : GlobalNumericVariableTable) - if (Var.first()[0] != '$') { - Var.getValue()->clearValue(); - LocalNumericVars.push_back(Var.first()); - } - - for (const auto &Var : LocalPatternVars) - GlobalVariableTable.erase(Var); - for (const auto &Var : LocalNumericVars) - GlobalNumericVariableTable.erase(Var); -} - -bool FileCheck::checkInput(SourceMgr &SM, StringRef Buffer, - std::vector<FileCheckDiag> *Diags) { - bool ChecksFailed = false; - - unsigned i = 0, j = 0, e = CheckStrings->size(); - while (true) { - StringRef CheckRegion; - if (j == e) { - CheckRegion = Buffer; - } else { - const FileCheckString &CheckLabelStr = (*CheckStrings)[j]; - if (CheckLabelStr.Pat.getCheckTy() != Check::CheckLabel) { - ++j; - continue; - } - - // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG - size_t MatchLabelLen = 0; - size_t MatchLabelPos = - CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags); - if (MatchLabelPos == StringRef::npos) - // Immediately bail if CHECK-LABEL fails, nothing else we can do. - return false; - - CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen); - Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen); - ++j; - } - - // Do not clear the first region as it's the one before the first - // CHECK-LABEL and it would clear variables defined on the command-line - // before they get used. - if (i != 0 && Req.EnableVarScope) - PatternContext->clearLocalVars(); - - for (; i != j; ++i) { - const FileCheckString &CheckStr = (*CheckStrings)[i]; - - // Check each string within the scanned region, including a second check - // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) - size_t MatchLen = 0; - size_t MatchPos = - CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags); - - if (MatchPos == StringRef::npos) { - ChecksFailed = true; - i = j; - break; - } - - CheckRegion = CheckRegion.substr(MatchPos + MatchLen); - } - - if (j == e) - break; - } - - // Success if no checks failed. - return !ChecksFailed; -} diff --git a/contrib/llvm-project/llvm/lib/Support/FileCheckImpl.h b/contrib/llvm-project/llvm/lib/Support/FileCheckImpl.h deleted file mode 100644 index 6ca67ec2964c..000000000000 --- a/contrib/llvm-project/llvm/lib/Support/FileCheckImpl.h +++ /dev/null @@ -1,832 +0,0 @@ -//===-- FileCheckImpl.h - Private FileCheck Interface ------------*- 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 defines the private interfaces of FileCheck. Its purpose is to -// allow unit testing of FileCheck and to separate the interface from the -// implementation. It is only meant to be used by FileCheck. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_SUPPORT_FILECHECKIMPL_H -#define LLVM_LIB_SUPPORT_FILECHECKIMPL_H - -#include "llvm/Support/FileCheck.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/SourceMgr.h" -#include <map> -#include <string> -#include <vector> - -namespace llvm { - -//===----------------------------------------------------------------------===// -// Numeric substitution handling code. -//===----------------------------------------------------------------------===// - -class ExpressionValue; - -/// Type representing the format an expression value should be textualized into -/// for matching. Used to represent both explicit format specifiers as well as -/// implicit format from using numeric variables. -struct ExpressionFormat { - enum class Kind { - /// Denote absence of format. Used for implicit format of literals and - /// empty expressions. - NoFormat, - /// Value is an unsigned integer and should be printed as a decimal number. - Unsigned, - /// Value is a signed integer and should be printed as a decimal number. - Signed, - /// Value should be printed as an uppercase hex number. - HexUpper, - /// Value should be printed as a lowercase hex number. - HexLower - }; - -private: - Kind Value; - -public: - /// Evaluates a format to true if it can be used in a match. - explicit operator bool() const { return Value != Kind::NoFormat; } - - /// Define format equality: formats are equal if neither is NoFormat and - /// their kinds are the same. - bool operator==(const ExpressionFormat &Other) const { - return Value != Kind::NoFormat && Value == Other.Value; - } - - bool operator!=(const ExpressionFormat &Other) const { - return !(*this == Other); - } - - bool operator==(Kind OtherValue) const { return Value == OtherValue; } - - bool operator!=(Kind OtherValue) const { return !(*this == OtherValue); } - - /// \returns the format specifier corresponding to this format as a string. - StringRef toString() const; - - ExpressionFormat() : Value(Kind::NoFormat){}; - explicit ExpressionFormat(Kind Value) : Value(Value){}; - - /// \returns a wildcard regular expression StringRef that matches any value - /// in the format represented by this instance, or an error if the format is - /// NoFormat. - Expected<StringRef> getWildcardRegex() const; - - /// \returns the string representation of \p Value in the format represented - /// by this instance, or an error if conversion to this format failed or the - /// format is NoFormat. - Expected<std::string> getMatchingString(ExpressionValue Value) const; - - /// \returns the value corresponding to string representation \p StrVal - /// according to the matching format represented by this instance or an error - /// with diagnostic against \p SM if \p StrVal does not correspond to a valid - /// and representable value. - Expected<ExpressionValue> valueFromStringRepr(StringRef StrVal, - const SourceMgr &SM) const; -}; - -/// Class to represent an overflow error that might result when manipulating a -/// value. -class OverflowError : public ErrorInfo<OverflowError> { -public: - static char ID; - - std::error_code convertToErrorCode() const override { - return std::make_error_code(std::errc::value_too_large); - } - - void log(raw_ostream &OS) const override { OS << "overflow error"; } -}; - -/// Class representing a numeric value. -class ExpressionValue { -private: - uint64_t Value; - bool Negative; - -public: - template <class T> - explicit ExpressionValue(T Val) : Value(Val), Negative(Val < 0) {} - - bool operator==(const ExpressionValue &Other) const { - return Value == Other.Value && isNegative() == Other.isNegative(); - } - - bool operator!=(const ExpressionValue &Other) const { - return !(*this == Other); - } - - /// Returns true if value is signed and negative, false otherwise. - bool isNegative() const { - assert((Value != 0 || !Negative) && "Unexpected negative zero!"); - return Negative; - } - - /// \returns the value as a signed integer or an error if the value is out of - /// range. - Expected<int64_t> getSignedValue() const; - - /// \returns the value as an unsigned integer or an error if the value is out - /// of range. - Expected<uint64_t> getUnsignedValue() const; - - /// \returns an unsigned ExpressionValue instance whose value is the absolute - /// value to this object's value. - ExpressionValue getAbsolute() const; -}; - -/// Performs operation and \returns its result or an error in case of failure, -/// such as if an overflow occurs. -Expected<ExpressionValue> operator+(const ExpressionValue &Lhs, - const ExpressionValue &Rhs); -Expected<ExpressionValue> operator-(const ExpressionValue &Lhs, - const ExpressionValue &Rhs); -Expected<ExpressionValue> operator*(const ExpressionValue &Lhs, - const ExpressionValue &Rhs); -Expected<ExpressionValue> operator/(const ExpressionValue &Lhs, - const ExpressionValue &Rhs); -Expected<ExpressionValue> max(const ExpressionValue &Lhs, - const ExpressionValue &Rhs); -Expected<ExpressionValue> min(const ExpressionValue &Lhs, - const ExpressionValue &Rhs); - -/// Base class representing the AST of a given expression. -class ExpressionAST { -private: - StringRef ExpressionStr; - -public: - ExpressionAST(StringRef ExpressionStr) : ExpressionStr(ExpressionStr) {} - - virtual ~ExpressionAST() = default; - - StringRef getExpressionStr() const { return ExpressionStr; } - - /// Evaluates and \returns the value of the expression represented by this - /// AST or an error if evaluation fails. - virtual Expected<ExpressionValue> eval() const = 0; - - /// \returns either the implicit format of this AST, a diagnostic against - /// \p SM if implicit formats of the AST's components conflict, or NoFormat - /// if the AST has no implicit format (e.g. AST is made up of a single - /// literal). - virtual Expected<ExpressionFormat> - getImplicitFormat(const SourceMgr &SM) const { - return ExpressionFormat(); - } -}; - -/// Class representing an unsigned literal in the AST of an expression. -class ExpressionLiteral : public ExpressionAST { -private: - /// Actual value of the literal. - ExpressionValue Value; - -public: - template <class T> - explicit ExpressionLiteral(StringRef ExpressionStr, T Val) - : ExpressionAST(ExpressionStr), Value(Val) {} - - /// \returns the literal's value. - Expected<ExpressionValue> eval() const override { return Value; } -}; - -/// Class to represent an undefined variable error, which quotes that -/// variable's name when printed. -class UndefVarError : public ErrorInfo<UndefVarError> { -private: - StringRef VarName; - -public: - static char ID; - - UndefVarError(StringRef VarName) : VarName(VarName) {} - - StringRef getVarName() const { return VarName; } - - std::error_code convertToErrorCode() const override { - return inconvertibleErrorCode(); - } - - /// Print name of variable associated with this error. - void log(raw_ostream &OS) const override { - OS << "\""; - OS.write_escaped(VarName) << "\""; - } -}; - -/// Class representing an expression and its matching format. -class Expression { -private: - /// Pointer to AST of the expression. - std::unique_ptr<ExpressionAST> AST; - - /// Format to use (e.g. hex upper case letters) when matching the value. - ExpressionFormat Format; - -public: - /// Generic constructor for an expression represented by the given \p AST and - /// whose matching format is \p Format. - Expression(std::unique_ptr<ExpressionAST> AST, ExpressionFormat Format) - : AST(std::move(AST)), Format(Format) {} - - /// \returns pointer to AST of the expression. Pointer is guaranteed to be - /// valid as long as this object is. - ExpressionAST *getAST() const { return AST.get(); } - - ExpressionFormat getFormat() const { return Format; } -}; - -/// Class representing a numeric variable and its associated current value. -class NumericVariable { -private: - /// Name of the numeric variable. - StringRef Name; - - /// Format to use for expressions using this variable without an explicit - /// format. - ExpressionFormat ImplicitFormat; - - /// Value of numeric variable, if defined, or None otherwise. - Optional<ExpressionValue> Value; - - /// Line number where this variable is defined, or None if defined before - /// input is parsed. Used to determine whether a variable is defined on the - /// same line as a given use. - Optional<size_t> DefLineNumber; - -public: - /// Constructor for a variable \p Name with implicit format \p ImplicitFormat - /// defined at line \p DefLineNumber or defined before input is parsed if - /// \p DefLineNumber is None. - explicit NumericVariable(StringRef Name, ExpressionFormat ImplicitFormat, - Optional<size_t> DefLineNumber = None) - : Name(Name), ImplicitFormat(ImplicitFormat), - DefLineNumber(DefLineNumber) {} - - /// \returns name of this numeric variable. - StringRef getName() const { return Name; } - - /// \returns implicit format of this numeric variable. - ExpressionFormat getImplicitFormat() const { return ImplicitFormat; } - - /// \returns this variable's value. - Optional<ExpressionValue> getValue() const { return Value; } - - /// Sets value of this numeric variable to \p NewValue. - void setValue(ExpressionValue NewValue) { Value = NewValue; } - - /// Clears value of this numeric variable, regardless of whether it is - /// currently defined or not. - void clearValue() { Value = None; } - - /// \returns the line number where this variable is defined, if any, or None - /// if defined before input is parsed. - Optional<size_t> getDefLineNumber() const { return DefLineNumber; } -}; - -/// Class representing the use of a numeric variable in the AST of an -/// expression. -class NumericVariableUse : public ExpressionAST { -private: - /// Pointer to the class instance for the variable this use is about. - NumericVariable *Variable; - -public: - NumericVariableUse(StringRef Name, NumericVariable *Variable) - : ExpressionAST(Name), Variable(Variable) {} - /// \returns the value of the variable referenced by this instance. - Expected<ExpressionValue> eval() const override; - - /// \returns implicit format of this numeric variable. - Expected<ExpressionFormat> - getImplicitFormat(const SourceMgr &SM) const override { - return Variable->getImplicitFormat(); - } -}; - -/// Type of functions evaluating a given binary operation. -using binop_eval_t = Expected<ExpressionValue> (*)(const ExpressionValue &, - const ExpressionValue &); - -/// Class representing a single binary operation in the AST of an expression. -class BinaryOperation : public ExpressionAST { -private: - /// Left operand. - std::unique_ptr<ExpressionAST> LeftOperand; - - /// Right operand. - std::unique_ptr<ExpressionAST> RightOperand; - - /// Pointer to function that can evaluate this binary operation. - binop_eval_t EvalBinop; - -public: - BinaryOperation(StringRef ExpressionStr, binop_eval_t EvalBinop, - std::unique_ptr<ExpressionAST> LeftOp, - std::unique_ptr<ExpressionAST> RightOp) - : ExpressionAST(ExpressionStr), EvalBinop(EvalBinop) { - LeftOperand = std::move(LeftOp); - RightOperand = std::move(RightOp); - } - - /// Evaluates the value of the binary operation represented by this AST, - /// using EvalBinop on the result of recursively evaluating the operands. - /// \returns the expression value or an error if an undefined numeric - /// variable is used in one of the operands. - Expected<ExpressionValue> eval() const override; - - /// \returns the implicit format of this AST, if any, a diagnostic against - /// \p SM if the implicit formats of the AST's components conflict, or no - /// format if the AST has no implicit format (e.g. AST is made of a single - /// literal). - Expected<ExpressionFormat> - getImplicitFormat(const SourceMgr &SM) const override; -}; - -class FileCheckPatternContext; - -/// Class representing a substitution to perform in the RegExStr string. -class Substitution { -protected: - /// Pointer to a class instance holding, among other things, the table with - /// the values of live string variables at the start of any given CHECK line. - /// Used for substituting string variables with the text they were defined - /// as. Expressions are linked to the numeric variables they use at - /// parse time and directly access the value of the numeric variable to - /// evaluate their value. - FileCheckPatternContext *Context; - - /// The string that needs to be substituted for something else. For a - /// string variable this is its name, otherwise this is the whole expression. - StringRef FromStr; - - // Index in RegExStr of where to do the substitution. - size_t InsertIdx; - -public: - Substitution(FileCheckPatternContext *Context, StringRef VarName, - size_t InsertIdx) - : Context(Context), FromStr(VarName), InsertIdx(InsertIdx) {} - - virtual ~Substitution() = default; - - /// \returns the string to be substituted for something else. - StringRef getFromString() const { return FromStr; } - - /// \returns the index where the substitution is to be performed in RegExStr. - size_t getIndex() const { return InsertIdx; } - - /// \returns a string containing the result of the substitution represented - /// by this class instance or an error if substitution failed. - virtual Expected<std::string> getResult() const = 0; -}; - -class StringSubstitution : public Substitution { -public: - StringSubstitution(FileCheckPatternContext *Context, StringRef VarName, - size_t InsertIdx) - : Substitution(Context, VarName, InsertIdx) {} - - /// \returns the text that the string variable in this substitution matched - /// when defined, or an error if the variable is undefined. - Expected<std::string> getResult() const override; -}; - -class NumericSubstitution : public Substitution { -private: - /// Pointer to the class representing the expression whose value is to be - /// substituted. - std::unique_ptr<Expression> ExpressionPointer; - -public: - NumericSubstitution(FileCheckPatternContext *Context, StringRef ExpressionStr, - std::unique_ptr<Expression> ExpressionPointer, - size_t InsertIdx) - : Substitution(Context, ExpressionStr, InsertIdx), - ExpressionPointer(std::move(ExpressionPointer)) {} - - /// \returns a string containing the result of evaluating the expression in - /// this substitution, or an error if evaluation failed. - Expected<std::string> getResult() const override; -}; - -//===----------------------------------------------------------------------===// -// Pattern handling code. -//===----------------------------------------------------------------------===// - -/// Class holding the Pattern global state, shared by all patterns: tables -/// holding values of variables and whether they are defined or not at any -/// given time in the matching process. -class FileCheckPatternContext { - friend class Pattern; - -private: - /// When matching a given pattern, this holds the value of all the string - /// variables defined in previous patterns. In a pattern, only the last - /// definition for a given variable is recorded in this table. - /// Back-references are used for uses after any the other definition. - StringMap<StringRef> GlobalVariableTable; - - /// Map of all string variables defined so far. Used at parse time to detect - /// a name conflict between a numeric variable and a string variable when - /// the former is defined on a later line than the latter. - StringMap<bool> DefinedVariableTable; - - /// When matching a given pattern, this holds the pointers to the classes - /// representing the numeric variables defined in previous patterns. When - /// matching a pattern all definitions for that pattern are recorded in the - /// NumericVariableDefs table in the Pattern instance of that pattern. - StringMap<NumericVariable *> GlobalNumericVariableTable; - - /// Pointer to the class instance representing the @LINE pseudo variable for - /// easily updating its value. - NumericVariable *LineVariable = nullptr; - - /// Vector holding pointers to all parsed numeric variables. Used to - /// automatically free them once they are guaranteed to no longer be used. - std::vector<std::unique_ptr<NumericVariable>> NumericVariables; - - /// Vector holding pointers to all parsed expressions. Used to automatically - /// free the expressions once they are guaranteed to no longer be used. - std::vector<std::unique_ptr<Expression>> Expressions; - - /// Vector holding pointers to all substitutions. Used to automatically free - /// them once they are guaranteed to no longer be used. - std::vector<std::unique_ptr<Substitution>> Substitutions; - -public: - /// \returns the value of string variable \p VarName or an error if no such - /// variable has been defined. - Expected<StringRef> getPatternVarValue(StringRef VarName); - - /// Defines string and numeric variables from definitions given on the - /// command line, passed as a vector of [#]VAR=VAL strings in - /// \p CmdlineDefines. \returns an error list containing diagnostics against - /// \p SM for all definition parsing failures, if any, or Success otherwise. - Error defineCmdlineVariables(ArrayRef<StringRef> CmdlineDefines, - SourceMgr &SM); - - /// Create @LINE pseudo variable. Value is set when pattern are being - /// matched. - void createLineVariable(); - - /// Undefines local variables (variables whose name does not start with a '$' - /// sign), i.e. removes them from GlobalVariableTable and from - /// GlobalNumericVariableTable and also clears the value of numeric - /// variables. - void clearLocalVars(); - -private: - /// Makes a new numeric variable and registers it for destruction when the - /// context is destroyed. - template <class... Types> NumericVariable *makeNumericVariable(Types... args); - - /// Makes a new string substitution and registers it for destruction when the - /// context is destroyed. - Substitution *makeStringSubstitution(StringRef VarName, size_t InsertIdx); - - /// Makes a new numeric substitution and registers it for destruction when - /// the context is destroyed. - Substitution *makeNumericSubstitution(StringRef ExpressionStr, - std::unique_ptr<Expression> Expression, - size_t InsertIdx); -}; - -/// Class to represent an error holding a diagnostic with location information -/// used when printing it. -class ErrorDiagnostic : public ErrorInfo<ErrorDiagnostic> { -private: - SMDiagnostic Diagnostic; - -public: - static char ID; - - ErrorDiagnostic(SMDiagnostic &&Diag) : Diagnostic(Diag) {} - - std::error_code convertToErrorCode() const override { - return inconvertibleErrorCode(); - } - - /// Print diagnostic associated with this error when printing the error. - void log(raw_ostream &OS) const override { Diagnostic.print(nullptr, OS); } - - static Error get(const SourceMgr &SM, SMLoc Loc, const Twine &ErrMsg) { - return make_error<ErrorDiagnostic>( - SM.GetMessage(Loc, SourceMgr::DK_Error, ErrMsg)); - } - - static Error get(const SourceMgr &SM, StringRef Buffer, const Twine &ErrMsg) { - return get(SM, SMLoc::getFromPointer(Buffer.data()), ErrMsg); - } -}; - -class NotFoundError : public ErrorInfo<NotFoundError> { -public: - static char ID; - - std::error_code convertToErrorCode() const override { - return inconvertibleErrorCode(); - } - - /// Print diagnostic associated with this error when printing the error. - void log(raw_ostream &OS) const override { - OS << "String not found in input"; - } -}; - -class Pattern { - SMLoc PatternLoc; - - /// A fixed string to match as the pattern or empty if this pattern requires - /// a regex match. - StringRef FixedStr; - - /// A regex string to match as the pattern or empty if this pattern requires - /// a fixed string to match. - std::string RegExStr; - - /// Entries in this vector represent a substitution of a string variable or - /// an expression in the RegExStr regex at match time. For example, in the - /// case of a CHECK directive with the pattern "foo[[bar]]baz[[#N+1]]", - /// RegExStr will contain "foobaz" and we'll get two entries in this vector - /// that tells us to insert the value of string variable "bar" at offset 3 - /// and the value of expression "N+1" at offset 6. - std::vector<Substitution *> Substitutions; - - /// Maps names of string variables defined in a pattern to the number of - /// their parenthesis group in RegExStr capturing their last definition. - /// - /// E.g. for the pattern "foo[[bar:.*]]baz([[bar]][[QUUX]][[bar:.*]])", - /// RegExStr will be "foo(.*)baz(\1<quux value>(.*))" where <quux value> is - /// the value captured for QUUX on the earlier line where it was defined, and - /// VariableDefs will map "bar" to the third parenthesis group which captures - /// the second definition of "bar". - /// - /// Note: uses std::map rather than StringMap to be able to get the key when - /// iterating over values. - std::map<StringRef, unsigned> VariableDefs; - - /// Structure representing the definition of a numeric variable in a pattern. - /// It holds the pointer to the class instance holding the value and matching - /// format of the numeric variable whose value is being defined and the - /// number of the parenthesis group in RegExStr to capture that value. - struct NumericVariableMatch { - /// Pointer to class instance holding the value and matching format of the - /// numeric variable being defined. - NumericVariable *DefinedNumericVariable; - - /// Number of the parenthesis group in RegExStr that captures the value of - /// this numeric variable definition. - unsigned CaptureParenGroup; - }; - - /// Holds the number of the parenthesis group in RegExStr and pointer to the - /// corresponding NumericVariable class instance of all numeric variable - /// definitions. Used to set the matched value of all those variables. - StringMap<NumericVariableMatch> NumericVariableDefs; - - /// Pointer to a class instance holding the global state shared by all - /// patterns: - /// - separate tables with the values of live string and numeric variables - /// respectively at the start of any given CHECK line; - /// - table holding whether a string variable has been defined at any given - /// point during the parsing phase. - FileCheckPatternContext *Context; - - Check::FileCheckType CheckTy; - - /// Line number for this CHECK pattern or None if it is an implicit pattern. - /// Used to determine whether a variable definition is made on an earlier - /// line to the one with this CHECK. - Optional<size_t> LineNumber; - - /// Ignore case while matching if set to true. - bool IgnoreCase = false; - -public: - Pattern(Check::FileCheckType Ty, FileCheckPatternContext *Context, - Optional<size_t> Line = None) - : Context(Context), CheckTy(Ty), LineNumber(Line) {} - - /// \returns the location in source code. - SMLoc getLoc() const { return PatternLoc; } - - /// \returns the pointer to the global state for all patterns in this - /// FileCheck instance. - FileCheckPatternContext *getContext() const { return Context; } - - /// \returns whether \p C is a valid first character for a variable name. - static bool isValidVarNameStart(char C); - - /// Parsing information about a variable. - struct VariableProperties { - StringRef Name; - bool IsPseudo; - }; - - /// Parses the string at the start of \p Str for a variable name. \returns - /// a VariableProperties structure holding the variable name and whether it - /// is the name of a pseudo variable, or an error holding a diagnostic - /// against \p SM if parsing fail. If parsing was successful, also strips - /// \p Str from the variable name. - static Expected<VariableProperties> parseVariable(StringRef &Str, - const SourceMgr &SM); - /// Parses \p Expr for a numeric substitution block at line \p LineNumber, - /// or before input is parsed if \p LineNumber is None. Parameter - /// \p IsLegacyLineExpr indicates whether \p Expr should be a legacy @LINE - /// expression and \p Context points to the class instance holding the live - /// string and numeric variables. \returns a pointer to the class instance - /// representing the expression whose value must be substitued, or an error - /// holding a diagnostic against \p SM if parsing fails. If substitution was - /// successful, sets \p DefinedNumericVariable to point to the class - /// representing the numeric variable defined in this numeric substitution - /// block, or None if this block does not define any variable. - static Expected<std::unique_ptr<Expression>> parseNumericSubstitutionBlock( - StringRef Expr, Optional<NumericVariable *> &DefinedNumericVariable, - bool IsLegacyLineExpr, Optional<size_t> LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM); - /// Parses the pattern in \p PatternStr and initializes this Pattern instance - /// accordingly. - /// - /// \p Prefix provides which prefix is being matched, \p Req describes the - /// global options that influence the parsing such as whitespace - /// canonicalization, \p SM provides the SourceMgr used for error reports. - /// \returns true in case of an error, false otherwise. - bool parsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM, - const FileCheckRequest &Req); - /// Matches the pattern string against the input buffer \p Buffer - /// - /// \returns the position that is matched or an error indicating why matching - /// failed. If there is a match, updates \p MatchLen with the size of the - /// matched string. - /// - /// The GlobalVariableTable StringMap in the FileCheckPatternContext class - /// instance provides the current values of FileCheck string variables and is - /// updated if this match defines new values. Likewise, the - /// GlobalNumericVariableTable StringMap in the same class provides the - /// current values of FileCheck numeric variables and is updated if this - /// match defines new numeric values. - Expected<size_t> match(StringRef Buffer, size_t &MatchLen, - const SourceMgr &SM) const; - /// Prints the value of successful substitutions or the name of the undefined - /// string or numeric variables preventing a successful substitution. - void printSubstitutions(const SourceMgr &SM, StringRef Buffer, - SMRange MatchRange = None) const; - void printFuzzyMatch(const SourceMgr &SM, StringRef Buffer, - std::vector<FileCheckDiag> *Diags) const; - - bool hasVariable() const { - return !(Substitutions.empty() && VariableDefs.empty()); - } - - Check::FileCheckType getCheckTy() const { return CheckTy; } - - int getCount() const { return CheckTy.getCount(); } - -private: - bool AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM); - void AddBackrefToRegEx(unsigned BackrefNum); - /// Computes an arbitrary estimate for the quality of matching this pattern - /// at the start of \p Buffer; a distance of zero should correspond to a - /// perfect match. - unsigned computeMatchDistance(StringRef Buffer) const; - /// Finds the closing sequence of a regex variable usage or definition. - /// - /// \p Str has to point in the beginning of the definition (right after the - /// opening sequence). \p SM holds the SourceMgr used for error reporting. - /// \returns the offset of the closing sequence within Str, or npos if it - /// was not found. - static size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM); - - /// Parses \p Expr for the name of a numeric variable to be defined at line - /// \p LineNumber, or before input is parsed if \p LineNumber is None. - /// \returns a pointer to the class instance representing that variable, - /// creating it if needed, or an error holding a diagnostic against \p SM - /// should defining such a variable be invalid. - static Expected<NumericVariable *> parseNumericVariableDefinition( - StringRef &Expr, FileCheckPatternContext *Context, - Optional<size_t> LineNumber, ExpressionFormat ImplicitFormat, - const SourceMgr &SM); - /// Parses \p Name as a (pseudo if \p IsPseudo is true) numeric variable use - /// at line \p LineNumber, or before input is parsed if \p LineNumber is - /// None. Parameter \p Context points to the class instance holding the live - /// string and numeric variables. \returns the pointer to the class instance - /// representing that variable if successful, or an error holding a - /// diagnostic against \p SM otherwise. - static Expected<std::unique_ptr<NumericVariableUse>> parseNumericVariableUse( - StringRef Name, bool IsPseudo, Optional<size_t> LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM); - enum class AllowedOperand { LineVar, LegacyLiteral, Any }; - /// Parses \p Expr for use of a numeric operand at line \p LineNumber, or - /// before input is parsed if \p LineNumber is None. Accepts literal values, - /// numeric variables and function calls, depending on the value of \p AO. - /// \p MaybeInvalidConstraint indicates whether the text being parsed could - /// be an invalid constraint. \p Context points to the class instance holding - /// the live string and numeric variables. \returns the class representing - /// that operand in the AST of the expression or an error holding a - /// diagnostic against \p SM otherwise. If \p Expr starts with a "(" this - /// function will attempt to parse a parenthesized expression. - static Expected<std::unique_ptr<ExpressionAST>> - parseNumericOperand(StringRef &Expr, AllowedOperand AO, bool ConstraintParsed, - Optional<size_t> LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM); - /// Parses and updates \p RemainingExpr for a binary operation at line - /// \p LineNumber, or before input is parsed if \p LineNumber is None. The - /// left operand of this binary operation is given in \p LeftOp and \p Expr - /// holds the string for the full expression, including the left operand. - /// Parameter \p IsLegacyLineExpr indicates whether we are parsing a legacy - /// @LINE expression. Parameter \p Context points to the class instance - /// holding the live string and numeric variables. \returns the class - /// representing the binary operation in the AST of the expression, or an - /// error holding a diagnostic against \p SM otherwise. - static Expected<std::unique_ptr<ExpressionAST>> - parseBinop(StringRef Expr, StringRef &RemainingExpr, - std::unique_ptr<ExpressionAST> LeftOp, bool IsLegacyLineExpr, - Optional<size_t> LineNumber, FileCheckPatternContext *Context, - const SourceMgr &SM); - - /// Parses a parenthesized expression inside \p Expr at line \p LineNumber, or - /// before input is parsed if \p LineNumber is None. \p Expr must start with - /// a '('. Accepts both literal values and numeric variables. Parameter \p - /// Context points to the class instance holding the live string and numeric - /// variables. \returns the class representing that operand in the AST of the - /// expression or an error holding a diagnostic against \p SM otherwise. - static Expected<std::unique_ptr<ExpressionAST>> - parseParenExpr(StringRef &Expr, Optional<size_t> LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM); - - /// Parses \p Expr for an argument list belonging to a call to function \p - /// FuncName at line \p LineNumber, or before input is parsed if \p LineNumber - /// is None. Parameter \p FuncLoc is the source location used for diagnostics. - /// Parameter \p Context points to the class instance holding the live string - /// and numeric variables. \returns the class representing that call in the - /// AST of the expression or an error holding a diagnostic against \p SM - /// otherwise. - static Expected<std::unique_ptr<ExpressionAST>> - parseCallExpr(StringRef &Expr, StringRef FuncName, - Optional<size_t> LineNumber, FileCheckPatternContext *Context, - const SourceMgr &SM); -}; - -//===----------------------------------------------------------------------===// -// Check Strings. -//===----------------------------------------------------------------------===// - -/// A check that we found in the input file. -struct FileCheckString { - /// The pattern to match. - Pattern Pat; - - /// Which prefix name this check matched. - StringRef Prefix; - - /// The location in the match file that the check string was specified. - SMLoc Loc; - - /// All of the strings that are disallowed from occurring between this match - /// string and the previous one (or start of file). - std::vector<Pattern> DagNotStrings; - - FileCheckString(const Pattern &P, StringRef S, SMLoc L) - : Pat(P), Prefix(S), Loc(L) {} - - /// Matches check string and its "not strings" and/or "dag strings". - size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode, - size_t &MatchLen, FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) const; - - /// Verifies that there is a single line in the given \p Buffer. Errors are - /// reported against \p SM. - bool CheckNext(const SourceMgr &SM, StringRef Buffer) const; - /// Verifies that there is no newline in the given \p Buffer. Errors are - /// reported against \p SM. - bool CheckSame(const SourceMgr &SM, StringRef Buffer) const; - /// Verifies that none of the strings in \p NotStrings are found in the given - /// \p Buffer. Errors are reported against \p SM and diagnostics recorded in - /// \p Diags according to the verbosity level set in \p Req. - bool CheckNot(const SourceMgr &SM, StringRef Buffer, - const std::vector<const Pattern *> &NotStrings, - const FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) const; - /// Matches "dag strings" and their mixed "not strings". - size_t CheckDag(const SourceMgr &SM, StringRef Buffer, - std::vector<const Pattern *> &NotStrings, - const FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) const; -}; - -} // namespace llvm - -#endif diff --git a/contrib/llvm-project/llvm/lib/Support/FileCollector.cpp b/contrib/llvm-project/llvm/lib/Support/FileCollector.cpp index 59755556a5a3..99482075f675 100644 --- a/contrib/llvm-project/llvm/lib/Support/FileCollector.cpp +++ b/contrib/llvm-project/llvm/lib/Support/FileCollector.cpp @@ -15,6 +15,22 @@ using namespace llvm; +FileCollectorBase::FileCollectorBase() = default; +FileCollectorBase::~FileCollectorBase() = default; + +void FileCollectorBase::addFile(const Twine &File) { + std::lock_guard<std::mutex> lock(Mutex); + std::string FileStr = File.str(); + if (markAsSeen(FileStr)) + addFileImpl(FileStr); +} + +void FileCollectorBase::addDirectory(const Twine &Dir) { + assert(sys::fs::is_directory(Dir)); + std::error_code EC; + addDirectoryImpl(Dir, vfs::getRealFileSystem(), EC); +} + static bool isCaseSensitivePath(StringRef Path) { SmallString<256> TmpDest = Path, UpperDest, RealDest; @@ -37,74 +53,82 @@ FileCollector::FileCollector(std::string Root, std::string OverlayRoot) : Root(std::move(Root)), OverlayRoot(std::move(OverlayRoot)) { } -bool FileCollector::getRealPath(StringRef SrcPath, - SmallVectorImpl<char> &Result) { +void FileCollector::PathCanonicalizer::updateWithRealPath( + SmallVectorImpl<char> &Path) { + StringRef SrcPath(Path.begin(), Path.size()); + StringRef Filename = sys::path::filename(SrcPath); + StringRef Directory = sys::path::parent_path(SrcPath); + + // Use real_path to fix any symbolic link component present in the directory + // part of the path, caching the search because computing the real path is + // expensive. SmallString<256> RealPath; - StringRef FileName = sys::path::filename(SrcPath); - std::string Directory = sys::path::parent_path(SrcPath).str(); - auto DirWithSymlink = SymlinkMap.find(Directory); - - // Use real_path to fix any symbolic link component present in a path. - // Computing the real path is expensive, cache the search through the parent - // path Directory. - if (DirWithSymlink == SymlinkMap.end()) { - auto EC = sys::fs::real_path(Directory, RealPath); - if (EC) - return false; - SymlinkMap[Directory] = std::string(RealPath.str()); + auto DirWithSymlink = CachedDirs.find(Directory); + if (DirWithSymlink == CachedDirs.end()) { + // FIXME: Should this be a call to FileSystem::getRealpath(), in some + // cases? What if there is nothing on disk? + if (sys::fs::real_path(Directory, RealPath)) + return; + CachedDirs[Directory] = std::string(RealPath.str()); } else { RealPath = DirWithSymlink->second; } - sys::path::append(RealPath, FileName); - Result.swap(RealPath); - return true; -} - -void FileCollector::addFile(const Twine &File) { - std::lock_guard<std::mutex> lock(Mutex); - std::string FileStr = File.str(); - if (markAsSeen(FileStr)) - addFileImpl(FileStr); -} + // Finish recreating the path by appending the original filename, since we + // don't need to resolve symlinks in the filename. + // + // FIXME: If we can cope with this, maybe we can cope without calling + // getRealPath() at all when there's no ".." component. + sys::path::append(RealPath, Filename); -void FileCollector::addDirectory(const Twine &Dir) { - assert(sys::fs::is_directory(Dir)); - std::error_code EC; - addDirectoryImpl(Dir, vfs::getRealFileSystem(), EC); + // Swap to create the output. + Path.swap(RealPath); } -void FileCollector::addFileImpl(StringRef SrcPath) { +/// Make Path absolute. +static void makeAbsolute(SmallVectorImpl<char> &Path) { // We need an absolute src path to append to the root. - SmallString<256> AbsoluteSrc = SrcPath; - sys::fs::make_absolute(AbsoluteSrc); + sys::fs::make_absolute(Path); // Canonicalize src to a native path to avoid mixed separator styles. - sys::path::native(AbsoluteSrc); + sys::path::native(Path); // Remove redundant leading "./" pieces and consecutive separators. - AbsoluteSrc = sys::path::remove_leading_dotslash(AbsoluteSrc); + Path.erase(Path.begin(), sys::path::remove_leading_dotslash( + StringRef(Path.begin(), Path.size())) + .begin()); +} - // Canonicalize the source path by removing "..", "." components. - SmallString<256> VirtualPath = AbsoluteSrc; - sys::path::remove_dots(VirtualPath, /*remove_dot_dot=*/true); +FileCollector::PathCanonicalizer::PathStorage +FileCollector::PathCanonicalizer::canonicalize(StringRef SrcPath) { + PathStorage Paths; + Paths.VirtualPath = SrcPath; + makeAbsolute(Paths.VirtualPath); // If a ".." component is present after a symlink component, remove_dots may // lead to the wrong real destination path. Let the source be canonicalized // like that but make sure we always use the real path for the destination. - SmallString<256> CopyFrom; - if (!getRealPath(AbsoluteSrc, CopyFrom)) - CopyFrom = VirtualPath; + Paths.CopyFrom = Paths.VirtualPath; + updateWithRealPath(Paths.CopyFrom); + + // Canonicalize the virtual path by removing "..", "." components. + sys::path::remove_dots(Paths.VirtualPath, /*remove_dot_dot=*/true); + + return Paths; +} + +void FileCollector::addFileImpl(StringRef SrcPath) { + PathCanonicalizer::PathStorage Paths = Canonicalizer.canonicalize(SrcPath); SmallString<256> DstPath = StringRef(Root); - sys::path::append(DstPath, sys::path::relative_path(CopyFrom)); + sys::path::append(DstPath, sys::path::relative_path(Paths.CopyFrom)); // Always map a canonical src path to its real path into the YAML, by doing // this we map different virtual src paths to the same entry in the VFS // overlay, which is a way to emulate symlink inside the VFS; this is also // needed for correctness, not doing that can lead to module redefinition // errors. - addFileToMapping(VirtualPath, DstPath); + addFileToMapping(Paths.VirtualPath, DstPath); } llvm::vfs::directory_iterator @@ -158,14 +182,6 @@ std::error_code FileCollector::copyFiles(bool StopOnError) { std::lock_guard<std::mutex> lock(Mutex); for (auto &entry : VFSWriter.getMappings()) { - // Create directory tree. - if (std::error_code EC = - sys::fs::create_directories(sys::path::parent_path(entry.RPath), - /*IgnoreExisting=*/true)) { - if (StopOnError) - return EC; - } - // Get the status of the original file/directory. sys::fs::file_status Stat; if (std::error_code EC = sys::fs::status(entry.VPath, Stat)) { @@ -174,6 +190,18 @@ std::error_code FileCollector::copyFiles(bool StopOnError) { continue; } + // Continue if the file doesn't exist. + if (Stat.type() == sys::fs::file_type::file_not_found) + continue; + + // Create directory tree. + if (std::error_code EC = + sys::fs::create_directories(sys::path::parent_path(entry.RPath), + /*IgnoreExisting=*/true)) { + if (StopOnError) + return EC; + } + if (Stat.type() == sys::fs::file_type::directory_file) { // Construct a directory when it's just a directory entry. if (std::error_code EC = diff --git a/contrib/llvm-project/llvm/lib/Support/FormatVariadic.cpp b/contrib/llvm-project/llvm/lib/Support/FormatVariadic.cpp index 632e879e540d..f6d48bcd50e8 100644 --- a/contrib/llvm-project/llvm/lib/Support/FormatVariadic.cpp +++ b/contrib/llvm-project/llvm/lib/Support/FormatVariadic.cpp @@ -91,27 +91,26 @@ formatv_object_base::parseReplacementItem(StringRef Spec) { std::pair<ReplacementItem, StringRef> formatv_object_base::splitLiteralAndReplacement(StringRef Fmt) { - std::size_t From = 0; - while (From < Fmt.size() && From != StringRef::npos) { - std::size_t BO = Fmt.find_first_of('{', From); + while (!Fmt.empty()) { // Everything up until the first brace is a literal. - if (BO != 0) + if (Fmt.front() != '{') { + std::size_t BO = Fmt.find_first_of('{'); return std::make_pair(ReplacementItem{Fmt.substr(0, BO)}, Fmt.substr(BO)); + } - StringRef Braces = - Fmt.drop_front(BO).take_while([](char C) { return C == '{'; }); + StringRef Braces = Fmt.take_while([](char C) { return C == '{'; }); // If there is more than one brace, then some of them are escaped. Treat // these as replacements. if (Braces.size() > 1) { size_t NumEscapedBraces = Braces.size() / 2; - StringRef Middle = Fmt.substr(BO, NumEscapedBraces); - StringRef Right = Fmt.drop_front(BO + NumEscapedBraces * 2); + StringRef Middle = Fmt.take_front(NumEscapedBraces); + StringRef Right = Fmt.drop_front(NumEscapedBraces * 2); return std::make_pair(ReplacementItem{Middle}, Right); } // An unterminated open brace is undefined. We treat the rest of the string // as a literal replacement, but we assert to indicate that this is // undefined and that we consider it an error. - std::size_t BC = Fmt.find_first_of('}', BO); + std::size_t BC = Fmt.find_first_of('}'); if (BC == StringRef::npos) { assert( false && @@ -122,12 +121,12 @@ formatv_object_base::splitLiteralAndReplacement(StringRef Fmt) { // Even if there is a closing brace, if there is another open brace before // this closing brace, treat this portion as literal, and try again with the // next one. - std::size_t BO2 = Fmt.find_first_of('{', BO + 1); + std::size_t BO2 = Fmt.find_first_of('{', 1); if (BO2 < BC) return std::make_pair(ReplacementItem{Fmt.substr(0, BO2)}, Fmt.substr(BO2)); - StringRef Spec = Fmt.slice(BO + 1, BC); + StringRef Spec = Fmt.slice(1, BC); StringRef Right = Fmt.substr(BC + 1); auto RI = parseReplacementItem(Spec); @@ -136,7 +135,7 @@ formatv_object_base::splitLiteralAndReplacement(StringRef Fmt) { // If there was an error parsing the replacement item, treat it as an // invalid replacement spec, and just continue. - From = BC + 1; + Fmt = Fmt.drop_front(BC + 1); } return std::make_pair(ReplacementItem{Fmt}, StringRef()); } diff --git a/contrib/llvm-project/llvm/lib/Support/Host.cpp b/contrib/llvm-project/llvm/lib/Support/Host.cpp index 36cecf9b2a16..a1bd3cc12f1d 100644 --- a/contrib/llvm-project/llvm/lib/Support/Host.cpp +++ b/contrib/llvm-project/llvm/lib/Support/Host.cpp @@ -161,11 +161,14 @@ StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) { // Look for the CPU implementer line. StringRef Implementer; StringRef Hardware; + StringRef Part; for (unsigned I = 0, E = Lines.size(); I != E; ++I) { if (Lines[I].startswith("CPU implementer")) Implementer = Lines[I].substr(15).ltrim("\t :"); if (Lines[I].startswith("Hardware")) Hardware = Lines[I].substr(8).ltrim("\t :"); + if (Lines[I].startswith("CPU part")) + Part = Lines[I].substr(8).ltrim("\t :"); } if (Implementer == "0x41") { // ARM Ltd. @@ -175,110 +178,89 @@ StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) { return "cortex-a53"; - // Look for the CPU part line. - for (unsigned I = 0, E = Lines.size(); I != E; ++I) - if (Lines[I].startswith("CPU part")) - // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The - // values correspond to the "Part number" in the CP15/c0 register. The - // contents are specified in the various processor manuals. - // This corresponds to the Main ID Register in Technical Reference Manuals. - // and is used in programs like sys-utils - return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) - .Case("0x926", "arm926ej-s") - .Case("0xb02", "mpcore") - .Case("0xb36", "arm1136j-s") - .Case("0xb56", "arm1156t2-s") - .Case("0xb76", "arm1176jz-s") - .Case("0xc08", "cortex-a8") - .Case("0xc09", "cortex-a9") - .Case("0xc0f", "cortex-a15") - .Case("0xc20", "cortex-m0") - .Case("0xc23", "cortex-m3") - .Case("0xc24", "cortex-m4") - .Case("0xd22", "cortex-m55") - .Case("0xd02", "cortex-a34") - .Case("0xd04", "cortex-a35") - .Case("0xd03", "cortex-a53") - .Case("0xd07", "cortex-a57") - .Case("0xd08", "cortex-a72") - .Case("0xd09", "cortex-a73") - .Case("0xd0a", "cortex-a75") - .Case("0xd0b", "cortex-a76") - .Case("0xd0d", "cortex-a77") - .Case("0xd41", "cortex-a78") - .Case("0xd44", "cortex-x1") - .Case("0xd0c", "neoverse-n1") - .Default("generic"); + // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The + // values correspond to the "Part number" in the CP15/c0 register. The + // contents are specified in the various processor manuals. + // This corresponds to the Main ID Register in Technical Reference Manuals. + // and is used in programs like sys-utils + return StringSwitch<const char *>(Part) + .Case("0x926", "arm926ej-s") + .Case("0xb02", "mpcore") + .Case("0xb36", "arm1136j-s") + .Case("0xb56", "arm1156t2-s") + .Case("0xb76", "arm1176jz-s") + .Case("0xc08", "cortex-a8") + .Case("0xc09", "cortex-a9") + .Case("0xc0f", "cortex-a15") + .Case("0xc20", "cortex-m0") + .Case("0xc23", "cortex-m3") + .Case("0xc24", "cortex-m4") + .Case("0xd22", "cortex-m55") + .Case("0xd02", "cortex-a34") + .Case("0xd04", "cortex-a35") + .Case("0xd03", "cortex-a53") + .Case("0xd07", "cortex-a57") + .Case("0xd08", "cortex-a72") + .Case("0xd09", "cortex-a73") + .Case("0xd0a", "cortex-a75") + .Case("0xd0b", "cortex-a76") + .Case("0xd0d", "cortex-a77") + .Case("0xd41", "cortex-a78") + .Case("0xd44", "cortex-x1") + .Case("0xd0c", "neoverse-n1") + .Case("0xd49", "neoverse-n2") + .Default("generic"); } if (Implementer == "0x42" || Implementer == "0x43") { // Broadcom | Cavium. - for (unsigned I = 0, E = Lines.size(); I != E; ++I) { - if (Lines[I].startswith("CPU part")) { - return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) - .Case("0x516", "thunderx2t99") - .Case("0x0516", "thunderx2t99") - .Case("0xaf", "thunderx2t99") - .Case("0x0af", "thunderx2t99") - .Case("0xa1", "thunderxt88") - .Case("0x0a1", "thunderxt88") - .Default("generic"); - } - } + return StringSwitch<const char *>(Part) + .Case("0x516", "thunderx2t99") + .Case("0x0516", "thunderx2t99") + .Case("0xaf", "thunderx2t99") + .Case("0x0af", "thunderx2t99") + .Case("0xa1", "thunderxt88") + .Case("0x0a1", "thunderxt88") + .Default("generic"); } if (Implementer == "0x46") { // Fujitsu Ltd. - for (unsigned I = 0, E = Lines.size(); I != E; ++I) { - if (Lines[I].startswith("CPU part")) { - return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) - .Case("0x001", "a64fx") - .Default("generic"); - } - } + return StringSwitch<const char *>(Part) + .Case("0x001", "a64fx") + .Default("generic"); } if (Implementer == "0x4e") { // NVIDIA Corporation - for (unsigned I = 0, E = Lines.size(); I != E; ++I) { - if (Lines[I].startswith("CPU part")) { - return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) - .Case("0x004", "carmel") - .Default("generic"); - } - } + return StringSwitch<const char *>(Part) + .Case("0x004", "carmel") + .Default("generic"); } if (Implementer == "0x48") // HiSilicon Technologies, Inc. - // Look for the CPU part line. - for (unsigned I = 0, E = Lines.size(); I != E; ++I) - if (Lines[I].startswith("CPU part")) - // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The - // values correspond to the "Part number" in the CP15/c0 register. The - // contents are specified in the various processor manuals. - return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) - .Case("0xd01", "tsv110") - .Default("generic"); + // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The + // values correspond to the "Part number" in the CP15/c0 register. The + // contents are specified in the various processor manuals. + return StringSwitch<const char *>(Part) + .Case("0xd01", "tsv110") + .Default("generic"); if (Implementer == "0x51") // Qualcomm Technologies, Inc. - // Look for the CPU part line. - for (unsigned I = 0, E = Lines.size(); I != E; ++I) - if (Lines[I].startswith("CPU part")) - // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The - // values correspond to the "Part number" in the CP15/c0 register. The - // contents are specified in the various processor manuals. - return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) - .Case("0x06f", "krait") // APQ8064 - .Case("0x201", "kryo") - .Case("0x205", "kryo") - .Case("0x211", "kryo") - .Case("0x800", "cortex-a73") - .Case("0x801", "cortex-a73") - .Case("0x802", "cortex-a73") - .Case("0x803", "cortex-a73") - .Case("0x804", "cortex-a73") - .Case("0x805", "cortex-a73") - .Case("0xc00", "falkor") - .Case("0xc01", "saphira") - .Default("generic"); - + // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The + // values correspond to the "Part number" in the CP15/c0 register. The + // contents are specified in the various processor manuals. + return StringSwitch<const char *>(Part) + .Case("0x06f", "krait") // APQ8064 + .Case("0x201", "kryo") + .Case("0x205", "kryo") + .Case("0x211", "kryo") + .Case("0x800", "cortex-a73") // Kryo 2xx Gold + .Case("0x801", "cortex-a73") // Kryo 2xx Silver + .Case("0x802", "cortex-a75") // Kryo 3xx Gold + .Case("0x803", "cortex-a75") // Kryo 3xx Silver + .Case("0x804", "cortex-a76") // Kryo 4xx Gold + .Case("0x805", "cortex-a76") // Kryo 4xx/5xx Silver + .Case("0xc00", "falkor") + .Case("0xc01", "saphira") + .Default("generic"); if (Implementer == "0x53") { // Samsung Electronics Co., Ltd. // The Exynos chips have a convoluted ID scheme that doesn't seem to follow // any predictive pattern across variants and parts. @@ -323,7 +305,7 @@ StringRef sys::detail::getHostCPUNameForS390x(StringRef ProcCpuinfoContent) { SmallVector<StringRef, 32> CPUFeatures; for (unsigned I = 0, E = Lines.size(); I != E; ++I) if (Lines[I].startswith("features")) { - size_t Pos = Lines[I].find(":"); + size_t Pos = Lines[I].find(':'); if (Pos != StringRef::npos) { Lines[I].drop_front(Pos + 1).split(CPUFeatures, ' '); break; @@ -730,6 +712,13 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, *Subtype = X86::INTEL_COREI7_ICELAKE_SERVER; break; + // Sapphire Rapids: + case 0x8f: + CPU = "sapphirerapids"; + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_SAPPHIRERAPIDS; + break; + case 0x1c: // Most 45 nm Intel Atom processors case 0x26: // 45 nm Atom Lincroft case 0x27: // 32 nm Atom Medfield @@ -956,6 +945,14 @@ getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, break; // 00h-0Fh: Zen1 } break; + case 25: + CPU = "znver3"; + *Type = X86::AMDFAM19H; + if (Model <= 0x0f) { + *Subtype = X86::AMDFAM19H_ZNVER3; + break; // 00h-0Fh: Zen3 + } + break; default: break; // Unknown AMD CPU. } @@ -1272,6 +1269,27 @@ int computeHostNumPhysicalCores() { } return CPU_COUNT(&Enabled); } +#elif defined(__linux__) && defined(__powerpc__) +int computeHostNumPhysicalCores() { + cpu_set_t Affinity; + if (sched_getaffinity(0, sizeof(Affinity), &Affinity) == 0) + return CPU_COUNT(&Affinity); + + // The call to sched_getaffinity() may have failed because the Affinity + // mask is too small for the number of CPU's on the system (i.e. the + // system has more than 1024 CPUs). Allocate a mask large enough for + // twice as many CPUs. + cpu_set_t *DynAffinity; + DynAffinity = CPU_ALLOC(2048); + if (sched_getaffinity(0, CPU_ALLOC_SIZE(2048), DynAffinity) == 0) { + int NumCPUs = CPU_COUNT(DynAffinity); + CPU_FREE(DynAffinity); + return NumCPUs; + } + return -1; +} +#elif defined(__linux__) && defined(__s390x__) +int computeHostNumPhysicalCores() { return sysconf(_SC_NPROCESSORS_ONLN); } #elif defined(__APPLE__) && defined(__x86_64__) #include <sys/param.h> #include <sys/sysctl.h> @@ -1291,6 +1309,28 @@ int computeHostNumPhysicalCores() { } return count; } +#elif defined(__MVS__) +int computeHostNumPhysicalCores() { + enum { + // Byte offset of the pointer to the Communications Vector Table (CVT) in + // the Prefixed Save Area (PSA). The table entry is a 31-bit pointer and + // will be zero-extended to uintptr_t. + FLCCVT = 16, + // Byte offset of the pointer to the Common System Data Area (CSD) in the + // CVT. The table entry is a 31-bit pointer and will be zero-extended to + // uintptr_t. + CVTCSD = 660, + // Byte offset to the number of live CPs in the LPAR, stored as a signed + // 32-bit value in the table. + CSD_NUMBER_ONLINE_STANDARD_CPS = 264, + }; + char *PSA = 0; + char *CVT = reinterpret_cast<char *>( + static_cast<uintptr_t>(reinterpret_cast<unsigned int &>(PSA[FLCCVT]))); + char *CSD = reinterpret_cast<char *>( + static_cast<uintptr_t>(reinterpret_cast<unsigned int &>(CVT[CVTCSD]))); + return reinterpret_cast<int &>(CSD[CSD_NUMBER_ONLINE_STANDARD_CPS]); +} #elif defined(_WIN32) && LLVM_ENABLE_THREADS != 0 // Defined in llvm/lib/Support/Windows/Threading.inc int computeHostNumPhysicalCores(); @@ -1420,11 +1460,13 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { Features["avx512bitalg"] = HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save; Features["avx512vpopcntdq"] = HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save; Features["rdpid"] = HasLeaf7 && ((ECX >> 22) & 1); + Features["kl"] = HasLeaf7 && ((ECX >> 23) & 1); // key locker Features["cldemote"] = HasLeaf7 && ((ECX >> 25) & 1); Features["movdiri"] = HasLeaf7 && ((ECX >> 27) & 1); Features["movdir64b"] = HasLeaf7 && ((ECX >> 28) & 1); Features["enqcmd"] = HasLeaf7 && ((ECX >> 29) & 1); + Features["uintr"] = HasLeaf7 && ((EDX >> 5) & 1); Features["avx512vp2intersect"] = HasLeaf7 && ((EDX >> 8) & 1) && HasAVX512Save; Features["serialize"] = HasLeaf7 && ((EDX >> 14) & 1); @@ -1445,7 +1487,9 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { Features["amx-int8"] = HasLeaf7 && ((EDX >> 25) & 1) && HasAMXSave; bool HasLeaf7Subleaf1 = MaxLevel >= 7 && !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX); + Features["avxvnni"] = HasLeaf7Subleaf1 && ((EAX >> 4) & 1) && HasAVXSave; Features["avx512bf16"] = HasLeaf7Subleaf1 && ((EAX >> 5) & 1) && HasAVX512Save; + Features["hreset"] = HasLeaf7Subleaf1 && ((EAX >> 22) & 1); bool HasLeafD = MaxLevel >= 0xd && !getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX); @@ -1460,6 +1504,10 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { Features["ptwrite"] = HasLeaf14 && ((EBX >> 4) & 1); + bool HasLeaf19 = + MaxLevel >= 0x19 && !getX86CpuIDAndInfo(0x19, &EAX, &EBX, &ECX, &EDX); + Features["widekl"] = HasLeaf7 && HasLeaf19 && ((EBX >> 2) & 1); + return true; } #elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) diff --git a/contrib/llvm-project/llvm/lib/Support/InitLLVM.cpp b/contrib/llvm-project/llvm/lib/Support/InitLLVM.cpp index 5c56b773ea69..152de6ebae0a 100644 --- a/contrib/llvm-project/llvm/lib/Support/InitLLVM.cpp +++ b/contrib/llvm-project/llvm/lib/Support/InitLLVM.cpp @@ -22,10 +22,17 @@ using namespace llvm; using namespace llvm::sys; InitLLVM::InitLLVM(int &Argc, const char **&Argv, - bool InstallPipeSignalExitHandler) - : StackPrinter(Argc, Argv) { + bool InstallPipeSignalExitHandler) { if (InstallPipeSignalExitHandler) + // The pipe signal handler must be installed before any other handlers are + // registered. This is because the Unix \ref RegisterHandlers function does + // not perform a sigaction() for SIGPIPE unless a one-shot handler is + // present, to allow long-lived processes (like lldb) to fully opt-out of + // llvm's SIGPIPE handling and ignore the signal safely. sys::SetOneShotPipeSignalFunction(sys::DefaultOneShotPipeSignalHandler); + // Initialize the stack printer after installing the one-shot pipe signal + // handler, so we can perform a sigaction() for SIGPIPE on Unix if requested. + StackPrinter.emplace(Argc, Argv); sys::PrintStackTraceOnErrorSignal(Argv[0]); install_out_of_memory_new_handler(); diff --git a/contrib/llvm-project/llvm/lib/Support/InstructionCost.cpp b/contrib/llvm-project/llvm/lib/Support/InstructionCost.cpp new file mode 100644 index 000000000000..c485ce9107af --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Support/InstructionCost.cpp @@ -0,0 +1,24 @@ +//===- InstructionCost.cpp --------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +/// \file +/// This file includes the function definitions for the InstructionCost class +/// that is used when calculating the cost of an instruction, or a group of +/// instructions. +//===----------------------------------------------------------------------===// + +#include "llvm/Support/InstructionCost.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +void InstructionCost::print(raw_ostream &OS) const { + if (isValid()) + OS << Value; + else + OS << "Invalid"; +} diff --git a/contrib/llvm-project/llvm/lib/Support/JSON.cpp b/contrib/llvm-project/llvm/lib/Support/JSON.cpp index 16b1d11efd08..dbfd673553f4 100644 --- a/contrib/llvm-project/llvm/lib/Support/JSON.cpp +++ b/contrib/llvm-project/llvm/lib/Support/JSON.cpp @@ -7,8 +7,11 @@ //===---------------------------------------------------------------------===// #include "llvm/Support/JSON.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" #include <cctype> namespace llvm { @@ -106,7 +109,7 @@ void Value::copyFrom(const Value &M) { case T_Boolean: case T_Double: case T_Integer: - memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer)); + memcpy(&Union, &M.Union, sizeof(Union)); break; case T_StringRef: create<StringRef>(M.as<StringRef>()); @@ -130,7 +133,7 @@ void Value::moveFrom(const Value &&M) { case T_Boolean: case T_Double: case T_Integer: - memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer)); + memcpy(&Union, &M.Union, sizeof(Union)); break; case T_StringRef: create<StringRef>(M.as<StringRef>()); @@ -198,6 +201,160 @@ bool operator==(const Value &L, const Value &R) { llvm_unreachable("Unknown value kind"); } +void Path::report(llvm::StringLiteral Msg) { + // Walk up to the root context, and count the number of segments. + unsigned Count = 0; + const Path *P; + for (P = this; P->Parent != nullptr; P = P->Parent) + ++Count; + Path::Root *R = P->Seg.root(); + // Fill in the error message and copy the path (in reverse order). + R->ErrorMessage = Msg; + R->ErrorPath.resize(Count); + auto It = R->ErrorPath.begin(); + for (P = this; P->Parent != nullptr; P = P->Parent) + *It++ = P->Seg; +} + +Error Path::Root::getError() const { + std::string S; + raw_string_ostream OS(S); + OS << (ErrorMessage.empty() ? "invalid JSON contents" : ErrorMessage); + if (ErrorPath.empty()) { + if (!Name.empty()) + OS << " when parsing " << Name; + } else { + OS << " at " << (Name.empty() ? "(root)" : Name); + for (const Path::Segment &S : llvm::reverse(ErrorPath)) { + if (S.isField()) + OS << '.' << S.field(); + else + OS << '[' << S.index() << ']'; + } + } + return createStringError(llvm::inconvertibleErrorCode(), OS.str()); +} + +namespace { + +std::vector<const Object::value_type *> sortedElements(const Object &O) { + std::vector<const Object::value_type *> Elements; + for (const auto &E : O) + Elements.push_back(&E); + llvm::sort(Elements, + [](const Object::value_type *L, const Object::value_type *R) { + return L->first < R->first; + }); + return Elements; +} + +// Prints a one-line version of a value that isn't our main focus. +// We interleave writes to OS and JOS, exploiting the lack of extra buffering. +// This is OK as we own the implementation. +void abbreviate(const Value &V, OStream &JOS) { + switch (V.kind()) { + case Value::Array: + JOS.rawValue(V.getAsArray()->empty() ? "[]" : "[ ... ]"); + break; + case Value::Object: + JOS.rawValue(V.getAsObject()->empty() ? "{}" : "{ ... }"); + break; + case Value::String: { + llvm::StringRef S = *V.getAsString(); + if (S.size() < 40) { + JOS.value(V); + } else { + std::string Truncated = fixUTF8(S.take_front(37)); + Truncated.append("..."); + JOS.value(Truncated); + } + break; + } + default: + JOS.value(V); + } +} + +// Prints a semi-expanded version of a value that is our main focus. +// Array/Object entries are printed, but not recursively as they may be huge. +void abbreviateChildren(const Value &V, OStream &JOS) { + switch (V.kind()) { + case Value::Array: + JOS.array([&] { + for (const auto &I : *V.getAsArray()) + abbreviate(I, JOS); + }); + break; + case Value::Object: + JOS.object([&] { + for (const auto *KV : sortedElements(*V.getAsObject())) { + JOS.attributeBegin(KV->first); + abbreviate(KV->second, JOS); + JOS.attributeEnd(); + } + }); + break; + default: + JOS.value(V); + } +} + +} // namespace + +void Path::Root::printErrorContext(const Value &R, raw_ostream &OS) const { + OStream JOS(OS, /*IndentSize=*/2); + // PrintValue recurses down the path, printing the ancestors of our target. + // Siblings of nodes along the path are printed with abbreviate(), and the + // target itself is printed with the somewhat richer abbreviateChildren(). + // 'Recurse' is the lambda itself, to allow recursive calls. + auto PrintValue = [&](const Value &V, ArrayRef<Segment> Path, auto &Recurse) { + // Print the target node itself, with the error as a comment. + // Also used if we can't follow our path, e.g. it names a field that + // *should* exist but doesn't. + auto HighlightCurrent = [&] { + std::string Comment = "error: "; + Comment.append(ErrorMessage.data(), ErrorMessage.size()); + JOS.comment(Comment); + abbreviateChildren(V, JOS); + }; + if (Path.empty()) // We reached our target. + return HighlightCurrent(); + const Segment &S = Path.back(); // Path is in reverse order. + if (S.isField()) { + // Current node is an object, path names a field. + llvm::StringRef FieldName = S.field(); + const Object *O = V.getAsObject(); + if (!O || !O->get(FieldName)) + return HighlightCurrent(); + JOS.object([&] { + for (const auto *KV : sortedElements(*O)) { + JOS.attributeBegin(KV->first); + if (FieldName.equals(KV->first)) + Recurse(KV->second, Path.drop_back(), Recurse); + else + abbreviate(KV->second, JOS); + JOS.attributeEnd(); + } + }); + } else { + // Current node is an array, path names an element. + const Array *A = V.getAsArray(); + if (!A || S.index() >= A->size()) + return HighlightCurrent(); + JOS.array([&] { + unsigned Current = 0; + for (const auto &V : *A) { + if (Current++ == S.index()) + Recurse(V, Path.drop_back(), Recurse); + else + abbreviate(V, JOS); + } + }); + } + }; + PrintValue(R, ErrorPath, PrintValue); +} + namespace { // Simple recursive-descent JSON parser. class Parser { @@ -518,17 +675,6 @@ Expected<Value> parse(StringRef JSON) { } char ParseError::ID = 0; -static std::vector<const Object::value_type *> sortedElements(const Object &O) { - std::vector<const Object::value_type *> Elements; - for (const auto &E : O) - Elements.push_back(&E); - llvm::sort(Elements, - [](const Object::value_type *L, const Object::value_type *R) { - return L->first < R->first; - }); - return Elements; -} - bool isUTF8(llvm::StringRef S, size_t *ErrOffset) { // Fast-path for ASCII, which is valid UTF-8. if (LLVM_LIKELY(isASCII(S))) @@ -633,9 +779,40 @@ void llvm::json::OStream::valueBegin() { } if (Stack.back().Ctx == Array) newline(); + flushComment(); Stack.back().HasValue = true; } +void OStream::comment(llvm::StringRef Comment) { + assert(PendingComment.empty() && "Only one comment per value!"); + PendingComment = Comment; +} + +void OStream::flushComment() { + if (PendingComment.empty()) + return; + OS << (IndentSize ? "/* " : "/*"); + // Be sure not to accidentally emit "*/". Transform to "* /". + while (!PendingComment.empty()) { + auto Pos = PendingComment.find("*/"); + if (Pos == StringRef::npos) { + OS << PendingComment; + PendingComment = ""; + } else { + OS << PendingComment.take_front(Pos) << "* /"; + PendingComment = PendingComment.drop_front(Pos + 2); + } + } + OS << (IndentSize ? " */" : "*/"); + // Comments are on their own line unless attached to an attribute value. + if (Stack.size() > 1 && Stack.back().Ctx == Singleton) { + if (IndentSize) + OS << ' '; + } else { + newline(); + } +} + void llvm::json::OStream::newline() { if (IndentSize) { OS.write('\n'); @@ -657,6 +834,7 @@ void llvm::json::OStream::arrayEnd() { if (Stack.back().HasValue) newline(); OS << ']'; + assert(PendingComment.empty()); Stack.pop_back(); assert(!Stack.empty()); } @@ -675,6 +853,7 @@ void llvm::json::OStream::objectEnd() { if (Stack.back().HasValue) newline(); OS << '}'; + assert(PendingComment.empty()); Stack.pop_back(); assert(!Stack.empty()); } @@ -684,6 +863,7 @@ void llvm::json::OStream::attributeBegin(llvm::StringRef Key) { if (Stack.back().HasValue) OS << ','; newline(); + flushComment(); Stack.back().HasValue = true; Stack.emplace_back(); Stack.back().Ctx = Singleton; @@ -701,10 +881,23 @@ void llvm::json::OStream::attributeBegin(llvm::StringRef Key) { void llvm::json::OStream::attributeEnd() { assert(Stack.back().Ctx == Singleton); assert(Stack.back().HasValue && "Attribute must have a value"); + assert(PendingComment.empty()); Stack.pop_back(); assert(Stack.back().Ctx == Object); } +raw_ostream &llvm::json::OStream::rawValueBegin() { + valueBegin(); + Stack.emplace_back(); + Stack.back().Ctx = RawValue; + return OS; +} + +void llvm::json::OStream::rawValueEnd() { + assert(Stack.back().Ctx == RawValue); + Stack.pop_back(); +} + } // namespace json } // namespace llvm diff --git a/contrib/llvm-project/llvm/lib/Support/KnownBits.cpp b/contrib/llvm-project/llvm/lib/Support/KnownBits.cpp index 1ff66d504cbe..3623a54ae476 100644 --- a/contrib/llvm-project/llvm/lib/Support/KnownBits.cpp +++ b/contrib/llvm-project/llvm/lib/Support/KnownBits.cpp @@ -83,6 +83,403 @@ KnownBits KnownBits::computeForAddSub(bool Add, bool NSW, return KnownOut; } +KnownBits KnownBits::sextInReg(unsigned SrcBitWidth) const { + unsigned BitWidth = getBitWidth(); + assert(0 < SrcBitWidth && SrcBitWidth <= BitWidth && + "Illegal sext-in-register"); + + if (SrcBitWidth == BitWidth) + return *this; + + unsigned ExtBits = BitWidth - SrcBitWidth; + KnownBits Result; + Result.One = One << ExtBits; + Result.Zero = Zero << ExtBits; + Result.One.ashrInPlace(ExtBits); + Result.Zero.ashrInPlace(ExtBits); + return Result; +} + +KnownBits KnownBits::makeGE(const APInt &Val) const { + // Count the number of leading bit positions where our underlying value is + // known to be less than or equal to Val. + unsigned N = (Zero | Val).countLeadingOnes(); + + // For each of those bit positions, if Val has a 1 in that bit then our + // underlying value must also have a 1. + APInt MaskedVal(Val); + MaskedVal.clearLowBits(getBitWidth() - N); + return KnownBits(Zero, One | MaskedVal); +} + +KnownBits KnownBits::umax(const KnownBits &LHS, const KnownBits &RHS) { + // If we can prove that LHS >= RHS then use LHS as the result. Likewise for + // RHS. Ideally our caller would already have spotted these cases and + // optimized away the umax operation, but we handle them here for + // completeness. + if (LHS.getMinValue().uge(RHS.getMaxValue())) + return LHS; + if (RHS.getMinValue().uge(LHS.getMaxValue())) + return RHS; + + // If the result of the umax is LHS then it must be greater than or equal to + // the minimum possible value of RHS. Likewise for RHS. Any known bits that + // are common to these two values are also known in the result. + KnownBits L = LHS.makeGE(RHS.getMinValue()); + KnownBits R = RHS.makeGE(LHS.getMinValue()); + return KnownBits::commonBits(L, R); +} + +KnownBits KnownBits::umin(const KnownBits &LHS, const KnownBits &RHS) { + // Flip the range of values: [0, 0xFFFFFFFF] <-> [0xFFFFFFFF, 0] + auto Flip = [](const KnownBits &Val) { return KnownBits(Val.One, Val.Zero); }; + return Flip(umax(Flip(LHS), Flip(RHS))); +} + +KnownBits KnownBits::smax(const KnownBits &LHS, const KnownBits &RHS) { + // Flip the range of values: [-0x80000000, 0x7FFFFFFF] <-> [0, 0xFFFFFFFF] + auto Flip = [](const KnownBits &Val) { + unsigned SignBitPosition = Val.getBitWidth() - 1; + APInt Zero = Val.Zero; + APInt One = Val.One; + Zero.setBitVal(SignBitPosition, Val.One[SignBitPosition]); + One.setBitVal(SignBitPosition, Val.Zero[SignBitPosition]); + return KnownBits(Zero, One); + }; + return Flip(umax(Flip(LHS), Flip(RHS))); +} + +KnownBits KnownBits::smin(const KnownBits &LHS, const KnownBits &RHS) { + // Flip the range of values: [-0x80000000, 0x7FFFFFFF] <-> [0xFFFFFFFF, 0] + auto Flip = [](const KnownBits &Val) { + unsigned SignBitPosition = Val.getBitWidth() - 1; + APInt Zero = Val.One; + APInt One = Val.Zero; + Zero.setBitVal(SignBitPosition, Val.Zero[SignBitPosition]); + One.setBitVal(SignBitPosition, Val.One[SignBitPosition]); + return KnownBits(Zero, One); + }; + return Flip(umax(Flip(LHS), Flip(RHS))); +} + +KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS) { + unsigned BitWidth = LHS.getBitWidth(); + KnownBits Known(BitWidth); + + // If the shift amount is a valid constant then transform LHS directly. + if (RHS.isConstant() && RHS.getConstant().ult(BitWidth)) { + unsigned Shift = RHS.getConstant().getZExtValue(); + Known = LHS; + Known.Zero <<= Shift; + Known.One <<= Shift; + // Low bits are known zero. + Known.Zero.setLowBits(Shift); + return Known; + } + + // No matter the shift amount, the trailing zeros will stay zero. + unsigned MinTrailingZeros = LHS.countMinTrailingZeros(); + + // Minimum shift amount low bits are known zero. + if (RHS.getMinValue().ult(BitWidth)) { + MinTrailingZeros += RHS.getMinValue().getZExtValue(); + MinTrailingZeros = std::min(MinTrailingZeros, BitWidth); + } + + Known.Zero.setLowBits(MinTrailingZeros); + return Known; +} + +KnownBits KnownBits::lshr(const KnownBits &LHS, const KnownBits &RHS) { + unsigned BitWidth = LHS.getBitWidth(); + KnownBits Known(BitWidth); + + if (RHS.isConstant() && RHS.getConstant().ult(BitWidth)) { + unsigned Shift = RHS.getConstant().getZExtValue(); + Known = LHS; + Known.Zero.lshrInPlace(Shift); + Known.One.lshrInPlace(Shift); + // High bits are known zero. + Known.Zero.setHighBits(Shift); + return Known; + } + + // No matter the shift amount, the leading zeros will stay zero. + unsigned MinLeadingZeros = LHS.countMinLeadingZeros(); + + // Minimum shift amount high bits are known zero. + if (RHS.getMinValue().ult(BitWidth)) { + MinLeadingZeros += RHS.getMinValue().getZExtValue(); + MinLeadingZeros = std::min(MinLeadingZeros, BitWidth); + } + + Known.Zero.setHighBits(MinLeadingZeros); + return Known; +} + +KnownBits KnownBits::ashr(const KnownBits &LHS, const KnownBits &RHS) { + unsigned BitWidth = LHS.getBitWidth(); + KnownBits Known(BitWidth); + + if (RHS.isConstant() && RHS.getConstant().ult(BitWidth)) { + unsigned Shift = RHS.getConstant().getZExtValue(); + Known = LHS; + Known.Zero.ashrInPlace(Shift); + Known.One.ashrInPlace(Shift); + return Known; + } + + // No matter the shift amount, the leading sign bits will stay. + unsigned MinLeadingZeros = LHS.countMinLeadingZeros(); + unsigned MinLeadingOnes = LHS.countMinLeadingOnes(); + + // Minimum shift amount high bits are known sign bits. + if (RHS.getMinValue().ult(BitWidth)) { + if (MinLeadingZeros) { + MinLeadingZeros += RHS.getMinValue().getZExtValue(); + MinLeadingZeros = std::min(MinLeadingZeros, BitWidth); + } + if (MinLeadingOnes) { + MinLeadingOnes += RHS.getMinValue().getZExtValue(); + MinLeadingOnes = std::min(MinLeadingOnes, BitWidth); + } + } + + Known.Zero.setHighBits(MinLeadingZeros); + Known.One.setHighBits(MinLeadingOnes); + return Known; +} + +Optional<bool> KnownBits::eq(const KnownBits &LHS, const KnownBits &RHS) { + if (LHS.isConstant() && RHS.isConstant()) + return Optional<bool>(LHS.getConstant() == RHS.getConstant()); + if (LHS.One.intersects(RHS.Zero) || RHS.One.intersects(LHS.Zero)) + return Optional<bool>(false); + return None; +} + +Optional<bool> KnownBits::ne(const KnownBits &LHS, const KnownBits &RHS) { + if (Optional<bool> KnownEQ = eq(LHS, RHS)) + return Optional<bool>(!KnownEQ.getValue()); + return None; +} + +Optional<bool> KnownBits::ugt(const KnownBits &LHS, const KnownBits &RHS) { + // LHS >u RHS -> false if umax(LHS) <= umax(RHS) + if (LHS.getMaxValue().ule(RHS.getMinValue())) + return Optional<bool>(false); + // LHS >u RHS -> true if umin(LHS) > umax(RHS) + if (LHS.getMinValue().ugt(RHS.getMaxValue())) + return Optional<bool>(true); + return None; +} + +Optional<bool> KnownBits::uge(const KnownBits &LHS, const KnownBits &RHS) { + if (Optional<bool> IsUGT = ugt(RHS, LHS)) + return Optional<bool>(!IsUGT.getValue()); + return None; +} + +Optional<bool> KnownBits::ult(const KnownBits &LHS, const KnownBits &RHS) { + return ugt(RHS, LHS); +} + +Optional<bool> KnownBits::ule(const KnownBits &LHS, const KnownBits &RHS) { + return uge(RHS, LHS); +} + +Optional<bool> KnownBits::sgt(const KnownBits &LHS, const KnownBits &RHS) { + // LHS >s RHS -> false if smax(LHS) <= smax(RHS) + if (LHS.getSignedMaxValue().sle(RHS.getSignedMinValue())) + return Optional<bool>(false); + // LHS >s RHS -> true if smin(LHS) > smax(RHS) + if (LHS.getSignedMinValue().sgt(RHS.getSignedMaxValue())) + return Optional<bool>(true); + return None; +} + +Optional<bool> KnownBits::sge(const KnownBits &LHS, const KnownBits &RHS) { + if (Optional<bool> KnownSGT = sgt(RHS, LHS)) + return Optional<bool>(!KnownSGT.getValue()); + return None; +} + +Optional<bool> KnownBits::slt(const KnownBits &LHS, const KnownBits &RHS) { + return sgt(RHS, LHS); +} + +Optional<bool> KnownBits::sle(const KnownBits &LHS, const KnownBits &RHS) { + return sge(RHS, LHS); +} + +KnownBits KnownBits::abs(bool IntMinIsPoison) const { + // If the source's MSB is zero then we know the rest of the bits already. + if (isNonNegative()) + return *this; + + // Absolute value preserves trailing zero count. + KnownBits KnownAbs(getBitWidth()); + KnownAbs.Zero.setLowBits(countMinTrailingZeros()); + + // 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())) + KnownAbs.Zero.setSignBit(); + + // FIXME: Handle known negative input? + // FIXME: Calculate the negated Known bits and combine them? + return KnownAbs; +} + +KnownBits KnownBits::computeForMul(const KnownBits &LHS, const KnownBits &RHS) { + unsigned BitWidth = LHS.getBitWidth(); + + assert(!LHS.hasConflict() && !RHS.hasConflict()); + // Compute a conservative estimate for high known-0 bits. + unsigned LeadZ = + std::max(LHS.countMinLeadingZeros() + RHS.countMinLeadingZeros(), + BitWidth) - + BitWidth; + LeadZ = std::min(LeadZ, BitWidth); + + // The result of the bottom bits of an integer multiply can be + // inferred by looking at the bottom bits of both operands and + // multiplying them together. + // We can infer at least the minimum number of known trailing bits + // of both operands. Depending on number of trailing zeros, we can + // infer more bits, because (a*b) <=> ((a/m) * (b/n)) * (m*n) assuming + // a and b are divisible by m and n respectively. + // We then calculate how many of those bits are inferrable and set + // the output. For example, the i8 mul: + // a = XXXX1100 (12) + // b = XXXX1110 (14) + // We know the bottom 3 bits are zero since the first can be divided by + // 4 and the second by 2, thus having ((12/4) * (14/2)) * (2*4). + // Applying the multiplication to the trimmed arguments gets: + // XX11 (3) + // X111 (7) + // ------- + // XX11 + // XX11 + // XX11 + // XX11 + // ------- + // XXXXX01 + // Which allows us to infer the 2 LSBs. Since we're multiplying the result + // by 8, the bottom 3 bits will be 0, so we can infer a total of 5 bits. + // The proof for this can be described as: + // Pre: (C1 >= 0) && (C1 < (1 << C5)) && (C2 >= 0) && (C2 < (1 << C6)) && + // (C7 == (1 << (umin(countTrailingZeros(C1), C5) + + // umin(countTrailingZeros(C2), C6) + + // umin(C5 - umin(countTrailingZeros(C1), C5), + // C6 - umin(countTrailingZeros(C2), C6)))) - 1) + // %aa = shl i8 %a, C5 + // %bb = shl i8 %b, C6 + // %aaa = or i8 %aa, C1 + // %bbb = or i8 %bb, C2 + // %mul = mul i8 %aaa, %bbb + // %mask = and i8 %mul, C7 + // => + // %mask = i8 ((C1*C2)&C7) + // Where C5, C6 describe the known bits of %a, %b + // C1, C2 describe the known bottom bits of %a, %b. + // C7 describes the mask of the known bits of the result. + const APInt &Bottom0 = LHS.One; + const APInt &Bottom1 = RHS.One; + + // How many times we'd be able to divide each argument by 2 (shr by 1). + // This gives us the number of trailing zeros on the multiplication result. + unsigned TrailBitsKnown0 = (LHS.Zero | LHS.One).countTrailingOnes(); + unsigned TrailBitsKnown1 = (RHS.Zero | RHS.One).countTrailingOnes(); + unsigned TrailZero0 = LHS.countMinTrailingZeros(); + unsigned TrailZero1 = RHS.countMinTrailingZeros(); + unsigned TrailZ = TrailZero0 + TrailZero1; + + // Figure out the fewest known-bits operand. + unsigned SmallestOperand = + std::min(TrailBitsKnown0 - TrailZero0, TrailBitsKnown1 - TrailZero1); + unsigned ResultBitsKnown = std::min(SmallestOperand + TrailZ, BitWidth); + + APInt BottomKnown = + Bottom0.getLoBits(TrailBitsKnown0) * Bottom1.getLoBits(TrailBitsKnown1); + + KnownBits Res(BitWidth); + Res.Zero.setHighBits(LeadZ); + Res.Zero |= (~BottomKnown).getLoBits(ResultBitsKnown); + Res.One = BottomKnown.getLoBits(ResultBitsKnown); + return Res; +} + +KnownBits KnownBits::udiv(const KnownBits &LHS, const KnownBits &RHS) { + unsigned BitWidth = LHS.getBitWidth(); + assert(!LHS.hasConflict() && !RHS.hasConflict()); + KnownBits Known(BitWidth); + + // For the purposes of computing leading zeros we can conservatively + // treat a udiv as a logical right shift by the power of 2 known to + // be less than the denominator. + unsigned LeadZ = LHS.countMinLeadingZeros(); + unsigned RHSMaxLeadingZeros = RHS.countMaxLeadingZeros(); + + if (RHSMaxLeadingZeros != BitWidth) + LeadZ = std::min(BitWidth, LeadZ + BitWidth - RHSMaxLeadingZeros - 1); + + Known.Zero.setHighBits(LeadZ); + return Known; +} + +KnownBits KnownBits::urem(const KnownBits &LHS, const KnownBits &RHS) { + unsigned BitWidth = LHS.getBitWidth(); + assert(!LHS.hasConflict() && !RHS.hasConflict()); + KnownBits Known(BitWidth); + + if (RHS.isConstant() && RHS.getConstant().isPowerOf2()) { + // The upper bits are all zero, the lower ones are unchanged. + APInt LowBits = RHS.getConstant() - 1; + Known.Zero = LHS.Zero | ~LowBits; + Known.One = LHS.One & LowBits; + return Known; + } + + // Since the result is less than or equal to either operand, any leading + // zero bits in either operand must also exist in the result. + uint32_t Leaders = + std::max(LHS.countMinLeadingZeros(), RHS.countMinLeadingZeros()); + Known.Zero.setHighBits(Leaders); + return Known; +} + +KnownBits KnownBits::srem(const KnownBits &LHS, const KnownBits &RHS) { + unsigned BitWidth = LHS.getBitWidth(); + assert(!LHS.hasConflict() && !RHS.hasConflict()); + KnownBits Known(BitWidth); + + if (RHS.isConstant() && RHS.getConstant().isPowerOf2()) { + // The low bits of the first operand are unchanged by the srem. + APInt LowBits = RHS.getConstant() - 1; + Known.Zero = LHS.Zero & LowBits; + Known.One = LHS.One & LowBits; + + // If the first operand is non-negative or has all low bits zero, then + // the upper bits are all zero. + if (LHS.isNonNegative() || LowBits.isSubsetOf(LHS.Zero)) + Known.Zero |= ~LowBits; + + // If the first operand is negative and not all low bits are zero, then + // the upper bits are all one. + if (LHS.isNegative() && LowBits.intersects(LHS.One)) + Known.One |= ~LowBits; + return Known; + } + + // The sign bit is the LHS's sign bit, except when the result of the + // remainder is zero. If it's known zero, our sign bit is also zero. + if (LHS.isNonNegative()) + Known.makeNonNegative(); + return Known; +} + KnownBits &KnownBits::operator&=(const KnownBits &RHS) { // Result bit is 0 if either operand bit is 0. Zero |= RHS.Zero; diff --git a/contrib/llvm-project/llvm/lib/Support/LineIterator.cpp b/contrib/llvm-project/llvm/lib/Support/LineIterator.cpp index 164436a2c48e..7bdf1271ac25 100644 --- a/contrib/llvm-project/llvm/lib/Support/LineIterator.cpp +++ b/contrib/llvm-project/llvm/lib/Support/LineIterator.cpp @@ -33,7 +33,11 @@ static bool skipIfAtLineEnd(const char *&P) { line_iterator::line_iterator(const MemoryBuffer &Buffer, bool SkipBlanks, char CommentMarker) - : Buffer(Buffer.getBufferSize() ? &Buffer : nullptr), + : line_iterator(Buffer.getMemBufferRef(), SkipBlanks, CommentMarker) {} + +line_iterator::line_iterator(const MemoryBufferRef &Buffer, bool SkipBlanks, + char CommentMarker) + : Buffer(Buffer.getBufferSize() ? Optional<MemoryBufferRef>(Buffer) : None), CommentMarker(CommentMarker), SkipBlanks(SkipBlanks), LineNumber(1), CurrentLine(Buffer.getBufferSize() ? Buffer.getBufferStart() : nullptr, 0) { @@ -78,7 +82,7 @@ void line_iterator::advance() { if (*Pos == '\0') { // We've hit the end of the buffer, reset ourselves to the end state. - Buffer = nullptr; + Buffer = None; CurrentLine = StringRef(); return; } diff --git a/contrib/llvm-project/llvm/lib/Support/LowLevelType.cpp b/contrib/llvm-project/llvm/lib/Support/LowLevelType.cpp index fe77cb3db413..63559d5ac3ee 100644 --- a/contrib/llvm-project/llvm/lib/Support/LowLevelType.cpp +++ b/contrib/llvm-project/llvm/lib/Support/LowLevelType.cpp @@ -23,7 +23,7 @@ LLT::LLT(MVT VT) { } else if (VT.isValid()) { // Aggregates are no different from real scalars as far as GlobalISel is // concerned. - assert(VT.getSizeInBits() != 0 && "invalid zero-sized type"); + assert(VT.getSizeInBits().isNonZero() && "invalid zero-sized type"); init(/*IsPointer=*/false, /*IsVector=*/false, /*NumElements=*/0, VT.getSizeInBits(), /*AddressSpace=*/0); } else { diff --git a/contrib/llvm-project/llvm/lib/Support/MemoryBufferRef.cpp b/contrib/llvm-project/llvm/lib/Support/MemoryBufferRef.cpp new file mode 100644 index 000000000000..a93853c0acb1 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Support/MemoryBufferRef.cpp @@ -0,0 +1,19 @@ +//===- MemoryBufferRef.cpp - Memory Buffer Reference ----------------------===// +// +// 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 MemoryBufferRef interface. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/MemoryBufferRef.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace llvm; + +MemoryBufferRef::MemoryBufferRef(const MemoryBuffer &Buffer) + : Buffer(Buffer.getBuffer()), Identifier(Buffer.getBufferIdentifier()) {} diff --git a/contrib/llvm-project/llvm/lib/Support/Path.cpp b/contrib/llvm-project/llvm/lib/Support/Path.cpp index 37b3086fddf5..ef223ae5ac1d 100644 --- a/contrib/llvm-project/llvm/lib/Support/Path.cpp +++ b/contrib/llvm-project/llvm/lib/Support/Path.cpp @@ -354,10 +354,9 @@ StringRef root_path(StringRef path, Style style) { if ((++pos != e) && is_separator((*pos)[0], style)) { // {C:/,//net/}, so get the first two components. return path.substr(0, b->size() + pos->size()); - } else { - // just {C:,//net}, return the first component. - return *b; } + // just {C:,//net}, return the first component. + return *b; } // POSIX style root directory. @@ -467,8 +466,7 @@ StringRef parent_path(StringRef path, Style style) { size_t end_pos = parent_path_end(path, style); if (end_pos == StringRef::npos) return StringRef(); - else - return path.substr(0, end_pos); + return path.substr(0, end_pos); } void remove_filename(SmallVectorImpl<char> &path, Style style) { @@ -581,12 +579,10 @@ StringRef stem(StringRef path, Style style) { size_t pos = fname.find_last_of('.'); if (pos == StringRef::npos) return fname; - else - if ((fname.size() == 1 && fname == ".") || - (fname.size() == 2 && fname == "..")) - return fname; - else - return fname.substr(0, pos); + if ((fname.size() == 1 && fname == ".") || + (fname.size() == 2 && fname == "..")) + return fname; + return fname.substr(0, pos); } StringRef extension(StringRef path, Style style) { @@ -594,12 +590,10 @@ StringRef extension(StringRef path, Style style) { size_t pos = fname.find_last_of('.'); if (pos == StringRef::npos) return StringRef(); - else - if ((fname.size() == 1 && fname == ".") || - (fname.size() == 2 && fname == "..")) - return StringRef(); - else - return fname.substr(pos); + if ((fname.size() == 1 && fname == ".") || + (fname.size() == 2 && fname == "..")) + return StringRef(); + return fname.substr(pos); } bool is_separator(char value, Style style) { @@ -683,6 +677,24 @@ bool is_absolute(const Twine &path, Style style) { return rootDir && rootName; } +bool is_absolute_gnu(const Twine &path, Style style) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + // Handle '/' which is absolute for both Windows and POSIX systems. + // Handle '\\' on Windows. + if (!p.empty() && is_separator(p.front(), style)) + return true; + + if (real_style(style) == Style::windows) { + // Handle drive letter pattern (a character followed by ':') on Windows. + if (p.size() >= 2 && (p[0] && p[1] == ':')) + return true; + } + + return false; +} + bool is_relative(const Twine &path, Style style) { return !is_absolute(path, style); } @@ -1281,7 +1293,7 @@ Expected<TempFile> TempFile::create(const Twine &Model, unsigned Mode) { #endif return std::move(Ret); } -} +} // namespace fs -} // end namsspace sys -} // end namespace llvm +} // namespace sys +} // namespace llvm diff --git a/contrib/llvm-project/llvm/lib/Support/PrettyStackTrace.cpp b/contrib/llvm-project/llvm/lib/Support/PrettyStackTrace.cpp index 9072f9d2d2ee..5d3d95b5e7cb 100644 --- a/contrib/llvm-project/llvm/lib/Support/PrettyStackTrace.cpp +++ b/contrib/llvm-project/llvm/lib/Support/PrettyStackTrace.cpp @@ -25,6 +25,7 @@ #include <cassert> #include <cstdarg> #include <cstdio> +#include <cstring> #include <tuple> #ifdef HAVE_CRASHREPORTERCLIENT_H @@ -253,8 +254,16 @@ void PrettyStackTraceFormat::print(raw_ostream &OS) const { OS << Str << "\n"; } void PrettyStackTraceProgram::print(raw_ostream &OS) const { OS << "Program arguments: "; // Print the argument list. - for (unsigned i = 0, e = ArgC; i != e; ++i) - OS << ArgV[i] << ' '; + for (int I = 0; I < ArgC; ++I) { + const bool HaveSpace = ::strchr(ArgV[I], ' '); + if (I) + OS << ' '; + if (HaveSpace) + OS << '"'; + OS.write_escaped(ArgV[I]); + if (HaveSpace) + OS << '"'; + } OS << '\n'; } diff --git a/contrib/llvm-project/llvm/lib/Support/Process.cpp b/contrib/llvm-project/llvm/lib/Support/Process.cpp index 9e6e233b26ac..e0814444876c 100644 --- a/contrib/llvm-project/llvm/lib/Support/Process.cpp +++ b/contrib/llvm-project/llvm/lib/Support/Process.cpp @@ -20,6 +20,8 @@ #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" +#include <stdlib.h> // for _Exit + using namespace llvm; using namespace sys; @@ -28,21 +30,22 @@ using namespace sys; //=== independent code. //===----------------------------------------------------------------------===// -Optional<std::string> Process::FindInEnvPath(StringRef EnvName, - StringRef FileName) { - return FindInEnvPath(EnvName, FileName, {}); +Optional<std::string> +Process::FindInEnvPath(StringRef EnvName, StringRef FileName, char Separator) { + return FindInEnvPath(EnvName, FileName, {}, Separator); } Optional<std::string> Process::FindInEnvPath(StringRef EnvName, StringRef FileName, - ArrayRef<std::string> IgnoreList) { + ArrayRef<std::string> IgnoreList, + char Separator) { assert(!path::is_absolute(FileName)); Optional<std::string> FoundPath; Optional<std::string> OptPath = Process::GetEnv(EnvName); if (!OptPath.hasValue()) return FoundPath; - const char EnvPathSeparatorStr[] = {EnvPathSeparator, '\0'}; + const char EnvPathSeparatorStr[] = {Separator, '\0'}; SmallVector<StringRef, 8> Dirs; SplitString(OptPath.getValue(), Dirs, EnvPathSeparatorStr); @@ -90,10 +93,14 @@ static bool coreFilesPrevented = !LLVM_ENABLE_CRASH_DUMPS; bool Process::AreCoreFilesPrevented() { return coreFilesPrevented; } LLVM_ATTRIBUTE_NORETURN -void Process::Exit(int RetCode) { +void Process::Exit(int RetCode, bool NoCleanup) { if (CrashRecoveryContext *CRC = CrashRecoveryContext::GetCurrent()) CRC->HandleExit(RetCode); - ::exit(RetCode); + + if (NoCleanup) + _Exit(RetCode); + else + ::exit(RetCode); } // Include the platform-specific parts of this class. diff --git a/contrib/llvm-project/llvm/lib/Support/Program.cpp b/contrib/llvm-project/llvm/lib/Support/Program.cpp index 5294f65bd5a5..c7a59642b27e 100644 --- a/contrib/llvm-project/llvm/lib/Support/Program.cpp +++ b/contrib/llvm-project/llvm/lib/Support/Program.cpp @@ -26,17 +26,20 @@ using namespace sys; static bool Execute(ProcessInfo &PI, StringRef Program, ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env, ArrayRef<Optional<StringRef>> Redirects, - unsigned MemoryLimit, std::string *ErrMsg); + unsigned MemoryLimit, std::string *ErrMsg, + BitVector *AffinityMask); int sys::ExecuteAndWait(StringRef Program, ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env, ArrayRef<Optional<StringRef>> Redirects, unsigned SecondsToWait, unsigned MemoryLimit, std::string *ErrMsg, bool *ExecutionFailed, - Optional<ProcessStatistics> *ProcStat) { + Optional<ProcessStatistics> *ProcStat, + BitVector *AffinityMask) { assert(Redirects.empty() || Redirects.size() == 3); ProcessInfo PI; - if (Execute(PI, Program, Args, Env, Redirects, MemoryLimit, ErrMsg)) { + if (Execute(PI, Program, Args, Env, Redirects, MemoryLimit, ErrMsg, + AffinityMask)) { if (ExecutionFailed) *ExecutionFailed = false; ProcessInfo Result = @@ -55,12 +58,13 @@ ProcessInfo sys::ExecuteNoWait(StringRef Program, ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env, ArrayRef<Optional<StringRef>> Redirects, unsigned MemoryLimit, std::string *ErrMsg, - bool *ExecutionFailed) { + bool *ExecutionFailed, BitVector *AffinityMask) { assert(Redirects.empty() || Redirects.size() == 3); ProcessInfo PI; if (ExecutionFailed) *ExecutionFailed = false; - if (!Execute(PI, Program, Args, Env, Redirects, MemoryLimit, ErrMsg)) + if (!Execute(PI, Program, Args, Env, Redirects, MemoryLimit, ErrMsg, + AffinityMask)) if (ExecutionFailed) *ExecutionFailed = true; diff --git a/contrib/llvm-project/llvm/lib/Support/SHA1.cpp b/contrib/llvm-project/llvm/lib/Support/SHA1.cpp index 417b13fea05a..5dce44af9ecd 100644 --- a/contrib/llvm-project/llvm/lib/Support/SHA1.cpp +++ b/contrib/llvm-project/llvm/lib/Support/SHA1.cpp @@ -225,7 +225,7 @@ void SHA1::update(ArrayRef<uint8_t> Data) { // Fast buffer filling for large inputs. while (Data.size() >= BLOCK_LENGTH) { assert(InternalState.BufferOffset == 0); - assert(BLOCK_LENGTH % 4 == 0); + static_assert(BLOCK_LENGTH % 4 == 0, ""); constexpr size_t BLOCK_LENGTH_32 = BLOCK_LENGTH / 4; for (size_t I = 0; I < BLOCK_LENGTH_32; ++I) InternalState.Buffer.L[I] = support::endian::read32be(&Data[I * 4]); diff --git a/contrib/llvm-project/llvm/lib/Support/Signals.cpp b/contrib/llvm-project/llvm/lib/Support/Signals.cpp index 2cfdf2d42a4a..29be4df95954 100644 --- a/contrib/llvm-project/llvm/lib/Support/Signals.cpp +++ b/contrib/llvm-project/llvm/lib/Support/Signals.cpp @@ -44,6 +44,9 @@ static cl::opt<bool, true> cl::desc("Disable symbolizing crash backtraces."), cl::location(DisableSymbolicationFlag), cl::Hidden); +constexpr char DisableSymbolizationEnv[] = "LLVM_DISABLE_SYMBOLIZATION"; +constexpr char LLVMSymbolizerPathEnv[] = "LLVM_SYMBOLIZER_PATH"; + // Callbacks to run in signal handler must be lock-free because a signal handler // could be running as we add new callbacks. We don't add unbounded numbers of // callbacks, an array is therefore sufficient. @@ -105,7 +108,7 @@ static FormattedNumber format_ptr(void *PC) { LLVM_ATTRIBUTE_USED static bool printSymbolizedStackTrace(StringRef Argv0, void **StackTrace, int Depth, llvm::raw_ostream &OS) { - if (DisableSymbolicationFlag) + if (DisableSymbolicationFlag || getenv(DisableSymbolizationEnv)) return false; // Don't recursively invoke the llvm-symbolizer binary. @@ -117,7 +120,9 @@ static bool printSymbolizedStackTrace(StringRef Argv0, void **StackTrace, // Use llvm-symbolizer tool to symbolize the stack traces. First look for it // alongside our binary, then in $PATH. ErrorOr<std::string> LLVMSymbolizerPathOrErr = std::error_code(); - if (!Argv0.empty()) { + if (const char *Path = getenv(LLVMSymbolizerPathEnv)) { + LLVMSymbolizerPathOrErr = sys::findProgramByName(Path); + } else if (!Argv0.empty()) { StringRef Parent = llvm::sys::path::parent_path(Argv0); if (!Parent.empty()) LLVMSymbolizerPathOrErr = sys::findProgramByName("llvm-symbolizer", Parent); diff --git a/contrib/llvm-project/llvm/lib/Support/Signposts.cpp b/contrib/llvm-project/llvm/lib/Support/Signposts.cpp index aa159e1da2ae..9353e9b294d1 100644 --- a/contrib/llvm-project/llvm/lib/Support/Signposts.cpp +++ b/contrib/llvm-project/llvm/lib/Support/Signposts.cpp @@ -13,6 +13,7 @@ #include "llvm/Config/config.h" #if LLVM_SUPPORT_XCODE_SIGNPOSTS #include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Mutex.h" #include <os/signpost.h> #endif // if LLVM_SUPPORT_XCODE_SIGNPOSTS @@ -33,21 +34,22 @@ void LogDeleter(os_log_t *X) { namespace llvm { class SignpostEmitterImpl { - using LogPtrTy = - std::unique_ptr<os_log_t, std::function<void(os_log_t *)>>; + using LogPtrTy = std::unique_ptr<os_log_t, std::function<void(os_log_t *)>>; using LogTy = LogPtrTy::element_type; LogPtrTy SignpostLog; - DenseMap<const Timer *, os_signpost_id_t> Signposts; + DenseMap<const void *, os_signpost_id_t> Signposts; + sys::SmartMutex<true> Mutex; LogTy &getLogger() const { return *SignpostLog; } - os_signpost_id_t getSignpostForTimer(const Timer *T) { - const auto &I = Signposts.find(T); + os_signpost_id_t getSignpostForObject(const void *O) { + sys::SmartScopedLock<true> Lock(Mutex); + const auto &I = Signposts.find(O); if (I != Signposts.end()) return I->second; const auto &Inserted = Signposts.insert( - std::make_pair(T, os_signpost_id_make_with_pointer(getLogger(), T))); + std::make_pair(O, os_signpost_id_make_with_pointer(getLogger(), O))); return Inserted.first->second; } @@ -56,20 +58,19 @@ public: bool isEnabled() const { return os_signpost_enabled(*SignpostLog); } - void startTimerInterval(Timer *T) { + void startInterval(const void *O, llvm::StringRef Name) { if (isEnabled()) { - // Both strings used here are required to be constant literal strings - os_signpost_interval_begin(getLogger(), getSignpostForTimer(T), - "Pass Timers", "Begin %s", - T->getName().c_str()); + // Both strings used here are required to be constant literal strings. + os_signpost_interval_begin(getLogger(), getSignpostForObject(O), + "LLVM Timers", "Begin %s", Name.data()); } } - void endTimerInterval(Timer *T) { + void endInterval(const void *O, llvm::StringRef Name) { if (isEnabled()) { - // Both strings used here are required to be constant literal strings - os_signpost_interval_end(getLogger(), getSignpostForTimer(T), - "Pass Timers", "End %s", T->getName().c_str()); + // Both strings used here are required to be constant literal strings. + os_signpost_interval_end(getLogger(), getSignpostForObject(O), + "LLVM Timers", "End %s", Name.data()); } } }; @@ -85,7 +86,7 @@ public: SignpostEmitter::SignpostEmitter() { #if HAVE_ANY_SIGNPOST_IMPL Impl = new SignpostEmitterImpl(); -#else // if HAVE_ANY_SIGNPOST_IMPL +#else // if HAVE_ANY_SIGNPOST_IMPL Impl = nullptr; #endif // if !HAVE_ANY_SIGNPOST_IMPL } @@ -104,18 +105,18 @@ bool SignpostEmitter::isEnabled() const { #endif // if !HAVE_ANY_SIGNPOST_IMPL } -void SignpostEmitter::startTimerInterval(Timer *T) { +void SignpostEmitter::startInterval(const void *O, StringRef Name) { #if HAVE_ANY_SIGNPOST_IMPL if (Impl == nullptr) return; - return Impl->startTimerInterval(T); + return Impl->startInterval(O, Name); #endif // if !HAVE_ANY_SIGNPOST_IMPL } -void SignpostEmitter::endTimerInterval(Timer *T) { +void SignpostEmitter::endInterval(const void *O, StringRef Name) { #if HAVE_ANY_SIGNPOST_IMPL if (Impl == nullptr) return; - Impl->endTimerInterval(T); + Impl->endInterval(O, Name); #endif // if !HAVE_ANY_SIGNPOST_IMPL } diff --git a/contrib/llvm-project/llvm/lib/Support/SmallVector.cpp b/contrib/llvm-project/llvm/lib/Support/SmallVector.cpp index 6d5fe7165f63..0005f7840912 100644 --- a/contrib/llvm-project/llvm/lib/Support/SmallVector.cpp +++ b/contrib/llvm-project/llvm/lib/Support/SmallVector.cpp @@ -12,6 +12,9 @@ #include "llvm/ADT/SmallVector.h" #include <cstdint> +#ifdef LLVM_ENABLE_EXCEPTIONS +#include <stdexcept> +#endif using namespace llvm; // Check that no bytes are wasted and everything is well-aligned. @@ -42,27 +45,72 @@ static_assert(sizeof(SmallVector<char, 0>) == sizeof(void *) * 2 + sizeof(void *), "1 byte elements have word-sized type for size and capacity"); +/// 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); +static void report_size_overflow(size_t MinSize, size_t MaxSize) { + std::string Reason = "SmallVector unable to grow. Requested capacity (" + + std::to_string(MinSize) + + ") is larger than maximum value for size type (" + + std::to_string(MaxSize) + ")"; +#ifdef LLVM_ENABLE_EXCEPTIONS + throw std::length_error(Reason); +#else + report_fatal_error(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); +static void report_at_maximum_capacity(size_t MaxSize) { + std::string Reason = + "SmallVector capacity unable to grow. Already at maximum size " + + std::to_string(MaxSize); +#ifdef LLVM_ENABLE_EXCEPTIONS + throw std::length_error(Reason); +#else + report_fatal_error(Reason); +#endif +} + // Note: Moving this function into the header may cause performance regression. template <class Size_T> -void SmallVectorBase<Size_T>::grow_pod(void *FirstEl, size_t MinCapacity, - size_t TSize) { +static size_t getNewCapacity(size_t MinSize, size_t TSize, size_t OldCapacity) { + constexpr size_t MaxSize = std::numeric_limits<Size_T>::max(); + // Ensure we can fit the new capacity. // This is only going to be applicable when the capacity is 32 bit. - if (MinCapacity > SizeTypeMax()) - report_bad_alloc_error("SmallVector capacity overflow during allocation"); + if (MinSize > MaxSize) + report_size_overflow(MinSize, MaxSize); // Ensure we can meet the guarantee of space for at least one more element. // The above check alone will not catch the case where grow is called with a - // default MinCapacity of 0, but the current capacity cannot be increased. + // default MinSize of 0, but the current capacity cannot be increased. // This is only going to be applicable when the capacity is 32 bit. - if (capacity() == SizeTypeMax()) - report_bad_alloc_error("SmallVector capacity unable to grow"); + if (OldCapacity == MaxSize) + report_at_maximum_capacity(MaxSize); // In theory 2*capacity can overflow if the capacity is 64 bit, but the // original capacity would never be large enough for this to be a problem. - size_t NewCapacity = 2 * capacity() + 1; // Always grow. - NewCapacity = std::min(std::max(NewCapacity, MinCapacity), SizeTypeMax()); + size_t NewCapacity = 2 * OldCapacity + 1; // Always grow. + return std::min(std::max(NewCapacity, MinSize), MaxSize); +} +// Note: Moving this function into the header may cause performance regression. +template <class Size_T> +void *SmallVectorBase<Size_T>::mallocForGrow(size_t MinSize, size_t TSize, + size_t &NewCapacity) { + NewCapacity = getNewCapacity<Size_T>(MinSize, TSize, this->capacity()); + return llvm::safe_malloc(NewCapacity * TSize); +} + +// Note: Moving this function into the header may cause performance regression. +template <class Size_T> +void SmallVectorBase<Size_T>::grow_pod(void *FirstEl, size_t MinSize, + size_t TSize) { + size_t NewCapacity = getNewCapacity<Size_T>(MinSize, TSize, this->capacity()); void *NewElts; if (BeginX == FirstEl) { NewElts = safe_malloc(NewCapacity * TSize); @@ -81,7 +129,7 @@ void SmallVectorBase<Size_T>::grow_pod(void *FirstEl, size_t MinCapacity, template class llvm::SmallVectorBase<uint32_t>; // Disable the uint64_t instantiation for 32-bit builds. -// Both uint32_t and uint64_t instantations are needed for 64-bit builds. +// Both uint32_t and uint64_t instantiations are needed for 64-bit builds. // This instantiation will never be used in 32-bit builds, and will cause // warnings when sizeof(Size_T) > sizeof(size_t). #if SIZE_MAX > UINT32_MAX diff --git a/contrib/llvm-project/llvm/lib/Support/SourceMgr.cpp b/contrib/llvm-project/llvm/lib/Support/SourceMgr.cpp index 9cc69732a964..89b7dc939dfc 100644 --- a/contrib/llvm-project/llvm/lib/Support/SourceMgr.cpp +++ b/contrib/llvm-project/llvm/lib/Support/SourceMgr.cpp @@ -180,7 +180,7 @@ std::pair<unsigned, unsigned> SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const { if (!BufferID) BufferID = FindBufferContainingLoc(Loc); - assert(BufferID && "Invalid Location!"); + assert(BufferID && "Invalid location!"); auto &SB = getBufferInfo(BufferID); const char *Ptr = Loc.getPointer(); @@ -193,6 +193,30 @@ SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const { return std::make_pair(LineNo, Ptr - BufStart - NewlineOffs); } +// FIXME: Note that the formatting of source locations is spread between +// multiple functions, some in SourceMgr and some in SMDiagnostic. A better +// solution would be a general-purpose source location formatter +// in one of those two classes, or possibly in SMLoc. + +/// Get a string with the source location formatted in the standard +/// style, but without the line offset. If \p IncludePath is true, the path +/// is included. If false, only the file name and extension are included. +std::string SourceMgr::getFormattedLocationNoOffset(SMLoc Loc, + bool IncludePath) const { + auto BufferID = FindBufferContainingLoc(Loc); + assert(BufferID && "Invalid location!"); + auto FileSpec = getBufferInfo(BufferID).Buffer->getBufferIdentifier(); + + if (IncludePath) { + return FileSpec.str() + ":" + std::to_string(FindLineNumber(Loc, BufferID)); + } else { + auto I = FileSpec.find_last_of("/\\"); + I = (I == FileSpec.size()) ? 0 : (I + 1); + return FileSpec.substr(I).str() + ":" + + std::to_string(FindLineNumber(Loc, BufferID)); + } +} + /// Given a line and column number in a mapped buffer, turn it into an SMLoc. /// This will return a null SMLoc if the line/column location is invalid. SMLoc SourceMgr::FindLocForLineAndColumn(unsigned BufferID, unsigned LineNo, @@ -243,7 +267,7 @@ SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind, SmallVector<std::pair<unsigned, unsigned>, 4> ColRanges; std::pair<unsigned, unsigned> LineAndCol; StringRef BufferID = "<unknown>"; - std::string LineStr; + StringRef LineStr; if (Loc.isValid()) { unsigned CurBuf = FindBufferContainingLoc(Loc); @@ -264,7 +288,7 @@ SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const char *BufEnd = CurMB->getBufferEnd(); while (LineEnd != BufEnd && LineEnd[0] != '\n' && LineEnd[0] != '\r') ++LineEnd; - LineStr = std::string(LineStart, LineEnd); + LineStr = StringRef(LineStart, LineEnd - LineStart); // Convert any ranges to column ranges that only intersect the line of the // location. @@ -346,8 +370,8 @@ SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN, int Line, ArrayRef<std::pair<unsigned, unsigned>> Ranges, ArrayRef<SMFixIt> Hints) : SM(&sm), Loc(L), Filename(std::string(FN)), LineNo(Line), ColumnNo(Col), - Kind(Kind), Message(std::string(Msg)), LineContents(std::string(LineStr)), - Ranges(Ranges.vec()), FixIts(Hints.begin(), Hints.end()) { + Kind(Kind), Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()), + FixIts(Hints.begin(), Hints.end()) { llvm::sort(FixIts); } @@ -362,13 +386,12 @@ static void buildFixItLine(std::string &CaretLine, std::string &FixItLine, size_t PrevHintEndCol = 0; - for (ArrayRef<SMFixIt>::iterator I = FixIts.begin(), E = FixIts.end(); I != E; - ++I) { + for (const llvm::SMFixIt &Fixit : FixIts) { // If the fixit contains a newline or tab, ignore it. - if (I->getText().find_first_of("\n\r\t") != StringRef::npos) + if (Fixit.getText().find_first_of("\n\r\t") != StringRef::npos) continue; - SMRange R = I->getRange(); + SMRange R = Fixit.getRange(); // If the line doesn't contain any part of the range, then ignore it. if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart) @@ -397,16 +420,15 @@ static void buildFixItLine(std::string &CaretLine, std::string &FixItLine, // FIXME: This assertion is intended to catch unintended use of multibyte // characters in fixits. If we decide to do this, we'll have to track // separate byte widths for the source and fixit lines. - assert((size_t)sys::locale::columnWidth(I->getText()) == - I->getText().size()); + assert((size_t)sys::locale::columnWidth(Fixit.getText()) == + Fixit.getText().size()); // This relies on one byte per column in our fixit hints. - unsigned LastColumnModified = HintCol + I->getText().size(); + unsigned LastColumnModified = HintCol + Fixit.getText().size(); if (LastColumnModified > FixItLine.size()) FixItLine.resize(LastColumnModified, ' '); - std::copy(I->getText().begin(), I->getText().end(), - FixItLine.begin() + HintCol); + llvm::copy(Fixit.getText(), FixItLine.begin() + HintCol); PrevHintEndCol = LastColumnModified; @@ -500,7 +522,7 @@ void SMDiagnostic::print(const char *ProgName, raw_ostream &OS, bool ShowColors, // map like Clang's TextDiagnostic. For now, we'll just handle tabs by // expanding them later, and bail out rather than show incorrect ranges and // misaligned fixits for any other odd characters. - if (find_if(LineContents, isNonASCII) != LineContents.end()) { + if (any_of(LineContents, isNonASCII)) { printSourceLine(OS, LineContents); return; } @@ -510,11 +532,9 @@ void SMDiagnostic::print(const char *ProgName, raw_ostream &OS, bool ShowColors, std::string CaretLine(NumColumns + 1, ' '); // Expand any ranges. - for (unsigned r = 0, e = Ranges.size(); r != e; ++r) { - std::pair<unsigned, unsigned> R = Ranges[r]; + for (const std::pair<unsigned, unsigned> &R : Ranges) std::fill(&CaretLine[R.first], &CaretLine[std::min((size_t)R.second, CaretLine.size())], '~'); - } // Add any fix-its. // FIXME: Find the beginning of the line properly for multibyte characters. diff --git a/contrib/llvm-project/llvm/lib/Support/TargetParser.cpp b/contrib/llvm-project/llvm/lib/Support/TargetParser.cpp index 031384ebaa91..3ccdc55b305d 100644 --- a/contrib/llvm-project/llvm/lib/Support/TargetParser.cpp +++ b/contrib/llvm-project/llvm/lib/Support/TargetParser.cpp @@ -30,7 +30,7 @@ struct GPUInfo { unsigned Features; }; -constexpr GPUInfo R600GPUs[26] = { +constexpr GPUInfo R600GPUs[] = { // Name Canonical Kind Features // Name {{"r600"}, {"r600"}, GK_R600, FEATURE_NONE }, @@ -63,16 +63,17 @@ constexpr GPUInfo R600GPUs[26] = { // This table should be sorted by the value of GPUKind // Don't bother listing the implicitly true features -constexpr GPUInfo AMDGCNGPUs[38] = { +constexpr GPUInfo AMDGCNGPUs[] = { // Name Canonical Kind Features // Name {{"gfx600"}, {"gfx600"}, GK_GFX600, FEATURE_FAST_FMA_F32}, {{"tahiti"}, {"gfx600"}, GK_GFX600, FEATURE_FAST_FMA_F32}, {{"gfx601"}, {"gfx601"}, GK_GFX601, FEATURE_NONE}, - {{"hainan"}, {"gfx601"}, GK_GFX601, FEATURE_NONE}, - {{"oland"}, {"gfx601"}, GK_GFX601, FEATURE_NONE}, {{"pitcairn"}, {"gfx601"}, GK_GFX601, FEATURE_NONE}, {{"verde"}, {"gfx601"}, GK_GFX601, FEATURE_NONE}, + {{"gfx602"}, {"gfx602"}, GK_GFX602, FEATURE_NONE}, + {{"hainan"}, {"gfx602"}, GK_GFX602, FEATURE_NONE}, + {{"oland"}, {"gfx602"}, GK_GFX602, FEATURE_NONE}, {{"gfx700"}, {"gfx700"}, GK_GFX700, FEATURE_NONE}, {{"kaveri"}, {"gfx700"}, GK_GFX700, FEATURE_NONE}, {{"gfx701"}, {"gfx701"}, GK_GFX701, FEATURE_FAST_FMA_F32}, @@ -83,36 +84,43 @@ constexpr GPUInfo AMDGCNGPUs[38] = { {{"mullins"}, {"gfx703"}, GK_GFX703, FEATURE_NONE}, {{"gfx704"}, {"gfx704"}, GK_GFX704, FEATURE_NONE}, {{"bonaire"}, {"gfx704"}, GK_GFX704, FEATURE_NONE}, - {{"gfx801"}, {"gfx801"}, GK_GFX801, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32}, - {{"carrizo"}, {"gfx801"}, GK_GFX801, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32}, - {{"gfx802"}, {"gfx802"}, GK_GFX802, FEATURE_FAST_DENORMAL_F32}, - {{"iceland"}, {"gfx802"}, GK_GFX802, FEATURE_FAST_DENORMAL_F32}, - {{"tonga"}, {"gfx802"}, GK_GFX802, FEATURE_FAST_DENORMAL_F32}, - {{"gfx803"}, {"gfx803"}, GK_GFX803, FEATURE_FAST_DENORMAL_F32}, - {{"fiji"}, {"gfx803"}, GK_GFX803, FEATURE_FAST_DENORMAL_F32}, - {{"polaris10"}, {"gfx803"}, GK_GFX803, FEATURE_FAST_DENORMAL_F32}, - {{"polaris11"}, {"gfx803"}, GK_GFX803, FEATURE_FAST_DENORMAL_F32}, - {{"gfx810"}, {"gfx810"}, GK_GFX810, FEATURE_FAST_DENORMAL_F32}, - {{"stoney"}, {"gfx810"}, GK_GFX810, FEATURE_FAST_DENORMAL_F32}, - {{"gfx900"}, {"gfx900"}, GK_GFX900, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32}, - {{"gfx902"}, {"gfx902"}, GK_GFX902, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32}, - {{"gfx904"}, {"gfx904"}, GK_GFX904, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32}, - {{"gfx906"}, {"gfx906"}, GK_GFX906, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32}, - {{"gfx908"}, {"gfx908"}, GK_GFX908, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32}, - {{"gfx909"}, {"gfx909"}, GK_GFX909, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32}, - {{"gfx1010"}, {"gfx1010"}, GK_GFX1010, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, - {{"gfx1011"}, {"gfx1011"}, GK_GFX1011, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, - {{"gfx1012"}, {"gfx1012"}, GK_GFX1012, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, + {{"gfx705"}, {"gfx705"}, GK_GFX705, FEATURE_NONE}, + {{"gfx801"}, {"gfx801"}, GK_GFX801, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"carrizo"}, {"gfx801"}, GK_GFX801, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx802"}, {"gfx802"}, GK_GFX802, FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"iceland"}, {"gfx802"}, GK_GFX802, FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"tonga"}, {"gfx802"}, GK_GFX802, FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx803"}, {"gfx803"}, GK_GFX803, FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"fiji"}, {"gfx803"}, GK_GFX803, FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"polaris10"}, {"gfx803"}, GK_GFX803, FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"polaris11"}, {"gfx803"}, GK_GFX803, FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx805"}, {"gfx805"}, GK_GFX805, FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"tongapro"}, {"gfx805"}, GK_GFX805, FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx810"}, {"gfx810"}, GK_GFX810, FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"stoney"}, {"gfx810"}, GK_GFX810, FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx900"}, {"gfx900"}, GK_GFX900, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx902"}, {"gfx902"}, GK_GFX902, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx904"}, {"gfx904"}, GK_GFX904, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx906"}, {"gfx906"}, GK_GFX906, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK|FEATURE_SRAMECC}, + {{"gfx908"}, {"gfx908"}, GK_GFX908, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK|FEATURE_SRAMECC}, + {{"gfx909"}, {"gfx909"}, GK_GFX909, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx90c"}, {"gfx90c"}, GK_GFX90C, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx1010"}, {"gfx1010"}, GK_GFX1010, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32|FEATURE_XNACK}, + {{"gfx1011"}, {"gfx1011"}, GK_GFX1011, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32|FEATURE_XNACK}, + {{"gfx1012"}, {"gfx1012"}, GK_GFX1012, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32|FEATURE_XNACK}, {{"gfx1030"}, {"gfx1030"}, GK_GFX1030, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, + {{"gfx1031"}, {"gfx1031"}, GK_GFX1031, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, + {{"gfx1032"}, {"gfx1032"}, GK_GFX1032, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, + {{"gfx1033"}, {"gfx1033"}, GK_GFX1033, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32}, }; const GPUInfo *getArchEntry(AMDGPU::GPUKind AK, ArrayRef<GPUInfo> Table) { GPUInfo Search = { {""}, {""}, AK, AMDGPU::FEATURE_NONE }; - auto I = std::lower_bound(Table.begin(), Table.end(), Search, - [](const GPUInfo &A, const GPUInfo &B) { - return A.Kind < B.Kind; - }); + auto I = + llvm::lower_bound(Table, Search, [](const GPUInfo &A, const GPUInfo &B) { + return A.Kind < B.Kind; + }); if (I == Table.end()) return nullptr; @@ -187,14 +195,17 @@ AMDGPU::IsaVersion AMDGPU::getIsaVersion(StringRef GPU) { switch (AK) { case GK_GFX600: return {6, 0, 0}; case GK_GFX601: return {6, 0, 1}; + case GK_GFX602: return {6, 0, 2}; case GK_GFX700: return {7, 0, 0}; case GK_GFX701: return {7, 0, 1}; case GK_GFX702: return {7, 0, 2}; case GK_GFX703: return {7, 0, 3}; case GK_GFX704: return {7, 0, 4}; + case GK_GFX705: return {7, 0, 5}; case GK_GFX801: return {8, 0, 1}; case GK_GFX802: return {8, 0, 2}; case GK_GFX803: return {8, 0, 3}; + case GK_GFX805: return {8, 0, 5}; case GK_GFX810: return {8, 1, 0}; case GK_GFX900: return {9, 0, 0}; case GK_GFX902: return {9, 0, 2}; @@ -202,14 +213,27 @@ AMDGPU::IsaVersion AMDGPU::getIsaVersion(StringRef GPU) { case GK_GFX906: return {9, 0, 6}; case GK_GFX908: return {9, 0, 8}; case GK_GFX909: return {9, 0, 9}; + case GK_GFX90C: return {9, 0, 12}; case GK_GFX1010: return {10, 1, 0}; case GK_GFX1011: return {10, 1, 1}; case GK_GFX1012: return {10, 1, 2}; case GK_GFX1030: return {10, 3, 0}; + case GK_GFX1031: return {10, 3, 1}; + case GK_GFX1032: return {10, 3, 2}; + case GK_GFX1033: return {10, 3, 3}; default: return {0, 0, 0}; } } +StringRef AMDGPU::getCanonicalArchName(const Triple &T, StringRef Arch) { + assert(T.isAMDGPU()); + auto ProcKind = T.isAMDGCN() ? parseArchAMDGCN(Arch) : parseArchR600(Arch); + if (ProcKind == GK_NONE) + return StringRef(); + + return T.isAMDGCN() ? getArchNameAMDGCN(ProcKind) : getArchNameR600(ProcKind); +} + namespace llvm { namespace RISCV { @@ -233,6 +257,12 @@ bool checkCPUKind(CPUKind Kind, bool IsRV64) { return RISCVCPUInfo[static_cast<unsigned>(Kind)].is64Bit() == IsRV64; } +bool checkTuneCPUKind(CPUKind Kind, bool IsRV64) { + if (Kind == CK_INVALID) + return false; + return RISCVCPUInfo[static_cast<unsigned>(Kind)].is64Bit() == IsRV64; +} + CPUKind parseCPUKind(StringRef CPU) { return llvm::StringSwitch<CPUKind>(CPU) #define PROC(ENUM, NAME, FEATURES, DEFAULT_MARCH) .Case(NAME, CK_##ENUM) @@ -240,6 +270,22 @@ CPUKind parseCPUKind(StringRef CPU) { .Default(CK_INVALID); } +StringRef resolveTuneCPUAlias(StringRef TuneCPU, bool IsRV64) { + return llvm::StringSwitch<StringRef>(TuneCPU) +#define PROC_ALIAS(NAME, RV32, RV64) .Case(NAME, IsRV64 ? StringRef(RV64) : StringRef(RV32)) +#include "llvm/Support/RISCVTargetParser.def" + .Default(TuneCPU); +} + +CPUKind parseTuneCPUKind(StringRef TuneCPU, bool IsRV64) { + TuneCPU = resolveTuneCPUAlias(TuneCPU, IsRV64); + + return llvm::StringSwitch<CPUKind>(TuneCPU) +#define PROC(ENUM, NAME, FEATURES, DEFAULT_MARCH) .Case(NAME, CK_##ENUM) +#include "llvm/Support/RISCVTargetParser.def" + .Default(CK_INVALID); +} + StringRef getMArchFromMcpu(StringRef CPU) { CPUKind Kind = parseCPUKind(CPU); return RISCVCPUInfo[static_cast<unsigned>(Kind)].DefaultMarch; @@ -252,6 +298,15 @@ void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) { } } +void fillValidTuneCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) { + for (const auto &C : RISCVCPUInfo) { + if (C.Kind != CK_INVALID && IsRV64 == C.is64Bit()) + Values.emplace_back(C.Name); + } +#define PROC_ALIAS(NAME, RV32, RV64) Values.emplace_back(StringRef(NAME)); +#include "llvm/Support/RISCVTargetParser.def" +} + // Get all features except standard extension feature bool getCPUFeaturesExceptStdExt(CPUKind Kind, std::vector<StringRef> &Features) { diff --git a/contrib/llvm-project/llvm/lib/Support/Timer.cpp b/contrib/llvm-project/llvm/lib/Support/Timer.cpp index c97538cb560a..f5a512f9a22d 100644 --- a/contrib/llvm-project/llvm/lib/Support/Timer.cpp +++ b/contrib/llvm-project/llvm/lib/Support/Timer.cpp @@ -53,6 +53,11 @@ namespace { InfoOutputFilename("info-output-file", cl::value_desc("filename"), cl::desc("File to append -stats and -timer output to"), cl::Hidden, cl::location(getLibSupportInfoOutputFilename())); + + static cl::opt<bool> + SortTimers("sort-timers", cl::desc("In the report, sort the timers in each group " + "in wall clock time order"), + cl::init(true), cl::Hidden); } std::unique_ptr<raw_fd_ostream> llvm::CreateInfoOutputFile() { @@ -138,7 +143,7 @@ TimeRecord TimeRecord::getCurrentTime(bool Start) { void Timer::startTimer() { assert(!Running && "Cannot start a running timer"); Running = Triggered = true; - Signposts->startTimerInterval(this); + Signposts->startInterval(this, getName()); StartTime = TimeRecord::getCurrentTime(true); } @@ -147,7 +152,7 @@ void Timer::stopTimer() { Running = false; Time += TimeRecord::getCurrentTime(false); Time -= StartTime; - Signposts->endTimerInterval(this); + Signposts->endInterval(this, getName()); } void Timer::clear() { @@ -301,8 +306,9 @@ void TimerGroup::addTimer(Timer &T) { } void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { - // Sort the timers in descending order by amount of time taken. - llvm::sort(TimersToPrint); + // Perhaps sort the timers in descending order by amount of time taken. + if (SortTimers) + llvm::sort(TimersToPrint); TimeRecord Total; for (const PrintRecord &Record : TimersToPrint) diff --git a/contrib/llvm-project/llvm/lib/Support/TrigramIndex.cpp b/contrib/llvm-project/llvm/lib/Support/TrigramIndex.cpp index 88375e6e7863..4370adc9c3e0 100644 --- a/contrib/llvm-project/llvm/lib/Support/TrigramIndex.cpp +++ b/contrib/llvm-project/llvm/lib/Support/TrigramIndex.cpp @@ -15,12 +15,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/TrigramIndex.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" - #include <set> -#include <string> -#include <unordered_map> using namespace llvm; @@ -30,7 +25,7 @@ static bool isAdvancedMetachar(unsigned Char) { return strchr(RegexAdvancedMetachars, Char) != nullptr; } -void TrigramIndex::insert(std::string Regex) { +void TrigramIndex::insert(const std::string &Regex) { if (Defeated) return; std::set<unsigned> Was; unsigned Cnt = 0; diff --git a/contrib/llvm-project/llvm/lib/Support/Triple.cpp b/contrib/llvm-project/llvm/lib/Support/Triple.cpp index fec1985ccaca..4f483c965282 100644 --- a/contrib/llvm-project/llvm/lib/Support/Triple.cpp +++ b/contrib/llvm-project/llvm/lib/Support/Triple.cpp @@ -36,6 +36,7 @@ StringRef Triple::getArchTypeName(ArchType Kind) { case avr: return "avr"; case bpfeb: return "bpfeb"; case bpfel: return "bpfel"; + case csky: return "csky"; case hexagon: return "hexagon"; case hsail64: return "hsail64"; case hsail: return "hsail"; @@ -53,6 +54,7 @@ StringRef Triple::getArchTypeName(ArchType Kind) { case ppc64: return "powerpc64"; case ppc64le: return "powerpc64le"; case ppc: return "powerpc"; + case ppcle: return "powerpcle"; case r600: return "r600"; case renderscript32: return "renderscript32"; case renderscript64: return "renderscript64"; @@ -100,7 +102,8 @@ StringRef Triple::getArchTypePrefix(ArchType Kind) { case ppc64: case ppc64le: - case ppc: return "ppc"; + case ppc: + case ppcle: return "ppc"; case mips: case mipsel: @@ -151,6 +154,7 @@ StringRef Triple::getArchTypePrefix(ArchType Kind) { case riscv64: return "riscv"; case ve: return "ve"; + case csky: return "csky"; } } @@ -160,8 +164,6 @@ StringRef Triple::getVendorTypeName(VendorType Kind) { case AMD: return "amd"; case Apple: return "apple"; - case BGP: return "bgp"; - case BGQ: return "bgq"; case CSR: return "csr"; case Freescale: return "fsl"; case IBM: return "ibm"; @@ -187,7 +189,6 @@ StringRef Triple::getOSTypeName(OSType Kind) { case AMDHSA: return "amdhsa"; case AMDPAL: return "amdpal"; case Ananas: return "ananas"; - case CNK: return "cnk"; case CUDA: return "cuda"; case CloudABI: return "cloudabi"; case Contiki: return "contiki"; @@ -218,6 +219,7 @@ StringRef Triple::getOSTypeName(OSType Kind) { case WASI: return "wasi"; case WatchOS: return "watchos"; case Win32: return "windows"; + case ZOS: return "zos"; } llvm_unreachable("Invalid OSType"); @@ -238,6 +240,7 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) { case GNUEABI: return "gnueabi"; case GNUEABIHF: return "gnueabihf"; case GNUX32: return "gnux32"; + case GNUILP32: return "gnu_ilp32"; case Itanium: return "itanium"; case MSVC: return "msvc"; case MacABI: return "macabi"; @@ -286,6 +289,8 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { .Case("ppc64", ppc64) .Case("ppc32", ppc) .Case("ppc", ppc) + .Case("ppc32le", ppcle) + .Case("ppcle", ppcle) .Case("ppc64le", ppc64le) .Case("r600", r600) .Case("amdgcn", amdgcn) @@ -321,6 +326,7 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { .Case("renderscript32", renderscript32) .Case("renderscript64", renderscript64) .Case("ve", ve) + .Case("csky", csky) .Default(UnknownArch); } @@ -396,6 +402,7 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Cases("i786", "i886", "i986", Triple::x86) .Cases("amd64", "x86_64", "x86_64h", Triple::x86_64) .Cases("powerpc", "powerpcspe", "ppc", "ppc32", Triple::ppc) + .Cases("powerpcle", "ppcle", "ppc32le", Triple::ppcle) .Cases("powerpc64", "ppu", "ppc64", Triple::ppc64) .Cases("powerpc64le", "ppc64le", Triple::ppc64le) .Case("xscale", Triple::arm) @@ -406,6 +413,7 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Case("arc", Triple::arc) .Case("arm64", Triple::aarch64) .Case("arm64_32", Triple::aarch64_32) + .Case("arm64e", Triple::aarch64) .Case("arm", Triple::arm) .Case("armeb", Triple::armeb) .Case("thumb", Triple::thumb) @@ -450,6 +458,7 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Case("ve", Triple::ve) .Case("wasm32", Triple::wasm32) .Case("wasm64", Triple::wasm64) + .Case("csky", Triple::csky) .Default(Triple::UnknownArch); // Some architectures require special parsing logic just to compute the @@ -470,8 +479,6 @@ static Triple::VendorType parseVendor(StringRef VendorName) { .Case("apple", Triple::Apple) .Case("pc", Triple::PC) .Case("scei", Triple::SCEI) - .Case("bgp", Triple::BGP) - .Case("bgq", Triple::BGQ) .Case("fsl", Triple::Freescale) .Case("ibm", Triple::IBM) .Case("img", Triple::ImaginationTechnologies) @@ -504,11 +511,11 @@ static Triple::OSType parseOS(StringRef OSName) { .StartsWith("solaris", Triple::Solaris) .StartsWith("win32", Triple::Win32) .StartsWith("windows", Triple::Win32) + .StartsWith("zos", Triple::ZOS) .StartsWith("haiku", Triple::Haiku) .StartsWith("minix", Triple::Minix) .StartsWith("rtems", Triple::RTEMS) .StartsWith("nacl", Triple::NaCl) - .StartsWith("cnk", Triple::CNK) .StartsWith("aix", Triple::AIX) .StartsWith("cuda", Triple::CUDA) .StartsWith("nvcl", Triple::NVCL) @@ -529,26 +536,27 @@ static Triple::OSType parseOS(StringRef OSName) { static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { return StringSwitch<Triple::EnvironmentType>(EnvironmentName) - .StartsWith("eabihf", Triple::EABIHF) - .StartsWith("eabi", Triple::EABI) - .StartsWith("gnuabin32", Triple::GNUABIN32) - .StartsWith("gnuabi64", Triple::GNUABI64) - .StartsWith("gnueabihf", Triple::GNUEABIHF) - .StartsWith("gnueabi", Triple::GNUEABI) - .StartsWith("gnux32", Triple::GNUX32) - .StartsWith("code16", Triple::CODE16) - .StartsWith("gnu", Triple::GNU) - .StartsWith("android", Triple::Android) - .StartsWith("musleabihf", Triple::MuslEABIHF) - .StartsWith("musleabi", Triple::MuslEABI) - .StartsWith("musl", Triple::Musl) - .StartsWith("msvc", Triple::MSVC) - .StartsWith("itanium", Triple::Itanium) - .StartsWith("cygnus", Triple::Cygnus) - .StartsWith("coreclr", Triple::CoreCLR) - .StartsWith("simulator", Triple::Simulator) - .StartsWith("macabi", Triple::MacABI) - .Default(Triple::UnknownEnvironment); + .StartsWith("eabihf", Triple::EABIHF) + .StartsWith("eabi", Triple::EABI) + .StartsWith("gnuabin32", Triple::GNUABIN32) + .StartsWith("gnuabi64", Triple::GNUABI64) + .StartsWith("gnueabihf", Triple::GNUEABIHF) + .StartsWith("gnueabi", Triple::GNUEABI) + .StartsWith("gnux32", Triple::GNUX32) + .StartsWith("gnu_ilp32", Triple::GNUILP32) + .StartsWith("code16", Triple::CODE16) + .StartsWith("gnu", Triple::GNU) + .StartsWith("android", Triple::Android) + .StartsWith("musleabihf", Triple::MuslEABIHF) + .StartsWith("musleabi", Triple::MuslEABI) + .StartsWith("musl", Triple::Musl) + .StartsWith("msvc", Triple::MSVC) + .StartsWith("itanium", Triple::Itanium) + .StartsWith("cygnus", Triple::Cygnus) + .StartsWith("coreclr", Triple::CoreCLR) + .StartsWith("simulator", Triple::Simulator) + .StartsWith("macabi", Triple::MacABI) + .Default(Triple::UnknownEnvironment); } static Triple::ObjectFormatType parseFormat(StringRef EnvironmentName) { @@ -558,6 +566,7 @@ static Triple::ObjectFormatType parseFormat(StringRef EnvironmentName) { .EndsWith("xcoff", Triple::XCOFF) .EndsWith("coff", Triple::COFF) .EndsWith("elf", Triple::ELF) + .EndsWith("goff", Triple::GOFF) .EndsWith("macho", Triple::MachO) .EndsWith("wasm", Triple::Wasm) .Default(Triple::UnknownObjectFormat); @@ -571,6 +580,9 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) { if (SubArchName == "powerpcspe") return Triple::PPCSubArch_spe; + if (SubArchName == "arm64e") + return Triple::AArch64SubArch_arm64e; + StringRef ARMSubArch = ARM::getCanonicalArchName(SubArchName); // For now, this is the small part. Early return. @@ -631,6 +643,8 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) { return Triple::ARMSubArch_v8_5a; case ARM::ArchKind::ARMV8_6A: return Triple::ARMSubArch_v8_6a; + case ARM::ArchKind::ARMV8_7A: + return Triple::ARMSubArch_v8_7a; case ARM::ArchKind::ARMV8R: return Triple::ARMSubArch_v8r; case ARM::ArchKind::ARMV8MBaseline: @@ -649,6 +663,7 @@ static StringRef getObjectFormatTypeName(Triple::ObjectFormatType Kind) { case Triple::UnknownObjectFormat: return ""; case Triple::COFF: return "coff"; case Triple::ELF: return "elf"; + case Triple::GOFF: return "goff"; case Triple::MachO: return "macho"; case Triple::Wasm: return "wasm"; case Triple::XCOFF: return "xcoff"; @@ -680,6 +695,7 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { case Triple::avr: case Triple::bpfeb: case Triple::bpfel: + case Triple::csky: case Triple::hexagon: case Triple::hsail64: case Triple::hsail: @@ -695,6 +711,7 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { case Triple::nvptx64: case Triple::nvptx: case Triple::ppc64le: + case Triple::ppcle: case Triple::r600: case Triple::renderscript32: case Triple::renderscript64: @@ -706,7 +723,6 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { case Triple::sparcv9: case Triple::spir64: case Triple::spir: - case Triple::systemz: case Triple::tce: case Triple::tcele: case Triple::thumbeb: @@ -720,6 +736,11 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { return Triple::XCOFF; return Triple::ELF; + case Triple::systemz: + if (T.isOSzOS()) + return Triple::GOFF; + return Triple::ELF; + case Triple::wasm32: case Triple::wasm64: return Triple::Wasm; @@ -1017,7 +1038,7 @@ StringRef Triple::getOSAndEnvironmentName() const { } static unsigned EatNumber(StringRef &Str) { - assert(!Str.empty() && Str[0] >= '0' && Str[0] <= '9' && "Not a number"); + assert(!Str.empty() && isDigit(Str[0]) && "Not a number"); unsigned Result = 0; do { @@ -1026,7 +1047,7 @@ static unsigned EatNumber(StringRef &Str) { // Eat the digit. Str = Str.substr(1); - } while (!Str.empty() && Str[0] >= '0' && Str[0] <= '9'); + } while (!Str.empty() && isDigit(Str[0])); return Result; } @@ -1249,6 +1270,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::arc: case llvm::Triple::arm: case llvm::Triple::armeb: + case llvm::Triple::csky: case llvm::Triple::hexagon: case llvm::Triple::hsail: case llvm::Triple::kalimba: @@ -1258,6 +1280,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::mipsel: case llvm::Triple::nvptx: case llvm::Triple::ppc: + case llvm::Triple::ppcle: case llvm::Triple::r600: case llvm::Triple::renderscript32: case llvm::Triple::riscv32: @@ -1321,7 +1344,6 @@ Triple Triple::get32BitArchVariant() const { case Triple::bpfeb: case Triple::bpfel: case Triple::msp430: - case Triple::ppc64le: case Triple::systemz: case Triple::ve: T.setArch(UnknownArch); @@ -1332,6 +1354,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::arc: case Triple::arm: case Triple::armeb: + case Triple::csky: case Triple::hexagon: case Triple::hsail: case Triple::kalimba: @@ -1341,6 +1364,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::mipsel: case Triple::nvptx: case Triple::ppc: + case Triple::ppcle: case Triple::r600: case Triple::renderscript32: case Triple::riscv32: @@ -1367,6 +1391,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::mips64el: T.setArch(Triple::mipsel); 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; case Triple::renderscript64: T.setArch(Triple::renderscript32); break; case Triple::riscv64: T.setArch(Triple::riscv32); break; case Triple::sparcv9: T.setArch(Triple::sparc); break; @@ -1383,6 +1408,7 @@ Triple Triple::get64BitArchVariant() const { case Triple::UnknownArch: case Triple::arc: case Triple::avr: + case Triple::csky: case Triple::hexagon: case Triple::kalimba: case Triple::lanai: @@ -1430,6 +1456,7 @@ Triple Triple::get64BitArchVariant() const { case Triple::mipsel: T.setArch(Triple::mips64el); 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; case Triple::renderscript32: T.setArch(Triple::renderscript64); break; case Triple::riscv32: T.setArch(Triple::riscv64); break; case Triple::sparc: T.setArch(Triple::sparcv9); break; @@ -1476,6 +1503,7 @@ Triple Triple::getBigEndianArchVariant() const { case Triple::x86_64: case Triple::xcore: case Triple::ve: + case Triple::csky: // ARM is intentionally unsupported here, changing the architecture would // drop any arch suffixes. @@ -1488,6 +1516,7 @@ Triple Triple::getBigEndianArchVariant() const { 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::ppcle: T.setArch(Triple::ppc); break; case Triple::ppc64le: T.setArch(Triple::ppc64); break; case Triple::sparcel: T.setArch(Triple::sparc); break; case Triple::tcele: T.setArch(Triple::tce); break; @@ -1505,7 +1534,6 @@ Triple Triple::getLittleEndianArchVariant() const { switch (getArch()) { case Triple::UnknownArch: case Triple::lanai: - case Triple::ppc: case Triple::sparcv9: case Triple::systemz: @@ -1520,6 +1548,7 @@ Triple Triple::getLittleEndianArchVariant() const { 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::ppc: T.setArch(Triple::ppcle); break; case Triple::ppc64: T.setArch(Triple::ppc64le); break; case Triple::sparc: T.setArch(Triple::sparcel); break; case Triple::tce: T.setArch(Triple::tcele); break; @@ -1539,6 +1568,7 @@ bool Triple::isLittleEndian() const { case Triple::arm: case Triple::avr: case Triple::bpfel: + case Triple::csky: case Triple::hexagon: case Triple::hsail64: case Triple::hsail: @@ -1550,6 +1580,7 @@ bool Triple::isLittleEndian() const { case Triple::msp430: case Triple::nvptx64: case Triple::nvptx: + case Triple::ppcle: case Triple::ppc64le: case Triple::r600: case Triple::renderscript32: @@ -1636,6 +1667,9 @@ VersionTuple Triple::getMinimumSupportedOSVersion() const { // ARM64 simulators are supported for iOS 14+. if (isMacCatalystEnvironment() || isSimulatorEnvironment()) return VersionTuple(14, 0, 0); + // ARM64e slice is supported starting from iOS 14. + if (isArm64e()) + return VersionTuple(14, 0, 0); break; case Triple::TvOS: // ARM64 simulators are supported for tvOS 14+. diff --git a/contrib/llvm-project/llvm/lib/Support/Unicode.cpp b/contrib/llvm-project/llvm/lib/Support/Unicode.cpp index 4d195069682b..bb6e75555b4c 100644 --- a/contrib/llvm-project/llvm/lib/Support/Unicode.cpp +++ b/contrib/llvm-project/llvm/lib/Support/Unicode.cpp @@ -339,11 +339,22 @@ static inline int charWidth(int UCS) return 1; } +static bool isprintableascii(char c) { return c > 31 && c < 127; } + int columnWidthUTF8(StringRef Text) { unsigned ColumnWidth = 0; unsigned Length; for (size_t i = 0, e = Text.size(); i < e; i += Length) { Length = getNumBytesForUTF8(Text[i]); + + // fast path for ASCII characters + if (Length == 1) { + if (!isprintableascii(Text[i])) + return ErrorNonPrintableCharacter; + ColumnWidth += 1; + continue; + } + if (Length <= 0 || i + Length > Text.size()) return ErrorInvalidUTF8; UTF32 buf[1]; diff --git a/contrib/llvm-project/llvm/lib/Support/Unix/Path.inc b/contrib/llvm-project/llvm/lib/Support/Unix/Path.inc index d91b269cc6d3..77f3f54bd881 100644 --- a/contrib/llvm-project/llvm/lib/Support/Unix/Path.inc +++ b/contrib/llvm-project/llvm/lib/Support/Unix/Path.inc @@ -33,6 +33,7 @@ #include <dirent.h> #include <pwd.h> +#include <sys/file.h> #ifdef __APPLE__ #include <mach-o/dyld.h> @@ -146,6 +147,9 @@ test_dir(char ret[PATH_MAX], const char *dir, const char *bin) static char * getprogpath(char ret[PATH_MAX], const char *bin) { + if (bin == nullptr) + return nullptr; + /* First approach: absolute path. */ if (bin[0] == '/') { if (test_dir(ret, "/", bin) == 0) @@ -681,8 +685,6 @@ void expand_tilde(const Twine &path, SmallVectorImpl<char> &dest) { path.toVector(dest); expandTildeExpr(dest); - - return; } static file_type typeForMode(mode_t Mode) { @@ -791,6 +793,16 @@ std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, if (::futimes(FD, Times)) return std::error_code(errno, std::generic_category()); return std::error_code(); +#elif defined(__MVS__) + attrib_t Attr; + memset(&Attr, 0, sizeof(Attr)); + Attr.att_atimechg = 1; + Attr.att_atime = sys::toTimeT(AccessTime); + Attr.att_mtimechg = 1; + Attr.att_mtime = sys::toTimeT(ModificationTime); + if (::__fchattr(FD, &Attr, sizeof(Attr)) != 0) + return std::error_code(errno, std::generic_category()); + return std::error_code(); #else #warning Missing futimes() and futimens() return make_error_code(errc::function_not_supported); @@ -1055,8 +1067,13 @@ file_t getStdoutHandle() { return 1; } file_t getStderrHandle() { return 2; } Expected<size_t> readNativeFile(file_t FD, MutableArrayRef<char> Buf) { +#if defined(__APPLE__) + size_t Size = std::min<size_t>(Buf.size(), INT32_MAX); +#else + size_t Size = Buf.size(); +#endif ssize_t NumRead = - sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Buf.size()); + sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Size); if (ssize_t(NumRead) == -1) return errorCodeToError(std::error_code(errno, std::generic_category())); return NumRead; @@ -1064,20 +1081,69 @@ Expected<size_t> readNativeFile(file_t FD, MutableArrayRef<char> Buf) { Expected<size_t> readNativeFileSlice(file_t FD, MutableArrayRef<char> Buf, uint64_t Offset) { +#if defined(__APPLE__) + size_t Size = std::min<size_t>(Buf.size(), INT32_MAX); +#else + size_t Size = Buf.size(); +#endif #ifdef HAVE_PREAD ssize_t NumRead = - sys::RetryAfterSignal(-1, ::pread, FD, Buf.data(), Buf.size(), Offset); + sys::RetryAfterSignal(-1, ::pread, FD, Buf.data(), Size, Offset); #else if (lseek(FD, Offset, SEEK_SET) == -1) return errorCodeToError(std::error_code(errno, std::generic_category())); ssize_t NumRead = - sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Buf.size()); + sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Size); #endif if (NumRead == -1) return errorCodeToError(std::error_code(errno, std::generic_category())); return NumRead; } +std::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout) { + auto Start = std::chrono::steady_clock::now(); + auto End = Start + Timeout; + do { + struct flock Lock; + memset(&Lock, 0, sizeof(Lock)); + Lock.l_type = F_WRLCK; + Lock.l_whence = SEEK_SET; + Lock.l_start = 0; + Lock.l_len = 0; + if (::fcntl(FD, F_SETLK, &Lock) != -1) + return std::error_code(); + int Error = errno; + if (Error != EACCES && Error != EAGAIN) + return std::error_code(Error, std::generic_category()); + usleep(1000); + } while (std::chrono::steady_clock::now() < End); + return make_error_code(errc::no_lock_available); +} + +std::error_code lockFile(int FD) { + struct flock Lock; + memset(&Lock, 0, sizeof(Lock)); + Lock.l_type = F_WRLCK; + Lock.l_whence = SEEK_SET; + Lock.l_start = 0; + Lock.l_len = 0; + if (::fcntl(FD, F_SETLKW, &Lock) != -1) + return std::error_code(); + int Error = errno; + return std::error_code(Error, std::generic_category()); +} + +std::error_code unlockFile(int FD) { + struct flock Lock; + Lock.l_type = F_UNLCK; + Lock.l_whence = SEEK_SET; + Lock.l_start = 0; + Lock.l_len = 0; + if (::fcntl(FD, F_SETLK, &Lock) != -1) + return std::error_code(); + return std::error_code(errno, std::generic_category()); +} + std::error_code closeFile(file_t &F) { file_t TmpF = F; F = kInvalidFile; diff --git a/contrib/llvm-project/llvm/lib/Support/Unix/Process.inc b/contrib/llvm-project/llvm/lib/Support/Unix/Process.inc index 24f16b51af7b..7425d084da27 100644 --- a/contrib/llvm-project/llvm/lib/Support/Unix/Process.inc +++ b/contrib/llvm-project/llvm/lib/Support/Unix/Process.inc @@ -313,7 +313,7 @@ unsigned Process::StandardErrColumns() { return getColumns(); } -#ifdef HAVE_TERMINFO +#ifdef LLVM_ENABLE_TERMINFO // We manually declare these extern functions because finding the correct // headers from various terminfo, curses, or other sources is harder than // writing their specs down. @@ -323,12 +323,12 @@ extern "C" int del_curterm(struct term *termp); extern "C" int tigetnum(char *capname); #endif -#ifdef HAVE_TERMINFO +#ifdef LLVM_ENABLE_TERMINFO static ManagedStatic<std::mutex> TermColorMutex; #endif static bool terminalHasColors(int fd) { -#ifdef HAVE_TERMINFO +#ifdef LLVM_ENABLE_TERMINFO // First, acquire a global lock because these C routines are thread hostile. std::lock_guard<std::mutex> G(*TermColorMutex); diff --git a/contrib/llvm-project/llvm/lib/Support/Unix/Program.inc b/contrib/llvm-project/llvm/lib/Support/Unix/Program.inc index 8f41fc015163..fb56fa4b0d1d 100644 --- a/contrib/llvm-project/llvm/lib/Support/Unix/Program.inc +++ b/contrib/llvm-project/llvm/lib/Support/Unix/Program.inc @@ -174,7 +174,8 @@ toNullTerminatedCStringArray(ArrayRef<StringRef> Strings, StringSaver &Saver) { static bool Execute(ProcessInfo &PI, StringRef Program, ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env, ArrayRef<Optional<StringRef>> Redirects, - unsigned MemoryLimit, std::string *ErrMsg) { + unsigned MemoryLimit, std::string *ErrMsg, + BitVector *AffinityMask) { if (!llvm::sys::fs::exists(Program)) { if (ErrMsg) *ErrMsg = std::string("Executable \"") + Program.str() + @@ -182,6 +183,9 @@ static bool Execute(ProcessInfo &PI, StringRef Program, return false; } + assert(!AffinityMask && "Starting a process with an affinity mask is " + "currently not supported on Unix!"); + BumpPtrAllocator Allocator; StringSaver Saver(Allocator); std::vector<const char *> ArgVector, EnvVector; diff --git a/contrib/llvm-project/llvm/lib/Support/Unix/Signals.inc b/contrib/llvm-project/llvm/lib/Support/Unix/Signals.inc index f68374d29f02..3d7b5d2fe5aa 100644 --- a/contrib/llvm-project/llvm/lib/Support/Unix/Signals.inc +++ b/contrib/llvm-project/llvm/lib/Support/Unix/Signals.inc @@ -36,6 +36,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Config/config.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/Support/ExitCodes.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/Format.h" @@ -46,7 +47,6 @@ #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <string> -#include <sysexits.h> #ifdef HAVE_BACKTRACE # include BACKTRACE_HEADER // For backtrace(). #endif @@ -331,7 +331,7 @@ static void RegisterHandlers() { // Not signal-safe. registerHandler(S, SignalKind::IsInfo); } -static void UnregisterHandlers() { +void sys::unregisterHandlers() { // Restore all of the signal handlers to how they were before we showed up. for (unsigned i = 0, e = NumRegisteredSignals.load(); i != e; ++i) { sigaction(RegisteredSignalInfo[i].SigNo, @@ -367,7 +367,7 @@ static RETSIGTYPE SignalHandler(int Sig) { // crashes when we return and the signal reissues. This also ensures that if // we crash in our signal handler that the program will terminate immediately // instead of recursing in the signal handler. - UnregisterHandlers(); + sys::unregisterHandlers(); // Unmask all potentially blocked kill signals. sigset_t SigMask; @@ -382,14 +382,15 @@ static RETSIGTYPE SignalHandler(int Sig) { OneShotPipeSignalFunction.exchange(nullptr)) return OldOneShotPipeFunction(); - if (std::find(std::begin(IntSigs), std::end(IntSigs), Sig) - != std::end(IntSigs)) { + bool IsIntSig = llvm::is_contained(IntSigs, Sig); + if (IsIntSig) if (auto OldInterruptFunction = InterruptFunction.exchange(nullptr)) return OldInterruptFunction(); - raise(Sig); // Execute the default handler. + if (Sig == SIGPIPE || IsIntSig) { + raise(Sig); // Execute the default handler. return; - } + } } // Otherwise if it is a fault (like SEGV) run any handler. @@ -554,7 +555,7 @@ static int unwindBacktrace(void **StackTrace, int MaxEntries) { // // On glibc systems we have the 'backtrace' function, which works nicely, but // doesn't demangle symbols. -void llvm::sys::PrintStackTrace(raw_ostream &OS) { +void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) { #if ENABLE_BACKTRACES static void *StackTrace[256]; int depth = 0; @@ -571,9 +572,15 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) { #endif if (!depth) return; - - if (printSymbolizedStackTrace(Argv0, StackTrace, depth, OS)) + // If "Depth" is not provided by the caller, use the return value of + // backtrace() for printing a symbolized stack trace. + if (!Depth) + Depth = depth; + if (printSymbolizedStackTrace(Argv0, StackTrace, Depth, OS)) return; + OS << "Stack dump without symbol names (ensure you have llvm-symbolizer in " + "your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point " + "to it):\n"; #if HAVE_DLFCN_H && HAVE_DLADDR int width = 0; for (int i = 0; i < depth; ++i) { @@ -615,7 +622,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) { OS << '\n'; } #elif defined(HAVE_BACKTRACE) - backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); + backtrace_symbols_fd(StackTrace, Depth, STDERR_FILENO); #endif #endif } diff --git a/contrib/llvm-project/llvm/lib/Support/VirtualFileSystem.cpp b/contrib/llvm-project/llvm/lib/Support/VirtualFileSystem.cpp index 5b757c9ea80d..05332b00bd1f 100644 --- a/contrib/llvm-project/llvm/lib/Support/VirtualFileSystem.cpp +++ b/contrib/llvm-project/llvm/lib/Support/VirtualFileSystem.cpp @@ -792,14 +792,12 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime, } bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime, - llvm::MemoryBuffer *Buffer, + const llvm::MemoryBufferRef &Buffer, Optional<uint32_t> User, Optional<uint32_t> Group, Optional<llvm::sys::fs::file_type> Type, Optional<llvm::sys::fs::perms> Perms) { - return addFile(P, ModificationTime, - llvm::MemoryBuffer::getMemBuffer( - Buffer->getBuffer(), Buffer->getBufferIdentifier()), + return addFile(P, ModificationTime, llvm::MemoryBuffer::getMemBuffer(Buffer), std::move(User), std::move(Group), std::move(Type), std::move(Perms)); } @@ -1018,7 +1016,6 @@ RedirectingFileSystem::RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> FS) if (auto ExternalWorkingDirectory = ExternalFS->getCurrentWorkingDirectory()) { WorkingDirectory = *ExternalWorkingDirectory; - ExternalFSValidWD = true; } } @@ -1077,12 +1074,6 @@ RedirectingFileSystem::setCurrentWorkingDirectory(const Twine &Path) { if (!exists(Path)) return errc::no_such_file_or_directory; - // Always change the external FS but ignore its result. - if (ExternalFS) { - auto EC = ExternalFS->setCurrentWorkingDirectory(Path); - ExternalFSValidWD = !static_cast<bool>(EC); - } - SmallString<128> AbsolutePath; Path.toVector(AbsolutePath); if (std::error_code EC = makeAbsolute(AbsolutePath)) @@ -1091,8 +1082,14 @@ RedirectingFileSystem::setCurrentWorkingDirectory(const Twine &Path) { return {}; } -std::error_code RedirectingFileSystem::isLocal(const Twine &Path, +std::error_code RedirectingFileSystem::isLocal(const Twine &Path_, bool &Result) { + SmallString<256> Path; + Path_.toVector(Path); + + if (std::error_code EC = makeCanonical(Path)) + return {}; + return ExternalFS->isLocal(Path, Result); } @@ -1127,14 +1124,21 @@ std::error_code RedirectingFileSystem::makeAbsolute(SmallVectorImpl<char> &Path) directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir, std::error_code &EC) { - ErrorOr<RedirectingFileSystem::Entry *> E = lookupPath(Dir); + SmallString<256> Path; + Dir.toVector(Path); + + EC = makeCanonical(Path); + if (EC) + return {}; + + ErrorOr<RedirectingFileSystem::Entry *> E = lookupPath(Path); if (!E) { EC = E.getError(); if (shouldUseExternalFS() && EC == errc::no_such_file_or_directory) - return ExternalFS->dir_begin(Dir, EC); + return ExternalFS->dir_begin(Path, EC); return {}; } - ErrorOr<Status> S = status(Dir, *E); + ErrorOr<Status> S = status(Path, *E); if (!S) { EC = S.getError(); return {}; @@ -1147,7 +1151,7 @@ directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir, auto *D = cast<RedirectingFileSystem::RedirectingDirectoryEntry>(*E); return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>( - Dir, D->contents_begin(), D->contents_end(), + Path, D->contents_begin(), D->contents_end(), /*IterateExternalFS=*/shouldUseExternalFS(), *ExternalFS, EC)); } @@ -1159,6 +1163,17 @@ StringRef RedirectingFileSystem::getExternalContentsPrefixDir() const { return ExternalContentsPrefixDir; } +void RedirectingFileSystem::setFallthrough(bool Fallthrough) { + IsFallthrough = Fallthrough; +} + +std::vector<StringRef> RedirectingFileSystem::getRoots() const { + std::vector<StringRef> R; + for (const auto &Root : Roots) + R.push_back(Root->getName()); + return R; +} + void RedirectingFileSystem::dump(raw_ostream &OS) const { for (const auto &Root : Roots) dumpEntry(OS, Root.get()); @@ -1263,7 +1278,8 @@ class llvm::vfs::RedirectingFileSystemParser { return true; } - RedirectingFileSystem::Entry * +public: + static RedirectingFileSystem::Entry * lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name, RedirectingFileSystem::Entry *ParentEntry = nullptr) { if (!ParentEntry) { // Look for a existent root @@ -1305,6 +1321,7 @@ class llvm::vfs::RedirectingFileSystemParser { return DE->getLastContent(); } +private: void uniqueOverlayTree(RedirectingFileSystem *FS, RedirectingFileSystem::Entry *SrcE, RedirectingFileSystem::Entry *NewParentE = nullptr) { @@ -1630,7 +1647,7 @@ public: } }; -RedirectingFileSystem * +std::unique_ptr<RedirectingFileSystem> RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer, SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext, @@ -1670,25 +1687,80 @@ RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer, if (!P.parse(Root, FS.get())) return nullptr; - return FS.release(); + return FS; } -ErrorOr<RedirectingFileSystem::Entry *> -RedirectingFileSystem::lookupPath(const Twine &Path_) const { - SmallString<256> Path; - Path_.toVector(Path); +std::unique_ptr<RedirectingFileSystem> RedirectingFileSystem::create( + ArrayRef<std::pair<std::string, std::string>> RemappedFiles, + bool UseExternalNames, FileSystem &ExternalFS) { + std::unique_ptr<RedirectingFileSystem> FS( + new RedirectingFileSystem(&ExternalFS)); + FS->UseExternalNames = UseExternalNames; + + StringMap<RedirectingFileSystem::Entry *> Entries; + + for (auto &Mapping : llvm::reverse(RemappedFiles)) { + SmallString<128> From = StringRef(Mapping.first); + SmallString<128> To = StringRef(Mapping.second); + { + auto EC = ExternalFS.makeAbsolute(From); + (void)EC; + assert(!EC && "Could not make absolute path"); + } - // Handle relative paths + // Check if we've already mapped this file. The first one we see (in the + // reverse iteration) wins. + RedirectingFileSystem::Entry *&ToEntry = Entries[From]; + if (ToEntry) + continue; + + // Add parent directories. + RedirectingFileSystem::Entry *Parent = nullptr; + StringRef FromDirectory = llvm::sys::path::parent_path(From); + for (auto I = llvm::sys::path::begin(FromDirectory), + E = llvm::sys::path::end(FromDirectory); + I != E; ++I) { + Parent = RedirectingFileSystemParser::lookupOrCreateEntry(FS.get(), *I, + Parent); + } + assert(Parent && "File without a directory?"); + { + auto EC = ExternalFS.makeAbsolute(To); + (void)EC; + assert(!EC && "Could not make absolute path"); + } + + // Add the file. + auto NewFile = + std::make_unique<RedirectingFileSystem::RedirectingFileEntry>( + llvm::sys::path::filename(From), To, + UseExternalNames + ? RedirectingFileSystem::RedirectingFileEntry::NK_External + : RedirectingFileSystem::RedirectingFileEntry::NK_Virtual); + ToEntry = NewFile.get(); + cast<RedirectingFileSystem::RedirectingDirectoryEntry>(Parent)->addContent( + std::move(NewFile)); + } + + return FS; +} + +std::error_code +RedirectingFileSystem::makeCanonical(SmallVectorImpl<char> &Path) const { if (std::error_code EC = makeAbsolute(Path)) return EC; - // Canonicalize path by removing ".", "..", "./", components. This is - // a VFS request, do not bother about symlinks in the path components - // but canonicalize in order to perform the correct entry search. - Path = canonicalize(Path); - if (Path.empty()) + llvm::SmallString<256> CanonicalPath = + canonicalize(StringRef(Path.data(), Path.size())); + if (CanonicalPath.empty()) return make_error_code(llvm::errc::invalid_argument); + Path.assign(CanonicalPath.begin(), CanonicalPath.end()); + return {}; +} + +ErrorOr<RedirectingFileSystem::Entry *> +RedirectingFileSystem::lookupPath(StringRef Path) const { sys::path::const_iterator Start = sys::path::begin(Path); sys::path::const_iterator End = sys::path::end(Path); for (const auto &Root : Roots) { @@ -1763,7 +1835,13 @@ ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path, } } -ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path) { +ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path_) { + SmallString<256> Path; + Path_.toVector(Path); + + if (std::error_code EC = makeCanonical(Path)) + return EC; + ErrorOr<RedirectingFileSystem::Entry *> Result = lookupPath(Path); if (!Result) { if (shouldUseExternalFS() && @@ -1801,7 +1879,13 @@ public: } // namespace ErrorOr<std::unique_ptr<File>> -RedirectingFileSystem::openFileForRead(const Twine &Path) { +RedirectingFileSystem::openFileForRead(const Twine &Path_) { + SmallString<256> Path; + Path_.toVector(Path); + + if (std::error_code EC = makeCanonical(Path)) + return EC; + ErrorOr<RedirectingFileSystem::Entry *> E = lookupPath(Path); if (!E) { if (shouldUseExternalFS() && @@ -1831,8 +1915,14 @@ RedirectingFileSystem::openFileForRead(const Twine &Path) { } std::error_code -RedirectingFileSystem::getRealPath(const Twine &Path, +RedirectingFileSystem::getRealPath(const Twine &Path_, SmallVectorImpl<char> &Output) const { + SmallString<256> Path; + Path_.toVector(Path); + + if (std::error_code EC = makeCanonical(Path)) + return EC; + ErrorOr<RedirectingFileSystem::Entry *> Result = lookupPath(Path); if (!Result) { if (shouldUseExternalFS() && @@ -1852,7 +1942,7 @@ RedirectingFileSystem::getRealPath(const Twine &Path, : llvm::errc::invalid_argument; } -IntrusiveRefCntPtr<FileSystem> +std::unique_ptr<FileSystem> vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer, SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext, @@ -1893,7 +1983,7 @@ void vfs::collectVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer, SmallVectorImpl<YAMLVFSEntry> &CollectedEntries, void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS) { - RedirectingFileSystem *VFS = RedirectingFileSystem::create( + std::unique_ptr<RedirectingFileSystem> VFS = RedirectingFileSystem::create( std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext, std::move(ExternalFS)); ErrorOr<RedirectingFileSystem::Entry *> RootE = VFS->lookupPath("/"); diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/Path.inc b/contrib/llvm-project/llvm/lib/Support/Windows/Path.inc index a4ffc0ec4313..dc9bcf868381 100644 --- a/contrib/llvm-project/llvm/lib/Support/Windows/Path.inc +++ b/contrib/llvm-project/llvm/lib/Support/Windows/Path.inc @@ -1273,6 +1273,43 @@ Expected<size_t> readNativeFileSlice(file_t FileHandle, return readNativeFileImpl(FileHandle, Buf, &Overlapped); } +std::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout) { + DWORD Flags = LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY; + OVERLAPPED OV = {}; + file_t File = convertFDToNativeFile(FD); + auto Start = std::chrono::steady_clock::now(); + auto End = Start + Timeout; + do { + if (::LockFileEx(File, Flags, 0, MAXDWORD, MAXDWORD, &OV)) + return std::error_code(); + DWORD Error = ::GetLastError(); + if (Error == ERROR_LOCK_VIOLATION) { + ::Sleep(1); + continue; + } + return mapWindowsError(Error); + } while (std::chrono::steady_clock::now() < End); + return mapWindowsError(ERROR_LOCK_VIOLATION); +} + +std::error_code lockFile(int FD) { + DWORD Flags = LOCKFILE_EXCLUSIVE_LOCK; + OVERLAPPED OV = {}; + file_t File = convertFDToNativeFile(FD); + if (::LockFileEx(File, Flags, 0, MAXDWORD, MAXDWORD, &OV)) + return std::error_code(); + DWORD Error = ::GetLastError(); + return mapWindowsError(Error); +} + +std::error_code unlockFile(int FD) { + OVERLAPPED OV = {}; + file_t File = convertFDToNativeFile(FD); + if (::UnlockFileEx(File, 0, MAXDWORD, MAXDWORD, &OV)) + return std::error_code(); + return mapWindowsError(::GetLastError()); +} + std::error_code closeFile(file_t &F) { file_t TmpF = F; F = kInvalidFile; diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/Process.inc b/contrib/llvm-project/llvm/lib/Support/Windows/Process.inc index 8064d4e17b29..910d2395d277 100644 --- a/contrib/llvm-project/llvm/lib/Support/Windows/Process.inc +++ b/contrib/llvm-project/llvm/lib/Support/Windows/Process.inc @@ -228,7 +228,8 @@ static std::error_code GetExecutableName(SmallVectorImpl<char> &Filename) { if (EC) return EC; - StringRef Base = sys::path::filename(Filename.data()); + // Make a copy of the filename since assign makes the StringRef invalid. + std::string Base = sys::path::filename(Filename.data()).str(); Filename.assign(Base.begin(), Base.end()); return std::error_code(); } diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/Program.inc b/contrib/llvm-project/llvm/lib/Support/Windows/Program.inc index 9fe05d24ec2e..f1d612cf3c98 100644 --- a/contrib/llvm-project/llvm/lib/Support/Windows/Program.inc +++ b/contrib/llvm-project/llvm/lib/Support/Windows/Program.inc @@ -171,7 +171,8 @@ static HANDLE RedirectIO(Optional<StringRef> Path, int fd, static bool Execute(ProcessInfo &PI, StringRef Program, ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env, ArrayRef<Optional<StringRef>> Redirects, - unsigned MemoryLimit, std::string *ErrMsg) { + unsigned MemoryLimit, std::string *ErrMsg, + BitVector *AffinityMask) { if (!sys::fs::can_execute(Program)) { if (ErrMsg) *ErrMsg = "program not executable"; @@ -189,7 +190,13 @@ static bool Execute(ProcessInfo &PI, StringRef Program, // Windows wants a command line, not an array of args, to pass to the new // process. We have to concatenate them all, while quoting the args that // have embedded spaces (or are empty). - std::string Command = flattenWindowsCommandLine(Args); + auto Result = flattenWindowsCommandLine(Args); + if (std::error_code ec = Result.getError()) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, std::string("Unable to convert command-line to UTF-16")); + return false; + } + std::wstring Command = *Result; // The pointer to the environment block for the new process. std::vector<wchar_t> EnvBlock; @@ -206,7 +213,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, return false; } - EnvBlock.insert(EnvBlock.end(), EnvString.begin(), EnvString.end()); + llvm::append_range(EnvBlock, EnvString); EnvBlock.push_back(0); } EnvBlock.push_back(0); @@ -271,18 +278,15 @@ static bool Execute(ProcessInfo &PI, StringRef Program, return false; } - SmallVector<wchar_t, MAX_PATH> CommandUtf16; - if (std::error_code ec = windows::UTF8ToUTF16(Command, CommandUtf16)) { - SetLastError(ec.value()); - MakeErrMsg(ErrMsg, - std::string("Unable to convert command-line to UTF-16")); - return false; - } + unsigned CreateFlags = CREATE_UNICODE_ENVIRONMENT; + if (AffinityMask) + CreateFlags |= CREATE_SUSPENDED; - BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0, - TRUE, CREATE_UNICODE_ENVIRONMENT, - EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si, - &pi); + std::vector<wchar_t> CommandUtf16(Command.size() + 1, 0); + std::copy(Command.begin(), Command.end(), CommandUtf16.begin()); + BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0, TRUE, + CreateFlags, EnvBlock.empty() ? 0 : EnvBlock.data(), + 0, &si, &pi); DWORD err = GetLastError(); // Regardless of whether the process got created or not, we are done with @@ -330,6 +334,13 @@ static bool Execute(ProcessInfo &PI, StringRef Program, } } + // Set the affinity mask + if (AffinityMask) { + ::SetProcessAffinityMask(pi.hProcess, + (DWORD_PTR)AffinityMask->getData().front()); + ::ResumeThread(pi.hThread); + } + return true; } @@ -376,7 +387,7 @@ static std::string quoteSingleArg(StringRef Arg) { } namespace llvm { -std::string sys::flattenWindowsCommandLine(ArrayRef<StringRef> Args) { +ErrorOr<std::wstring> sys::flattenWindowsCommandLine(ArrayRef<StringRef> Args) { std::string Command; for (StringRef Arg : Args) { if (argNeedsQuotes(Arg)) @@ -387,7 +398,11 @@ std::string sys::flattenWindowsCommandLine(ArrayRef<StringRef> Args) { Command.push_back(' '); } - return Command; + SmallVector<wchar_t, MAX_PATH> CommandUtf16; + if (std::error_code ec = windows::UTF8ToUTF16(Command, CommandUtf16)) + return ec; + + return std::wstring(CommandUtf16.begin(), CommandUtf16.end()); } ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, @@ -532,12 +547,16 @@ llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents, bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, ArrayRef<StringRef> Args) { - // The documented max length of the command line passed to CreateProcess. - static const size_t MaxCommandStringLength = 32768; + // The documentation on CreateProcessW states that the size of the argument + // lpCommandLine must not be greater than 32767 characters, including the + // Unicode terminating null character. We use smaller value to reduce risk + // of getting invalid command line due to unaccounted factors. + static const size_t MaxCommandStringLength = 32000; SmallVector<StringRef, 8> FullArgs; FullArgs.push_back(Program); FullArgs.append(Args.begin(), Args.end()); - std::string Result = flattenWindowsCommandLine(FullArgs); - return (Result.size() + 1) <= MaxCommandStringLength; + auto Result = flattenWindowsCommandLine(FullArgs); + assert(!Result.getError()); + return (Result->size() + 1) <= MaxCommandStringLength; } } diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/Signals.inc b/contrib/llvm-project/llvm/lib/Support/Windows/Signals.inc index 0c3681fa9654..3758582b35f7 100644 --- a/contrib/llvm-project/llvm/lib/Support/Windows/Signals.inc +++ b/contrib/llvm-project/llvm/lib/Support/Windows/Signals.inc @@ -552,7 +552,8 @@ static void LocalPrintStackTrace(raw_ostream &OS, PCONTEXT C) { StackFrame, C); } -void llvm::sys::PrintStackTrace(raw_ostream &OS) { +void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) { + // FIXME: Handle "Depth" parameter to print stack trace upto specified Depth LocalPrintStackTrace(OS, nullptr); } @@ -868,3 +869,5 @@ static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { #pragma GCC diagnostic warning "-Wformat" #pragma GCC diagnostic warning "-Wformat-extra-args" #endif + +void sys::unregisterHandlers() {} diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/Threading.inc b/contrib/llvm-project/llvm/lib/Support/Windows/Threading.inc index 296e87b77695..6448bb478d0c 100644 --- a/contrib/llvm-project/llvm/lib/Support/Windows/Threading.inc +++ b/contrib/llvm-project/llvm/lib/Support/Windows/Threading.inc @@ -195,14 +195,27 @@ static ArrayRef<ProcessorGroup> getProcessorGroups() { if (!IterateProcInfo(RelationProcessorCore, HandleProc)) return std::vector<ProcessorGroup>(); - // If there's an affinity mask set on one of the CPUs, then assume the user - // wants to constrain the current process to only a single CPU. - for (auto &G : Groups) { - if (G.UsableThreads != G.AllThreads) { - ProcessorGroup NewG{G}; + // If there's an affinity mask set, assume the user wants to constrain the + // current process to only a single CPU group. On Windows, it is not + // possible for affinity masks to cross CPU group boundaries. + DWORD_PTR ProcessAffinityMask = 0, SystemAffinityMask = 0; + if (::GetProcessAffinityMask(GetCurrentProcess(), &ProcessAffinityMask, + &SystemAffinityMask) && + ProcessAffinityMask != SystemAffinityMask) { + // We don't expect more that 4 CPU groups on Windows (256 processors). + USHORT GroupCount = 4; + USHORT GroupArray[4]{}; + if (::GetProcessGroupAffinity(GetCurrentProcess(), &GroupCount, + GroupArray)) { + assert(GroupCount == 1 && + "On startup, a program is expected to be assigned only to " + "one processor group!"); + unsigned CurrentGroupID = GroupArray[0]; + ProcessorGroup NewG{Groups[CurrentGroupID]}; + NewG.Affinity = ProcessAffinityMask; + NewG.UsableThreads = countPopulation(ProcessAffinityMask); Groups.clear(); Groups.push_back(NewG); - break; } } diff --git a/contrib/llvm-project/llvm/lib/Support/X86TargetParser.cpp b/contrib/llvm-project/llvm/lib/Support/X86TargetParser.cpp index 4c2d4efbfca8..d738511465b4 100644 --- a/contrib/llvm-project/llvm/lib/Support/X86TargetParser.cpp +++ b/contrib/llvm-project/llvm/lib/Support/X86TargetParser.cpp @@ -11,7 +11,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/X86TargetParser.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" using namespace llvm; @@ -117,147 +116,160 @@ struct FeatureInfo { } // end anonymous namespace #define X86_FEATURE(ENUM, STRING) \ - static constexpr FeatureBitset Feature##ENUM = {X86::FEATURE_##ENUM}; + constexpr FeatureBitset Feature##ENUM = {X86::FEATURE_##ENUM}; #include "llvm/Support/X86TargetParser.def" // Pentium with MMX. -static constexpr FeatureBitset FeaturesPentiumMMX = +constexpr FeatureBitset FeaturesPentiumMMX = FeatureX87 | FeatureCMPXCHG8B | FeatureMMX; // Pentium 2 and 3. -static constexpr FeatureBitset FeaturesPentium2 = +constexpr FeatureBitset FeaturesPentium2 = FeatureX87 | FeatureCMPXCHG8B | FeatureMMX | FeatureFXSR; -static constexpr FeatureBitset FeaturesPentium3 = FeaturesPentium2 | FeatureSSE; +constexpr FeatureBitset FeaturesPentium3 = FeaturesPentium2 | FeatureSSE; // Pentium 4 CPUs -static constexpr FeatureBitset FeaturesPentium4 = - FeaturesPentium3 | FeatureSSE2; -static constexpr FeatureBitset FeaturesPrescott = - FeaturesPentium4 | FeatureSSE3; -static constexpr FeatureBitset FeaturesNocona = +constexpr FeatureBitset FeaturesPentium4 = FeaturesPentium3 | FeatureSSE2; +constexpr FeatureBitset FeaturesPrescott = FeaturesPentium4 | FeatureSSE3; +constexpr FeatureBitset FeaturesNocona = FeaturesPrescott | Feature64BIT | FeatureCMPXCHG16B; // Basic 64-bit capable CPU. -static constexpr FeatureBitset FeaturesX86_64 = FeaturesPentium4 | Feature64BIT; +constexpr FeatureBitset FeaturesX86_64 = FeaturesPentium4 | Feature64BIT; +constexpr FeatureBitset FeaturesX86_64_V2 = FeaturesX86_64 | FeatureSAHF | + FeaturePOPCNT | FeatureSSE4_2 | + FeatureCMPXCHG16B; +constexpr FeatureBitset FeaturesX86_64_V3 = + FeaturesX86_64_V2 | FeatureAVX2 | FeatureBMI | FeatureBMI2 | FeatureF16C | + FeatureFMA | FeatureLZCNT | FeatureMOVBE | FeatureXSAVE; +constexpr FeatureBitset FeaturesX86_64_V4 = FeaturesX86_64_V3 | + FeatureAVX512BW | FeatureAVX512CD | + FeatureAVX512DQ | FeatureAVX512VL; // Intel Core CPUs -static constexpr FeatureBitset FeaturesCore2 = +constexpr FeatureBitset FeaturesCore2 = FeaturesNocona | FeatureSAHF | FeatureSSSE3; -static constexpr FeatureBitset FeaturesPenryn = FeaturesCore2 | FeatureSSE4_1; -static constexpr FeatureBitset FeaturesNehalem = +constexpr FeatureBitset FeaturesPenryn = FeaturesCore2 | FeatureSSE4_1; +constexpr FeatureBitset FeaturesNehalem = FeaturesPenryn | FeaturePOPCNT | FeatureSSE4_2; -static constexpr FeatureBitset FeaturesWestmere = - FeaturesNehalem | FeaturePCLMUL; -static constexpr FeatureBitset FeaturesSandyBridge = +constexpr FeatureBitset FeaturesWestmere = FeaturesNehalem | FeaturePCLMUL; +constexpr FeatureBitset FeaturesSandyBridge = FeaturesWestmere | FeatureAVX | FeatureXSAVE | FeatureXSAVEOPT; -static constexpr FeatureBitset FeaturesIvyBridge = +constexpr FeatureBitset FeaturesIvyBridge = FeaturesSandyBridge | FeatureF16C | FeatureFSGSBASE | FeatureRDRND; -static constexpr FeatureBitset FeaturesHaswell = +constexpr FeatureBitset FeaturesHaswell = FeaturesIvyBridge | FeatureAVX2 | FeatureBMI | FeatureBMI2 | FeatureFMA | FeatureINVPCID | FeatureLZCNT | FeatureMOVBE; -static constexpr FeatureBitset FeaturesBroadwell = +constexpr FeatureBitset FeaturesBroadwell = FeaturesHaswell | FeatureADX | FeaturePRFCHW | FeatureRDSEED; // Intel Knights Landing and Knights Mill // Knights Landing has feature parity with Broadwell. -static constexpr FeatureBitset FeaturesKNL = +constexpr FeatureBitset FeaturesKNL = FeaturesBroadwell | FeatureAES | FeatureAVX512F | FeatureAVX512CD | FeatureAVX512ER | FeatureAVX512PF | FeaturePREFETCHWT1; -static constexpr FeatureBitset FeaturesKNM = - FeaturesKNL | FeatureAVX512VPOPCNTDQ; +constexpr FeatureBitset FeaturesKNM = FeaturesKNL | FeatureAVX512VPOPCNTDQ; // Intel Skylake processors. -static constexpr FeatureBitset FeaturesSkylakeClient = +constexpr FeatureBitset FeaturesSkylakeClient = FeaturesBroadwell | FeatureAES | FeatureCLFLUSHOPT | FeatureXSAVEC | FeatureXSAVES | FeatureSGX; // SkylakeServer inherits all SkylakeClient features except SGX. // FIXME: That doesn't match gcc. -static constexpr FeatureBitset FeaturesSkylakeServer = +constexpr FeatureBitset FeaturesSkylakeServer = (FeaturesSkylakeClient & ~FeatureSGX) | FeatureAVX512F | FeatureAVX512CD | FeatureAVX512DQ | FeatureAVX512BW | FeatureAVX512VL | FeatureCLWB | FeaturePKU; -static constexpr FeatureBitset FeaturesCascadeLake = +constexpr FeatureBitset FeaturesCascadeLake = FeaturesSkylakeServer | FeatureAVX512VNNI; -static constexpr FeatureBitset FeaturesCooperLake = +constexpr FeatureBitset FeaturesCooperLake = FeaturesCascadeLake | FeatureAVX512BF16; // Intel 10nm processors. -static constexpr FeatureBitset FeaturesCannonlake = +constexpr FeatureBitset FeaturesCannonlake = FeaturesSkylakeClient | FeatureAVX512F | FeatureAVX512CD | FeatureAVX512DQ | FeatureAVX512BW | FeatureAVX512VL | FeatureAVX512IFMA | FeatureAVX512VBMI | FeaturePKU | FeatureSHA; -static constexpr FeatureBitset FeaturesICLClient = +constexpr FeatureBitset FeaturesICLClient = FeaturesCannonlake | FeatureAVX512BITALG | FeatureAVX512VBMI2 | FeatureAVX512VNNI | FeatureAVX512VPOPCNTDQ | FeatureCLWB | FeatureGFNI | FeatureRDPID | FeatureVAES | FeatureVPCLMULQDQ; -static constexpr FeatureBitset FeaturesICLServer = +constexpr FeatureBitset FeaturesICLServer = FeaturesICLClient | FeaturePCONFIG | FeatureWBNOINVD; -static constexpr FeatureBitset FeaturesTigerlake = +constexpr FeatureBitset FeaturesTigerlake = FeaturesICLClient | FeatureAVX512VP2INTERSECT | FeatureMOVDIR64B | - FeatureMOVDIRI | FeatureSHSTK; + 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; +constexpr FeatureBitset FeaturesAlderlake = + FeaturesSkylakeClient | FeatureCLDEMOTE | FeatureHRESET | FeaturePTWRITE | + FeatureSERIALIZE | FeatureWAITPKG | FeatureAVXVNNI; // Intel Atom processors. // Bonnell has feature parity with Core2 and adds MOVBE. -static constexpr FeatureBitset FeaturesBonnell = FeaturesCore2 | FeatureMOVBE; +constexpr FeatureBitset FeaturesBonnell = FeaturesCore2 | FeatureMOVBE; // Silvermont has parity with Westmere and Bonnell plus PRFCHW and RDRND. -static constexpr FeatureBitset FeaturesSilvermont = +constexpr FeatureBitset FeaturesSilvermont = FeaturesBonnell | FeaturesWestmere | FeaturePRFCHW | FeatureRDRND; -static constexpr FeatureBitset FeaturesGoldmont = +constexpr FeatureBitset FeaturesGoldmont = FeaturesSilvermont | FeatureAES | FeatureCLFLUSHOPT | FeatureFSGSBASE | FeatureRDSEED | FeatureSHA | FeatureXSAVE | FeatureXSAVEC | FeatureXSAVEOPT | FeatureXSAVES; -static constexpr FeatureBitset FeaturesGoldmontPlus = +constexpr FeatureBitset FeaturesGoldmontPlus = FeaturesGoldmont | FeaturePTWRITE | FeatureRDPID | FeatureSGX; -static constexpr FeatureBitset FeaturesTremont = +constexpr FeatureBitset FeaturesTremont = FeaturesGoldmontPlus | FeatureCLWB | FeatureGFNI; // Geode Processor. -static constexpr FeatureBitset FeaturesGeode = +constexpr FeatureBitset FeaturesGeode = FeatureX87 | FeatureCMPXCHG8B | FeatureMMX | Feature3DNOW | Feature3DNOWA; // K6 processor. -static constexpr FeatureBitset FeaturesK6 = - FeatureX87 | FeatureCMPXCHG8B | FeatureMMX; +constexpr FeatureBitset FeaturesK6 = FeatureX87 | FeatureCMPXCHG8B | FeatureMMX; // K7 and K8 architecture processors. -static constexpr FeatureBitset FeaturesAthlon = +constexpr FeatureBitset FeaturesAthlon = FeatureX87 | FeatureCMPXCHG8B | FeatureMMX | Feature3DNOW | Feature3DNOWA; -static constexpr FeatureBitset FeaturesAthlonXP = +constexpr FeatureBitset FeaturesAthlonXP = FeaturesAthlon | FeatureFXSR | FeatureSSE; -static constexpr FeatureBitset FeaturesK8 = +constexpr FeatureBitset FeaturesK8 = FeaturesAthlonXP | FeatureSSE2 | Feature64BIT; -static constexpr FeatureBitset FeaturesK8SSE3 = FeaturesK8 | FeatureSSE3; -static constexpr FeatureBitset FeaturesAMDFAM10 = +constexpr FeatureBitset FeaturesK8SSE3 = FeaturesK8 | FeatureSSE3; +constexpr FeatureBitset FeaturesAMDFAM10 = FeaturesK8SSE3 | FeatureCMPXCHG16B | FeatureLZCNT | FeaturePOPCNT | FeaturePRFCHW | FeatureSAHF | FeatureSSE4_A; // Bobcat architecture processors. -static constexpr FeatureBitset FeaturesBTVER1 = +constexpr FeatureBitset FeaturesBTVER1 = FeatureX87 | FeatureCMPXCHG8B | FeatureCMPXCHG16B | Feature64BIT | FeatureFXSR | FeatureLZCNT | FeatureMMX | FeaturePOPCNT | FeaturePRFCHW | FeatureSSE | FeatureSSE2 | FeatureSSE3 | FeatureSSSE3 | FeatureSSE4_A | FeatureSAHF; -static constexpr FeatureBitset FeaturesBTVER2 = +constexpr FeatureBitset FeaturesBTVER2 = FeaturesBTVER1 | FeatureAES | FeatureAVX | FeatureBMI | FeatureF16C | FeatureMOVBE | FeaturePCLMUL | FeatureXSAVE | FeatureXSAVEOPT; // AMD Bulldozer architecture processors. -static constexpr FeatureBitset FeaturesBDVER1 = +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; -static constexpr FeatureBitset FeaturesBDVER2 = +constexpr FeatureBitset FeaturesBDVER2 = FeaturesBDVER1 | FeatureBMI | FeatureFMA | FeatureF16C | FeatureTBM; -static constexpr FeatureBitset FeaturesBDVER3 = +constexpr FeatureBitset FeaturesBDVER3 = FeaturesBDVER2 | FeatureFSGSBASE | FeatureXSAVEOPT; -static constexpr FeatureBitset FeaturesBDVER4 = - FeaturesBDVER3 | FeatureAVX2 | FeatureBMI2 | FeatureMOVBE | FeatureMWAITX | - FeatureRDRND; +constexpr FeatureBitset FeaturesBDVER4 = FeaturesBDVER3 | FeatureAVX2 | + FeatureBMI2 | FeatureMOVBE | + FeatureMWAITX | FeatureRDRND; // AMD Zen architecture processors. -static constexpr FeatureBitset FeaturesZNVER1 = +constexpr FeatureBitset FeaturesZNVER1 = FeatureX87 | FeatureADX | FeatureAES | FeatureAVX | FeatureAVX2 | FeatureBMI | FeatureBMI2 | FeatureCLFLUSHOPT | FeatureCLZERO | FeatureCMPXCHG8B | FeatureCMPXCHG16B | Feature64BIT | FeatureF16C | @@ -267,10 +279,13 @@ static constexpr FeatureBitset FeaturesZNVER1 = FeatureSSE | FeatureSSE2 | FeatureSSE3 | FeatureSSSE3 | FeatureSSE4_1 | FeatureSSE4_2 | FeatureSSE4_A | FeatureXSAVE | FeatureXSAVEC | FeatureXSAVEOPT | FeatureXSAVES; -static constexpr FeatureBitset FeaturesZNVER2 = +constexpr FeatureBitset FeaturesZNVER2 = FeaturesZNVER1 | FeatureCLWB | FeatureRDPID | FeatureWBNOINVD; +static constexpr FeatureBitset FeaturesZNVER3 = FeaturesZNVER2 | + FeatureINVPCID | FeaturePKU | + FeatureVAES | FeatureVPCLMULQDQ; -static constexpr ProcInfo Processors[] = { +constexpr ProcInfo Processors[] = { // Empty processor. Include X87 and CMPXCHG8 for backwards compatibility. { {""}, CK_None, ~0U, FeatureX87 | FeatureCMPXCHG8B }, // i386-generation processors. @@ -342,6 +357,10 @@ static constexpr ProcInfo Processors[] = { { {"icelake-server"}, CK_IcelakeServer, FEATURE_AVX512VBMI2, FeaturesICLServer }, // Tigerlake microarchitecture based processors. { {"tigerlake"}, CK_Tigerlake, FEATURE_AVX512VP2INTERSECT, FeaturesTigerlake }, + // Sapphire Rapids microarchitecture based processors. + { {"sapphirerapids"}, CK_SapphireRapids, FEATURE_AVX512VP2INTERSECT, FeaturesSapphireRapids }, + // Alderlake microarchitecture based processors. + { {"alderlake"}, CK_Alderlake, FEATURE_AVX2, FeaturesAlderlake }, // Knights Landing processor. { {"knl"}, CK_KNL, FEATURE_AVX512F, FeaturesKNL }, // Knights Mill processor. @@ -379,12 +398,18 @@ static constexpr ProcInfo Processors[] = { // Zen architecture processors. { {"znver1"}, CK_ZNVER1, FEATURE_AVX2, FeaturesZNVER1 }, { {"znver2"}, CK_ZNVER2, FEATURE_AVX2, FeaturesZNVER2 }, + { {"znver3"}, CK_ZNVER3, FEATURE_AVX2, FeaturesZNVER3 }, // Generic 64-bit processor. { {"x86-64"}, CK_x86_64, ~0U, FeaturesX86_64 }, + { {"x86-64-v2"}, CK_x86_64_v2, ~0U, FeaturesX86_64_V2 }, + { {"x86-64-v3"}, CK_x86_64_v3, ~0U, FeaturesX86_64_V3 }, + { {"x86-64-v4"}, CK_x86_64_v4, ~0U, FeaturesX86_64_V4 }, // Geode processors. { {"geode"}, CK_Geode, ~0U, FeaturesGeode }, }; +constexpr const char *NoTuneList[] = {"x86-64-v2", "x86-64-v3", "x86-64-v4"}; + X86::CPUKind llvm::X86::parseArchX86(StringRef CPU, bool Only64Bit) { for (const auto &P : Processors) if (P.Name == CPU && (P.Features[FEATURE_64BIT] || !Only64Bit)) @@ -393,6 +418,12 @@ X86::CPUKind llvm::X86::parseArchX86(StringRef CPU, bool Only64Bit) { return CK_None; } +X86::CPUKind llvm::X86::parseTuneCPU(StringRef CPU, bool Only64Bit) { + if (llvm::is_contained(NoTuneList, CPU)) + return CK_None; + return parseArchX86(CPU, Only64Bit); +} + void llvm::X86::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, bool Only64Bit) { for (const auto &P : Processors) @@ -400,6 +431,14 @@ void llvm::X86::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, Values.emplace_back(P.Name); } +void llvm::X86::fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values, + bool Only64Bit) { + for (const ProcInfo &P : Processors) + if (!P.Name.empty() && (P.Features[FEATURE_64BIT] || !Only64Bit) && + !llvm::is_contained(NoTuneList, P.Name)) + Values.emplace_back(P.Name); +} + ProcessorFeatures llvm::X86::getKeyFeature(X86::CPUKind Kind) { // FIXME: Can we avoid a linear search here? The table might be sorted by // CPUKind so we could binary search? @@ -414,136 +453,135 @@ ProcessorFeatures llvm::X86::getKeyFeature(X86::CPUKind Kind) { } // Features with no dependencies. -static constexpr FeatureBitset ImpliedFeatures64BIT = {}; -static constexpr FeatureBitset ImpliedFeaturesADX = {}; -static constexpr FeatureBitset ImpliedFeaturesBMI = {}; -static constexpr FeatureBitset ImpliedFeaturesBMI2 = {}; -static constexpr FeatureBitset ImpliedFeaturesCLDEMOTE = {}; -static constexpr FeatureBitset ImpliedFeaturesCLFLUSHOPT = {}; -static constexpr FeatureBitset ImpliedFeaturesCLWB = {}; -static constexpr FeatureBitset ImpliedFeaturesCLZERO = {}; -static constexpr FeatureBitset ImpliedFeaturesCMOV = {}; -static constexpr FeatureBitset ImpliedFeaturesCMPXCHG16B = {}; -static constexpr FeatureBitset ImpliedFeaturesCMPXCHG8B = {}; -static constexpr FeatureBitset ImpliedFeaturesENQCMD = {}; -static constexpr FeatureBitset ImpliedFeaturesFSGSBASE = {}; -static constexpr FeatureBitset ImpliedFeaturesFXSR = {}; -static constexpr FeatureBitset ImpliedFeaturesINVPCID = {}; -static constexpr FeatureBitset ImpliedFeaturesLWP = {}; -static constexpr FeatureBitset ImpliedFeaturesLZCNT = {}; -static constexpr FeatureBitset ImpliedFeaturesMWAITX = {}; -static constexpr FeatureBitset ImpliedFeaturesMOVBE = {}; -static constexpr FeatureBitset ImpliedFeaturesMOVDIR64B = {}; -static constexpr FeatureBitset ImpliedFeaturesMOVDIRI = {}; -static constexpr FeatureBitset ImpliedFeaturesPCONFIG = {}; -static constexpr FeatureBitset ImpliedFeaturesPOPCNT = {}; -static constexpr FeatureBitset ImpliedFeaturesPKU = {}; -static constexpr FeatureBitset ImpliedFeaturesPREFETCHWT1 = {}; -static constexpr FeatureBitset ImpliedFeaturesPRFCHW = {}; -static constexpr FeatureBitset ImpliedFeaturesPTWRITE = {}; -static constexpr FeatureBitset ImpliedFeaturesRDPID = {}; -static constexpr FeatureBitset ImpliedFeaturesRDRND = {}; -static constexpr FeatureBitset ImpliedFeaturesRDSEED = {}; -static constexpr FeatureBitset ImpliedFeaturesRTM = {}; -static constexpr FeatureBitset ImpliedFeaturesSAHF = {}; -static constexpr FeatureBitset ImpliedFeaturesSERIALIZE = {}; -static constexpr FeatureBitset ImpliedFeaturesSGX = {}; -static constexpr FeatureBitset ImpliedFeaturesSHSTK = {}; -static constexpr FeatureBitset ImpliedFeaturesTBM = {}; -static constexpr FeatureBitset ImpliedFeaturesTSXLDTRK = {}; -static constexpr FeatureBitset ImpliedFeaturesWAITPKG = {}; -static constexpr FeatureBitset ImpliedFeaturesWBNOINVD = {}; -static constexpr FeatureBitset ImpliedFeaturesVZEROUPPER = {}; -static constexpr FeatureBitset ImpliedFeaturesX87 = {}; -static constexpr FeatureBitset ImpliedFeaturesXSAVE = {}; +constexpr FeatureBitset ImpliedFeatures64BIT = {}; +constexpr FeatureBitset ImpliedFeaturesADX = {}; +constexpr FeatureBitset ImpliedFeaturesBMI = {}; +constexpr FeatureBitset ImpliedFeaturesBMI2 = {}; +constexpr FeatureBitset ImpliedFeaturesCLDEMOTE = {}; +constexpr FeatureBitset ImpliedFeaturesCLFLUSHOPT = {}; +constexpr FeatureBitset ImpliedFeaturesCLWB = {}; +constexpr FeatureBitset ImpliedFeaturesCLZERO = {}; +constexpr FeatureBitset ImpliedFeaturesCMOV = {}; +constexpr FeatureBitset ImpliedFeaturesCMPXCHG16B = {}; +constexpr FeatureBitset ImpliedFeaturesCMPXCHG8B = {}; +constexpr FeatureBitset ImpliedFeaturesENQCMD = {}; +constexpr FeatureBitset ImpliedFeaturesFSGSBASE = {}; +constexpr FeatureBitset ImpliedFeaturesFXSR = {}; +constexpr FeatureBitset ImpliedFeaturesINVPCID = {}; +constexpr FeatureBitset ImpliedFeaturesLWP = {}; +constexpr FeatureBitset ImpliedFeaturesLZCNT = {}; +constexpr FeatureBitset ImpliedFeaturesMWAITX = {}; +constexpr FeatureBitset ImpliedFeaturesMOVBE = {}; +constexpr FeatureBitset ImpliedFeaturesMOVDIR64B = {}; +constexpr FeatureBitset ImpliedFeaturesMOVDIRI = {}; +constexpr FeatureBitset ImpliedFeaturesPCONFIG = {}; +constexpr FeatureBitset ImpliedFeaturesPOPCNT = {}; +constexpr FeatureBitset ImpliedFeaturesPKU = {}; +constexpr FeatureBitset ImpliedFeaturesPREFETCHWT1 = {}; +constexpr FeatureBitset ImpliedFeaturesPRFCHW = {}; +constexpr FeatureBitset ImpliedFeaturesPTWRITE = {}; +constexpr FeatureBitset ImpliedFeaturesRDPID = {}; +constexpr FeatureBitset ImpliedFeaturesRDRND = {}; +constexpr FeatureBitset ImpliedFeaturesRDSEED = {}; +constexpr FeatureBitset ImpliedFeaturesRTM = {}; +constexpr FeatureBitset ImpliedFeaturesSAHF = {}; +constexpr FeatureBitset ImpliedFeaturesSERIALIZE = {}; +constexpr FeatureBitset ImpliedFeaturesSGX = {}; +constexpr FeatureBitset ImpliedFeaturesSHSTK = {}; +constexpr FeatureBitset ImpliedFeaturesTBM = {}; +constexpr FeatureBitset ImpliedFeaturesTSXLDTRK = {}; +constexpr FeatureBitset ImpliedFeaturesUINTR = {}; +constexpr FeatureBitset ImpliedFeaturesWAITPKG = {}; +constexpr FeatureBitset ImpliedFeaturesWBNOINVD = {}; +constexpr FeatureBitset ImpliedFeaturesVZEROUPPER = {}; +constexpr FeatureBitset ImpliedFeaturesX87 = {}; +constexpr FeatureBitset ImpliedFeaturesXSAVE = {}; // Not really CPU features, but need to be in the table because clang uses // target features to communicate them to the backend. -static constexpr FeatureBitset ImpliedFeaturesRETPOLINE_EXTERNAL_THUNK = {}; -static constexpr FeatureBitset ImpliedFeaturesRETPOLINE_INDIRECT_BRANCHES = {}; -static constexpr FeatureBitset ImpliedFeaturesRETPOLINE_INDIRECT_CALLS = {}; -static constexpr FeatureBitset ImpliedFeaturesLVI_CFI = {}; -static constexpr FeatureBitset ImpliedFeaturesLVI_LOAD_HARDENING = {}; +constexpr FeatureBitset ImpliedFeaturesRETPOLINE_EXTERNAL_THUNK = {}; +constexpr FeatureBitset ImpliedFeaturesRETPOLINE_INDIRECT_BRANCHES = {}; +constexpr FeatureBitset ImpliedFeaturesRETPOLINE_INDIRECT_CALLS = {}; +constexpr FeatureBitset ImpliedFeaturesLVI_CFI = {}; +constexpr FeatureBitset ImpliedFeaturesLVI_LOAD_HARDENING = {}; // XSAVE features are dependent on basic XSAVE. -static constexpr FeatureBitset ImpliedFeaturesXSAVEC = FeatureXSAVE; -static constexpr FeatureBitset ImpliedFeaturesXSAVEOPT = FeatureXSAVE; -static constexpr FeatureBitset ImpliedFeaturesXSAVES = FeatureXSAVE; +constexpr FeatureBitset ImpliedFeaturesXSAVEC = FeatureXSAVE; +constexpr FeatureBitset ImpliedFeaturesXSAVEOPT = FeatureXSAVE; +constexpr FeatureBitset ImpliedFeaturesXSAVES = FeatureXSAVE; // MMX->3DNOW->3DNOWA chain. -static constexpr FeatureBitset ImpliedFeaturesMMX = {}; -static constexpr FeatureBitset ImpliedFeatures3DNOW = FeatureMMX; -static constexpr FeatureBitset ImpliedFeatures3DNOWA = Feature3DNOW; +constexpr FeatureBitset ImpliedFeaturesMMX = {}; +constexpr FeatureBitset ImpliedFeatures3DNOW = FeatureMMX; +constexpr FeatureBitset ImpliedFeatures3DNOWA = Feature3DNOW; // SSE/AVX/AVX512F chain. -static constexpr FeatureBitset ImpliedFeaturesSSE = {}; -static constexpr FeatureBitset ImpliedFeaturesSSE2 = FeatureSSE; -static constexpr FeatureBitset ImpliedFeaturesSSE3 = FeatureSSE2; -static constexpr FeatureBitset ImpliedFeaturesSSSE3 = FeatureSSE3; -static constexpr FeatureBitset ImpliedFeaturesSSE4_1 = FeatureSSSE3; -static constexpr FeatureBitset ImpliedFeaturesSSE4_2 = FeatureSSE4_1; -static constexpr FeatureBitset ImpliedFeaturesAVX = FeatureSSE4_2; -static constexpr FeatureBitset ImpliedFeaturesAVX2 = FeatureAVX; -static constexpr FeatureBitset ImpliedFeaturesAVX512F = +constexpr FeatureBitset ImpliedFeaturesSSE = {}; +constexpr FeatureBitset ImpliedFeaturesSSE2 = FeatureSSE; +constexpr FeatureBitset ImpliedFeaturesSSE3 = FeatureSSE2; +constexpr FeatureBitset ImpliedFeaturesSSSE3 = FeatureSSE3; +constexpr FeatureBitset ImpliedFeaturesSSE4_1 = FeatureSSSE3; +constexpr FeatureBitset ImpliedFeaturesSSE4_2 = FeatureSSE4_1; +constexpr FeatureBitset ImpliedFeaturesAVX = FeatureSSE4_2; +constexpr FeatureBitset ImpliedFeaturesAVX2 = FeatureAVX; +constexpr FeatureBitset ImpliedFeaturesAVX512F = FeatureAVX2 | FeatureF16C | FeatureFMA; // Vector extensions that build on SSE or AVX. -static constexpr FeatureBitset ImpliedFeaturesAES = FeatureSSE2; -static constexpr FeatureBitset ImpliedFeaturesF16C = FeatureAVX; -static constexpr FeatureBitset ImpliedFeaturesFMA = FeatureAVX; -static constexpr FeatureBitset ImpliedFeaturesGFNI = FeatureSSE2; -static constexpr FeatureBitset ImpliedFeaturesPCLMUL = FeatureSSE2; -static constexpr FeatureBitset ImpliedFeaturesSHA = FeatureSSE2; -static constexpr FeatureBitset ImpliedFeaturesVAES = FeatureAES | FeatureAVX; -static constexpr FeatureBitset ImpliedFeaturesVPCLMULQDQ = - FeatureAVX | FeaturePCLMUL; +constexpr FeatureBitset ImpliedFeaturesAES = FeatureSSE2; +constexpr FeatureBitset ImpliedFeaturesF16C = FeatureAVX; +constexpr FeatureBitset ImpliedFeaturesFMA = FeatureAVX; +constexpr FeatureBitset ImpliedFeaturesGFNI = FeatureSSE2; +constexpr FeatureBitset ImpliedFeaturesPCLMUL = FeatureSSE2; +constexpr FeatureBitset ImpliedFeaturesSHA = FeatureSSE2; +constexpr FeatureBitset ImpliedFeaturesVAES = FeatureAES | FeatureAVX; +constexpr FeatureBitset ImpliedFeaturesVPCLMULQDQ = FeatureAVX | FeaturePCLMUL; // AVX512 features. -static constexpr FeatureBitset ImpliedFeaturesAVX512CD = FeatureAVX512F; -static constexpr FeatureBitset ImpliedFeaturesAVX512BW = FeatureAVX512F; -static constexpr FeatureBitset ImpliedFeaturesAVX512DQ = FeatureAVX512F; -static constexpr FeatureBitset ImpliedFeaturesAVX512ER = FeatureAVX512F; -static constexpr FeatureBitset ImpliedFeaturesAVX512PF = FeatureAVX512F; -static constexpr FeatureBitset ImpliedFeaturesAVX512VL = FeatureAVX512F; - -static constexpr FeatureBitset ImpliedFeaturesAVX512BF16 = FeatureAVX512BW; -static constexpr FeatureBitset ImpliedFeaturesAVX512BITALG = FeatureAVX512BW; -static constexpr FeatureBitset ImpliedFeaturesAVX512IFMA = FeatureAVX512F; -static constexpr FeatureBitset ImpliedFeaturesAVX512VNNI = FeatureAVX512F; -static constexpr FeatureBitset ImpliedFeaturesAVX512VPOPCNTDQ = FeatureAVX512F; -static constexpr FeatureBitset ImpliedFeaturesAVX512VBMI = FeatureAVX512BW; -static constexpr FeatureBitset ImpliedFeaturesAVX512VBMI2 = FeatureAVX512BW; -static constexpr FeatureBitset ImpliedFeaturesAVX512VP2INTERSECT = - FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512CD = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512BW = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512DQ = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512ER = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512PF = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512VL = FeatureAVX512F; + +constexpr FeatureBitset ImpliedFeaturesAVX512BF16 = FeatureAVX512BW; +constexpr FeatureBitset ImpliedFeaturesAVX512BITALG = FeatureAVX512BW; +constexpr FeatureBitset ImpliedFeaturesAVX512IFMA = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512VNNI = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512VPOPCNTDQ = FeatureAVX512F; +constexpr FeatureBitset ImpliedFeaturesAVX512VBMI = FeatureAVX512BW; +constexpr FeatureBitset ImpliedFeaturesAVX512VBMI2 = FeatureAVX512BW; +constexpr FeatureBitset ImpliedFeaturesAVX512VP2INTERSECT = FeatureAVX512F; // FIXME: These two aren't really implemented and just exist in the feature // list for __builtin_cpu_supports. So omit their dependencies. -static constexpr FeatureBitset ImpliedFeaturesAVX5124FMAPS = {}; -static constexpr FeatureBitset ImpliedFeaturesAVX5124VNNIW = {}; +constexpr FeatureBitset ImpliedFeaturesAVX5124FMAPS = {}; +constexpr FeatureBitset ImpliedFeaturesAVX5124VNNIW = {}; // SSE4_A->FMA4->XOP chain. -static constexpr FeatureBitset ImpliedFeaturesSSE4_A = FeatureSSE3; -static constexpr FeatureBitset ImpliedFeaturesFMA4 = FeatureAVX | FeatureSSE4_A; -static constexpr FeatureBitset ImpliedFeaturesXOP = FeatureFMA4; +constexpr FeatureBitset ImpliedFeaturesSSE4_A = FeatureSSE3; +constexpr FeatureBitset ImpliedFeaturesFMA4 = FeatureAVX | FeatureSSE4_A; +constexpr FeatureBitset ImpliedFeaturesXOP = FeatureFMA4; // AMX Features -static constexpr FeatureBitset ImpliedFeaturesAMX_TILE = {}; -static constexpr FeatureBitset ImpliedFeaturesAMX_BF16 = FeatureAMX_TILE; -static constexpr FeatureBitset ImpliedFeaturesAMX_INT8 = FeatureAMX_TILE; +constexpr FeatureBitset ImpliedFeaturesAMX_TILE = {}; +constexpr FeatureBitset ImpliedFeaturesAMX_BF16 = FeatureAMX_TILE; +constexpr FeatureBitset ImpliedFeaturesAMX_INT8 = FeatureAMX_TILE; +constexpr FeatureBitset ImpliedFeaturesHRESET = {}; + +// Key Locker Features +constexpr FeatureBitset ImpliedFeaturesKL = FeatureSSE2; +constexpr FeatureBitset ImpliedFeaturesWIDEKL = FeatureKL; -static constexpr FeatureInfo FeatureInfos[X86::CPU_FEATURE_MAX] = { +// AVXVNNI Features +constexpr FeatureBitset ImpliedFeaturesAVXVNNI = FeatureAVX2; + +constexpr FeatureInfo FeatureInfos[X86::CPU_FEATURE_MAX] = { #define X86_FEATURE(ENUM, STR) {{STR}, ImpliedFeatures##ENUM}, #include "llvm/Support/X86TargetParser.def" }; -// Convert the set bits in FeatureBitset to a list of strings. -static void getFeatureBitsAsStrings(const FeatureBitset &Bits, - SmallVectorImpl<StringRef> &Features) { - for (unsigned i = 0; i != CPU_FEATURE_MAX; ++i) - if (Bits[i] && !FeatureInfos[i].Name.empty()) - Features.push_back(FeatureInfos[i].Name); -} - void llvm::X86::getFeaturesForCPU(StringRef CPU, SmallVectorImpl<StringRef> &EnabledFeatures) { auto I = llvm::find_if(Processors, @@ -557,7 +595,9 @@ void llvm::X86::getFeaturesForCPU(StringRef CPU, Bits &= ~Feature64BIT; // Add the string version of all set bits. - getFeatureBitsAsStrings(Bits, EnabledFeatures); + for (unsigned i = 0; i != CPU_FEATURE_MAX; ++i) + if (Bits[i] && !FeatureInfos[i].Name.empty()) + EnabledFeatures.push_back(FeatureInfos[i].Name); } // For each feature that is (transitively) implied by this feature, set it. @@ -591,9 +631,9 @@ static void getImpliedDisabledFeatures(FeatureBitset &Bits, unsigned Value) { } while (Prev != Bits); } -void llvm::X86::getImpliedFeatures( +void llvm::X86::updateImpliedFeatures( StringRef Feature, bool Enabled, - SmallVectorImpl<StringRef> &ImpliedFeatures) { + StringMap<bool> &Features) { auto I = llvm::find_if( FeatureInfos, [&](const FeatureInfo &FI) { return FI.Name == Feature; }); if (I == std::end(FeatureInfos)) { @@ -609,6 +649,8 @@ void llvm::X86::getImpliedFeatures( getImpliedDisabledFeatures(ImpliedBits, std::distance(std::begin(FeatureInfos), I)); - // Convert all the found bits into strings. - getFeatureBitsAsStrings(ImpliedBits, ImpliedFeatures); + // Update the map entry for all implied features. + for (unsigned i = 0; i != CPU_FEATURE_MAX; ++i) + if (ImpliedBits[i] && !FeatureInfos[i].Name.empty()) + Features[FeatureInfos[i].Name] = Enabled; } diff --git a/contrib/llvm-project/llvm/lib/Support/YAMLParser.cpp b/contrib/llvm-project/llvm/lib/Support/YAMLParser.cpp index ca8ffdc47afa..f68ba0d065c1 100644 --- a/contrib/llvm-project/llvm/lib/Support/YAMLParser.cpp +++ b/contrib/llvm-project/llvm/lib/Support/YAMLParser.cpp @@ -200,13 +200,12 @@ static UTF8Decoded decodeUTF8(StringRef Range) { StringRef::iterator End = Range.end(); // 1 byte: [0x00, 0x7f] // Bit pattern: 0xxxxxxx - if ((*Position & 0x80) == 0) { - return std::make_pair(*Position, 1); + if (Position < End && (*Position & 0x80) == 0) { + return std::make_pair(*Position, 1); } // 2 bytes: [0x80, 0x7ff] // Bit pattern: 110xxxxx 10xxxxxx - if (Position + 1 != End && - ((*Position & 0xE0) == 0xC0) && + if (Position + 1 < End && ((*Position & 0xE0) == 0xC0) && ((*(Position + 1) & 0xC0) == 0x80)) { uint32_t codepoint = ((*Position & 0x1F) << 6) | (*(Position + 1) & 0x3F); @@ -215,8 +214,7 @@ static UTF8Decoded decodeUTF8(StringRef Range) { } // 3 bytes: [0x8000, 0xffff] // Bit pattern: 1110xxxx 10xxxxxx 10xxxxxx - if (Position + 2 != End && - ((*Position & 0xF0) == 0xE0) && + if (Position + 2 < End && ((*Position & 0xF0) == 0xE0) && ((*(Position + 1) & 0xC0) == 0x80) && ((*(Position + 2) & 0xC0) == 0x80)) { uint32_t codepoint = ((*Position & 0x0F) << 12) | @@ -230,8 +228,7 @@ static UTF8Decoded decodeUTF8(StringRef Range) { } // 4 bytes: [0x10000, 0x10FFFF] // Bit pattern: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - if (Position + 3 != End && - ((*Position & 0xF8) == 0xF0) && + if (Position + 3 < End && ((*Position & 0xF8) == 0xF0) && ((*(Position + 1) & 0xC0) == 0x80) && ((*(Position + 2) & 0xC0) == 0x80) && ((*(Position + 3) & 0xC0) == 0x80)) { @@ -718,7 +715,7 @@ std::string yaml::escape(StringRef Input, bool EscapePrintable) { // Found invalid char. SmallString<4> Val; encodeUTF8(0xFFFD, Val); - EscapedInput.insert(EscapedInput.end(), Val.begin(), Val.end()); + llvm::append_range(EscapedInput, Val); // FIXME: Error reporting. return EscapedInput; } @@ -749,6 +746,92 @@ std::string yaml::escape(StringRef Input, bool EscapePrintable) { return EscapedInput; } +llvm::Optional<bool> yaml::parseBool(StringRef S) { + switch (S.size()) { + case 1: + switch (S.front()) { + case 'y': + case 'Y': + return true; + case 'n': + case 'N': + return false; + default: + return None; + } + case 2: + switch (S.front()) { + case 'O': + if (S[1] == 'N') // ON + return true; + LLVM_FALLTHROUGH; + case 'o': + if (S[1] == 'n') //[Oo]n + return true; + return None; + case 'N': + if (S[1] == 'O') // NO + return false; + LLVM_FALLTHROUGH; + case 'n': + if (S[1] == 'o') //[Nn]o + return false; + return None; + default: + return None; + } + case 3: + switch (S.front()) { + case 'O': + if (S.drop_front() == "FF") // OFF + return false; + LLVM_FALLTHROUGH; + case 'o': + if (S.drop_front() == "ff") //[Oo]ff + return false; + return None; + case 'Y': + if (S.drop_front() == "ES") // YES + return true; + LLVM_FALLTHROUGH; + case 'y': + if (S.drop_front() == "es") //[Yy]es + return true; + return None; + default: + return None; + } + case 4: + switch (S.front()) { + case 'T': + if (S.drop_front() == "RUE") // TRUE + return true; + LLVM_FALLTHROUGH; + case 't': + if (S.drop_front() == "rue") //[Tt]rue + return true; + return None; + default: + return None; + } + case 5: + switch (S.front()) { + case 'F': + if (S.drop_front() == "ALSE") // FALSE + return false; + LLVM_FALLTHROUGH; + case 'f': + if (S.drop_front() == "alse") //[Ff]alse + return false; + return None; + default: + return None; + } + default: + return None; + } +} + Scanner::Scanner(StringRef Input, SourceMgr &sm, bool ShowColors, std::error_code *EC) : SM(sm), ShowColors(ShowColors), EC(EC) { @@ -773,7 +856,7 @@ void Scanner::init(MemoryBufferRef Buffer) { IsSimpleKeyAllowed = true; Failed = false; std::unique_ptr<MemoryBuffer> InputBufferOwner = - MemoryBuffer::getMemBuffer(Buffer); + MemoryBuffer::getMemBuffer(Buffer, /*RequiresNullTerminator=*/false); SM.AddNewSourceBuffer(std::move(InputBufferOwner), SMLoc()); } @@ -898,17 +981,9 @@ void Scanner::advanceWhile(SkipWhileFunc Func) { Current = Final; } -static bool is_ns_hex_digit(const char C) { - return (C >= '0' && C <= '9') - || (C >= 'a' && C <= 'z') - || (C >= 'A' && C <= 'Z'); -} +static bool is_ns_hex_digit(const char C) { return isAlnum(C); } -static bool is_ns_word_char(const char C) { - return C == '-' - || (C >= 'a' && C <= 'z') - || (C >= 'A' && C <= 'Z'); -} +static bool is_ns_word_char(const char C) { return C == '-' || isAlpha(C); } void Scanner::scan_ns_uri_char() { while (true) { @@ -1036,7 +1111,7 @@ bool Scanner::rollIndent( int ToColumn } void Scanner::skipComment() { - if (*Current != '#') + if (Current == End || *Current != '#') return; while (true) { // This may skip more than one byte, thus Column is only incremented @@ -1051,7 +1126,7 @@ void Scanner::skipComment() { void Scanner::scanToNextToken() { while (true) { - while (*Current == ' ' || *Current == '\t') { + while (Current != End && (*Current == ' ' || *Current == '\t')) { skip(1); } @@ -1286,7 +1361,7 @@ bool Scanner::scanFlowScalar(bool IsDoubleQuoted) { && wasEscaped(Start + 1, Current)); } else { skip(1); - while (true) { + while (Current != End) { // Skip a ' followed by another '. if (Current + 1 < End && *Current == '\'' && *(Current + 1) == '\'') { skip(2); @@ -1334,13 +1409,14 @@ bool Scanner::scanPlainScalar() { unsigned LeadingBlanks = 0; assert(Indent >= -1 && "Indent must be >= -1 !"); unsigned indent = static_cast<unsigned>(Indent + 1); - while (true) { + while (Current != End) { if (*Current == '#') break; - while (!isBlankOrBreak(Current)) { - if ( FlowLevel && *Current == ':' - && !(isBlankOrBreak(Current + 1) || *(Current + 1) == ',')) { + while (Current != End && !isBlankOrBreak(Current)) { + if (FlowLevel && *Current == ':' && + (Current + 1 == End || + !(isBlankOrBreak(Current + 1) || *(Current + 1) == ','))) { setError("Found unexpected ':' while scanning a plain scalar", Current); return false; } @@ -1410,7 +1486,7 @@ bool Scanner::scanAliasOrAnchor(bool IsAlias) { StringRef::iterator Start = Current; unsigned ColStart = Column; skip(1); - while(true) { + while (Current != End) { if ( *Current == '[' || *Current == ']' || *Current == '{' || *Current == '}' || *Current == ',' @@ -1423,7 +1499,7 @@ bool Scanner::scanAliasOrAnchor(bool IsAlias) { ++Column; } - if (Start == Current) { + if (Start + 1 == Current) { setError("Got empty alias or anchor", Start); return false; } @@ -1775,12 +1851,13 @@ Stream::~Stream() = default; bool Stream::failed() { return scanner->failed(); } -void Stream::printError(Node *N, const Twine &Msg) { - SMRange Range = N ? N->getSourceRange() : SMRange(); - scanner->printError( Range.Start - , SourceMgr::DK_Error - , Msg - , Range); +void Stream::printError(Node *N, const Twine &Msg, SourceMgr::DiagKind Kind) { + printError(N ? N->getSourceRange() : SMRange(), Msg, Kind); +} + +void Stream::printError(const SMRange &Range, const Twine &Msg, + SourceMgr::DiagKind Kind) { + scanner->printError(Range.Start, Kind, Msg, Range); } document_iterator Stream::begin() { @@ -1899,11 +1976,11 @@ StringRef ScalarNode::getValue(SmallVectorImpl<char> &Storage) const { Storage.reserve(UnquotedValue.size()); for (; i != StringRef::npos; i = UnquotedValue.find('\'')) { StringRef Valid(UnquotedValue.begin(), i); - Storage.insert(Storage.end(), Valid.begin(), Valid.end()); + llvm::append_range(Storage, Valid); Storage.push_back('\''); UnquotedValue = UnquotedValue.substr(i + 2); } - Storage.insert(Storage.end(), UnquotedValue.begin(), UnquotedValue.end()); + llvm::append_range(Storage, UnquotedValue); return StringRef(Storage.begin(), Storage.size()); } return UnquotedValue; @@ -1922,7 +1999,7 @@ StringRef ScalarNode::unescapeDoubleQuoted( StringRef UnquotedValue for (; i != StringRef::npos; i = UnquotedValue.find_first_of("\\\r\n")) { // Insert all previous chars into Storage. StringRef Valid(UnquotedValue.begin(), i); - Storage.insert(Storage.end(), Valid.begin(), Valid.end()); + llvm::append_range(Storage, Valid); // Chop off inserted chars. UnquotedValue = UnquotedValue.substr(i); @@ -2054,7 +2131,7 @@ StringRef ScalarNode::unescapeDoubleQuoted( StringRef UnquotedValue UnquotedValue = UnquotedValue.substr(1); } } - Storage.insert(Storage.end(), UnquotedValue.begin(), UnquotedValue.end()); + llvm::append_range(Storage, UnquotedValue); return StringRef(Storage.begin(), Storage.size()); } diff --git a/contrib/llvm-project/llvm/lib/Support/YAMLTraits.cpp b/contrib/llvm-project/llvm/lib/Support/YAMLTraits.cpp index 9ac7c65e19f7..aa6163a76161 100644 --- a/contrib/llvm-project/llvm/lib/Support/YAMLTraits.cpp +++ b/contrib/llvm-project/llvm/lib/Support/YAMLTraits.cpp @@ -48,6 +48,10 @@ void IO::setContext(void *Context) { Ctxt = Context; } +void IO::setAllowUnknownKeys(bool Allow) { + llvm_unreachable("Only supported for Input"); +} + //===----------------------------------------------------------------------===// // Input //===----------------------------------------------------------------------===// @@ -171,7 +175,7 @@ bool Input::preflightKey(const char *Key, bool Required, bool, bool &UseDefault, return false; } MN->ValidKeys.push_back(Key); - HNode *Value = MN->Mapping[Key].get(); + HNode *Value = MN->Mapping[Key].first.get(); if (!Value) { if (Required) setError(CurrentNode, Twine("missing required key '") + Key + "'"); @@ -197,8 +201,12 @@ void Input::endMapping() { return; for (const auto &NN : MN->Mapping) { if (!is_contained(MN->ValidKeys, NN.first())) { - setError(NN.second.get(), Twine("unknown key '") + NN.first() + "'"); - break; + const SMRange &ReportLoc = NN.second.second; + if (!AllowUnknownKeys) { + setError(ReportLoc, Twine("unknown key '") + NN.first() + "'"); + break; + } else + reportWarning(ReportLoc, Twine("unknown key '") + NN.first() + "'"); } } } @@ -370,6 +378,24 @@ void Input::setError(Node *node, const Twine &message) { EC = make_error_code(errc::invalid_argument); } +void Input::setError(const SMRange &range, const Twine &message) { + Strm->printError(range, message); + EC = make_error_code(errc::invalid_argument); +} + +void Input::reportWarning(HNode *hnode, const Twine &message) { + assert(hnode && "HNode must not be NULL"); + Strm->printError(hnode->_node, message, SourceMgr::DK_Warning); +} + +void Input::reportWarning(Node *node, const Twine &message) { + Strm->printError(node, message, SourceMgr::DK_Warning); +} + +void Input::reportWarning(const SMRange &range, const Twine &message) { + Strm->printError(range, message, SourceMgr::DK_Warning); +} + std::unique_ptr<Input::HNode> Input::createHNodes(Node *N) { SmallString<128> StringStorage; if (ScalarNode *SN = dyn_cast<ScalarNode>(N)) { @@ -413,7 +439,8 @@ std::unique_ptr<Input::HNode> Input::createHNodes(Node *N) { auto ValueHNode = createHNodes(Value); if (EC) break; - mapHNode->Mapping[KeyStr] = std::move(ValueHNode); + mapHNode->Mapping[KeyStr] = + std::make_pair(std::move(ValueHNode), KeyNode->getSourceRange()); } return std::move(mapHNode); } else if (isa<NullNode>(N)) { @@ -428,6 +455,8 @@ void Input::setError(const Twine &Message) { setError(CurrentNode, Message); } +void Input::setAllowUnknownKeys(bool Allow) { AllowUnknownKeys = Allow; } + bool Input::canElideEmptySequence() { return false; } @@ -563,7 +592,7 @@ void Output::endSequence() { // If we did not emit anything, we should explicitly emit an empty sequence if (StateStack.back() == inSeqFirstElement) { Padding = PaddingBeforeContainer; - newLineCheck(); + newLineCheck(/*EmptySequence=*/true); output("[]"); Padding = "\n"; } @@ -769,7 +798,7 @@ void Output::outputNewLine() { // if seq in middle, use "- " if firstKey, else use " " // -void Output::newLineCheck() { +void Output::newLineCheck(bool EmptySequence) { if (Padding != "\n") { output(Padding); Padding = {}; @@ -778,7 +807,7 @@ void Output::newLineCheck() { outputNewLine(); Padding = {}; - if (StateStack.size() == 0) + if (StateStack.size() == 0 || EmptySequence) return; unsigned Indent = StateStack.size() - 1; @@ -802,7 +831,6 @@ void Output::newLineCheck() { if (OutputDash) { output("- "); } - } void Output::paddedKey(StringRef key) { @@ -856,11 +884,8 @@ void ScalarTraits<bool>::output(const bool &Val, void *, raw_ostream &Out) { } StringRef ScalarTraits<bool>::input(StringRef Scalar, void *, bool &Val) { - if (Scalar.equals("true")) { - Val = true; - return StringRef(); - } else if (Scalar.equals("false")) { - Val = false; + if (llvm::Optional<bool> Parsed = parseBool(Scalar)) { + Val = *Parsed; return StringRef(); } return "invalid boolean"; @@ -1031,8 +1056,7 @@ StringRef ScalarTraits<float>::input(StringRef Scalar, void *, float &Val) { } void ScalarTraits<Hex8>::output(const Hex8 &Val, void *, raw_ostream &Out) { - uint8_t Num = Val; - Out << format("0x%02X", Num); + Out << format("0x%" PRIX8, (uint8_t)Val); } StringRef ScalarTraits<Hex8>::input(StringRef Scalar, void *, Hex8 &Val) { @@ -1046,8 +1070,7 @@ StringRef ScalarTraits<Hex8>::input(StringRef Scalar, void *, Hex8 &Val) { } void ScalarTraits<Hex16>::output(const Hex16 &Val, void *, raw_ostream &Out) { - uint16_t Num = Val; - Out << format("0x%04X", Num); + Out << format("0x%" PRIX16, (uint16_t)Val); } StringRef ScalarTraits<Hex16>::input(StringRef Scalar, void *, Hex16 &Val) { @@ -1061,8 +1084,7 @@ StringRef ScalarTraits<Hex16>::input(StringRef Scalar, void *, Hex16 &Val) { } void ScalarTraits<Hex32>::output(const Hex32 &Val, void *, raw_ostream &Out) { - uint32_t Num = Val; - Out << format("0x%08X", Num); + Out << format("0x%" PRIX32, (uint32_t)Val); } StringRef ScalarTraits<Hex32>::input(StringRef Scalar, void *, Hex32 &Val) { @@ -1076,8 +1098,7 @@ StringRef ScalarTraits<Hex32>::input(StringRef Scalar, void *, Hex32 &Val) { } void ScalarTraits<Hex64>::output(const Hex64 &Val, void *, raw_ostream &Out) { - uint64_t Num = Val; - Out << format("0x%016llX", Num); + Out << format("0x%" PRIX64, (uint64_t)Val); } StringRef ScalarTraits<Hex64>::input(StringRef Scalar, void *, Hex64 &Val) { @@ -1087,3 +1108,15 @@ StringRef ScalarTraits<Hex64>::input(StringRef Scalar, void *, Hex64 &Val) { Val = Num; return StringRef(); } + +void ScalarTraits<VersionTuple>::output(const VersionTuple &Val, void *, + llvm::raw_ostream &Out) { + Out << Val.getAsString(); +} + +StringRef ScalarTraits<VersionTuple>::input(StringRef Scalar, void *, + VersionTuple &Val) { + if (Val.tryParse(Scalar)) + return "invalid version format"; + return StringRef(); +} diff --git a/contrib/llvm-project/llvm/lib/Support/raw_ostream.cpp b/contrib/llvm-project/llvm/lib/Support/raw_ostream.cpp index f2d78d773239..8f10d136bc38 100644 --- a/contrib/llvm-project/llvm/lib/Support/raw_ostream.cpp +++ b/contrib/llvm-project/llvm/lib/Support/raw_ostream.cpp @@ -12,7 +12,6 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" @@ -30,7 +29,6 @@ #include <cstdio> #include <iterator> #include <sys/stat.h> -#include <system_error> // <fcntl.h> may provide O_BINARY. #if defined(HAVE_FCNTL_H) @@ -620,8 +618,9 @@ raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC, /// FD is the file descriptor that this writes to. If ShouldClose is true, this /// closes the file when the stream is destroyed. -raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered) - : raw_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose) { +raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered, + OStreamKind K) + : raw_pwrite_stream(unbuffered, K), FD(fd), ShouldClose(shouldClose) { if (FD < 0 ) { ShouldClose = false; return; @@ -858,7 +857,24 @@ bool raw_fd_ostream::is_displayed() const { } bool raw_fd_ostream::has_colors() const { - return sys::Process::FileDescriptorHasColors(FD); + if (!HasColors) + HasColors = sys::Process::FileDescriptorHasColors(FD); + return *HasColors; +} + +Expected<sys::fs::FileLocker> raw_fd_ostream::lock() { + std::error_code EC = sys::fs::lockFile(FD); + if (!EC) + return sys::fs::FileLocker(FD); + return errorCodeToError(EC); +} + +Expected<sys::fs::FileLocker> +raw_fd_ostream::tryLockFor(std::chrono::milliseconds Timeout) { + std::error_code EC = sys::fs::tryLockFile(FD, Timeout); + if (!EC) + return sys::fs::FileLocker(FD); + return errorCodeToError(EC); } void raw_fd_ostream::anchor() {} @@ -888,6 +904,37 @@ raw_ostream &llvm::nulls() { } //===----------------------------------------------------------------------===// +// File Streams +//===----------------------------------------------------------------------===// + +raw_fd_stream::raw_fd_stream(StringRef Filename, std::error_code &EC) + : raw_fd_ostream(getFD(Filename, EC, sys::fs::CD_CreateAlways, + sys::fs::FA_Write | sys::fs::FA_Read, + sys::fs::OF_None), + true, false, OStreamKind::OK_FDStream) { + if (EC) + return; + + // Do not support non-seekable files. + if (!supportsSeeking()) + EC = std::make_error_code(std::errc::invalid_argument); +} + +ssize_t raw_fd_stream::read(char *Ptr, size_t Size) { + assert(get_fd() >= 0 && "File already closed."); + ssize_t Ret = ::read(get_fd(), (void *)Ptr, Size); + if (Ret >= 0) + inc_pos(Ret); + else + error_detected(std::error_code(errno, std::generic_category())); + return Ret; +} + +bool raw_fd_stream::classof(const raw_ostream *OS) { + return OS->get_kind() == OStreamKind::OK_FDStream; +} + +//===----------------------------------------------------------------------===// // raw_string_ostream //===----------------------------------------------------------------------===// @@ -940,3 +987,5 @@ void raw_null_ostream::pwrite_impl(const char *Ptr, size_t Size, void raw_pwrite_stream::anchor() {} void buffer_ostream::anchor() {} + +void buffer_unique_ostream::anchor() {} |