aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Support
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Support')
-rw-r--r--contrib/llvm-project/llvm/lib/Support/AArch64TargetParser.cpp16
-rw-r--r--contrib/llvm-project/llvm/lib/Support/AMDGPUMetadata.cpp3
-rw-r--r--contrib/llvm-project/llvm/lib/Support/APFixedPoint.cpp574
-rw-r--r--contrib/llvm-project/llvm/lib/Support/APFloat.cpp108
-rw-r--r--contrib/llvm-project/llvm/lib/Support/APInt.cpp17
-rw-r--r--contrib/llvm-project/llvm/lib/Support/ARMAttributeParser.cpp2
-rw-r--r--contrib/llvm-project/llvm/lib/Support/ARMTargetParser.cpp33
-rw-r--r--contrib/llvm-project/llvm/lib/Support/CRC.cpp2
-rw-r--r--contrib/llvm-project/llvm/lib/Support/CachePruning.cpp5
-rw-r--r--contrib/llvm-project/llvm/lib/Support/CommandLine.cpp70
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Compression.cpp4
-rw-r--r--contrib/llvm-project/llvm/lib/Support/ConvertUTFWrapper.cpp2
-rw-r--r--contrib/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp39
-rw-r--r--contrib/llvm-project/llvm/lib/Support/DebugCounter.cpp2
-rw-r--r--contrib/llvm-project/llvm/lib/Support/DynamicLibrary.cpp4
-rw-r--r--contrib/llvm-project/llvm/lib/Support/ELFAttributeParser.cpp2
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Error.cpp4
-rw-r--r--contrib/llvm-project/llvm/lib/Support/ErrorHandling.cpp11
-rw-r--r--contrib/llvm-project/llvm/lib/Support/FileCheck.cpp2580
-rw-r--r--contrib/llvm-project/llvm/lib/Support/FileCheckImpl.h832
-rw-r--r--contrib/llvm-project/llvm/lib/Support/FileCollector.cpp128
-rw-r--r--contrib/llvm-project/llvm/lib/Support/FormatVariadic.cpp23
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Host.cpp230
-rw-r--r--contrib/llvm-project/llvm/lib/Support/InitLLVM.cpp11
-rw-r--r--contrib/llvm-project/llvm/lib/Support/InstructionCost.cpp24
-rw-r--r--contrib/llvm-project/llvm/lib/Support/JSON.cpp219
-rw-r--r--contrib/llvm-project/llvm/lib/Support/KnownBits.cpp397
-rw-r--r--contrib/llvm-project/llvm/lib/Support/LineIterator.cpp8
-rw-r--r--contrib/llvm-project/llvm/lib/Support/LowLevelType.cpp2
-rw-r--r--contrib/llvm-project/llvm/lib/Support/MemoryBufferRef.cpp19
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Path.cpp52
-rw-r--r--contrib/llvm-project/llvm/lib/Support/PrettyStackTrace.cpp13
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Process.cpp21
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Program.cpp14
-rw-r--r--contrib/llvm-project/llvm/lib/Support/SHA1.cpp2
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Signals.cpp9
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Signposts.cpp41
-rw-r--r--contrib/llvm-project/llvm/lib/Support/SmallVector.cpp68
-rw-r--r--contrib/llvm-project/llvm/lib/Support/SourceMgr.cpp56
-rw-r--r--contrib/llvm-project/llvm/lib/Support/TargetParser.cpp111
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Timer.cpp14
-rw-r--r--contrib/llvm-project/llvm/lib/Support/TrigramIndex.cpp7
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Triple.cpp98
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Unicode.cpp11
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Unix/Path.inc76
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Unix/Process.inc6
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Unix/Program.inc6
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Unix/Signals.inc29
-rw-r--r--contrib/llvm-project/llvm/lib/Support/VirtualFileSystem.cpp158
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Windows/Path.inc37
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Windows/Process.inc3
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Windows/Program.inc59
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Windows/Signals.inc5
-rw-r--r--contrib/llvm-project/llvm/lib/Support/Windows/Threading.inc25
-rw-r--r--contrib/llvm-project/llvm/lib/Support/X86TargetParser.cpp372
-rw-r--r--contrib/llvm-project/llvm/lib/Support/YAMLParser.cpp155
-rw-r--r--contrib/llvm-project/llvm/lib/Support/YAMLTraits.cpp75
-rw-r--r--contrib/llvm-project/llvm/lib/Support/raw_ostream.cpp59
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() {}